arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/statedb/txprocessors.go
db/statedb/txprocessors.goRaw
  1package statedb
  2
  3import (
  4	"errors"
  5	"io/ioutil"
  6	"math/big"
  7	"os"
  8
  9	"github.com/hermeznetwork/hermez-node/common"
 10	"github.com/hermeznetwork/hermez-node/log"
 11	"github.com/iden3/go-iden3-crypto/babyjub"
 12	"github.com/iden3/go-merkletree"
 13	"github.com/iden3/go-merkletree/db"
 14	"github.com/iden3/go-merkletree/db/pebble"
 15)
 16
 17var (
 18	// keyidx is used as key in the db to store the current Idx
 19	keyidx = []byte("k:idx")
 20)
 21
 22func (s *StateDB) resetZKInputs() {
 23	s.zki = nil
 24	s.i = 0 // initialize current transaction index in the ZKInputs generation
 25}
 26
 27type processedExit struct {
 28	exit    bool
 29	newExit bool
 30	idx     common.Idx
 31	acc     common.Account
 32}
 33
 34// ProcessTxOutput contains the output of the ProcessTxs method
 35type ProcessTxOutput struct {
 36	ZKInputs           *common.ZKInputs
 37	ExitInfos          []common.ExitInfo
 38	CreatedAccounts    []common.Account
 39	CoordinatorIdxsMap map[common.TokenID]common.Idx
 40	CollectedFees      map[common.TokenID]*big.Int
 41}
 42
 43// ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
 44// the StateDB depending on the transaction Type.  If StateDB
 45// type==TypeBatchBuilder, returns the common.ZKInputs to generate the
 46// SnarkProof later used by the BatchBuilder.  If StateDB
 47// type==TypeSynchronizer, assumes that the call is done from the Synchronizer,
 48// returns common.ExitTreeLeaf that is later used by the Synchronizer to update
 49// the HistoryDB, and adds Nonce & TokenID to the L2Txs.
 50// And if TypeSynchronizer returns an array of common.Account with all the
 51// created accounts.
 52func (s *StateDB) ProcessTxs(coordIdxs []common.Idx, l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) (ptOut *ProcessTxOutput, err error) {
 53	defer func() {
 54		if err == nil {
 55			err = s.MakeCheckpoint()
 56		}
 57	}()
 58
 59	var exitTree *merkletree.MerkleTree
 60	var createdAccounts []common.Account
 61
 62	if s.zki != nil {
 63		return nil, errors.New("Expected StateDB.zki==nil, something went wrong and it's not empty")
 64	}
 65	defer s.resetZKInputs()
 66
 67	nTx := len(l1usertxs) + len(l1coordinatortxs) + len(l2txs)
 68	if nTx == 0 {
 69		// TODO return ZKInputs of batch without txs
 70		return &ProcessTxOutput{
 71			ZKInputs:           nil,
 72			ExitInfos:          nil,
 73			CreatedAccounts:    nil,
 74			CoordinatorIdxsMap: nil,
 75			CollectedFees:      nil,
 76		}, nil
 77	}
 78	exits := make([]processedExit, nTx)
 79
 80	// get TokenIDs of coordIdxs
 81	coordIdxsMap, err := s.getTokenIDsFromIdxs(coordIdxs)
 82	if err != nil {
 83		return nil, err
 84	}
 85
 86	var collectedFees map[common.TokenID]*big.Int
 87	if s.typ == TypeSynchronizer {
 88		collectedFees = make(map[common.TokenID]*big.Int)
 89		for tokenID := range coordIdxsMap {
 90			collectedFees[tokenID] = big.NewInt(0)
 91		}
 92	}
 93
 94	if s.typ == TypeBatchBuilder {
 95		maxFeeTx := 2 // TODO this value will be a parameter
 96		s.zki = common.NewZKInputs(nTx, maxFeeTx, s.mt.MaxLevels())
 97		s.zki.OldLastIdx = (s.idx - 1).BigInt()
 98		s.zki.OldStateRoot = s.mt.Root().BigInt()
 99	}
100
101	// TBD if ExitTree is only in memory or stored in disk, for the moment
102	// only needed in memory
103	if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
104		tmpDir, err := ioutil.TempDir("", "hermez-statedb-exittree")
105		if err != nil {
106			return nil, err
107		}
108		defer func() {
109			if err := os.RemoveAll(tmpDir); err != nil {
110				log.Errorw("Deleting statedb temp exit tree", "err", err)
111			}
112		}()
113		sto, err := pebble.NewPebbleStorage(tmpDir, false)
114		if err != nil {
115			return nil, err
116		}
117		exitTree, err = merkletree.NewMerkleTree(sto, s.mt.MaxLevels())
118		if err != nil {
119			return nil, err
120		}
121	}
122
123	// assumption: l1usertx are sorted by L1Tx.Position
124	for i := 0; i < len(l1usertxs); i++ {
125		exitIdx, exitAccount, newExit, createdAccount, err := s.processL1Tx(exitTree, &l1usertxs[i])
126		if err != nil {
127			return nil, err
128		}
129		if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
130			if exitIdx != nil && exitTree != nil {
131				exits[s.i] = processedExit{
132					exit:    true,
133					newExit: newExit,
134					idx:     *exitIdx,
135					acc:     *exitAccount,
136				}
137			}
138			s.i++
139		}
140		if s.typ == TypeSynchronizer && createdAccount != nil {
141			createdAccounts = append(createdAccounts, *createdAccount)
142		}
143	}
144	for i := 0; i < len(l1coordinatortxs); i++ {
145		exitIdx, _, _, createdAccount, err := s.processL1Tx(exitTree, &l1coordinatortxs[i])
146		if err != nil {
147			return nil, err
148		}
149		if exitIdx != nil {
150			log.Error("Unexpected Exit in L1CoordinatorTx")
151		}
152		if s.typ == TypeSynchronizer && createdAccount != nil {
153			createdAccounts = append(createdAccounts, *createdAccount)
154		}
155	}
156	for i := 0; i < len(l2txs); i++ {
157		exitIdx, exitAccount, newExit, err := s.processL2Tx(coordIdxsMap, collectedFees, exitTree, &l2txs[i])
158		if err != nil {
159			return nil, err
160		}
161		if s.typ == TypeSynchronizer || s.typ == TypeBatchBuilder {
162			if exitIdx != nil && exitTree != nil {
163				exits[s.i] = processedExit{
164					exit:    true,
165					newExit: newExit,
166					idx:     *exitIdx,
167					acc:     *exitAccount,
168				}
169			}
170			s.i++
171		}
172	}
173
174	if s.typ == TypeTxSelector {
175		return nil, nil
176	}
177
178	// once all txs processed (exitTree root frozen), for each Exit,
179	// generate common.ExitInfo data
180	var exitInfos []common.ExitInfo
181	// exitInfos := []common.ExitInfo{}
182	for i := 0; i < nTx; i++ {
183		if !exits[i].exit {
184			continue
185		}
186		exitIdx := exits[i].idx
187		exitAccount := exits[i].acc
188
189		// 0. generate MerkleProof
190		p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil)
191		if err != nil {
192			return nil, err
193		}
194		// 1. generate common.ExitInfo
195		ei := common.ExitInfo{
196			AccountIdx:  exitIdx,
197			MerkleProof: p,
198			Balance:     exitAccount.Balance,
199		}
200		exitInfos = append(exitInfos, ei)
201
202		if s.zki != nil {
203			s.zki.TokenID2[i] = exitAccount.TokenID.BigInt()
204			s.zki.Nonce2[i] = exitAccount.Nonce.BigInt()
205			if babyjub.PointCoordSign(exitAccount.PublicKey.X) {
206				s.zki.Sign2[i] = big.NewInt(1)
207			}
208			s.zki.Ay2[i] = exitAccount.PublicKey.Y
209			s.zki.Balance2[i] = exitAccount.Balance
210			s.zki.EthAddr2[i] = common.EthAddrToBigInt(exitAccount.EthAddr)
211			for j := 0; j < len(p.Siblings); j++ {
212				s.zki.Siblings2[i][j] = p.Siblings[j].BigInt()
213			}
214			if exits[i].newExit {
215				s.zki.NewExit[i] = big.NewInt(1)
216			}
217			if p.IsOld0 {
218				s.zki.IsOld0_2[i] = big.NewInt(1)
219			}
220			s.zki.OldKey2[i] = p.OldKey.BigInt()
221			s.zki.OldValue2[i] = p.OldValue.BigInt()
222		}
223	}
224	if s.typ == TypeSynchronizer {
225		// return exitInfos, createdAccounts and collectedFees, so Synchronizer will
226		// be able to store it into HistoryDB for the concrete BatchNum
227		return &ProcessTxOutput{
228			ZKInputs:           nil,
229			ExitInfos:          exitInfos,
230			CreatedAccounts:    createdAccounts,
231			CoordinatorIdxsMap: coordIdxsMap,
232			CollectedFees:      collectedFees,
233		}, nil
234	}
235
236	// compute last ZKInputs parameters
237	s.zki.GlobalChainID = big.NewInt(0) // TODO, 0: ethereum, this will be get from config file
238	// zki.FeeIdxs = ? // TODO, this will be get from the config file
239	tokenIDs, err := s.getTokenIDsBigInt(l1usertxs, l1coordinatortxs, l2txs)
240	if err != nil {
241		log.Error(err)
242		return nil, err
243	}
244	s.zki.FeePlanTokens = tokenIDs
245
246	// s.zki.ISInitStateRootFee = s.mt.Root().BigInt()
247
248	// TODO once the Node Config sets the Accounts where to send the Fees
249	// compute fees & update ZKInputs
250
251	// return ZKInputs as the BatchBuilder will return it to forge the Batch
252	return &ProcessTxOutput{
253		ZKInputs:           s.zki,
254		ExitInfos:          nil,
255		CreatedAccounts:    nil,
256		CoordinatorIdxsMap: coordIdxsMap,
257		CollectedFees:      nil,
258	}, nil
259}
260
261// getTokenIDsBigInt returns the list of TokenIDs in *big.Int format
262func (s *StateDB) getTokenIDsBigInt(l1usertxs, l1coordinatortxs []common.L1Tx, l2txs []common.PoolL2Tx) ([]*big.Int, error) {
263	tokenIDs := make(map[common.TokenID]bool)
264	for i := 0; i < len(l1usertxs); i++ {
265		tokenIDs[l1usertxs[i].TokenID] = true
266	}
267	for i := 0; i < len(l1coordinatortxs); i++ {
268		tokenIDs[l1coordinatortxs[i].TokenID] = true
269	}
270	for i := 0; i < len(l2txs); i++ {
271		// as L2Tx does not have parameter TokenID, get it from the
272		// AccountsDB (in the StateDB)
273		acc, err := s.GetAccount(l2txs[i].FromIdx)
274		if err != nil {
275			log.Errorf("could not get account to determine TokenID of L2Tx: FromIdx %d not found: %s", l2txs[i].FromIdx, err.Error())
276			return nil, err
277		}
278		tokenIDs[acc.TokenID] = true
279	}
280	var tBI []*big.Int
281	for t := range tokenIDs {
282		tBI = append(tBI, t.BigInt())
283	}
284	return tBI, nil
285}
286
287// processL1Tx process the given L1Tx applying the needed updates to the
288// StateDB depending on the transaction Type. It returns the 3 parameters
289// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
290// the Exit created a new Leaf in the ExitTree.
291// And another *common.Account parameter which contains the created account in
292// case that has been a new created account and that the StateDB is of type
293// TypeSynchronizer.
294func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, bool, *common.Account, error) {
295	// ZKInputs
296	if s.zki != nil {
297		// Txs
298		// s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
299		s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
300		s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
301		s.zki.OnChain[s.i] = big.NewInt(1)
302
303		// L1Txs
304		s.zki.LoadAmountF[s.i] = tx.LoadAmount
305		s.zki.FromEthAddr[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
306		if tx.FromBJJ != nil {
307			s.zki.FromBJJCompressed[s.i] = BJJCompressedTo256BigInts(tx.FromBJJ.Compress())
308		}
309
310		// Intermediate States, for all the transactions except for the last one
311		if s.i < len(s.zki.ISOnChain) { // len(s.zki.ISOnChain) == nTx
312			s.zki.ISOnChain[s.i] = big.NewInt(1)
313		}
314	}
315
316	switch tx.Type {
317	case common.TxTypeForceTransfer:
318		// go to the MT account of sender and receiver, and update balance
319		// & nonce
320
321		// coordIdxsMap is 'nil', as at L1Txs there is no L2 fees
322		// 0 for the parameter toIdx, as at L1Tx ToIdx can only be 0 in the Deposit type case.
323		err := s.applyTransfer(nil, nil, tx.Tx(), 0)
324		if err != nil {
325			log.Error(err)
326			return nil, nil, false, nil, err
327		}
328	case common.TxTypeCreateAccountDeposit:
329		// add new account to the MT, update balance of the MT account
330		err := s.applyCreateAccount(tx)
331		if err != nil {
332			log.Error(err)
333			return nil, nil, false, nil, err
334		}
335		// TODO applyCreateAccount will return the created account,
336		// which in the case type==TypeSynchronizer will be added to an
337		// array of created accounts that will be returned
338
339		if s.zki != nil {
340			s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
341			s.zki.NewAccount[s.i] = big.NewInt(1)
342		}
343	case common.TxTypeDeposit:
344		// update balance of the MT account
345		err := s.applyDeposit(tx, false)
346		if err != nil {
347			log.Error(err)
348			return nil, nil, false, nil, err
349		}
350	case common.TxTypeDepositTransfer:
351		// update balance in MT account, update balance & nonce of sender
352		// & receiver
353		err := s.applyDeposit(tx, true)
354		if err != nil {
355			log.Error(err)
356			return nil, nil, false, nil, err
357		}
358	case common.TxTypeCreateAccountDepositTransfer:
359		// add new account to the merkletree, update balance in MT account,
360		// update balance & nonce of sender & receiver
361		err := s.applyCreateAccountDepositTransfer(tx)
362		if err != nil {
363			log.Error(err)
364			return nil, nil, false, nil, err
365		}
366
367		if s.zki != nil {
368			s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
369			s.zki.NewAccount[s.i] = big.NewInt(1)
370		}
371	case common.TxTypeForceExit:
372		// execute exit flow
373		// coordIdxsMap is 'nil', as at L1Txs there is no L2 fees
374		exitAccount, newExit, err := s.applyExit(nil, nil, exitTree, tx.Tx())
375		if err != nil {
376			log.Error(err)
377			return nil, nil, false, nil, err
378		}
379		return &tx.FromIdx, exitAccount, newExit, nil, nil
380	default:
381	}
382
383	var createdAccount *common.Account
384	if s.typ == TypeSynchronizer && (tx.Type == common.TxTypeCreateAccountDeposit || tx.Type == common.TxTypeCreateAccountDepositTransfer) {
385		var err error
386		createdAccount, err = s.GetAccount(s.idx)
387		if err != nil {
388			log.Error(err)
389			return nil, nil, false, nil, err
390		}
391	}
392
393	return nil, nil, false, createdAccount, nil
394}
395
396// processL2Tx process the given L2Tx applying the needed updates to the
397// StateDB depending on the transaction Type. It returns the 3 parameters
398// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
399// the Exit created a new Leaf in the ExitTree.
400func (s *StateDB) processL2Tx(coordIdxsMap map[common.TokenID]common.Idx, collectedFees map[common.TokenID]*big.Int,
401	exitTree *merkletree.MerkleTree, tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) {
402	var err error
403	// if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
404	if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) {
405		// case when tx.Type== common.TxTypeTransferToEthAddr or common.TxTypeTransferToBJJ
406		tx.AuxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ, tx.TokenID)
407		if err != nil {
408			return nil, nil, false, err
409		}
410	}
411
412	// ZKInputs
413	if s.zki != nil {
414		// Txs
415		// s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
416		// s.zki.TxCompressedDataV2[s.i] = tx.TxCompressedDataV2() // uncomment once L2Tx.TxCompressedDataV2 is ready
417		s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
418		s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
419
420		// fill AuxToIdx if needed
421		if tx.ToIdx == 0 {
422			// use toIdx that can have been filled by tx.ToIdx or
423			// if tx.Idx==0 (this case), toIdx is filled by the Idx
424			// from db by ToEthAddr&ToBJJ
425			s.zki.AuxToIdx[s.i] = tx.AuxToIdx.BigInt()
426		}
427
428		if tx.ToBJJ != nil {
429			s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
430		}
431		s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
432
433		s.zki.OnChain[s.i] = big.NewInt(0)
434		s.zki.NewAccount[s.i] = big.NewInt(0)
435
436		// L2Txs
437		// s.zki.RqOffset[s.i] =  // TODO Rq once TxSelector is ready
438		// s.zki.RqTxCompressedDataV2[s.i] = // TODO
439		// s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
440		// s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO
441		signature, err := tx.Signature.Decompress()
442		if err != nil {
443			log.Error(err)
444			return nil, nil, false, err
445		}
446		s.zki.S[s.i] = signature.S
447		s.zki.R8x[s.i] = signature.R8.X
448		s.zki.R8y[s.i] = signature.R8.Y
449	}
450
451	// if StateDB type==TypeSynchronizer, will need to add Nonce
452	if s.typ == TypeSynchronizer {
453		// as type==TypeSynchronizer, always tx.ToIdx!=0
454		acc, err := s.GetAccount(tx.FromIdx)
455		if err != nil {
456			log.Errorw("GetAccount", "fromIdx", tx.FromIdx, "err", err)
457			return nil, nil, false, err
458		}
459		tx.Nonce = acc.Nonce + 1
460		tx.TokenID = acc.TokenID
461	}
462
463	switch tx.Type {
464	case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
465		// go to the MT account of sender and receiver, and update
466		// balance & nonce
467		err = s.applyTransfer(coordIdxsMap, collectedFees, tx.Tx(), tx.AuxToIdx)
468		if err != nil {
469			log.Error(err)
470			return nil, nil, false, err
471		}
472	case common.TxTypeExit:
473		// execute exit flow
474		exitAccount, newExit, err := s.applyExit(coordIdxsMap, collectedFees, exitTree, tx.Tx())
475		if err != nil {
476			log.Error(err)
477			return nil, nil, false, err
478		}
479		return &tx.FromIdx, exitAccount, newExit, nil
480	default:
481	}
482	return nil, nil, false, nil
483}
484
485// applyCreateAccount creates a new account in the account of the depositer, it
486// stores the deposit value
487func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
488	account := &common.Account{
489		TokenID:   tx.TokenID,
490		Nonce:     0,
491		Balance:   tx.LoadAmount,
492		PublicKey: tx.FromBJJ,
493		EthAddr:   tx.FromEthAddr,
494	}
495
496	p, err := s.CreateAccount(common.Idx(s.idx+1), account)
497	if err != nil {
498		return err
499	}
500	if s.zki != nil {
501		s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
502		s.zki.Nonce1[s.i] = big.NewInt(0)
503		if babyjub.PointCoordSign(tx.FromBJJ.X) {
504			s.zki.Sign1[s.i] = big.NewInt(1)
505		}
506		s.zki.Ay1[s.i] = tx.FromBJJ.Y
507		s.zki.Balance1[s.i] = tx.LoadAmount
508		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
509		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
510		if p.IsOld0 {
511			s.zki.IsOld0_1[s.i] = big.NewInt(1)
512		}
513		s.zki.OldKey1[s.i] = p.OldKey.BigInt()
514		s.zki.OldValue1[s.i] = p.OldValue.BigInt()
515	}
516
517	s.idx = s.idx + 1
518	return s.setIdx(s.idx)
519}
520
521// applyDeposit updates the balance in the account of the depositer, if
522// andTransfer parameter is set to true, the method will also apply the
523// Transfer of the L1Tx/DepositTransfer
524func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
525	// deposit the tx.LoadAmount into the sender account
526	accSender, err := s.GetAccount(tx.FromIdx)
527	if err != nil {
528		return err
529	}
530	accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
531
532	// in case that the tx is a L1Tx>DepositTransfer
533	var accReceiver *common.Account
534	if transfer {
535		accReceiver, err = s.GetAccount(tx.ToIdx)
536		if err != nil {
537			return err
538		}
539		// subtract amount to the sender
540		accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
541		// add amount to the receiver
542		accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
543	}
544	// update sender account in localStateDB
545	p, err := s.UpdateAccount(tx.FromIdx, accSender)
546	if err != nil {
547		return err
548	}
549	if s.zki != nil {
550		s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
551		s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
552		if babyjub.PointCoordSign(accSender.PublicKey.X) {
553			s.zki.Sign1[s.i] = big.NewInt(1)
554		}
555		s.zki.Ay1[s.i] = accSender.PublicKey.Y
556		s.zki.Balance1[s.i] = accSender.Balance
557		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
558		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
559		// IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
560	}
561
562	// this is done after updating Sender Account (depositer)
563	if transfer {
564		// update receiver account in localStateDB
565		p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
566		if err != nil {
567			return err
568		}
569		if s.zki != nil {
570			s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
571			s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
572			if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
573				s.zki.Sign2[s.i] = big.NewInt(1)
574			}
575			s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
576			s.zki.Balance2[s.i] = accReceiver.Balance
577			s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
578			s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
579			// IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
580		}
581	}
582
583	return nil
584}
585
586// applyTransfer updates the balance & nonce in the account of the sender, and
587// the balance in the account of the receiver.
588// Parameter 'toIdx' should be at 0 if the tx already has tx.ToIdx!=0, if
589// tx.ToIdx==0, then toIdx!=0, and will be used the toIdx parameter as Idx of
590// the receiver. This parameter is used when the tx.ToIdx is not specified and
591// the real ToIdx is found trhrough the ToEthAddr or ToBJJ.
592func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, collectedFees map[common.TokenID]*big.Int,
593	tx common.Tx, auxToIdx common.Idx) error {
594	if auxToIdx == common.Idx(0) {
595		auxToIdx = tx.ToIdx
596	}
597	// get sender and receiver accounts from localStateDB
598	accSender, err := s.GetAccount(tx.FromIdx)
599	if err != nil {
600		log.Error(err)
601		return err
602	}
603	accReceiver, err := s.GetAccount(auxToIdx)
604	if err != nil {
605		log.Error(err)
606		return err
607	}
608
609	// increment nonce
610	accSender.Nonce++
611
612	if !tx.IsL1 {
613		// compute fee and subtract it from the accSender
614		fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
615		if err != nil {
616			return err
617		}
618		feeAndAmount := new(big.Int).Add(tx.Amount, fee)
619		accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount)
620
621		// send the fee to the Idx of the Coordinator for the TokenID
622		accCoord, err := s.GetAccount(coordIdxsMap[accSender.TokenID])
623		if err != nil {
624			log.Debugw("No coord Idx to receive fee", "tx", tx)
625		} else {
626			accCoord.Balance = new(big.Int).Add(accCoord.Balance, fee)
627			_, err = s.UpdateAccount(coordIdxsMap[accSender.TokenID], accCoord)
628			if err != nil {
629				log.Error(err)
630				return err
631			}
632			if s.typ == TypeSynchronizer {
633				collected := collectedFees[accSender.TokenID]
634				collected.Add(collected, fee)
635			}
636		}
637	} else {
638		accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
639	}
640
641	// add amount-feeAmount to the receiver
642	accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
643
644	// update sender account in localStateDB
645	pSender, err := s.UpdateAccount(tx.FromIdx, accSender)
646	if err != nil {
647		log.Error(err)
648		return err
649	}
650	if s.zki != nil {
651		s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
652		s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
653		if babyjub.PointCoordSign(accSender.PublicKey.X) {
654			s.zki.Sign1[s.i] = big.NewInt(1)
655		}
656		s.zki.Ay1[s.i] = accSender.PublicKey.Y
657		s.zki.Balance1[s.i] = accSender.Balance
658		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
659		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings)
660	}
661
662	// update receiver account in localStateDB
663	pReceiver, err := s.UpdateAccount(auxToIdx, accReceiver)
664	if err != nil {
665		return err
666	}
667	if s.zki != nil {
668		s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
669		s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
670		if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
671			s.zki.Sign2[s.i] = big.NewInt(1)
672		}
673		s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
674		s.zki.Balance2[s.i] = accReceiver.Balance
675		s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
676		s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings)
677	}
678
679	return nil
680}
681
682// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
683// makes a deposit, and performs a transfer to another account
684func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
685	accSender := &common.Account{
686		TokenID:   tx.TokenID,
687		Nonce:     0,
688		Balance:   tx.LoadAmount,
689		PublicKey: tx.FromBJJ,
690		EthAddr:   tx.FromEthAddr,
691	}
692	accReceiver, err := s.GetAccount(tx.ToIdx)
693	if err != nil {
694		return err
695	}
696	// subtract amount to the sender
697	accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
698	// add amount to the receiver
699	accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
700
701	// create Account of the Sender
702	p, err := s.CreateAccount(common.Idx(s.idx+1), accSender)
703	if err != nil {
704		return err
705	}
706	if s.zki != nil {
707		s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
708		s.zki.Nonce1[s.i] = big.NewInt(0)
709		if babyjub.PointCoordSign(tx.FromBJJ.X) {
710			s.zki.Sign1[s.i] = big.NewInt(1)
711		}
712		s.zki.Ay1[s.i] = tx.FromBJJ.Y
713		s.zki.Balance1[s.i] = tx.LoadAmount
714		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
715		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
716		if p.IsOld0 {
717			s.zki.IsOld0_1[s.i] = big.NewInt(1)
718		}
719		s.zki.OldKey1[s.i] = p.OldKey.BigInt()
720		s.zki.OldValue1[s.i] = p.OldValue.BigInt()
721	}
722
723	// update receiver account in localStateDB
724	p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
725	if err != nil {
726		return 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	}
739
740	s.idx = s.idx + 1
741	return s.setIdx(s.idx)
742}
743
744// It returns the ExitAccount and a boolean determining if the Exit created a
745// new Leaf in the ExitTree.
746func (s *StateDB) applyExit(coordIdxsMap map[common.TokenID]common.Idx, collectedFees map[common.TokenID]*big.Int,
747	exitTree *merkletree.MerkleTree, tx common.Tx) (*common.Account, bool, error) {
748	// 0. subtract tx.Amount from current Account in StateMT
749	// add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
750	acc, err := s.GetAccount(tx.FromIdx)
751	if err != nil {
752		return nil, false, err
753	}
754
755	if !tx.IsL1 {
756		// compute fee and subtract it from the accSender
757		fee, err := common.CalcFeeAmount(tx.Amount, *tx.Fee)
758		if err != nil {
759			return nil, false, err
760		}
761		feeAndAmount := new(big.Int).Add(tx.Amount, fee)
762		acc.Balance = new(big.Int).Sub(acc.Balance, feeAndAmount)
763
764		// send the fee to the Idx of the Coordinator for the TokenID
765		accCoord, err := s.GetAccount(coordIdxsMap[acc.TokenID])
766		if err != nil {
767			log.Debugw("No coord Idx to receive fee", "tx", tx)
768		} else {
769			accCoord.Balance = new(big.Int).Add(accCoord.Balance, fee)
770			_, err = s.UpdateAccount(coordIdxsMap[acc.TokenID], accCoord)
771			if err != nil {
772				log.Error(err)
773				return nil, false, err
774			}
775			if s.typ == TypeSynchronizer {
776				collected := collectedFees[acc.TokenID]
777				collected.Add(collected, fee)
778			}
779		}
780	} else {
781		acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
782	}
783
784	p, err := s.UpdateAccount(tx.FromIdx, acc)
785	if err != nil {
786		return nil, false, err
787	}
788	if s.zki != nil {
789		s.zki.TokenID1[s.i] = acc.TokenID.BigInt()
790		s.zki.Nonce1[s.i] = acc.Nonce.BigInt()
791		if babyjub.PointCoordSign(acc.PublicKey.X) {
792			s.zki.Sign1[s.i] = big.NewInt(1)
793		}
794		s.zki.Ay1[s.i] = acc.PublicKey.Y
795		s.zki.Balance1[s.i] = acc.Balance
796		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(acc.EthAddr)
797		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
798	}
799
800	if exitTree == nil {
801		return nil, false, nil
802	}
803	exitAccount, err := getAccountInTreeDB(exitTree.DB(), tx.FromIdx)
804	if err == db.ErrNotFound {
805		// 1a. if idx does not exist in exitTree:
806		// add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance = exitAmount (exitAmount=tx.Amount)
807		exitAccount := &common.Account{
808			TokenID:   acc.TokenID,
809			Nonce:     common.Nonce(1),
810			Balance:   tx.Amount,
811			PublicKey: acc.PublicKey,
812			EthAddr:   acc.EthAddr,
813		}
814		_, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
815		return exitAccount, true, err
816	} else if err != nil {
817		return exitAccount, false, err
818	}
819
820	// 1b. if idx already exist in exitTree:
821	// update account, where account.Balance += exitAmount
822	exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
823	_, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
824	return exitAccount, false, err
825}
826
827// getIdx returns the stored Idx from the localStateDB, which is the last Idx
828// used for an Account in the localStateDB.
829func (s *StateDB) getIdx() (common.Idx, error) {
830	idxBytes, err := s.DB().Get(keyidx)
831	if err == db.ErrNotFound {
832		return 0, nil
833	}
834	if err != nil {
835		return 0, err
836	}
837	return common.IdxFromBytes(idxBytes[:])
838}
839
840// setIdx stores Idx in the localStateDB
841func (s *StateDB) setIdx(idx common.Idx) error {
842	tx, err := s.DB().NewTx()
843	if err != nil {
844		return err
845	}
846	idxBytes, err := idx.Bytes()
847	if err != nil {
848		return err
849	}
850	err = tx.Put(keyidx, idxBytes[:])
851	if err != nil {
852		return err
853	}
854	if err := tx.Commit(); err != nil {
855		return err
856	}
857	return nil
858}