hermez-node/db/statedb/txprocessors.go
db/statedb/txprocessors.goRaw
1package statedb
2
3import (
4 "errors"
5 "fmt"
6 "io/ioutil"
7 "math/big"
8 "os"
9
10 "github.com/hermeznetwork/hermez-node/common"
11 "github.com/hermeznetwork/hermez-node/log"
12 "github.com/iden3/go-iden3-crypto/babyjub"
13 "github.com/iden3/go-merkletree"
14 "github.com/iden3/go-merkletree/db"
15 "github.com/iden3/go-merkletree/db/pebble"
16)
17
18var (
19 // keyidx is used as key in the db to store the current Idx
20 keyidx = []byte("k:idx")
21)
22
23func (s *StateDB) resetZKInputs() {
24 s.zki = nil
25 s.i = 0 // initialize current transaction index in the ZKInputs generation
26}
27
28type processedExit struct {
29 exit bool
30 newExit bool
31 idx common.Idx
32 acc common.Account
33}
34
35// ProcessTxOutput contains the output of the ProcessTxs method
36type ProcessTxOutput struct {
37 ZKInputs *common.ZKInputs
38 ExitInfos []common.ExitInfo
39 CreatedAccounts []common.Account
40 CoordinatorIdxsMap map[common.TokenID]common.Idx
41 CollectedFees map[common.TokenID]*big.Int
42}
43
44// ProcessTxsConfig contains the config for ProcessTxs
45type ProcessTxsConfig struct {
46 NLevels uint32
47 MaxFeeTx uint32
48 MaxTx uint32
49 MaxL1Tx uint32
50}
51
52// ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
53// the StateDB depending on the transaction Type. If StateDB
54// type==TypeBatchBuilder, returns the common.ZKInputs to generate the
55// SnarkProof later used by the BatchBuilder. If StateDB
56// type==TypeSynchronizer, assumes that the call is done from the Synchronizer,
57// returns common.ExitTreeLeaf that is later used by the Synchronizer to update
58// the HistoryDB, and adds Nonce & TokenID to the L2Txs.
59// And if TypeSynchronizer returns an array of common.Account with all the
60// created accounts.
61func (s *StateDB) ProcessTxs(ptc ProcessTxsConfig, coordIdxs []common.Idx, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (ptOut *ProcessTxOutput, err error) {
62 defer func() {
63 if err == nil {
64 err = s.MakeCheckpoint()
65 }
66 }()
67
68 var exitTree *merkletree.MerkleTree
69 var createdAccounts []common.Account
70
71 if s.zki != nil {
72 return nil, errors.New("Expected StateDB.zki==nil, something went wrong and it's not empty")
73 }
74 defer s.resetZKInputs()
75
76 if len(coordIdxs) >= int(ptc.MaxFeeTx) {
77 return nil, fmt.Errorf("CoordIdxs (%d) length must be smaller than MaxFeeTx (%d)", len(coordIdxs), ptc.MaxFeeTx)
78 }
79
80 s.accumulatedFees = make(map[common.Idx]*big.Int)
81
82 nTx := len(l1usertxs) + len(l1coordinatortxs) + len(l2txs)
83 if nTx == 0 {
84 // TODO return ZKInputs of batch without txs
85 return &ProcessTxOutput{
86 ZKInputs: nil,
87 ExitInfos: nil,
88 CreatedAccounts: nil,
89 CoordinatorIdxsMap: nil,
90 CollectedFees: nil,
91 }, nil
92 }
93 exits := make([]processedExit, nTx)
94
95 if s.typ == TypeBatchBuilder {
96 s.zki = common.NewZKInputs(uint32(nTx), ptc.MaxL1Tx, ptc.MaxTx, ptc.MaxFeeTx, ptc.NLevels)
97 s.zki.OldLastIdx = s.idx.BigInt()
98 s.zki.OldStateRoot = s.mt.Root().BigInt()
99 }
100
101 // TBD if ExitTree is only in memory or stored in disk, for the moment
102 // is only needed in memory
103 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
104 tmpDir, err := ioutil.TempDir("", "hermez-statedb-exittree")
105 if err != nil {
106 return nil, err
107 }
108 defer func() {
109 if err := os.RemoveAll(tmpDir); err != nil {
110 log.Errorw("Deleting statedb temp exit tree", "err", err)
111 }
112 }()
113 sto, err := pebble.NewPebbleStorage(tmpDir, false)
114 if err != nil {
115 return nil, err
116 }
117 exitTree, err = merkletree.NewMerkleTree(sto, s.mt.MaxLevels())
118 if err != nil {
119 return nil, err
120 }
121 }
122
123 // Process L1UserTxs
124 for i := 0; i < len(l1usertxs); i++ {
125 // assumption: l1usertx are sorted by L1Tx.Position
126 exitIdx, exitAccount, newExit, createdAccount, err := s.processL1Tx(exitTree, &l1usertxs[i])
127 if err != nil {
128 return nil, err
129 }
130 if s.typ == TypeSynchronizer && createdAccount != nil {
131 createdAccounts = append(createdAccounts, *createdAccount)
132 }
133
134 if s.zki != nil {
135 l1TxData, err := l1usertxs[i].BytesGeneric()
136 if err != nil {
137 return nil, err
138 }
139 s.zki.Metadata.L1TxsData = append(s.zki.Metadata.L1TxsData, l1TxData)
140
141 if s.i < nTx-1 {
142 s.zki.ISOutIdx[s.i] = s.idx.BigInt()
143 s.zki.ISStateRoot[s.i] = s.mt.Root().BigInt()
144 }
145 }
146 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
147 if exitIdx != nil && exitTree != nil {
148 exits[s.i] = processedExit{
149 exit: true,
150 newExit: newExit,
151 idx: *exitIdx,
152 acc: *exitAccount,
153 }
154 }
155 s.i++
156 }
157 }
158
159 // Process L1CoordinatorTxs
160 for i := 0; i < len(l1coordinatortxs); i++ {
161 exitIdx, _, _, createdAccount, err := s.processL1Tx(exitTree, &l1coordinatortxs[i])
162 if err != nil {
163 return nil, err
164 }
165 if exitIdx != nil {
166 log.Error("Unexpected Exit in L1CoordinatorTx")
167 }
168 if s.typ == TypeSynchronizer && createdAccount != nil {
169 createdAccounts = append(createdAccounts, *createdAccount)
170 }
171 if s.zki != nil {
172 l1TxData, err := l1coordinatortxs[i].BytesGeneric()
173 if err != nil {
174 return nil, err
175 }
176 s.zki.Metadata.L1TxsData = append(s.zki.Metadata.L1TxsData, l1TxData)
177
178 if s.i < nTx-1 {
179 s.zki.ISOutIdx[s.i] = s.idx.BigInt()
180 s.zki.ISStateRoot[s.i] = s.mt.Root().BigInt()
181 }
182 s.i++
183 }
184 }
185
186 s.accumulatedFees = make(map[common.Idx]*big.Int)
187 for _, idx := range coordIdxs {
188 s.accumulatedFees[idx] = big.NewInt(0)
189 }
190
191 // once L1UserTxs & L1CoordinatorTxs are processed, get TokenIDs of
192 // coordIdxs. In this way, if a coordIdx uses an Idx that is being
193 // created in the current batch, at this point the Idx will be created
194 coordIdxsMap, err := s.getTokenIDsFromIdxs(coordIdxs)
195 if err != nil {
196 return nil, err
197 }
198 // collectedFees will contain the amount of fee collected for each
199 // TokenID
200 var collectedFees map[common.TokenID]*big.Int
201 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
202 collectedFees = make(map[common.TokenID]*big.Int)
203 for tokenID := range coordIdxsMap {
204 collectedFees[tokenID] = big.NewInt(0)
205 }
206 }
207
208 if s.zki != nil {
209 // get the feePlanTokens
210 feePlanTokens, err := s.getFeePlanTokens(coordIdxs, l2txs)
211 if err != nil {
212 log.Error(err)
213 return nil, err
214 }
215 copy(s.zki.FeePlanTokens, feePlanTokens)
216 }
217
218 // Process L2Txs
219 for i := 0; i < len(l2txs); i++ {
220 exitIdx, exitAccount, newExit, err := s.processL2Tx(coordIdxsMap, collectedFees, exitTree, &l2txs[i])
221 if err != nil {
222 return nil, err
223 }
224 if s.zki != nil {
225 l2TxData, err := l2txs[i].L2Tx().Bytes(s.zki.Metadata.NLevels)
226 if err != nil {
227 return nil, err
228 }
229 s.zki.Metadata.L2TxsData = append(s.zki.Metadata.L2TxsData, l2TxData)
230
231 if s.i < nTx-1 {
232 // Intermediate States
233 s.zki.ISOutIdx[s.i] = s.idx.BigInt()
234 s.zki.ISStateRoot[s.i] = s.mt.Root().BigInt()
235 s.zki.ISAccFeeOut[s.i] = formatAccumulatedFees(collectedFees, s.zki.FeePlanTokens)
236 }
237 if s.i == nTx-1 {
238 s.zki.ISFinalAccFee = formatAccumulatedFees(collectedFees, s.zki.FeePlanTokens)
239 }
240 }
241 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
242 if exitIdx != nil && exitTree != nil {
243 exits[s.i] = processedExit{
244 exit: true,
245 newExit: newExit,
246 idx: *exitIdx,
247 acc: *exitAccount,
248 }
249 }
250 s.i++
251 }
252 }
253
254 if s.zki != nil {
255 // before computing the Fees txs, set the ISInitStateRootFee
256 s.zki.ISInitStateRootFee = s.mt.Root().BigInt()
257 }
258
259 // distribute the AccumulatedFees from the processed L2Txs into the
260 // Coordinator Idxs
261 iFee := 0
262 for idx, accumulatedFee := range s.accumulatedFees {
263 // send the fee to the Idx of the Coordinator for the TokenID
264 accCoord, err := s.GetAccount(idx)
265 if err != nil {
266 log.Errorw("Can not distribute accumulated fees to coordinator account: No coord Idx to receive fee", "idx", idx)
267 return nil, err
268 }
269 accCoord.Balance = new(big.Int).Add(accCoord.Balance, accumulatedFee)
270 pFee, err := s.UpdateAccount(idx, accCoord)
271 if err != nil {
272 log.Error(err)
273 return nil, err
274 }
275 if s.zki != nil {
276 s.zki.TokenID3[iFee] = accCoord.TokenID.BigInt()
277 s.zki.Nonce3[iFee] = accCoord.Nonce.BigInt()
278 if babyjub.PointCoordSign(accCoord.PublicKey.X) {
279 s.zki.Sign3[iFee] = big.NewInt(1)
280 }
281 s.zki.Ay3[iFee] = accCoord.PublicKey.Y
282 s.zki.Balance3[iFee] = accCoord.Balance
283 s.zki.EthAddr3[iFee] = common.EthAddrToBigInt(accCoord.EthAddr)
284 s.zki.Siblings3[iFee] = siblingsToZKInputFormat(pFee.Siblings)
285
286 // add Coord Idx to ZKInputs.FeeTxsData
287 s.zki.FeeIdxs[iFee] = idx.BigInt()
288
289 s.zki.ISStateRootFee[iFee] = s.mt.Root().BigInt()
290 }
291 iFee++
292 }
293
294 if s.typ == TypeTxSelector {
295 return nil, nil
296 }
297
298 // once all txs processed (exitTree root frozen), for each Exit,
299 // generate common.ExitInfo data
300 var exitInfos []common.ExitInfo
301 for i := 0; i < nTx; i++ {
302 if !exits[i].exit {
303 continue
304 }
305 exitIdx := exits[i].idx
306 exitAccount := exits[i].acc
307
308 // 0. generate MerkleProof
309 p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil)
310 if err != nil {
311 return nil, err
312 }
313 // 1. generate common.ExitInfo
314 ei := common.ExitInfo{
315 AccountIdx: exitIdx,
316 MerkleProof: p,
317 Balance: exitAccount.Balance,
318 }
319 exitInfos = append(exitInfos, ei)
320
321 if s.zki != nil {
322 s.zki.TokenID2[i] = exitAccount.TokenID.BigInt()
323 s.zki.Nonce2[i] = exitAccount.Nonce.BigInt()
324 if babyjub.PointCoordSign(exitAccount.PublicKey.X) {
325 s.zki.Sign2[i] = big.NewInt(1)
326 }
327 s.zki.Ay2[i] = exitAccount.PublicKey.Y
328 s.zki.Balance2[i] = exitAccount.Balance
329 s.zki.EthAddr2[i] = common.EthAddrToBigInt(exitAccount.EthAddr)
330 for j := 0; j < len(p.Siblings); j++ {
331 s.zki.Siblings2[i][j] = p.Siblings[j].BigInt()
332 }
333 if exits[i].newExit {
334 s.zki.NewExit[i] = big.NewInt(1)
335 }
336 if p.IsOld0 {
337 s.zki.IsOld0_2[i] = big.NewInt(1)
338 }
339 s.zki.OldKey2[i] = p.OldKey.BigInt()
340 s.zki.OldValue2[i] = p.OldValue.BigInt()
341
342 if i < nTx-1 {
343 s.zki.ISExitRoot[i] = exitTree.Root().BigInt()
344 }
345 }
346 }
347 if s.typ == TypeSynchronizer {
348 // return exitInfos, createdAccounts and collectedFees, so Synchronizer will
349 // be able to store it into HistoryDB for the concrete BatchNum
350 return &ProcessTxOutput{
351 ZKInputs: nil,
352 ExitInfos: exitInfos,
353 CreatedAccounts: createdAccounts,
354 CoordinatorIdxsMap: coordIdxsMap,
355 CollectedFees: collectedFees,
356 }, nil
357 }
358
359 // compute last ZKInputs parameters
360 s.zki.GlobalChainID = big.NewInt(0) // TODO, 0: ethereum, this will be get from config file
361 // zki.FeeIdxs = ? // TODO, this will be get from the config file
362 s.zki.Metadata.NewStateRootRaw = s.mt.Root()
363 s.zki.Metadata.NewExitRootRaw = exitTree.Root()
364
365 // return ZKInputs as the BatchBuilder will return it to forge the Batch
366 return &ProcessTxOutput{
367 ZKInputs: s.zki,
368 ExitInfos: nil,
369 CreatedAccounts: nil,
370 CoordinatorIdxsMap: coordIdxsMap,
371 CollectedFees: nil,
372 }, nil
373}
374
375// getFeePlanTokens returns an array of *big.Int containing a list of tokenIDs
376// corresponding to the given CoordIdxs and the processed L2Txs
377func (s *StateDB) getFeePlanTokens(coordIdxs []common.Idx, l2txs []common.PoolL2Tx) ([]*big.Int, error) {
378 // get Coordinator TokenIDs corresponding to the Idxs where the Fees
379 // will be sent
380 coordTokenIDs := make(map[common.TokenID]bool)
381 for i := 0; i < len(coordIdxs); i++ {
382 acc, err := s.GetAccount(coordIdxs[i])
383 if err != nil {
384 log.Errorf("could not get account to determine TokenID of CoordIdx %d not found: %s", coordIdxs[i], err.Error())
385 return nil, err
386 }
387 coordTokenIDs[acc.TokenID] = true
388 }
389
390 tokenIDs := make(map[common.TokenID]bool)
391 for i := 0; i < len(l2txs); i++ {
392 // as L2Tx does not have parameter TokenID, get it from the
393 // AccountsDB (in the StateDB)
394 acc, err := s.GetAccount(l2txs[i].FromIdx)
395 if err != nil {
396 log.Errorf("could not get account to determine TokenID of L2Tx: FromIdx %d not found: %s", l2txs[i].FromIdx, err.Error())
397 return nil, err
398 }
399 if _, ok := coordTokenIDs[acc.TokenID]; ok {
400 tokenIDs[acc.TokenID] = true
401 }
402 }
403 var tBI []*big.Int
404 for t := range tokenIDs {
405 tBI = append(tBI, t.BigInt())
406 }
407 return tBI, nil
408}
409
410// processL1Tx process the given L1Tx applying the needed updates to the
411// StateDB depending on the transaction Type. It returns the 3 parameters
412// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
413// the Exit created a new Leaf in the ExitTree.
414// And another *common.Account parameter which contains the created account in
415// case that has been a new created account and that the StateDB is of type
416// TypeSynchronizer.
417func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, bool, *common.Account, error) {
418 // ZKInputs
419 if s.zki != nil {
420 // Txs
421 var err error
422 s.zki.TxCompressedData[s.i], err = tx.TxCompressedData()
423 if err != nil {
424 log.Error(err)
425 return nil, nil, false, nil, err
426 }
427 s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
428 s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
429 s.zki.OnChain[s.i] = big.NewInt(1)
430
431 // L1Txs
432 s.zki.LoadAmountF[s.i] = tx.LoadAmount
433 s.zki.FromEthAddr[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
434 if tx.FromBJJ != nil {
435 s.zki.FromBJJCompressed[s.i] = BJJCompressedTo256BigInts(tx.FromBJJ.Compress())
436 }
437
438 // Intermediate States, for all the transactions except for the last one
439 if s.i < len(s.zki.ISOnChain) { // len(s.zki.ISOnChain) == nTx
440 s.zki.ISOnChain[s.i] = big.NewInt(1)
441 }
442 }
443
444 switch tx.Type {
445 case common.TxTypeForceTransfer:
446 // go to the MT account of sender and receiver, and update balance
447 // & nonce
448
449 // coordIdxsMap is 'nil', as at L1Txs there is no L2 fees
450 // 0 for the parameter toIdx, as at L1Tx ToIdx can only be 0 in the Deposit type case.
451 err := s.applyTransfer(nil, nil, tx.Tx(), 0)
452 if err != nil {
453 log.Error(err)
454 return nil, nil, false, nil, err
455 }
456 case common.TxTypeCreateAccountDeposit:
457 // add new account to the MT, update balance of the MT account
458 err := s.applyCreateAccount(tx)
459 if err != nil {
460 log.Error(err)
461 return nil, nil, false, nil, err
462 }
463 // TODO applyCreateAccount will return the created account,
464 // which in the case type==TypeSynchronizer will be added to an
465 // array of created accounts that will be returned
466 case common.TxTypeDeposit:
467 // update balance of the MT account
468 err := s.applyDeposit(tx, false)
469 if err != nil {
470 log.Error(err)
471 return nil, nil, false, nil, err
472 }
473 case common.TxTypeDepositTransfer:
474 // update balance in MT account, update balance & nonce of sender
475 // & receiver
476 err := s.applyDeposit(tx, true)
477 if err != nil {
478 log.Error(err)
479 return nil, nil, false, nil, err
480 }
481 case common.TxTypeCreateAccountDepositTransfer:
482 // add new account to the merkletree, update balance in MT account,
483 // update balance & nonce of sender & receiver
484 err := s.applyCreateAccountDepositTransfer(tx)
485 if err != nil {
486 log.Error(err)
487 return nil, nil, false, nil, err
488 }
489 case common.TxTypeForceExit:
490 // execute exit flow
491 // coordIdxsMap is 'nil', as at L1Txs there is no L2 fees
492 exitAccount, newExit, err := s.applyExit(nil, nil, exitTree, tx.Tx())
493 if err != nil {
494 log.Error(err)
495 return nil, nil, false, nil, err
496 }
497 return &tx.FromIdx, exitAccount, newExit, nil, nil
498 default:
499 }
500
501 var createdAccount *common.Account
502 if s.typ == TypeSynchronizer && (tx.Type == common.TxTypeCreateAccountDeposit || tx.Type == common.TxTypeCreateAccountDepositTransfer) {
503 var err error
504 createdAccount, err = s.GetAccount(s.idx)
505 if err != nil {
506 log.Error(err)
507 return nil, nil, false, nil, err
508 }
509 }
510
511 return nil, nil, false, createdAccount, nil
512}
513
514// processL2Tx process the given L2Tx applying the needed updates to the
515// StateDB depending on the transaction Type. It returns the 3 parameters
516// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
517// the Exit created a new Leaf in the ExitTree.
518func (s *StateDB) processL2Tx(coordIdxsMap map[common.TokenID]common.Idx, collectedFees map[common.TokenID]*big.Int,
519 exitTree *merkletree.MerkleTree, tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) {
520 var err error
521 // if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
522 if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) {
523 // case when tx.Type== common.TxTypeTransferToEthAddr or common.TxTypeTransferToBJJ
524 tx.AuxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ, tx.TokenID)
525 if err != nil {
526 return nil, nil, false, err
527 }
528 }
529
530 // ZKInputs
531 if s.zki != nil {
532 // Txs
533 s.zki.TxCompressedData[s.i], err = tx.TxCompressedData()
534 if err != nil {
535 return nil, nil, false, err
536 }
537 s.zki.TxCompressedDataV2[s.i], err = tx.TxCompressedDataV2()
538 if err != nil {
539 return nil, nil, false, err
540 }
541 s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
542 s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
543
544 // fill AuxToIdx if needed
545 if tx.ToIdx == 0 {
546 // use toIdx that can have been filled by tx.ToIdx or
547 // if tx.Idx==0 (this case), toIdx is filled by the Idx
548 // from db by ToEthAddr&ToBJJ
549 s.zki.AuxToIdx[s.i] = tx.AuxToIdx.BigInt()
550 }
551
552 if tx.ToBJJ != nil {
553 s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
554 }
555 s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
556
557 s.zki.OnChain[s.i] = big.NewInt(0)
558 s.zki.NewAccount[s.i] = big.NewInt(0)
559
560 // L2Txs
561 // s.zki.RqOffset[s.i] = // TODO Rq once TxSelector is ready
562 // s.zki.RqTxCompressedDataV2[s.i] = // TODO
563 // s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
564 // s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO
565 signature, err := tx.Signature.Decompress()
566 if err != nil {
567 log.Error(err)
568 return nil, nil, false, err
569 }
570 s.zki.S[s.i] = signature.S
571 s.zki.R8x[s.i] = signature.R8.X
572 s.zki.R8y[s.i] = signature.R8.Y
573 }
574
575 // if StateDB type==TypeSynchronizer, will need to add Nonce
576 if s.typ == TypeSynchronizer {
577 // as type==TypeSynchronizer, always tx.ToIdx!=0
578 acc, err := s.GetAccount(tx.FromIdx)
579 if err != nil {
580 log.Errorw("GetAccount", "fromIdx", tx.FromIdx, "err", err)
581 return nil, nil, false, err
582 }
583 tx.Nonce = acc.Nonce + 1
584 tx.TokenID = acc.TokenID
585 }
586
587 switch tx.Type {
588 case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
589 // go to the MT account of sender and receiver, and update
590 // balance & nonce
591 err = s.applyTransfer(coordIdxsMap, collectedFees, tx.Tx(), tx.AuxToIdx)
592 if err != nil {
593 log.Error(err)
594 return nil, nil, false, err
595 }
596 case common.TxTypeExit:
597 // execute exit flow
598 exitAccount, newExit, err := s.applyExit(coordIdxsMap, collectedFees, exitTree, tx.Tx())
599 if err != nil {
600 log.Error(err)
601 return nil, nil, false, err
602 }
603 return &tx.FromIdx, exitAccount, newExit, nil
604 default:
605 }
606 return nil, nil, false, nil
607}
608
609// applyCreateAccount creates a new account in the account of the depositer, it
610// stores the deposit value
611func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
612 account := &common.Account{
613 TokenID: tx.TokenID,
614 Nonce: 0,
615 Balance: tx.LoadAmount,
616 PublicKey: tx.FromBJJ,
617 EthAddr: tx.FromEthAddr,
618 }
619
620 p, err := s.CreateAccount(common.Idx(s.idx+1), account)
621 if err != nil {
622 return err
623 }
624 if s.zki != nil {
625 s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
626 s.zki.Nonce1[s.i] = big.NewInt(0)
627 if babyjub.PointCoordSign(tx.FromBJJ.X) {
628 s.zki.Sign1[s.i] = big.NewInt(1)
629 }
630 s.zki.Ay1[s.i] = tx.FromBJJ.Y
631 s.zki.Balance1[s.i] = tx.LoadAmount
632 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
633 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
634 if p.IsOld0 {
635 s.zki.IsOld0_1[s.i] = big.NewInt(1)
636 }
637 s.zki.OldKey1[s.i] = p.OldKey.BigInt()
638 s.zki.OldValue1[s.i] = p.OldValue.BigInt()
639
640 s.zki.Metadata.NewLastIdxRaw = s.idx + 1
641
642 s.zki.AuxFromIdx[s.i] = common.Idx(s.idx + 1).BigInt()
643 s.zki.NewAccount[s.i] = big.NewInt(1)
644
645 if s.i < len(s.zki.ISOnChain) { // len(s.zki.ISOnChain) == nTx
646 // intermediate states
647 s.zki.ISOnChain[s.i] = big.NewInt(1)
648 }
649 }
650
651 s.idx = s.idx + 1
652 return s.setIdx(s.idx)
653}
654
655// applyDeposit updates the balance in the account of the depositer, if
656// andTransfer parameter is set to true, the method will also apply the
657// Transfer of the L1Tx/DepositTransfer
658func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
659 // deposit the tx.LoadAmount into the sender account
660 accSender, err := s.GetAccount(tx.FromIdx)
661 if err != nil {
662 return err
663 }
664 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
665
666 // in case that the tx is a L1Tx>DepositTransfer
667 var accReceiver *common.Account
668 if transfer {
669 accReceiver, err = s.GetAccount(tx.ToIdx)
670 if err != nil {
671 return err
672 }
673 // subtract amount to the sender
674 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
675 // add amount to the receiver
676 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
677 }
678 // update sender account in localStateDB
679 p, err := s.UpdateAccount(tx.FromIdx, accSender)
680 if err != nil {
681 return err
682 }
683 if s.zki != nil {
684 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
685 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
686 if babyjub.PointCoordSign(accSender.PublicKey.X) {
687 s.zki.Sign1[s.i] = big.NewInt(1)
688 }
689 s.zki.Ay1[s.i] = accSender.PublicKey.Y
690 s.zki.Balance1[s.i] = accSender.Balance
691 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
692 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
693 // IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
694 }
695
696 // this is done after updating Sender Account (depositer)
697 if transfer {
698 // update receiver account in localStateDB
699 p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
700 if err != nil {
701 return err
702 }
703 if s.zki != nil {
704 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
705 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
706 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
707 s.zki.Sign2[s.i] = big.NewInt(1)
708 }
709 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
710 s.zki.Balance2[s.i] = accReceiver.Balance
711 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
712 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
713 // IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
714 }
715 }
716
717 return nil
718}
719
720// applyTransfer updates the balance & nonce in the account of the sender, and
721// the balance in the account of the receiver.
722// Parameter 'toIdx' should be at 0 if the tx already has tx.ToIdx!=0, if
723// tx.ToIdx==0, then toIdx!=0, and will be used the toIdx parameter as Idx of
724// the receiver. This parameter is used when the tx.ToIdx is not specified and
725// the real ToIdx is found trhrough the ToEthAddr or ToBJJ.
726func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, collectedFees map[common.TokenID]*big.Int,
727 tx common.Tx, auxToIdx common.Idx) error {
728 if auxToIdx == common.Idx(0) {
729 auxToIdx = tx.ToIdx
730 }
731 // get sender and receiver accounts from localStateDB
732 accSender, err := s.GetAccount(tx.FromIdx)
733 if err != nil {
734 log.Error(err)
735 return err
736 }
737 if !tx.IsL1 {
738 // increment nonce
739 accSender.Nonce++
740
741 // compute fee and subtract it from the accSender
742 fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
743 if err != nil {
744 return err
745 }
746 feeAndAmount := new(big.Int).Add(tx.Amount, fee)
747 accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount)
748
749 accCoord, err := s.GetAccount(coordIdxsMap[accSender.TokenID])
750 if err != nil {
751 log.Debugw("No coord Idx to receive fee", "tx", tx)
752 } else {
753 // accumulate the fee for the Coord account
754 accumulated := s.accumulatedFees[accCoord.Idx]
755 accumulated.Add(accumulated, fee)
756
757 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
758 collected := collectedFees[accCoord.TokenID]
759 collected.Add(collected, fee)
760 }
761 }
762 } else {
763 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
764 }
765
766 var accReceiver *common.Account
767 if tx.FromIdx == auxToIdx {
768 // if Sender is the Receiver, reuse 'accSender' pointer,
769 // because in the DB the account for 'auxToIdx' won't be
770 // updated yet
771 accReceiver = accSender
772 } else {
773 accReceiver, err = s.GetAccount(auxToIdx)
774 if err != nil {
775 log.Error(err)
776 return err
777 }
778 }
779
780 // add amount-feeAmount to the receiver
781 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
782
783 // update sender account in localStateDB
784 pSender, err := s.UpdateAccount(tx.FromIdx, accSender)
785 if err != nil {
786 log.Error(err)
787 return err
788 }
789 if s.zki != nil {
790 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
791 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
792 if babyjub.PointCoordSign(accSender.PublicKey.X) {
793 s.zki.Sign1[s.i] = big.NewInt(1)
794 }
795 s.zki.Ay1[s.i] = accSender.PublicKey.Y
796 s.zki.Balance1[s.i] = accSender.Balance
797 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
798 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings)
799 }
800
801 // update receiver account in localStateDB
802 pReceiver, err := s.UpdateAccount(auxToIdx, accReceiver)
803 if err != nil {
804 return err
805 }
806 if s.zki != nil {
807 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
808 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
809 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
810 s.zki.Sign2[s.i] = big.NewInt(1)
811 }
812 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
813 s.zki.Balance2[s.i] = accReceiver.Balance
814 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
815 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings)
816 }
817
818 return nil
819}
820
821// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
822// makes a deposit, and performs a transfer to another account
823func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
824 accSender := &common.Account{
825 TokenID: tx.TokenID,
826 Nonce: 0,
827 Balance: tx.LoadAmount,
828 PublicKey: tx.FromBJJ,
829 EthAddr: tx.FromEthAddr,
830 }
831 accReceiver, err := s.GetAccount(tx.ToIdx)
832 if err != nil {
833 return err
834 }
835 // subtract amount to the sender
836 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
837 // add amount to the receiver
838 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
839
840 // create Account of the Sender
841 p, err := s.CreateAccount(common.Idx(s.idx+1), accSender)
842 if err != nil {
843 return err
844 }
845 if s.zki != nil {
846 s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
847 s.zki.Nonce1[s.i] = big.NewInt(0)
848 if babyjub.PointCoordSign(tx.FromBJJ.X) {
849 s.zki.Sign1[s.i] = big.NewInt(1)
850 }
851 s.zki.Ay1[s.i] = tx.FromBJJ.Y
852 s.zki.Balance1[s.i] = tx.LoadAmount
853 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
854 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
855 if p.IsOld0 {
856 s.zki.IsOld0_1[s.i] = big.NewInt(1)
857 }
858 s.zki.OldKey1[s.i] = p.OldKey.BigInt()
859 s.zki.OldValue1[s.i] = p.OldValue.BigInt()
860
861 s.zki.Metadata.NewLastIdxRaw = s.idx + 1
862
863 s.zki.AuxFromIdx[s.i] = common.Idx(s.idx + 1).BigInt()
864 s.zki.NewAccount[s.i] = big.NewInt(1)
865
866 // intermediate states
867 s.zki.ISOnChain[s.i] = big.NewInt(1)
868 }
869
870 // update receiver account in localStateDB
871 p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
872 if err != nil {
873 return err
874 }
875 if s.zki != nil {
876 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
877 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
878 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
879 s.zki.Sign2[s.i] = big.NewInt(1)
880 }
881 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
882 s.zki.Balance2[s.i] = accReceiver.Balance
883 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
884 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
885 }
886
887 s.idx = s.idx + 1
888 return s.setIdx(s.idx)
889}
890
891// It returns the ExitAccount and a boolean determining if the Exit created a
892// new Leaf in the ExitTree.
893func (s *StateDB) applyExit(coordIdxsMap map[common.TokenID]common.Idx, collectedFees map[common.TokenID]*big.Int,
894 exitTree *merkletree.MerkleTree, tx common.Tx) (*common.Account, bool, error) {
895 // 0. subtract tx.Amount from current Account in StateMT
896 // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
897 acc, err := s.GetAccount(tx.FromIdx)
898 if err != nil {
899 return nil, false, err
900 }
901
902 if !tx.IsL1 {
903 // increment nonce
904 acc.Nonce++
905
906 // compute fee and subtract it from the accSender
907 fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
908 if err != nil {
909 return nil, false, err
910 }
911 feeAndAmount := new(big.Int).Add(tx.Amount, fee)
912 acc.Balance = new(big.Int).Sub(acc.Balance, feeAndAmount)
913
914 accCoord, err := s.GetAccount(coordIdxsMap[acc.TokenID])
915 if err != nil {
916 log.Debugw("No coord Idx to receive fee", "tx", tx)
917 } else {
918 // accumulate the fee for the Coord account
919 accumulated := s.accumulatedFees[accCoord.Idx]
920 accumulated.Add(accumulated, fee)
921
922 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
923 collected := collectedFees[accCoord.TokenID]
924 collected.Add(collected, fee)
925 }
926 }
927 } else {
928 acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
929 }
930
931 p, err := s.UpdateAccount(tx.FromIdx, acc)
932 if err != nil {
933 return nil, false, err
934 }
935 if s.zki != nil {
936 s.zki.TokenID1[s.i] = acc.TokenID.BigInt()
937 s.zki.Nonce1[s.i] = acc.Nonce.BigInt()
938 if babyjub.PointCoordSign(acc.PublicKey.X) {
939 s.zki.Sign1[s.i] = big.NewInt(1)
940 }
941 s.zki.Ay1[s.i] = acc.PublicKey.Y
942 s.zki.Balance1[s.i] = acc.Balance
943 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(acc.EthAddr)
944 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
945 }
946
947 if exitTree == nil {
948 return nil, false, nil
949 }
950 exitAccount, err := getAccountInTreeDB(exitTree.DB(), tx.FromIdx)
951 if err == db.ErrNotFound {
952 // 1a. if idx does not exist in exitTree:
953 // add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance = exitAmount (exitAmount=tx.Amount)
954 exitAccount := &common.Account{
955 TokenID: acc.TokenID,
956 Nonce: common.Nonce(1),
957 Balance: tx.Amount,
958 PublicKey: acc.PublicKey,
959 EthAddr: acc.EthAddr,
960 }
961 _, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
962 return exitAccount, true, err
963 } else if err != nil {
964 return exitAccount, false, err
965 }
966
967 // 1b. if idx already exist in exitTree:
968 // update account, where account.Balance += exitAmount
969 exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
970 _, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
971 return exitAccount, false, err
972}
973
974// getIdx returns the stored Idx from the localStateDB, which is the last Idx
975// used for an Account in the localStateDB.
976func (s *StateDB) getIdx() (common.Idx, error) {
977 idxBytes, err := s.DB().Get(keyidx)
978 if err == db.ErrNotFound {
979 return 0, nil
980 }
981 if err != nil {
982 return 0, err
983 }
984 return common.IdxFromBytes(idxBytes[:])
985}
986
987// setIdx stores Idx in the localStateDB
988func (s *StateDB) setIdx(idx common.Idx) error {
989 tx, err := s.DB().NewTx()
990 if err != nil {
991 return err
992 }
993 idxBytes, err := idx.Bytes()
994 if err != nil {
995 return err
996 }
997 err = tx.Put(keyidx, idxBytes[:])
998 if err != nil {
999 return err
1000 }
1001 if err := tx.Commit(); err != nil {
1002 return err
1003 }
1004 return nil
1005}