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 if tx.Type == common.TxTypeForceTransfer ||
520 tx.Type == common.TxTypeDepositTransfer ||
521 tx.Type == common.TxTypeCreateAccountDepositTransfer ||
522 tx.Type == common.TxTypeForceExit {
523 // in the cases where at L1Tx there is usage of the
524 // Amount parameter, add it at the ZKInputs.AmountF
525 // slot
526 amountF40, err := common.NewFloat40(tx.Amount)
527 if err != nil {
528 return nil, nil, false, nil, tracerr.Wrap(err)
529 }
530 tp.zki.AmountF[tp.i] = big.NewInt(int64(amountF40))
531 }
532 }
533
534 switch tx.Type {
535 case common.TxTypeForceTransfer:
536 tp.computeEffectiveAmounts(tx)
537
538 // go to the MT account of sender and receiver, and update balance
539 // & nonce
540
541 // coordIdxsMap is 'nil', as at L1Txs there is no L2 fees.
542 // 0 for the parameter toIdx, as at L1Tx ToIdx can only be 0 in
543 // the Deposit type case.
544 err := tp.applyTransfer(nil, nil, tx.Tx(), 0)
545 if err != nil {
546 log.Error(err)
547 return nil, nil, false, nil, tracerr.Wrap(err)
548 }
549 case common.TxTypeCreateAccountDeposit:
550 tp.computeEffectiveAmounts(tx)
551
552 // add new account to the MT, update balance of the MT account
553 err := tp.applyCreateAccount(tx)
554 if err != nil {
555 log.Error(err)
556 return nil, nil, false, nil, tracerr.Wrap(err)
557 }
558 // TODO applyCreateAccount will return the created account,
559 // which in the case type==TypeSynchronizer will be added to an
560 // array of created accounts that will be returned
561 case common.TxTypeDeposit:
562 tp.computeEffectiveAmounts(tx)
563
564 // update balance of the MT account
565 err := tp.applyDeposit(tx, false)
566 if err != nil {
567 log.Error(err)
568 return nil, nil, false, nil, tracerr.Wrap(err)
569 }
570 case common.TxTypeDepositTransfer:
571 tp.computeEffectiveAmounts(tx)
572
573 // update balance in MT account, update balance & nonce of sender
574 // & receiver
575 err := tp.applyDeposit(tx, true)
576 if err != nil {
577 log.Error(err)
578 return nil, nil, false, nil, tracerr.Wrap(err)
579 }
580 case common.TxTypeCreateAccountDepositTransfer:
581 tp.computeEffectiveAmounts(tx)
582
583 // add new account to the merkletree, update balance in MT account,
584 // update balance & nonce of sender & receiver
585 err := tp.applyCreateAccountDepositTransfer(tx)
586 if err != nil {
587 log.Error(err)
588 return nil, nil, false, nil, tracerr.Wrap(err)
589 }
590 case common.TxTypeForceExit:
591 tp.computeEffectiveAmounts(tx)
592
593 // execute exit flow
594 // coordIdxsMap is 'nil', as at L1Txs there is no L2 fees
595 exitAccount, newExit, err := tp.applyExit(nil, nil, exitTree, tx.Tx())
596 if err != nil {
597 log.Error(err)
598 return nil, nil, false, nil, tracerr.Wrap(err)
599 }
600 return &tx.FromIdx, exitAccount, newExit, nil, nil
601 default:
602 }
603
604 var createdAccount *common.Account
605 if tp.s.Type() == statedb.TypeSynchronizer &&
606 (tx.Type == common.TxTypeCreateAccountDeposit ||
607 tx.Type == common.TxTypeCreateAccountDepositTransfer) {
608 var err error
609 createdAccount, err = tp.s.GetAccount(tp.s.CurrentIdx())
610 if err != nil {
611 log.Error(err)
612 return nil, nil, false, nil, tracerr.Wrap(err)
613 }
614 }
615
616 return nil, nil, false, createdAccount, nil
617}
618
619// ProcessL2Tx process the given L2Tx applying the needed updates to the
620// StateDB depending on the transaction Type. It returns the 3 parameters
621// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
622// the Exit created a new Leaf in the ExitTree.
623func (tp *TxProcessor) ProcessL2Tx(coordIdxsMap map[common.TokenID]common.Idx,
624 collectedFees map[common.TokenID]*big.Int, exitTree *merkletree.MerkleTree,
625 tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) {
626 var err error
627 // if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
628 if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) {
629 if tp.s.Type() == statedb.TypeSynchronizer {
630 // thisTypeould never be reached
631 log.Error("WARNING: In StateDB with Synchronizer mode L2.ToIdx can't be 0")
632 return nil, nil, false, tracerr.Wrap(fmt.Errorf("In StateDB with Synchronizer mode L2.ToIdx can't be 0"))
633 }
634 // case when tx.Type== common.TxTypeTransferToEthAddr or common.TxTypeTransferToBJJ
635
636 accSender, err := tp.s.GetAccount(tx.FromIdx)
637 if err != nil {
638 return nil, nil, false, tracerr.Wrap(err)
639 }
640 tx.AuxToIdx, err = tp.s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ, accSender.TokenID)
641 if err != nil {
642 return nil, nil, false, tracerr.Wrap(err)
643 }
644 }
645
646 // ZKInputs
647 if tp.zki != nil {
648 // Txs
649 tp.zki.TxCompressedData[tp.i], err = tx.TxCompressedData(tp.config.ChainID)
650 if err != nil {
651 return nil, nil, false, tracerr.Wrap(err)
652 }
653 tp.zki.TxCompressedDataV2[tp.i], err = tx.TxCompressedDataV2()
654 if err != nil {
655 return nil, nil, false, tracerr.Wrap(err)
656 }
657 tp.zki.FromIdx[tp.i] = tx.FromIdx.BigInt()
658 tp.zki.ToIdx[tp.i] = tx.ToIdx.BigInt()
659
660 // fill AuxToIdx if needed
661 if tx.ToIdx == 0 {
662 // use toIdx that can have been filled by tx.ToIdx or
663 // if tx.Idx==0 (this case), toIdx is filled by the Idx
664 // from db by ToEthAddr&ToBJJ
665 tp.zki.AuxToIdx[tp.i] = tx.AuxToIdx.BigInt()
666 }
667
668 if tx.ToBJJ != common.EmptyBJJComp {
669 _, tp.zki.ToBJJAy[tp.i] = babyjub.UnpackSignY(tx.ToBJJ)
670 }
671 tp.zki.ToEthAddr[tp.i] = common.EthAddrToBigInt(tx.ToEthAddr)
672
673 tp.zki.OnChain[tp.i] = big.NewInt(0)
674 amountF40, err := common.NewFloat40(tx.Amount)
675 if err != nil {
676 return nil, nil, false, tracerr.Wrap(err)
677 }
678 tp.zki.AmountF[tp.i] = big.NewInt(int64(amountF40))
679 tp.zki.NewAccount[tp.i] = big.NewInt(0)
680
681 // L2Txs
682 // tp.zki.RqOffset[tp.i] = // TODO Rq once TxSelector is ready
683 // tp.zki.RqTxCompressedDataV2[tp.i] = // TODO
684 // tp.zki.RqToEthAddr[tp.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
685 // tp.zki.RqToBJJAy[tp.i] = tx.ToBJJ.Y // TODO
686
687 signature, err := tx.Signature.Decompress()
688 if err != nil {
689 log.Error(err)
690 return nil, nil, false, tracerr.Wrap(err)
691 }
692 tp.zki.S[tp.i] = signature.S
693 tp.zki.R8x[tp.i] = signature.R8.X
694 tp.zki.R8y[tp.i] = signature.R8.Y
695 }
696
697 // if StateDB type==TypeSynchronizer, will need to add Nonce
698 if tp.s.Type() == statedb.TypeSynchronizer {
699 // as tType==TypeSynchronizer, always tx.ToIdx!=0
700 acc, err := tp.s.GetAccount(tx.FromIdx)
701 if err != nil {
702 log.Errorw("GetAccount", "fromIdx", tx.FromIdx, "err", err)
703 return nil, nil, false, tracerr.Wrap(err)
704 }
705 tx.Nonce = acc.Nonce
706 tx.TokenID = acc.TokenID
707 }
708
709 switch tx.Type {
710 case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
711 // go to the MT account of sender and receiver, and update
712 // balance & nonce
713 err = tp.applyTransfer(coordIdxsMap, collectedFees, tx.Tx(), tx.AuxToIdx)
714 if err != nil {
715 log.Error(err)
716 return nil, nil, false, tracerr.Wrap(err)
717 }
718 case common.TxTypeExit:
719 // execute exit flow
720 exitAccount, newExit, err := tp.applyExit(coordIdxsMap, collectedFees, exitTree, tx.Tx())
721 if err != nil {
722 log.Error(err)
723 return nil, nil, false, tracerr.Wrap(err)
724 }
725 return &tx.FromIdx, exitAccount, newExit, nil
726 default:
727 }
728 return nil, nil, false, nil
729}
730
731// applyCreateAccount creates a new account in the account of the depositer, it
732// stores the deposit value
733func (tp *TxProcessor) applyCreateAccount(tx *common.L1Tx) error {
734 account := &common.Account{
735 TokenID: tx.TokenID,
736 Nonce: 0,
737 Balance: tx.EffectiveDepositAmount,
738 BJJ: tx.FromBJJ,
739 EthAddr: tx.FromEthAddr,
740 }
741
742 p, err := tp.s.CreateAccount(common.Idx(tp.s.CurrentIdx()+1), account)
743 if err != nil {
744 return tracerr.Wrap(err)
745 }
746 if tp.zki != nil {
747 tp.zki.TokenID1[tp.i] = tx.TokenID.BigInt()
748 tp.zki.Nonce1[tp.i] = big.NewInt(0)
749 fromBJJSign, fromBJJY := babyjub.UnpackSignY(tx.FromBJJ)
750 if fromBJJSign {
751 tp.zki.Sign1[tp.i] = big.NewInt(1)
752 }
753 tp.zki.Ay1[tp.i] = fromBJJY
754 tp.zki.Balance1[tp.i] = tx.EffectiveDepositAmount
755 tp.zki.EthAddr1[tp.i] = common.EthAddrToBigInt(tx.FromEthAddr)
756 tp.zki.Siblings1[tp.i] = siblingsToZKInputFormat(p.Siblings)
757 if p.IsOld0 {
758 tp.zki.IsOld0_1[tp.i] = big.NewInt(1)
759 }
760 tp.zki.OldKey1[tp.i] = p.OldKey.BigInt()
761 tp.zki.OldValue1[tp.i] = p.OldValue.BigInt()
762
763 tp.zki.Metadata.NewLastIdxRaw = tp.s.CurrentIdx() + 1
764
765 tp.zki.AuxFromIdx[tp.i] = common.Idx(tp.s.CurrentIdx() + 1).BigInt()
766 tp.zki.NewAccount[tp.i] = big.NewInt(1)
767
768 if tp.i < len(tp.zki.ISOnChain) { // len(tp.zki.ISOnChain) == nTx
769 // intermediate states
770 tp.zki.ISOnChain[tp.i] = big.NewInt(1)
771 }
772 }
773
774 return tp.s.SetCurrentIdx(tp.s.CurrentIdx() + 1)
775}
776
777// applyDeposit updates the balance in the account of the depositer, if
778// andTransfer parameter is set to true, the method will also apply the
779// Transfer of the L1Tx/DepositTransfer
780func (tp *TxProcessor) applyDeposit(tx *common.L1Tx, transfer bool) error {
781 accSender, err := tp.s.GetAccount(tx.FromIdx)
782 if err != nil {
783 return tracerr.Wrap(err)
784 }
785
786 if tp.zki != nil {
787 tp.zki.TokenID1[tp.i] = accSender.TokenID.BigInt()
788 tp.zki.Nonce1[tp.i] = accSender.Nonce.BigInt()
789 senderBJJSign, senderBJJY := babyjub.UnpackSignY(accSender.BJJ)
790 if senderBJJSign {
791 tp.zki.Sign1[tp.i] = big.NewInt(1)
792 }
793 tp.zki.Ay1[tp.i] = senderBJJY
794 tp.zki.Balance1[tp.i] = accSender.Balance
795 tp.zki.EthAddr1[tp.i] = common.EthAddrToBigInt(accSender.EthAddr)
796 }
797
798 // add the deposit to the sender
799 accSender.Balance = new(big.Int).Add(accSender.Balance, tx.EffectiveDepositAmount)
800 // subtract amount to the sender
801 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.EffectiveAmount)
802 if accSender.Balance.Cmp(big.NewInt(0)) == -1 { // balance<0
803 return newErrorNotEnoughBalance(tx.Tx())
804 }
805
806 // update sender account in localStateDB
807 p, err := tp.s.UpdateAccount(tx.FromIdx, accSender)
808 if err != nil {
809 return tracerr.Wrap(err)
810 }
811 if tp.zki != nil {
812 tp.zki.Siblings1[tp.i] = siblingsToZKInputFormat(p.Siblings)
813 // IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
814 }
815
816 // in case that the tx is a L1Tx>DepositTransfer
817 var accReceiver *common.Account
818 if transfer {
819 if tx.ToIdx == tx.FromIdx {
820 accReceiver = accSender
821 } else {
822 accReceiver, err = tp.s.GetAccount(tx.ToIdx)
823 if err != nil {
824 return tracerr.Wrap(err)
825 }
826 }
827
828 if tp.zki != nil {
829 tp.zki.TokenID2[tp.i] = accReceiver.TokenID.BigInt()
830 tp.zki.Nonce2[tp.i] = accReceiver.Nonce.BigInt()
831 receiverBJJSign, receiverBJJY := babyjub.UnpackSignY(accReceiver.BJJ)
832 if receiverBJJSign {
833 tp.zki.Sign2[tp.i] = big.NewInt(1)
834 }
835 tp.zki.Ay2[tp.i] = receiverBJJY
836 tp.zki.Balance2[tp.i] = accReceiver.Balance
837 tp.zki.EthAddr2[tp.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
838 }
839
840 // add amount to the receiver
841 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.EffectiveAmount)
842
843 // update receiver account in localStateDB
844 p, err := tp.s.UpdateAccount(tx.ToIdx, accReceiver)
845 if err != nil {
846 return tracerr.Wrap(err)
847 }
848 if tp.zki != nil {
849 tp.zki.Siblings2[tp.i] = siblingsToZKInputFormat(p.Siblings)
850 // IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
851 }
852 }
853
854 return nil
855}
856
857// applyTransfer updates the balance & nonce in the account of the sender, and
858// the balance in the account of the receiver.
859// Parameter 'toIdx' should be at 0 if the tx already has tx.ToIdx!=0, if
860// tx.ToIdx==0, then toIdx!=0, and will be used the toIdx parameter as Idx of
861// the receiver. This parameter is used when the tx.ToIdx is not specified and
862// the real ToIdx is found trhrough the ToEthAddr or ToBJJ.
863func (tp *TxProcessor) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx,
864 collectedFees map[common.TokenID]*big.Int, tx common.Tx, auxToIdx common.Idx) error {
865 if auxToIdx == common.Idx(0) {
866 auxToIdx = tx.ToIdx
867 }
868 // get sender and receiver accounts from localStateDB
869 accSender, err := tp.s.GetAccount(tx.FromIdx)
870 if err != nil {
871 log.Error(err)
872 return tracerr.Wrap(err)
873 }
874
875 if tp.zki != nil {
876 // Set the State1 before updating the Sender leaf
877 tp.zki.TokenID1[tp.i] = accSender.TokenID.BigInt()
878 tp.zki.Nonce1[tp.i] = accSender.Nonce.BigInt()
879 senderBJJSign, senderBJJY := babyjub.UnpackSignY(accSender.BJJ)
880 if senderBJJSign {
881 tp.zki.Sign1[tp.i] = big.NewInt(1)
882 }
883 tp.zki.Ay1[tp.i] = senderBJJY
884 tp.zki.Balance1[tp.i] = accSender.Balance
885 tp.zki.EthAddr1[tp.i] = common.EthAddrToBigInt(accSender.EthAddr)
886 }
887 if !tx.IsL1 { // L2
888 // increment nonce
889 accSender.Nonce++
890
891 // compute fee and subtract it from the accSender
892 fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
893 if err != nil {
894 return tracerr.Wrap(err)
895 }
896 feeAndAmount := new(big.Int).Add(tx.Amount, fee)
897 accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount)
898 if accSender.Balance.Cmp(big.NewInt(0)) == -1 { // balance<0
899 return newErrorNotEnoughBalance(tx)
900 }
901
902 if _, ok := coordIdxsMap[accSender.TokenID]; ok {
903 accCoord, err := tp.s.GetAccount(coordIdxsMap[accSender.TokenID])
904 if err != nil {
905 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]))
906 }
907 // accumulate the fee for the Coord account
908 accumulated := tp.AccumulatedFees[accCoord.Idx]
909 accumulated.Add(accumulated, fee)
910
911 if tp.s.Type() == statedb.TypeSynchronizer ||
912 tp.s.Type() == statedb.TypeBatchBuilder {
913 collected := collectedFees[accCoord.TokenID]
914 collected.Add(collected, fee)
915 }
916 } else {
917 log.Debugw("No coord Idx to receive fee", "tx", tx)
918 }
919 } else {
920 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
921 if accSender.Balance.Cmp(big.NewInt(0)) == -1 { // balance<0
922 return newErrorNotEnoughBalance(tx)
923 }
924 }
925
926 // update sender account in localStateDB
927 pSender, err := tp.s.UpdateAccount(tx.FromIdx, accSender)
928 if err != nil {
929 log.Error(err)
930 return tracerr.Wrap(err)
931 }
932 if tp.zki != nil {
933 tp.zki.Siblings1[tp.i] = siblingsToZKInputFormat(pSender.Siblings)
934 }
935
936 var accReceiver *common.Account
937 if auxToIdx == tx.FromIdx {
938 // if Sender is the Receiver, reuse 'accSender' pointer,
939 // because in the DB the account for 'auxToIdx' won't be
940 // updated yet
941 accReceiver = accSender
942 } else {
943 accReceiver, err = tp.s.GetAccount(auxToIdx)
944 if err != nil {
945 log.Error(err, auxToIdx)
946 return tracerr.Wrap(err)
947 }
948 }
949 if tp.zki != nil {
950 // Set the State2 before updating the Receiver leaf
951 tp.zki.TokenID2[tp.i] = accReceiver.TokenID.BigInt()
952 tp.zki.Nonce2[tp.i] = accReceiver.Nonce.BigInt()
953 receiverBJJSign, receiverBJJY := babyjub.UnpackSignY(accReceiver.BJJ)
954 if receiverBJJSign {
955 tp.zki.Sign2[tp.i] = big.NewInt(1)
956 }
957 tp.zki.Ay2[tp.i] = receiverBJJY
958 tp.zki.Balance2[tp.i] = accReceiver.Balance
959 tp.zki.EthAddr2[tp.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
960 }
961
962 // add amount-feeAmount to the receiver
963 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
964
965 // update receiver account in localStateDB
966 pReceiver, err := tp.s.UpdateAccount(auxToIdx, accReceiver)
967 if err != nil {
968 return tracerr.Wrap(err)
969 }
970 if tp.zki != nil {
971 tp.zki.Siblings2[tp.i] = siblingsToZKInputFormat(pReceiver.Siblings)
972 }
973
974 return nil
975}
976
977// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
978// makes a deposit, and performs a transfer to another account
979func (tp *TxProcessor) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
980 auxFromIdx := common.Idx(tp.s.CurrentIdx() + 1)
981 accSender := &common.Account{
982 TokenID: tx.TokenID,
983 Nonce: 0,
984 Balance: tx.EffectiveDepositAmount,
985 BJJ: tx.FromBJJ,
986 EthAddr: tx.FromEthAddr,
987 }
988
989 if tp.zki != nil {
990 // Set the State1 before updating the Sender leaf
991 tp.zki.TokenID1[tp.i] = tx.TokenID.BigInt()
992 tp.zki.Nonce1[tp.i] = big.NewInt(0)
993 fromBJJSign, fromBJJY := babyjub.UnpackSignY(tx.FromBJJ)
994 if fromBJJSign {
995 tp.zki.Sign1[tp.i] = big.NewInt(1)
996 }
997 tp.zki.Ay1[tp.i] = fromBJJY
998 tp.zki.Balance1[tp.i] = tx.EffectiveDepositAmount
999 tp.zki.EthAddr1[tp.i] = common.EthAddrToBigInt(tx.FromEthAddr)
1000 }
1001
1002 // subtract amount to the sender
1003 accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.EffectiveAmount)
1004 if accSender.Balance.Cmp(big.NewInt(0)) == -1 { // balance<0
1005 return newErrorNotEnoughBalance(tx.Tx())
1006 }
1007
1008 // create Account of the Sender
1009 p, err := tp.s.CreateAccount(common.Idx(tp.s.CurrentIdx()+1), accSender)
1010 if err != nil {
1011 return tracerr.Wrap(err)
1012 }
1013 if tp.zki != nil {
1014 tp.zki.Siblings1[tp.i] = siblingsToZKInputFormat(p.Siblings)
1015 if p.IsOld0 {
1016 tp.zki.IsOld0_1[tp.i] = big.NewInt(1)
1017 }
1018 tp.zki.OldKey1[tp.i] = p.OldKey.BigInt()
1019 tp.zki.OldValue1[tp.i] = p.OldValue.BigInt()
1020
1021 tp.zki.Metadata.NewLastIdxRaw = tp.s.CurrentIdx() + 1
1022
1023 tp.zki.AuxFromIdx[tp.i] = auxFromIdx.BigInt()
1024 tp.zki.NewAccount[tp.i] = big.NewInt(1)
1025
1026 // intermediate states
1027 tp.zki.ISOnChain[tp.i] = big.NewInt(1)
1028 }
1029 var accReceiver *common.Account
1030 if tx.ToIdx == auxFromIdx {
1031 accReceiver = accSender
1032 } else {
1033 accReceiver, err = tp.s.GetAccount(tx.ToIdx)
1034 if err != nil {
1035 log.Error(err)
1036 return tracerr.Wrap(err)
1037 }
1038 }
1039
1040 if tp.zki != nil {
1041 // Set the State2 before updating the Receiver leaf
1042 tp.zki.TokenID2[tp.i] = accReceiver.TokenID.BigInt()
1043 tp.zki.Nonce2[tp.i] = accReceiver.Nonce.BigInt()
1044 receiverBJJSign, receiverBJJY := babyjub.UnpackSignY(accReceiver.BJJ)
1045 if receiverBJJSign {
1046 tp.zki.Sign2[tp.i] = big.NewInt(1)
1047 }
1048 tp.zki.Ay2[tp.i] = receiverBJJY
1049 tp.zki.Balance2[tp.i] = accReceiver.Balance
1050 tp.zki.EthAddr2[tp.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
1051 }
1052
1053 // add amount to the receiver
1054 accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.EffectiveAmount)
1055
1056 // update receiver account in localStateDB
1057 p, err = tp.s.UpdateAccount(tx.ToIdx, accReceiver)
1058 if err != nil {
1059 return tracerr.Wrap(err)
1060 }
1061 if tp.zki != nil {
1062 tp.zki.Siblings2[tp.i] = siblingsToZKInputFormat(p.Siblings)
1063 }
1064
1065 return tp.s.SetCurrentIdx(tp.s.CurrentIdx() + 1)
1066}
1067
1068// It returns the ExitAccount and a boolean determining if the Exit created a
1069// new Leaf in the ExitTree.
1070func (tp *TxProcessor) applyExit(coordIdxsMap map[common.TokenID]common.Idx,
1071 collectedFees map[common.TokenID]*big.Int, exitTree *merkletree.MerkleTree,
1072 tx common.Tx) (*common.Account, bool, error) {
1073 // 0. subtract tx.Amount from current Account in StateMT
1074 // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
1075 acc, err := tp.s.GetAccount(tx.FromIdx)
1076 if err != nil {
1077 return nil, false, tracerr.Wrap(err)
1078 }
1079 if tp.zki != nil {
1080 tp.zki.TokenID1[tp.i] = acc.TokenID.BigInt()
1081 tp.zki.Nonce1[tp.i] = acc.Nonce.BigInt()
1082 accBJJSign, accBJJY := babyjub.UnpackSignY(acc.BJJ)
1083 if accBJJSign {
1084 tp.zki.Sign1[tp.i] = big.NewInt(1)
1085 }
1086 tp.zki.Ay1[tp.i] = accBJJY
1087 tp.zki.Balance1[tp.i] = acc.Balance
1088 tp.zki.EthAddr1[tp.i] = common.EthAddrToBigInt(acc.EthAddr)
1089 }
1090
1091 if !tx.IsL1 {
1092 // increment nonce
1093 acc.Nonce++
1094
1095 // compute fee and subtract it from the accSender
1096 fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
1097 if err != nil {
1098 return nil, false, tracerr.Wrap(err)
1099 }
1100 feeAndAmount := new(big.Int).Add(tx.Amount, fee)
1101 acc.Balance = new(big.Int).Sub(acc.Balance, feeAndAmount)
1102 if acc.Balance.Cmp(big.NewInt(0)) == -1 { // balance<0
1103 return nil, false, newErrorNotEnoughBalance(tx)
1104 }
1105
1106 if _, ok := coordIdxsMap[acc.TokenID]; ok {
1107 accCoord, err := tp.s.GetAccount(coordIdxsMap[acc.TokenID])
1108 if err != nil {
1109 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]))
1110 }
1111
1112 // accumulate the fee for the Coord account
1113 accumulated := tp.AccumulatedFees[accCoord.Idx]
1114 accumulated.Add(accumulated, fee)
1115
1116 if tp.s.Type() == statedb.TypeSynchronizer ||
1117 tp.s.Type() == statedb.TypeBatchBuilder {
1118 collected := collectedFees[accCoord.TokenID]
1119 collected.Add(collected, fee)
1120 }
1121 } else {
1122 log.Debugw("No coord Idx to receive fee", "tx", tx)
1123 }
1124 } else {
1125 acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
1126 if acc.Balance.Cmp(big.NewInt(0)) == -1 { // balance<0
1127 return nil, false, newErrorNotEnoughBalance(tx)
1128 }
1129 }
1130
1131 p, err := tp.s.UpdateAccount(tx.FromIdx, acc)
1132 if err != nil {
1133 return nil, false, tracerr.Wrap(err)
1134 }
1135 if tp.zki != nil {
1136 tp.zki.Siblings1[tp.i] = siblingsToZKInputFormat(p.Siblings)
1137 }
1138
1139 if exitTree == nil {
1140 return nil, false, nil
1141 }
1142 exitAccount, err := statedb.GetAccountInTreeDB(exitTree.DB(), tx.FromIdx)
1143 if tracerr.Unwrap(err) == db.ErrNotFound {
1144 // 1a. if idx does not exist in exitTree:
1145 // add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance =
1146 // exitAmount (exitAmount=tx.Amount)
1147 exitAccount := &common.Account{
1148 TokenID: acc.TokenID,
1149 Nonce: common.Nonce(0),
1150 Balance: tx.Amount,
1151 BJJ: acc.BJJ,
1152 EthAddr: acc.EthAddr,
1153 }
1154 if tp.zki != nil {
1155 // Set the State2 before creating the Exit leaf
1156 tp.zki.TokenID2[tp.i] = acc.TokenID.BigInt()
1157 tp.zki.Nonce2[tp.i] = big.NewInt(0)
1158 accBJJSign, accBJJY := babyjub.UnpackSignY(acc.BJJ)
1159 if accBJJSign {
1160 tp.zki.Sign2[tp.i] = big.NewInt(1)
1161 }
1162 tp.zki.Ay2[tp.i] = accBJJY
1163 tp.zki.Balance2[tp.i] = tx.Amount
1164 tp.zki.EthAddr2[tp.i] = common.EthAddrToBigInt(acc.EthAddr)
1165 // as Leaf didn't exist in the ExitTree, set NewExit[i]=1
1166 tp.zki.NewExit[tp.i] = big.NewInt(1)
1167 }
1168 p, err = statedb.CreateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
1169 if err != nil {
1170 return nil, false, tracerr.Wrap(err)
1171 }
1172 if tp.zki != nil {
1173 tp.zki.Siblings2[tp.i] = siblingsToZKInputFormat(p.Siblings)
1174 if p.IsOld0 {
1175 tp.zki.IsOld0_2[tp.i] = big.NewInt(1)
1176 }
1177 tp.zki.OldKey2[tp.i] = p.OldKey.BigInt()
1178 tp.zki.OldValue2[tp.i] = p.OldValue.BigInt()
1179 tp.zki.ISExitRoot[tp.i] = exitTree.Root().BigInt()
1180 }
1181 return exitAccount, true, nil
1182 } else if err != nil {
1183 return exitAccount, false, tracerr.Wrap(err)
1184 }
1185
1186 // 1b. if idx already exist in exitTree:
1187 if tp.zki != nil {
1188 // Set the State2 before updating the Exit leaf
1189 tp.zki.TokenID2[tp.i] = acc.TokenID.BigInt()
1190 // increment nonce from existing ExitLeaf
1191 tp.zki.Nonce2[tp.i] = exitAccount.Nonce.BigInt()
1192 accBJJSign, accBJJY := babyjub.UnpackSignY(acc.BJJ)
1193 if accBJJSign {
1194 tp.zki.Sign2[tp.i] = big.NewInt(1)
1195 }
1196 tp.zki.Ay2[tp.i] = accBJJY
1197 tp.zki.Balance2[tp.i] = tx.Amount
1198 tp.zki.EthAddr2[tp.i] = common.EthAddrToBigInt(acc.EthAddr)
1199 }
1200
1201 // update account, where account.Balance += exitAmount
1202 exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
1203 p, err = statedb.UpdateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
1204 if err != nil {
1205 return nil, false, tracerr.Wrap(err)
1206 }
1207
1208 if tp.zki != nil {
1209 tp.zki.Siblings2[tp.i] = siblingsToZKInputFormat(p.Siblings)
1210 if p.IsOld0 {
1211 tp.zki.IsOld0_2[tp.i] = big.NewInt(1)
1212 }
1213 tp.zki.OldKey2[tp.i] = p.OldKey.BigInt()
1214 tp.zki.OldValue2[tp.i] = p.OldValue.BigInt()
1215 }
1216
1217 return exitAccount, false, nil
1218}
1219
1220// computeEffectiveAmounts checks that the L1Tx data is correct
1221func (tp *TxProcessor) computeEffectiveAmounts(tx *common.L1Tx) {
1222 tx.EffectiveAmount = tx.Amount
1223 tx.EffectiveDepositAmount = tx.DepositAmount
1224
1225 if !tx.UserOrigin {
1226 // case where the L1Tx is generated by the Coordinator
1227 tx.EffectiveAmount = big.NewInt(0)
1228 tx.EffectiveDepositAmount = big.NewInt(0)
1229 return
1230 }
1231
1232 if tx.Type == common.TxTypeCreateAccountDeposit {
1233 return
1234 }
1235
1236 if tx.ToIdx >= common.UserThreshold && tx.FromIdx == common.Idx(0) {
1237 // CreateAccountDepositTransfer case
1238 cmp := tx.DepositAmount.Cmp(tx.Amount)
1239 if cmp == -1 { // DepositAmount<Amount
1240 tx.EffectiveAmount = big.NewInt(0)
1241 return
1242 }
1243
1244 // check if tx.TokenID==receiver.TokenID
1245 accReceiver, err := tp.s.GetAccount(tx.ToIdx)
1246 if err != nil {
1247 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: can not get account for tx.ToIdx: %d", tx.ToIdx)
1248 tx.EffectiveDepositAmount = big.NewInt(0)
1249 tx.EffectiveAmount = big.NewInt(0)
1250 return
1251 }
1252 if tx.TokenID != accReceiver.TokenID {
1253 log.Debugf("EffectiveAmount = 0: tx TokenID (%d) != receiver account TokenID (%d)", tx.TokenID, accReceiver.TokenID)
1254 tx.EffectiveAmount = big.NewInt(0)
1255 return
1256 }
1257 return
1258 }
1259
1260 accSender, err := tp.s.GetAccount(tx.FromIdx)
1261 if err != nil {
1262 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: can not get account for tx.FromIdx: %d", tx.FromIdx)
1263 tx.EffectiveDepositAmount = big.NewInt(0)
1264 tx.EffectiveAmount = big.NewInt(0)
1265 return
1266 }
1267
1268 // check that tx.TokenID corresponds to the Sender account TokenID
1269 if tx.TokenID != accSender.TokenID {
1270 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: tx.TokenID (%d) !=sender account TokenID (%d)", tx.TokenID, accSender.TokenID)
1271 tx.EffectiveDepositAmount = big.NewInt(0)
1272 tx.EffectiveAmount = big.NewInt(0)
1273 return
1274 }
1275
1276 // check that Sender has enough balance
1277 bal := accSender.Balance
1278 if tx.DepositAmount != nil {
1279 bal = new(big.Int).Add(bal, tx.EffectiveDepositAmount)
1280 }
1281 cmp := bal.Cmp(tx.Amount)
1282 if cmp == -1 {
1283 log.Debugf("EffectiveAmount = 0: Not enough funds (%s<%s)", bal.String(), tx.Amount.String())
1284 tx.EffectiveAmount = big.NewInt(0)
1285 return
1286 }
1287
1288 // check that the tx.FromEthAddr is the same than the EthAddress of the
1289 // Sender
1290 if !bytes.Equal(tx.FromEthAddr.Bytes(), accSender.EthAddr.Bytes()) {
1291 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())
1292 tx.EffectiveAmount = big.NewInt(0)
1293 }
1294
1295 if tx.ToIdx == common.Idx(1) || tx.ToIdx == common.Idx(0) {
1296 // if transfer is Exit type, there are no more checks
1297 return
1298 }
1299
1300 // check that TokenID is the same for Sender & Receiver account
1301 accReceiver, err := tp.s.GetAccount(tx.ToIdx)
1302 if err != nil {
1303 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: can not get account for tx.ToIdx: %d", tx.ToIdx)
1304 tx.EffectiveDepositAmount = big.NewInt(0)
1305 tx.EffectiveAmount = big.NewInt(0)
1306 return
1307 }
1308 if accSender.TokenID != accReceiver.TokenID {
1309 log.Debugf("EffectiveAmount = 0: sender account TokenID (%d) != receiver account TokenID (%d)", accSender.TokenID, accReceiver.TokenID)
1310 tx.EffectiveAmount = big.NewInt(0)
1311 return
1312 }
1313 if tx.TokenID != accReceiver.TokenID {
1314 log.Debugf("EffectiveAmount & EffectiveDepositAmount = 0: tx TokenID (%d) != receiver account TokenID (%d)", tx.TokenID, accReceiver.TokenID)
1315 tx.EffectiveAmount = big.NewInt(0)
1316 return
1317 }
1318}
1319
1320// CheckEnoughBalance returns true if the sender of the transaction has enough
1321// balance in the account to send the Amount+Fee, and also returns the account
1322// Balance and the Fee+Amount (which is used to give information about why the
1323// transaction is not selected in case that this method returns false.
1324func (tp *TxProcessor) CheckEnoughBalance(tx common.PoolL2Tx) (bool, *big.Int, *big.Int) {
1325 acc, err := tp.s.GetAccount(tx.FromIdx)
1326 if err != nil {
1327 return false, nil, nil
1328 }
1329 fee, err := common.CalcFeeAmount(tx.Amount, tx.Fee)
1330 if err != nil {
1331 return false, nil, nil
1332 }
1333 feeAndAmount := new(big.Int).Add(tx.Amount, fee)
1334 return acc.Balance.Cmp(feeAndAmount) != -1, // !=-1 balance<amount
1335 acc.Balance, feeAndAmount
1336}