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