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