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