hermez-node/db/statedb/txprocessors.go
db/statedb/txprocessors.goRaw
1package statedb
2
3import (
4 "encoding/binary"
5 "math/big"
6
7 "github.com/hermeznetwork/hermez-node/common"
8 "github.com/iden3/go-merkletree/db"
9)
10
11// KEYIDX is used as key in the db to store the current Idx
12var KEYIDX = []byte("idx")
13
14// ProcessPoolL2Tx process the given PoolL2Tx applying the needed updates to
15// the StateDB depending on the transaction Type.
16func (s *StateDB) ProcessPoolL2Tx(tx *common.PoolL2Tx) error {
17 switch tx.Type {
18 case common.TxTypeTransfer:
19 // go to the MT account of sender and receiver, and update
20 // balance & nonce
21 err := s.applyTransfer(tx.Tx())
22 if err != nil {
23 return err
24 }
25 case common.TxTypeExit:
26 // execute exit flow
27 default:
28 }
29 return nil
30}
31
32// ProcessL1Tx process the given L1Tx applying the needed updates to the
33// StateDB depending on the transaction Type.
34func (s *StateDB) ProcessL1Tx(tx *common.L1Tx) error {
35 switch tx.Type {
36 case common.TxTypeForceTransfer, common.TxTypeTransfer:
37 // go to the MT account of sender and receiver, and update balance
38 // & nonce
39 err := s.applyTransfer(tx.Tx())
40 if err != nil {
41 return err
42 }
43 case common.TxTypeCreateAccountDeposit:
44 // add new account to the MT, update balance of the MT account
45 err := s.applyCreateAccount(tx)
46 if err != nil {
47 return err
48 }
49 case common.TxTypeDeposit:
50 // update balance of the MT account
51 err := s.applyDeposit(tx, false)
52 if err != nil {
53 return err
54 }
55 case common.TxTypeDepositTransfer:
56 // update balance in MT account, update balance & nonce of sender
57 // & receiver
58 err := s.applyDeposit(tx, true)
59 if err != nil {
60 return err
61 }
62 case common.TxTypeCreateAccountDepositTransfer:
63 // add new account to the merkletree, update balance in MT account,
64 // update balance & nonce of sender & receiver
65 err := s.applyCreateAccount(tx)
66 if err != nil {
67 return err
68 }
69 err = s.applyTransfer(tx.Tx())
70 if err != nil {
71 return err
72 }
73 case common.TxTypeExit:
74 // execute exit flow
75 default:
76 }
77
78 return nil
79}
80
81// applyCreateAccount creates a new account in the account of the depositer, it
82// stores the deposit value
83func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
84 account := &common.Account{
85 TokenID: tx.TokenID,
86 Nonce: 0,
87 Balance: tx.LoadAmount,
88 PublicKey: tx.FromBJJ,
89 EthAddr: tx.FromEthAddr,
90 }
91
92 _, err := s.CreateAccount(common.Idx(s.idx+1), account)
93 if err != nil {
94 return err
95 }
96
97 s.idx = s.idx + 1
98 return s.setIdx(s.idx)
99}
100
101// applyDeposit updates the balance in the account of the depositer, if
102// andTransfer parameter is set to true, the method will also apply the
103// Transfer of the L1Tx/DepositTransfer
104func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
105 // deposit the tx.LoadAmount into the sender account
106 accSender, err := s.GetAccount(tx.FromIdx)
107 if err != nil {
108 return err
109 }
110 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
111
112 // in case that the tx is a L1Tx>DepositTransfer
113 if transfer {
114 accReceiver, err := s.GetAccount(tx.ToIdx)
115 if err != nil {
116 return err
117 }
118 // substract amount to the sender
119 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
120 // add amount to the receiver
121 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
122 // update receiver account in localStateDB
123 _, err = s.UpdateAccount(tx.ToIdx, accReceiver)
124 if err != nil {
125 return err
126 }
127 }
128 // update sender account in localStateDB
129 _, err = s.UpdateAccount(tx.FromIdx, accSender)
130 if err != nil {
131 return err
132 }
133 return nil
134}
135
136// applyTransfer updates the balance & nonce in the account of the sender, and
137// the balance in the account of the receiver
138func (s *StateDB) applyTransfer(tx *common.Tx) error {
139 // get sender and receiver accounts from localStateDB
140 accSender, err := s.GetAccount(tx.FromIdx)
141 if err != nil {
142 return err
143 }
144 accReceiver, err := s.GetAccount(tx.ToIdx)
145 if err != nil {
146 return err
147 }
148
149 // increment nonce
150 accSender.Nonce++
151
152 // substract amount to the sender
153 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
154 // add amount to the receiver
155 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
156
157 // update receiver account in localStateDB
158 _, err = s.UpdateAccount(tx.ToIdx, accReceiver)
159 if err != nil {
160 return err
161 }
162 // update sender account in localStateDB
163 _, err = s.UpdateAccount(tx.FromIdx, accSender)
164 if err != nil {
165 return err
166 }
167
168 return nil
169}
170
171// getIdx returns the stored Idx from the localStateDB, which is the last Idx
172// used for an Account in the localStateDB.
173func (s *StateDB) getIdx() (uint64, error) {
174 idxBytes, err := s.DB().Get(KEYIDX)
175 if err == db.ErrNotFound {
176 return 0, nil
177 }
178 if err != nil {
179 return 0, err
180 }
181 idx := binary.LittleEndian.Uint64(idxBytes[:8])
182 return idx, nil
183}
184
185// setIdx stores Idx in the localStateDB
186func (s *StateDB) setIdx(idx uint64) error {
187 tx, err := s.DB().NewTx()
188 if err != nil {
189 return err
190 }
191 var idxBytes [8]byte
192 binary.LittleEndian.PutUint64(idxBytes[:], idx)
193 tx.Put(KEYIDX, idxBytes[:])
194 if err := tx.Commit(); err != nil {
195 return err
196 }
197 return nil
198}