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 log.Error(err)
323 return nil, nil, false, ErrToIdxNotFound
324 }
325 } else if !bytes.Equal(tx.ToEthAddr.Bytes(), common.EmptyAddr.Bytes()) && tx.ToBJJ != nil {
326 // case ToEthAddr!=0 && ToBJJ!=0
327 idx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ)
328 if err != nil {
329 log.Error(err)
330 return nil, nil, false, ErrToIdxNotFound
331 }
332 } else {
333 // rest of cases (included case ToEthAddr==0) are not possible
334 log.Error(err)
335 return nil, nil, false, ErrToIdxNotFound
336 }
337 s.zki.AuxToIdx[s.i] = idx.BigInt()
338 }
339 s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
340 s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
341
342 s.zki.OnChain[s.i] = big.NewInt(0)
343 s.zki.NewAccount[s.i] = big.NewInt(0)
344
345 // L2Txs
346 // s.zki.RqOffset[s.i] = // TODO Rq once TxSelector is ready
347 // s.zki.RqTxCompressedDataV2[s.i] = // TODO
348 // s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
349 // s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO
350 s.zki.S[s.i] = tx.Signature.S
351 s.zki.R8x[s.i] = tx.Signature.R8.X
352 s.zki.R8y[s.i] = tx.Signature.R8.Y
353 }
354
355 switch tx.Type {
356 case common.TxTypeTransfer:
357 // go to the MT account of sender and receiver, and update
358 // balance & nonce
359 err = s.applyTransfer(tx.Tx())
360 if err != nil {
361 return nil, nil, false, err
362 }
363 case common.TxTypeExit:
364 // execute exit flow
365 exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
366 if err != nil {
367 return nil, nil, false, err
368 }
369 return &tx.FromIdx, exitAccount, newExit, nil
370 default:
371 }
372 return nil, nil, false, nil
373}
374
375// applyCreateAccount creates a new account in the account of the depositer, it
376// stores the deposit value
377func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
378 account := &common.Account{
379 TokenID: tx.TokenID,
380 Nonce: 0,
381 Balance: tx.LoadAmount,
382 PublicKey: tx.FromBJJ,
383 EthAddr: tx.FromEthAddr,
384 }
385
386 p, err := s.CreateAccount(common.Idx(s.idx+1), account)
387 if err != nil {
388 return err
389 }
390 if s.zki != nil {
391 s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
392 s.zki.Nonce1[s.i] = big.NewInt(0)
393 if babyjub.PointCoordSign(tx.FromBJJ.X) {
394 s.zki.Sign1[s.i] = big.NewInt(1)
395 }
396 s.zki.Ay1[s.i] = tx.FromBJJ.Y
397 s.zki.Balance1[s.i] = tx.LoadAmount
398 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
399 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
400 if p.IsOld0 {
401 s.zki.IsOld0_1[s.i] = big.NewInt(1)
402 }
403 s.zki.OldKey1[s.i] = p.OldKey.BigInt()
404 s.zki.OldValue1[s.i] = p.OldValue.BigInt()
405 }
406
407 s.idx = s.idx + 1
408 return s.setIdx(s.idx)
409}
410
411// applyDeposit updates the balance in the account of the depositer, if
412// andTransfer parameter is set to true, the method will also apply the
413// Transfer of the L1Tx/DepositTransfer
414func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
415 // deposit the tx.LoadAmount into the sender account
416 accSender, err := s.GetAccount(tx.FromIdx)
417 if err != nil {
418 return err
419 }
420 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
421
422 // in case that the tx is a L1Tx>DepositTransfer
423 var accReceiver *common.Account
424 if transfer {
425 accReceiver, err = s.GetAccount(tx.ToIdx)
426 if err != nil {
427 return err
428 }
429 // subtract amount to the sender
430 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
431 // add amount to the receiver
432 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
433 }
434 // update sender account in localStateDB
435 p, err := s.UpdateAccount(tx.FromIdx, accSender)
436 if err != nil {
437 return err
438 }
439 if s.zki != nil {
440 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
441 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
442 if babyjub.PointCoordSign(accSender.PublicKey.X) {
443 s.zki.Sign1[s.i] = big.NewInt(1)
444 }
445 s.zki.Ay1[s.i] = accSender.PublicKey.Y
446 s.zki.Balance1[s.i] = accSender.Balance
447 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
448 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
449 // IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
450 }
451
452 // this is done after updating Sender Account (depositer)
453 if transfer {
454 // update receiver account in localStateDB
455 p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
456 if err != nil {
457 return err
458 }
459 if s.zki != nil {
460 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
461 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
462 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
463 s.zki.Sign2[s.i] = big.NewInt(1)
464 }
465 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
466 s.zki.Balance2[s.i] = accReceiver.Balance
467 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
468 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
469 // IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
470 }
471 }
472
473 return nil
474}
475
476// applyTransfer updates the balance & nonce in the account of the sender, and
477// the balance in the account of the receiver
478func (s *StateDB) applyTransfer(tx *common.Tx) error {
479 // get sender and receiver accounts from localStateDB
480 accSender, err := s.GetAccount(tx.FromIdx)
481 if err != nil {
482 return err
483 }
484 accReceiver, err := s.GetAccount(tx.ToIdx)
485 if err != nil {
486 return err
487 }
488
489 // increment nonce
490 accSender.Nonce++
491
492 // subtract amount to the sender
493 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
494 // add amount to the receiver
495 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
496
497 // update sender account in localStateDB
498 pSender, err := s.UpdateAccount(tx.FromIdx, accSender)
499 if err != nil {
500 return err
501 }
502 if s.zki != nil {
503 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
504 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
505 if babyjub.PointCoordSign(accSender.PublicKey.X) {
506 s.zki.Sign1[s.i] = big.NewInt(1)
507 }
508 s.zki.Ay1[s.i] = accSender.PublicKey.Y
509 s.zki.Balance1[s.i] = accSender.Balance
510 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
511 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings)
512 }
513
514 // update receiver account in localStateDB
515 pReceiver, err := s.UpdateAccount(tx.ToIdx, accReceiver)
516 if err != nil {
517 return err
518 }
519 if s.zki != nil {
520 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
521 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
522 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
523 s.zki.Sign2[s.i] = big.NewInt(1)
524 }
525 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
526 s.zki.Balance2[s.i] = accReceiver.Balance
527 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
528 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings)
529 }
530
531 return nil
532}
533
534// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
535// makes a deposit, and performs a transfer to another account
536func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
537 accSender := &common.Account{
538 TokenID: tx.TokenID,
539 Nonce: 0,
540 Balance: tx.LoadAmount,
541 PublicKey: tx.FromBJJ,
542 EthAddr: tx.FromEthAddr,
543 }
544 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
545 accReceiver, err := s.GetAccount(tx.ToIdx)
546 if err != nil {
547 return err
548 }
549 // subtract amount to the sender
550 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
551 // add amount to the receiver
552 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
553
554 // create Account of the Sender
555 p, err := s.CreateAccount(common.Idx(s.idx+1), accSender)
556 if err != nil {
557 return err
558 }
559 if s.zki != nil {
560 s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
561 s.zki.Nonce1[s.i] = big.NewInt(0)
562 if babyjub.PointCoordSign(tx.FromBJJ.X) {
563 s.zki.Sign1[s.i] = big.NewInt(1)
564 }
565 s.zki.Ay1[s.i] = tx.FromBJJ.Y
566 s.zki.Balance1[s.i] = tx.LoadAmount
567 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
568 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
569 if p.IsOld0 {
570 s.zki.IsOld0_1[s.i] = big.NewInt(1)
571 }
572 s.zki.OldKey1[s.i] = p.OldKey.BigInt()
573 s.zki.OldValue1[s.i] = p.OldValue.BigInt()
574 }
575
576 // update receiver account in localStateDB
577 p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
578 if err != nil {
579 return err
580 }
581 if s.zki != nil {
582 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
583 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
584 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
585 s.zki.Sign2[s.i] = big.NewInt(1)
586 }
587 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
588 s.zki.Balance2[s.i] = accReceiver.Balance
589 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
590 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
591 }
592
593 s.idx = s.idx + 1
594 return s.setIdx(s.idx)
595}
596
597// It returns the ExitAccount and a boolean determining if the Exit created a
598// new Leaf in the ExitTree.
599func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx *common.Tx) (*common.Account, bool, error) {
600 // 0. subtract tx.Amount from current Account in StateMT
601 // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
602 acc, err := s.GetAccount(tx.FromIdx)
603 if err != nil {
604 return nil, false, err
605 }
606 acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
607 p, err := s.UpdateAccount(tx.FromIdx, acc)
608 if err != nil {
609 return nil, false, err
610 }
611 if s.zki != nil {
612 s.zki.TokenID1[s.i] = acc.TokenID.BigInt()
613 s.zki.Nonce1[s.i] = acc.Nonce.BigInt()
614 if babyjub.PointCoordSign(acc.PublicKey.X) {
615 s.zki.Sign1[s.i] = big.NewInt(1)
616 }
617 s.zki.Ay1[s.i] = acc.PublicKey.Y
618 s.zki.Balance1[s.i] = acc.Balance
619 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(acc.EthAddr)
620 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
621 }
622
623 if exitTree == nil {
624 return nil, false, nil
625 }
626 exitAccount, err := getAccountInTreeDB(exitTree.DB(), tx.FromIdx)
627 if err == db.ErrNotFound {
628 // 1a. if idx does not exist in exitTree:
629 // add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance = exitAmount (exitAmount=tx.Amount)
630 exitAccount := &common.Account{
631 TokenID: acc.TokenID,
632 Nonce: common.Nonce(1),
633 Balance: tx.Amount,
634 PublicKey: acc.PublicKey,
635 EthAddr: acc.EthAddr,
636 }
637 _, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
638 return exitAccount, true, err
639 } else if err != nil {
640 return exitAccount, false, err
641 }
642
643 // 1b. if idx already exist in exitTree:
644 // update account, where account.Balance += exitAmount
645 exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
646 _, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
647 return exitAccount, false, err
648}
649
650// getIdx returns the stored Idx from the localStateDB, which is the last Idx
651// used for an Account in the localStateDB.
652func (s *StateDB) getIdx() (common.Idx, error) {
653 idxBytes, err := s.DB().Get(keyidx)
654 if err == db.ErrNotFound {
655 return 0, nil
656 }
657 if err != nil {
658 return 0, err
659 }
660 return common.IdxFromBytes(idxBytes[:4])
661}
662
663// setIdx stores Idx in the localStateDB
664func (s *StateDB) setIdx(idx common.Idx) error {
665 tx, err := s.DB().NewTx()
666 if err != nil {
667 return err
668 }
669 idxBytes, err := idx.Bytes()
670 if err != nil {
671 return err
672 }
673 err = tx.Put(keyidx, idxBytes[:])
674 if err != nil {
675 return err
676 }
677 if err := tx.Commit(); err != nil {
678 return err
679 }
680 return nil
681}