hermez-node/db/statedb/txprocessors.go
db/statedb/txprocessors.goRaw
1package statedb
2
3import (
4 "bytes"
5 "errors"
6 "math/big"
7
8 "github.com/hermeznetwork/hermez-node/common"
9 "github.com/hermeznetwork/hermez-node/log"
10 "github.com/iden3/go-iden3-crypto/babyjub"
11 "github.com/iden3/go-merkletree"
12 "github.com/iden3/go-merkletree/db"
13 "github.com/iden3/go-merkletree/db/memory"
14)
15
16var (
17 // keyidx is used as key in the db to store the current Idx
18 keyidx = []byte("idx")
19)
20
21func (s *StateDB) resetZKInputs() {
22 s.zki = nil
23 s.i = 0
24}
25
26type processedExit struct {
27 exit bool
28 newExit bool
29 idx common.Idx
30 acc common.Account
31}
32
33// ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
34// the StateDB depending on the transaction Type. Returns the common.ZKInputs
35// to generate the SnarkProof later used by the BatchBuilder, and if
36// cmpExitTree is set to true, returns common.ExitTreeLeaf that is later used
37// by the Synchronizer to update the HistoryDB.
38func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.PoolL2Tx) (*common.ZKInputs, []*common.ExitInfo, error) {
39 var err error
40 var exitTree *merkletree.MerkleTree
41
42 if s.zki != nil {
43 return nil, nil, errors.New("Expected StateDB.zki==nil, something went wrong and it's not empty")
44 }
45 defer s.resetZKInputs()
46
47 nTx := len(l1usertxs) + len(l1coordinatortxs) + len(l2txs)
48 if nTx == 0 {
49 // TODO return ZKInputs of batch without txs
50 return nil, nil, nil
51 }
52 exits := make([]processedExit, nTx)
53
54 if cmpZKInputs {
55 s.zki = common.NewZKInputs(nTx, 24, 32) // TODO this values will be parameters of the function, taken from config file/coordinator call
56 s.zki.OldLastIdx = (s.idx - 1).BigInt()
57 s.zki.OldStateRoot = s.mt.Root().BigInt()
58 }
59
60 // TBD if ExitTree is only in memory or stored in disk, for the moment
61 // only needed in memory
62 if cmpExitTree {
63 exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels())
64 if err != nil {
65 return nil, nil, err
66 }
67 }
68
69 // assumption: l1usertx are sorted by L1Tx.Position
70 for _, tx := range l1usertxs {
71 exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, tx)
72 if err != nil {
73 return nil, nil, err
74 }
75 if exitIdx != nil && cmpExitTree {
76 exits[s.i] = processedExit{
77 exit: true,
78 newExit: newExit,
79 idx: *exitIdx,
80 acc: *exitAccount,
81 }
82 }
83 if s.zki != nil {
84 s.i++
85 }
86 }
87 for _, tx := range l1coordinatortxs {
88 exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, tx)
89 if err != nil {
90 return nil, nil, err
91 }
92 if exitIdx != nil {
93 log.Error("Unexpected Exit in L1CoordinatorTx")
94 }
95 if exitIdx != nil && cmpExitTree {
96 exits[s.i] = processedExit{
97 exit: true,
98 newExit: newExit,
99 idx: *exitIdx,
100 acc: *exitAccount,
101 }
102 }
103 if s.zki != nil {
104 s.i++
105 }
106 }
107 for _, tx := range l2txs {
108 exitIdx, exitAccount, newExit, err := s.processL2Tx(exitTree, tx)
109 if err != nil {
110 return nil, nil, err
111 }
112 if exitIdx != nil && cmpExitTree {
113 exits[s.i] = processedExit{
114 exit: true,
115 newExit: newExit,
116 idx: *exitIdx,
117 acc: *exitAccount,
118 }
119 }
120 if s.zki != nil {
121 s.i++
122 }
123 }
124
125 if !cmpExitTree && !cmpZKInputs {
126 return nil, nil, nil
127 }
128
129 // once all txs processed (exitTree root frozen), for each Exit,
130 // generate common.ExitInfo data
131 var exitInfos []*common.ExitInfo
132 for i := 0; i < nTx; i++ {
133 if !exits[i].exit {
134 continue
135 }
136 exitIdx := exits[i].idx
137 exitAccount := exits[i].acc
138
139 // 0. generate MerkleProof
140 p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil)
141 if err != nil {
142 return nil, nil, err
143 }
144 // 1. generate common.ExitInfo
145 ei := &common.ExitInfo{
146 AccountIdx: exitIdx,
147 MerkleProof: p,
148 Balance: exitAccount.Balance,
149 }
150 exitInfos = append(exitInfos, ei)
151
152 if s.zki != nil {
153 s.zki.TokenID2[i] = exitAccount.TokenID.BigInt()
154 s.zki.Nonce2[i] = exitAccount.Nonce.BigInt()
155 if babyjub.PointCoordSign(exitAccount.PublicKey.X) {
156 s.zki.Sign2[i] = big.NewInt(1)
157 }
158 s.zki.Ay2[i] = exitAccount.PublicKey.Y
159 s.zki.Balance2[i] = exitAccount.Balance
160 s.zki.EthAddr2[i] = common.EthAddrToBigInt(exitAccount.EthAddr)
161 s.zki.Siblings2[i] = p.Siblings
162 if exits[i].newExit {
163 s.zki.NewExit[i] = big.NewInt(1)
164 }
165 if p.IsOld0 {
166 s.zki.IsOld0_2[i] = big.NewInt(1)
167 }
168 s.zki.OldKey2[i] = p.OldKey.BigInt()
169 s.zki.OldValue2[i] = p.OldValue.BigInt()
170 }
171 }
172 if !cmpZKInputs {
173 return nil, exitInfos, nil
174 }
175
176 // compute last ZKInputs parameters
177 s.zki.GlobalChainID = big.NewInt(0) // TODO, 0: ethereum, this will be get from config file
178 // zki.FeeIdxs = ? // TODO, this will be get from the config file
179 tokenIDs, err := s.getTokenIDsBigInt(l1usertxs, l1coordinatortxs, l2txs)
180 if err != nil {
181 return nil, nil, err
182 }
183 s.zki.FeePlanTokens = tokenIDs
184
185 // s.zki.ISInitStateRootFee = s.mt.Root().BigInt()
186
187 // TODO once the Node Config sets the Accounts where to send the Fees
188 // compute fees & update ZKInputs
189
190 // return exitInfos, so Synchronizer will be able to store it into
191 // HistoryDB for the concrete BatchNum
192 return s.zki, exitInfos, nil
193}
194
195// getTokenIDsBigInt returns the list of TokenIDs in *big.Int format
196func (s *StateDB) getTokenIDsBigInt(l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.PoolL2Tx) ([]*big.Int, error) {
197 tokenIDs := make(map[common.TokenID]bool)
198 for i := 0; i < len(l1usertxs); i++ {
199 tokenIDs[l1usertxs[i].TokenID] = true
200 }
201 for i := 0; i < len(l1coordinatortxs); i++ {
202 tokenIDs[l1coordinatortxs[i].TokenID] = true
203 }
204 for i := 0; i < len(l2txs); i++ {
205 // as L2Tx does not have parameter TokenID, get it from the
206 // AccountsDB (in the StateDB)
207 acc, err := s.GetAccount(l2txs[i].ToIdx)
208 if err != nil {
209 return nil, err
210 }
211 tokenIDs[acc.TokenID] = true
212 }
213 var tBI []*big.Int
214 for t := range tokenIDs {
215 tBI = append(tBI, t.BigInt())
216 }
217 return tBI, nil
218}
219
220// processL1Tx process the given L1Tx applying the needed updates to the
221// StateDB depending on the transaction Type. It returns the 3 parameters
222// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
223// the Exit created a new Leaf in the ExitTree.
224func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, bool, error) {
225 // ZKInputs
226 if s.zki != nil {
227 // Txs
228 // s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
229 s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
230 s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
231 s.zki.OnChain[s.i] = big.NewInt(1)
232
233 // L1Txs
234 s.zki.LoadAmountF[s.i] = tx.LoadAmount
235 s.zki.FromEthAddr[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
236 if tx.FromBJJ != nil {
237 s.zki.FromBJJCompressed[s.i] = BJJCompressedTo256BigInts(tx.FromBJJ.Compress())
238 }
239
240 // Intermediate States
241 s.zki.ISOnChain[s.i] = big.NewInt(1)
242 }
243
244 switch tx.Type {
245 case common.TxTypeForceTransfer, common.TxTypeTransfer:
246 // go to the MT account of sender and receiver, and update balance
247 // & nonce
248 err := s.applyTransfer(tx.Tx())
249 if err != nil {
250 return nil, nil, false, err
251 }
252 case common.TxTypeCreateAccountDeposit:
253 // add new account to the MT, update balance of the MT account
254 err := s.applyCreateAccount(tx)
255 if err != nil {
256 return nil, nil, false, err
257 }
258
259 if s.zki != nil {
260 s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
261 s.zki.NewAccount[s.i] = big.NewInt(1)
262 }
263 case common.TxTypeDeposit:
264 // update balance of the MT account
265 err := s.applyDeposit(tx, false)
266 if err != nil {
267 return nil, nil, false, err
268 }
269 case common.TxTypeDepositTransfer:
270 // update balance in MT account, update balance & nonce of sender
271 // & receiver
272 err := s.applyDeposit(tx, true)
273 if err != nil {
274 return nil, nil, false, err
275 }
276 case common.TxTypeCreateAccountDepositTransfer:
277 // add new account to the merkletree, update balance in MT account,
278 // update balance & nonce of sender & receiver
279 err := s.applyCreateAccountDepositTransfer(tx)
280 if err != nil {
281 return nil, nil, false, err
282 }
283
284 if s.zki != nil {
285 s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
286 s.zki.NewAccount[s.i] = big.NewInt(1)
287 }
288 case common.TxTypeExit:
289 // execute exit flow
290 exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
291 if err != nil {
292 return nil, nil, false, err
293 }
294 return &tx.FromIdx, exitAccount, newExit, nil
295 default:
296 }
297
298 return nil, nil, false, nil
299}
300
301// processL2Tx process the given L2Tx applying the needed updates to the
302// StateDB depending on the transaction Type. It returns the 3 parameters
303// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
304// the Exit created a new Leaf in the ExitTree.
305func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) {
306 var err error
307 // ZKInputs
308 if s.zki != nil {
309 // Txs
310 // s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
311 // s.zki.TxCompressedDataV2[s.i] = tx.TxCompressedDataV2() // uncomment once L2Tx.TxCompressedDataV2 is ready
312 s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
313 s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
314
315 // fill AuxToIdx if needed
316 if tx.ToIdx == common.Idx(0) {
317 var idx common.Idx
318 if !bytes.Equal(tx.ToEthAddr.Bytes(), common.EmptyAddr.Bytes()) && tx.ToBJJ == nil {
319 // case ToEthAddr!=0 && ToBJJ=0
320 idx, err = s.GetIdxByEthAddr(tx.ToEthAddr)
321 if err != nil {
322 return nil, nil, false, ErrToIdxNotFound
323 }
324 } else if !bytes.Equal(tx.ToEthAddr.Bytes(), common.EmptyAddr.Bytes()) && tx.ToBJJ != nil {
325 // case ToEthAddr!=0 && ToBJJ!=0
326 idx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ)
327 if err != nil {
328 return nil, nil, false, ErrToIdxNotFound
329 }
330 } else {
331 // rest of cases (included case ToEthAddr==0) are not possible
332 return nil, nil, false, ErrToIdxNotFound
333 }
334 s.zki.AuxToIdx[s.i] = idx.BigInt()
335 }
336 s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
337 s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
338
339 s.zki.OnChain[s.i] = big.NewInt(0)
340 s.zki.NewAccount[s.i] = big.NewInt(0)
341
342 // L2Txs
343 // s.zki.RqOffset[s.i] = // TODO Rq once TxSelector is ready
344 // s.zki.RqTxCompressedDataV2[s.i] = // TODO
345 // s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
346 // s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO
347 s.zki.S[s.i] = tx.Signature.S
348 s.zki.R8x[s.i] = tx.Signature.R8.X
349 s.zki.R8y[s.i] = tx.Signature.R8.Y
350 }
351
352 switch tx.Type {
353 case common.TxTypeTransfer:
354 // go to the MT account of sender and receiver, and update
355 // balance & nonce
356 err = s.applyTransfer(tx.Tx())
357 if err != nil {
358 return nil, nil, false, err
359 }
360 case common.TxTypeExit:
361 // execute exit flow
362 exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
363 if err != nil {
364 return nil, nil, false, err
365 }
366 return &tx.FromIdx, exitAccount, newExit, nil
367 default:
368 }
369 return nil, nil, false, nil
370}
371
372// applyCreateAccount creates a new account in the account of the depositer, it
373// stores the deposit value
374func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
375 account := &common.Account{
376 TokenID: tx.TokenID,
377 Nonce: 0,
378 Balance: tx.LoadAmount,
379 PublicKey: tx.FromBJJ,
380 EthAddr: tx.FromEthAddr,
381 }
382
383 p, err := s.CreateAccount(common.Idx(s.idx+1), account)
384 if err != nil {
385 return err
386 }
387 if s.zki != nil {
388 s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
389 s.zki.Nonce1[s.i] = big.NewInt(0)
390 if babyjub.PointCoordSign(tx.FromBJJ.X) {
391 s.zki.Sign1[s.i] = big.NewInt(1)
392 }
393 s.zki.Ay1[s.i] = tx.FromBJJ.Y
394 s.zki.Balance1[s.i] = tx.LoadAmount
395 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
396 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
397 if p.IsOld0 {
398 s.zki.IsOld0_1[s.i] = big.NewInt(1)
399 }
400 s.zki.OldKey1[s.i] = p.OldKey.BigInt()
401 s.zki.OldValue1[s.i] = p.OldValue.BigInt()
402 }
403
404 s.idx = s.idx + 1
405 return s.setIdx(s.idx)
406}
407
408// applyDeposit updates the balance in the account of the depositer, if
409// andTransfer parameter is set to true, the method will also apply the
410// Transfer of the L1Tx/DepositTransfer
411func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
412 // deposit the tx.LoadAmount into the sender account
413 accSender, err := s.GetAccount(tx.FromIdx)
414 if err != nil {
415 return err
416 }
417 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
418
419 // in case that the tx is a L1Tx>DepositTransfer
420 var accReceiver *common.Account
421 if transfer {
422 accReceiver, err = s.GetAccount(tx.ToIdx)
423 if err != nil {
424 return err
425 }
426 // subtract amount to the sender
427 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
428 // add amount to the receiver
429 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
430 }
431 // update sender account in localStateDB
432 p, err := s.UpdateAccount(tx.FromIdx, accSender)
433 if err != nil {
434 return err
435 }
436 if s.zki != nil {
437 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
438 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
439 if babyjub.PointCoordSign(accSender.PublicKey.X) {
440 s.zki.Sign1[s.i] = big.NewInt(1)
441 }
442 s.zki.Ay1[s.i] = accSender.PublicKey.Y
443 s.zki.Balance1[s.i] = accSender.Balance
444 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
445 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
446 // IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
447 }
448
449 // this is done after updating Sender Account (depositer)
450 if transfer {
451 // update receiver account in localStateDB
452 p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
453 if err != nil {
454 return err
455 }
456 if s.zki != nil {
457 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
458 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
459 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
460 s.zki.Sign2[s.i] = big.NewInt(1)
461 }
462 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
463 s.zki.Balance2[s.i] = accReceiver.Balance
464 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
465 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
466 // IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
467 }
468 }
469
470 return nil
471}
472
473// applyTransfer updates the balance & nonce in the account of the sender, and
474// the balance in the account of the receiver
475func (s *StateDB) applyTransfer(tx *common.Tx) error {
476 // get sender and receiver accounts from localStateDB
477 accSender, err := s.GetAccount(tx.FromIdx)
478 if err != nil {
479 return err
480 }
481 accReceiver, err := s.GetAccount(tx.ToIdx)
482 if err != nil {
483 return err
484 }
485
486 // increment nonce
487 accSender.Nonce++
488
489 // subtract amount to the sender
490 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
491 // add amount to the receiver
492 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
493
494 // update sender account in localStateDB
495 pSender, err := s.UpdateAccount(tx.FromIdx, accSender)
496 if err != nil {
497 return err
498 }
499 if s.zki != nil {
500 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
501 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
502 if babyjub.PointCoordSign(accSender.PublicKey.X) {
503 s.zki.Sign1[s.i] = big.NewInt(1)
504 }
505 s.zki.Ay1[s.i] = accSender.PublicKey.Y
506 s.zki.Balance1[s.i] = accSender.Balance
507 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
508 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings)
509 }
510
511 // update receiver account in localStateDB
512 pReceiver, err := s.UpdateAccount(tx.ToIdx, accReceiver)
513 if err != nil {
514 return err
515 }
516 if s.zki != nil {
517 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
518 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
519 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
520 s.zki.Sign2[s.i] = big.NewInt(1)
521 }
522 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
523 s.zki.Balance2[s.i] = accReceiver.Balance
524 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
525 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings)
526 }
527
528 return nil
529}
530
531// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
532// makes a deposit, and performs a transfer to another account
533func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
534 accSender := &common.Account{
535 TokenID: tx.TokenID,
536 Nonce: 0,
537 Balance: tx.LoadAmount,
538 PublicKey: tx.FromBJJ,
539 EthAddr: tx.FromEthAddr,
540 }
541 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
542 accReceiver, err := s.GetAccount(tx.ToIdx)
543 if err != nil {
544 return err
545 }
546 // subtract amount to the sender
547 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
548 // add amount to the receiver
549 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
550
551 // create Account of the Sender
552 p, err := s.CreateAccount(common.Idx(s.idx+1), accSender)
553 if err != nil {
554 return err
555 }
556 if s.zki != nil {
557 s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
558 s.zki.Nonce1[s.i] = big.NewInt(0)
559 if babyjub.PointCoordSign(tx.FromBJJ.X) {
560 s.zki.Sign1[s.i] = big.NewInt(1)
561 }
562 s.zki.Ay1[s.i] = tx.FromBJJ.Y
563 s.zki.Balance1[s.i] = tx.LoadAmount
564 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
565 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
566 if p.IsOld0 {
567 s.zki.IsOld0_1[s.i] = big.NewInt(1)
568 }
569 s.zki.OldKey1[s.i] = p.OldKey.BigInt()
570 s.zki.OldValue1[s.i] = p.OldValue.BigInt()
571 }
572
573 // update receiver account in localStateDB
574 p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
575 if err != nil {
576 return err
577 }
578 if s.zki != nil {
579 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
580 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
581 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
582 s.zki.Sign2[s.i] = big.NewInt(1)
583 }
584 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
585 s.zki.Balance2[s.i] = accReceiver.Balance
586 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
587 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
588 }
589
590 s.idx = s.idx + 1
591 return s.setIdx(s.idx)
592}
593
594// It returns the ExitAccount and a boolean determining if the Exit created a
595// new Leaf in the ExitTree.
596func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx *common.Tx) (*common.Account, bool, error) {
597 // 0. subtract tx.Amount from current Account in StateMT
598 // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
599 acc, err := s.GetAccount(tx.FromIdx)
600 if err != nil {
601 return nil, false, err
602 }
603 acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
604 p, err := s.UpdateAccount(tx.FromIdx, acc)
605 if err != nil {
606 return nil, false, err
607 }
608 if s.zki != nil {
609 s.zki.TokenID1[s.i] = acc.TokenID.BigInt()
610 s.zki.Nonce1[s.i] = acc.Nonce.BigInt()
611 if babyjub.PointCoordSign(acc.PublicKey.X) {
612 s.zki.Sign1[s.i] = big.NewInt(1)
613 }
614 s.zki.Ay1[s.i] = acc.PublicKey.Y
615 s.zki.Balance1[s.i] = acc.Balance
616 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(acc.EthAddr)
617 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
618 }
619
620 if exitTree == nil {
621 return nil, false, nil
622 }
623 exitAccount, err := getAccountInTreeDB(exitTree.DB(), tx.FromIdx)
624 if err == db.ErrNotFound {
625 // 1a. if idx does not exist in exitTree:
626 // add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance = exitAmount (exitAmount=tx.Amount)
627 exitAccount := &common.Account{
628 TokenID: acc.TokenID,
629 Nonce: common.Nonce(1),
630 Balance: tx.Amount,
631 PublicKey: acc.PublicKey,
632 EthAddr: acc.EthAddr,
633 }
634 _, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
635 return exitAccount, true, err
636 } else if err != nil {
637 return exitAccount, false, err
638 }
639
640 // 1b. if idx already exist in exitTree:
641 // update account, where account.Balance += exitAmount
642 exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
643 _, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
644 return exitAccount, false, err
645}
646
647// getIdx returns the stored Idx from the localStateDB, which is the last Idx
648// used for an Account in the localStateDB.
649func (s *StateDB) getIdx() (common.Idx, error) {
650 idxBytes, err := s.DB().Get(keyidx)
651 if err == db.ErrNotFound {
652 return 0, nil
653 }
654 if err != nil {
655 return 0, err
656 }
657 return common.IdxFromBytes(idxBytes[:4])
658}
659
660// setIdx stores Idx in the localStateDB
661func (s *StateDB) setIdx(idx common.Idx) error {
662 tx, err := s.DB().NewTx()
663 if err != nil {
664 return err
665 }
666 err = tx.Put(keyidx, idx.Bytes())
667 if err != nil {
668 return err
669 }
670 if err := tx.Commit(); err != nil {
671 return err
672 }
673 return nil
674}