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