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 // deposit the tx.EffectiveDepositAmount into the sender account
710 accSender, err := s.GetAccount(tx.FromIdx)
711 if err != nil {
712 return tracerr.Wrap(err)
713 }
714 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.EffectiveDepositAmount)
715
716 // in case that the tx is a L1Tx>DepositTransfer
717 var accReceiver *common.Account
718 if transfer {
719 accReceiver, err = s.GetAccount(tx.ToIdx)
720 if err != nil {
721 return tracerr.Wrap(err)
722 }
723 // subtract amount to the sender
724 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.EffectiveAmount)
725 // add amount to the receiver
726 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.EffectiveAmount)
727 }
728 // update sender account in localStateDB
729 p, err := s.UpdateAccount(tx.FromIdx, accSender)
730 if err != nil {
731 return tracerr.Wrap(err)
732 }
733 if s.zki != nil {
734 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
735 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
736 if babyjub.PointCoordSign(accSender.PublicKey.X) {
737 s.zki.Sign1[s.i] = big.NewInt(1)
738 }
739 s.zki.Ay1[s.i] = accSender.PublicKey.Y
740 s.zki.Balance1[s.i] = accSender.Balance
741 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
742 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
743 // IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
744 }
745
746 // this is done after updating Sender Account (depositer)
747 if transfer {
748 // update receiver account in localStateDB
749 p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
750 if err != nil {
751 return tracerr.Wrap(err)
752 }
753 if s.zki != nil {
754 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
755 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
756 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
757 s.zki.Sign2[s.i] = big.NewInt(1)
758 }
759 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
760 s.zki.Balance2[s.i] = accReceiver.Balance
761 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
762 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
763 // IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
764 }
765 }
766
767 return nil
768}
769
770// applyTransfer updates the balance & nonce in the account of the sender, and
771// the balance in the account of the receiver.
772// Parameter 'toIdx' should be at 0 if the tx already has tx.ToIdx!=0, if
773// tx.ToIdx==0, then toIdx!=0, and will be used the toIdx parameter as Idx of
774// the receiver. This parameter is used when the tx.ToIdx is not specified and
775// the real ToIdx is found trhrough the ToEthAddr or ToBJJ.
776func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx,
777 collectedFees map[common.TokenID]*big.Int,
778 tx common.Tx, auxToIdx common.Idx) error {
779 if auxToIdx == common.Idx(0) {
780 auxToIdx = tx.ToIdx
781 }
782 // get sender and receiver accounts from localStateDB
783 accSender, err := s.GetAccount(tx.FromIdx)
784 if err != nil {
785 log.Error(err)
786 return tracerr.Wrap(err)
787 }
788
789 if s.zki != nil {
790 // Set the State1 before updating the Sender leaf
791 s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
792 s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
793 if babyjub.PointCoordSign(accSender.PublicKey.X) {
794 s.zki.Sign1[s.i] = big.NewInt(1)
795 }
796 s.zki.Ay1[s.i] = accSender.PublicKey.Y
797 s.zki.Balance1[s.i] = accSender.Balance
798 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
799 }
800 if !tx.IsL1 {
801 // increment nonce
802 accSender.Nonce++
803
804 // compute fee and subtract it from the accSender
805 fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
806 if err != nil {
807 return tracerr.Wrap(err)
808 }
809 feeAndAmount := new(big.Int).Add(tx.Amount, fee)
810 accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount)
811
812 if _, ok := coordIdxsMap[accSender.TokenID]; ok {
813 accCoord, err := s.GetAccount(coordIdxsMap[accSender.TokenID])
814 if err != nil {
815 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]))
816 }
817 // accumulate the fee for the Coord account
818 accumulated := s.accumulatedFees[accCoord.Idx]
819 accumulated.Add(accumulated, fee)
820
821 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
822 collected := collectedFees[accCoord.TokenID]
823 collected.Add(collected, fee)
824 }
825 } else {
826 log.Debugw("No coord Idx to receive fee", "tx", tx)
827 }
828 } else {
829 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
830 }
831
832 // update sender account in localStateDB
833 pSender, err := s.UpdateAccount(tx.FromIdx, accSender)
834 if err != nil {
835 log.Error(err)
836 return tracerr.Wrap(err)
837 }
838 if s.zki != nil {
839 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings)
840 }
841
842 var accReceiver *common.Account
843 if tx.FromIdx == auxToIdx {
844 // if Sender is the Receiver, reuse 'accSender' pointer,
845 // because in the DB the account for 'auxToIdx' won't be
846 // updated yet
847 accReceiver = accSender
848 } else {
849 accReceiver, err = s.GetAccount(auxToIdx)
850 if err != nil {
851 log.Error(err)
852 return tracerr.Wrap(err)
853 }
854 }
855 if s.zki != nil {
856 // Set the State2 before updating the Receiver leaf
857 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
858 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
859 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
860 s.zki.Sign2[s.i] = big.NewInt(1)
861 }
862 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
863 s.zki.Balance2[s.i] = accReceiver.Balance
864 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
865 }
866
867 // add amount-feeAmount to the receiver
868 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
869
870 // update receiver account in localStateDB
871 pReceiver, err := s.UpdateAccount(auxToIdx, accReceiver)
872 if err != nil {
873 return tracerr.Wrap(err)
874 }
875 if s.zki != nil {
876 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings)
877 }
878
879 return nil
880}
881
882// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
883// makes a deposit, and performs a transfer to another account
884func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
885 accSender := &common.Account{
886 TokenID: tx.TokenID,
887 Nonce: 0,
888 Balance: tx.EffectiveDepositAmount,
889 PublicKey: tx.FromBJJ,
890 EthAddr: tx.FromEthAddr,
891 }
892 accReceiver, err := s.GetAccount(tx.ToIdx)
893 if err != nil {
894 return tracerr.Wrap(err)
895 }
896 // subtract amount to the sender
897 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.EffectiveAmount)
898 // add amount to the receiver
899 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.EffectiveAmount)
900
901 // create Account of the Sender
902 p, err := s.CreateAccount(common.Idx(s.idx+1), accSender)
903 if err != nil {
904 return tracerr.Wrap(err)
905 }
906 if s.zki != nil {
907 s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
908 s.zki.Nonce1[s.i] = big.NewInt(0)
909 if babyjub.PointCoordSign(tx.FromBJJ.X) {
910 s.zki.Sign1[s.i] = big.NewInt(1)
911 }
912 s.zki.Ay1[s.i] = tx.FromBJJ.Y
913 s.zki.Balance1[s.i] = tx.EffectiveDepositAmount
914 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
915 s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
916 if p.IsOld0 {
917 s.zki.IsOld0_1[s.i] = big.NewInt(1)
918 }
919 s.zki.OldKey1[s.i] = p.OldKey.BigInt()
920 s.zki.OldValue1[s.i] = p.OldValue.BigInt()
921
922 s.zki.Metadata.NewLastIdxRaw = s.idx + 1
923
924 s.zki.AuxFromIdx[s.i] = common.Idx(s.idx + 1).BigInt()
925 s.zki.NewAccount[s.i] = big.NewInt(1)
926
927 // intermediate states
928 s.zki.ISOnChain[s.i] = big.NewInt(1)
929 }
930
931 // update receiver account in localStateDB
932 p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
933 if err != nil {
934 return tracerr.Wrap(err)
935 }
936 if s.zki != nil {
937 s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
938 s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
939 if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
940 s.zki.Sign2[s.i] = big.NewInt(1)
941 }
942 s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
943 s.zki.Balance2[s.i] = accReceiver.Balance
944 s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
945 s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
946 }
947
948 s.idx = s.idx + 1
949 return s.setIdx(s.idx)
950}
951
952// It returns the ExitAccount and a boolean determining if the Exit created a
953// new Leaf in the ExitTree.
954func (s *StateDB) applyExit(coordIdxsMap map[common.TokenID]common.Idx,
955 collectedFees map[common.TokenID]*big.Int, exitTree *merkletree.MerkleTree,
956 tx common.Tx) (*common.Account, bool, error) {
957 // 0. subtract tx.Amount from current Account in StateMT
958 // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
959 acc, err := s.GetAccount(tx.FromIdx)
960 if err != nil {
961 return nil, false, tracerr.Wrap(err)
962 }
963
964 if !tx.IsL1 {
965 // increment nonce
966 acc.Nonce++
967
968 // compute fee and subtract it from the accSender
969 fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
970 if err != nil {
971 return nil, false, tracerr.Wrap(err)
972 }
973 feeAndAmount := new(big.Int).Add(tx.Amount, fee)
974 acc.Balance = new(big.Int).Sub(acc.Balance, feeAndAmount)
975
976 if _, ok := coordIdxsMap[acc.TokenID]; ok {
977 accCoord, err := s.GetAccount(coordIdxsMap[acc.TokenID])
978 if err != nil {
979 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]))
980 }
981 // accumulate the fee for the Coord account
982 accumulated := s.accumulatedFees[accCoord.Idx]
983 accumulated.Add(accumulated, fee)
984
985 if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
986 collected := collectedFees[accCoord.TokenID]
987 collected.Add(collected, fee)
988 }
989 } else {
990 log.Debugw("No coord Idx to receive fee", "tx", tx)
991 }
992 } else {
993 acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
994 }
995
996 p, err := s.UpdateAccount(tx.FromIdx, acc)
997 if err != nil {
998 return nil, false, tracerr.Wrap(err)
999 }
1000 if s.zki != nil {
1001 s.zki.TokenID1[s.i] = acc.TokenID.BigInt()
1002 s.zki.Nonce1[s.i] = acc.Nonce.BigInt()
1003 if babyjub.PointCoordSign(acc.PublicKey.X) {
1004 s.zki.Sign1[s.i] = big.NewInt(1)
1005 }
1006 s.zki.Ay1[s.i] = acc.PublicKey.Y
1007 s.zki.Balance1[s.i] = acc.Balance
1008 s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(acc.EthAddr)
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(1),
1022 Balance: tx.Amount,
1023 PublicKey: acc.PublicKey,
1024 EthAddr: acc.EthAddr,
1025 }
1026 _, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
1027 return exitAccount, true, tracerr.Wrap(err)
1028 } else if err != nil {
1029 return exitAccount, false, tracerr.Wrap(err)
1030 }
1031
1032 // 1b. if idx already exist in exitTree:
1033 // update account, where account.Balance += exitAmount
1034 exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
1035 _, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
1036 return exitAccount, false, tracerr.Wrap(err)
1037}
1038
1039// computeEffectiveAmounts checks that the L1Tx data is correct
1040func (s *StateDB) computeEffectiveAmounts(tx *common.L1Tx) {
1041 if !tx.UserOrigin {
1042 // case where the L1Tx is generated by the Coordinator
1043 tx.EffectiveAmount = big.NewInt(0)
1044 tx.EffectiveDepositAmount = big.NewInt(0)
1045 return
1046 }
1047
1048 tx.EffectiveAmount = tx.Amount
1049 tx.EffectiveDepositAmount = tx.DepositAmount
1050 if tx.Type == common.TxTypeCreateAccountDeposit {
1051 return
1052 }
1053
1054 if tx.ToIdx >= common.UserThreshold && tx.FromIdx == common.Idx(0) {
1055 // CreateAccountDepositTransfer case
1056 cmp := tx.DepositAmount.Cmp(tx.Amount)
1057 if cmp == -1 { // DepositAmount<Amount
1058 tx.EffectiveAmount = big.NewInt(0)
1059 return
1060 }
1061 return
1062 }
1063
1064 accSender, err := s.GetAccount(tx.FromIdx)
1065 if err != nil {
1066 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: can not get account for tx.FromIdx: %d", tx.FromIdx)
1067 tx.EffectiveDepositAmount = big.NewInt(0)
1068 tx.EffectiveAmount = big.NewInt(0)
1069 return
1070 }
1071
1072 // check that tx.TokenID corresponds to the Sender account TokenID
1073 if tx.TokenID != accSender.TokenID {
1074 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: tx.TokenID (%d) !=sender account TokenID (%d)", tx.TokenID, accSender.TokenID)
1075 tx.EffectiveDepositAmount = big.NewInt(0)
1076 tx.EffectiveAmount = big.NewInt(0)
1077 return
1078 }
1079
1080 // check that Sender has enough balance
1081 bal := accSender.Balance
1082 if tx.DepositAmount != nil {
1083 bal = new(big.Int).Add(bal, tx.EffectiveDepositAmount)
1084 }
1085 cmp := bal.Cmp(tx.Amount)
1086 if cmp == -1 {
1087 log.Debugf("EffectiveAmount = 0: Not enough funds (%s<%s)", bal.String(), tx.Amount.String())
1088 tx.EffectiveAmount = big.NewInt(0)
1089 return
1090 }
1091
1092 // check that the tx.FromEthAddr is the same than the EthAddress of the
1093 // Sender
1094 if !bytes.Equal(tx.FromEthAddr.Bytes(), accSender.EthAddr.Bytes()) {
1095 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())
1096 tx.EffectiveDepositAmount = big.NewInt(0)
1097 tx.EffectiveAmount = big.NewInt(0)
1098 return
1099 }
1100
1101 if tx.ToIdx == common.Idx(1) || tx.ToIdx == common.Idx(0) {
1102 // if transfer is Exit type, there are no more checks
1103 return
1104 }
1105
1106 // check that TokenID is the same for Sender & Receiver account
1107 accReceiver, err := s.GetAccount(tx.ToIdx)
1108 if err != nil {
1109 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: can not get account for tx.ToIdx: %d", tx.ToIdx)
1110 tx.EffectiveDepositAmount = big.NewInt(0)
1111 tx.EffectiveAmount = big.NewInt(0)
1112 return
1113 }
1114 if accSender.TokenID != accReceiver.TokenID {
1115 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: sender account TokenID (%d) != receiver account TokenID (%d)", tx.TokenID, accSender.TokenID)
1116 tx.EffectiveDepositAmount = big.NewInt(0)
1117 tx.EffectiveAmount = big.NewInt(0)
1118 return
1119 }
1120}
1121
1122// getIdx returns the stored Idx from the localStateDB, which is the last Idx
1123// used for an Account in the localStateDB.
1124func (s *StateDB) getIdx() (common.Idx, error) {
1125 idxBytes, err := s.DB().Get(keyidx)
1126 if tracerr.Unwrap(err) == db.ErrNotFound {
1127 return 0, nil
1128 }
1129 if err != nil {
1130 return 0, tracerr.Wrap(err)
1131 }
1132 return common.IdxFromBytes(idxBytes[:])
1133}
1134
1135// setIdx stores Idx in the localStateDB
1136func (s *StateDB) setIdx(idx common.Idx) error {
1137 tx, err := s.DB().NewTx()
1138 if err != nil {
1139 return tracerr.Wrap(err)
1140 }
1141 idxBytes, err := idx.Bytes()
1142 if err != nil {
1143 return tracerr.Wrap(err)
1144 }
1145 err = tx.Put(keyidx, idxBytes[:])
1146 if err != nil {
1147 return tracerr.Wrap(err)
1148 }
1149 if err := tx.Commit(); err != nil {
1150 return tracerr.Wrap(err)
1151 }
1152 return nil
1153}