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