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