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