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