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