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	"math/big"
  8
  9	ethCommon "github.com/ethereum/go-ethereum/common"
 10	"github.com/hermeznetwork/hermez-node/common"
 11	"github.com/hermeznetwork/hermez-node/log"
 12	"github.com/iden3/go-iden3-crypto/babyjub"
 13	"github.com/iden3/go-iden3-crypto/poseidon"
 14	"github.com/iden3/go-merkletree"
 15	"github.com/iden3/go-merkletree/db"
 16	"github.com/iden3/go-merkletree/db/memory"
 17)
 18
 19var (
 20	// keyidx is used as key in the db to store the current Idx
 21	keyidx = []byte("idx")
 22
 23	ffAddr = ethCommon.HexToAddress("0xffffffffffffffffffffffffffffffffffffffff")
 24)
 25
 26func (s *StateDB) resetZKInputs() {
 27	s.zki = nil
 28	s.i = 0
 29}
 30
 31type processedExit struct {
 32	exit    bool
 33	newExit bool
 34	idx     common.Idx
 35	acc     common.Account
 36}
 37
 38// ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
 39// the StateDB depending on the transaction Type. Returns the common.ZKInputs
 40// to generate the SnarkProof later used by the BatchBuilder, and if
 41// cmpExitTree is set to true, returns common.ExitTreeLeaf that is later used
 42// by the Synchronizer to update the HistoryDB.
 43func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.PoolL2Tx) (*common.ZKInputs, []*common.ExitInfo, error) {
 44	var err error
 45	var exitTree *merkletree.MerkleTree
 46
 47	if s.zki != nil {
 48		return nil, nil, errors.New("Expected StateDB.zki==nil, something went wrong and it's not empty")
 49	}
 50	defer s.resetZKInputs()
 51
 52	nTx := len(l1usertxs) + len(l1coordinatortxs) + len(l2txs)
 53	if nTx == 0 {
 54		// TODO return ZKInputs of batch without txs
 55		return nil, nil, nil
 56	}
 57	exits := make([]processedExit, nTx)
 58
 59	if cmpZKInputs {
 60		s.zki = common.NewZKInputs(nTx, 24, 32) // TODO this values will be parameters of the function, taken from config file/coordinator call
 61		s.zki.OldLastIdx = (s.idx - 1).BigInt()
 62		s.zki.OldStateRoot = s.mt.Root().BigInt()
 63	}
 64
 65	// TBD if ExitTree is only in memory or stored in disk, for the moment
 66	// only needed in memory
 67	exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels())
 68	if err != nil {
 69		return nil, nil, err
 70	}
 71
 72	// assumption: l1usertx are sorted by L1Tx.Position
 73	for _, tx := range l1usertxs {
 74		exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, tx)
 75		if err != nil {
 76			return nil, nil, err
 77		}
 78		if exitIdx != nil && cmpExitTree {
 79			exits[s.i] = processedExit{
 80				exit:    true,
 81				newExit: newExit,
 82				idx:     *exitIdx,
 83				acc:     *exitAccount,
 84			}
 85		}
 86		if s.zki != nil {
 87			s.i++
 88		}
 89	}
 90	for _, tx := range l1coordinatortxs {
 91		exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, tx)
 92		if err != nil {
 93			return nil, nil, err
 94		}
 95		if exitIdx != nil {
 96			log.Error("Unexpected Exit in L1CoordinatorTx")
 97		}
 98		if exitIdx != nil && cmpExitTree {
 99			exits[s.i] = processedExit{
100				exit:    true,
101				newExit: newExit,
102				idx:     *exitIdx,
103				acc:     *exitAccount,
104			}
105		}
106		if s.zki != nil {
107			s.i++
108		}
109	}
110	for _, tx := range l2txs {
111		exitIdx, exitAccount, newExit, err := s.processL2Tx(exitTree, tx)
112		if err != nil {
113			return nil, nil, err
114		}
115		if exitIdx != nil && cmpExitTree {
116			exits[s.i] = processedExit{
117				exit:    true,
118				newExit: newExit,
119				idx:     *exitIdx,
120				acc:     *exitAccount,
121			}
122		}
123		if s.zki != nil {
124			s.i++
125		}
126	}
127
128	if !cmpExitTree && !cmpZKInputs {
129		return nil, nil, nil
130	}
131
132	// once all txs processed (exitTree root frozen), for each Exit,
133	// generate common.ExitInfo data
134	var exitInfos []*common.ExitInfo
135	for i := 0; i < nTx; i++ {
136		if !exits[i].exit {
137			continue
138		}
139		exitIdx := exits[i].idx
140		exitAccount := exits[i].acc
141
142		// 0. generate MerkleProof
143		p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil)
144		if err != nil {
145			return nil, nil, err
146		}
147		// 1. compute nullifier
148		exitAccStateValue, err := exitAccount.HashValue()
149		if err != nil {
150			return nil, nil, err
151		}
152		nullifier, err := poseidon.Hash([]*big.Int{
153			exitAccStateValue,
154			big.NewInt(int64(s.currentBatch)),
155			exitTree.Root().BigInt(),
156		})
157		if err != nil {
158			return nil, nil, err
159		}
160		// 2. generate common.ExitInfo
161		ei := &common.ExitInfo{
162			AccountIdx:  exitIdx,
163			MerkleProof: p,
164			Nullifier:   nullifier,
165			Balance:     exitAccount.Balance,
166		}
167		exitInfos = append(exitInfos, ei)
168
169		if s.zki != nil {
170			s.zki.TokenID2[i] = exitAccount.TokenID.BigInt()
171			s.zki.Nonce2[i] = exitAccount.Nonce.BigInt()
172			if babyjub.PointCoordSign(exitAccount.PublicKey.X) {
173				s.zki.Sign2[i] = big.NewInt(1)
174			}
175			s.zki.Ay2[i] = exitAccount.PublicKey.Y
176			s.zki.Balance2[i] = exitAccount.Balance
177			s.zki.EthAddr2[i] = common.EthAddrToBigInt(exitAccount.EthAddr)
178			s.zki.Siblings2[i] = p.Siblings
179			if exits[i].newExit {
180				s.zki.NewExit[i] = big.NewInt(1)
181			}
182			if p.IsOld0 {
183				s.zki.IsOld0_2[i] = big.NewInt(1)
184			}
185			s.zki.OldKey2[i] = p.OldKey.BigInt()
186			s.zki.OldValue2[i] = p.OldValue.BigInt()
187		}
188	}
189	if !cmpZKInputs {
190		return nil, exitInfos, nil
191	}
192
193	// compute last ZKInputs parameters
194	s.zki.GlobalChainID = big.NewInt(0) // TODO, 0: ethereum, this will be get from config file
195	// zki.FeeIdxs = ? // TODO, this will be get from the config file
196	tokenIDs, err := s.getTokenIDsBigInt(l1usertxs, l1coordinatortxs, l2txs)
197	if err != nil {
198		return nil, nil, err
199	}
200	s.zki.FeePlanTokens = tokenIDs
201
202	// s.zki.ISInitStateRootFee = s.mt.Root().BigInt()
203
204	// TODO once the Node Config sets the Accounts where to send the Fees
205	// compute fees & update ZKInputs
206
207	// return exitInfos, so Synchronizer will be able to store it into
208	// HistoryDB for the concrete BatchNum
209	return s.zki, exitInfos, nil
210}
211
212// getTokenIDsBigInt returns the list of TokenIDs in *big.Int format
213func (s *StateDB) getTokenIDsBigInt(l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.PoolL2Tx) ([]*big.Int, error) {
214	tokenIDs := make(map[common.TokenID]bool)
215	for i := 0; i < len(l1usertxs); i++ {
216		tokenIDs[l1usertxs[i].TokenID] = true
217	}
218	for i := 0; i < len(l1coordinatortxs); i++ {
219		tokenIDs[l1coordinatortxs[i].TokenID] = true
220	}
221	for i := 0; i < len(l2txs); i++ {
222		// as L2Tx does not have parameter TokenID, get it from the
223		// AccountsDB (in the StateDB)
224		acc, err := s.GetAccount(l2txs[i].ToIdx)
225		if err != nil {
226			return nil, err
227		}
228		tokenIDs[acc.TokenID] = true
229	}
230	var tBI []*big.Int
231	for t := range tokenIDs {
232		tBI = append(tBI, t.BigInt())
233	}
234	return tBI, nil
235}
236
237// processL1Tx process the given L1Tx applying the needed updates to the
238// StateDB depending on the transaction Type. It returns the 3 parameters
239// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
240// the Exit created a new Leaf in the ExitTree.
241func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, bool, error) {
242	// ZKInputs
243	if s.zki != nil {
244		// Txs
245		// s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
246		s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
247		s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
248		s.zki.OnChain[s.i] = big.NewInt(1)
249
250		// L1Txs
251		s.zki.LoadAmountF[s.i] = tx.LoadAmount
252		s.zki.FromEthAddr[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
253		if tx.FromBJJ != nil {
254			s.zki.FromBJJCompressed[s.i] = BJJCompressedTo256BigInts(tx.FromBJJ.Compress())
255		}
256
257		// Intermediate States
258		s.zki.ISOnChain[s.i] = big.NewInt(1)
259	}
260
261	switch tx.Type {
262	case common.TxTypeForceTransfer, common.TxTypeTransfer:
263		// go to the MT account of sender and receiver, and update balance
264		// & nonce
265		err := s.applyTransfer(tx.Tx())
266		if err != nil {
267			return nil, nil, false, err
268		}
269	case common.TxTypeCreateAccountDeposit:
270		// add new account to the MT, update balance of the MT account
271		err := s.applyCreateAccount(tx)
272		if err != nil {
273			return nil, nil, false, err
274		}
275
276		if s.zki != nil {
277			s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
278			s.zki.NewAccount[s.i] = big.NewInt(1)
279		}
280	case common.TxTypeDeposit:
281		// update balance of the MT account
282		err := s.applyDeposit(tx, false)
283		if err != nil {
284			return nil, nil, false, err
285		}
286	case common.TxTypeDepositTransfer:
287		// update balance in MT account, update balance & nonce of sender
288		// & receiver
289		err := s.applyDeposit(tx, true)
290		if err != nil {
291			return nil, nil, false, err
292		}
293	case common.TxTypeCreateAccountDepositTransfer:
294		// add new account to the merkletree, update balance in MT account,
295		// update balance & nonce of sender & receiver
296		err := s.applyCreateAccountDepositTransfer(tx)
297		if err != nil {
298			return nil, nil, false, err
299		}
300
301		if s.zki != nil {
302			s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
303			s.zki.NewAccount[s.i] = big.NewInt(1)
304		}
305	case common.TxTypeExit:
306		// execute exit flow
307		exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
308		if err != nil {
309			return nil, nil, false, err
310		}
311		return &tx.FromIdx, exitAccount, newExit, nil
312	default:
313	}
314
315	return nil, nil, false, nil
316}
317
318// processL2Tx process the given L2Tx applying the needed updates to the
319// StateDB depending on the transaction Type. It returns the 3 parameters
320// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
321// the Exit created a new Leaf in the ExitTree.
322func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) {
323	// ZKInputs
324	if s.zki != nil {
325		// Txs
326		// s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
327		// s.zki.TxCompressedDataV2[s.i] = tx.TxCompressedDataV2() // uncomment once L2Tx.TxCompressedDataV2 is ready
328		s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
329		s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
330
331		// fill AuxToIdx if needed
332		if tx.ToIdx == common.Idx(0) {
333			// Idx not set in the Tx, get it from DB through ToEthAddr or ToBJJ
334			var idx common.Idx
335			if !bytes.Equal(tx.ToEthAddr.Bytes(), ffAddr.Bytes()) {
336				idx = s.getIdxByEthAddr(tx.ToEthAddr)
337				if idx == common.Idx(0) {
338					return nil, nil, false, fmt.Errorf("Idx can not be found for given tx.FromEthAddr")
339				}
340			} else {
341				idx = s.getIdxByBJJ(tx.ToBJJ)
342				if idx == common.Idx(0) {
343					return nil, nil, false, fmt.Errorf("Idx can not be found for given tx.FromBJJ")
344				}
345			}
346			s.zki.AuxToIdx[s.i] = idx.BigInt()
347		}
348		s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
349		s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
350
351		s.zki.OnChain[s.i] = big.NewInt(0)
352		s.zki.NewAccount[s.i] = big.NewInt(0)
353
354		// L2Txs
355		// s.zki.RqOffset[s.i] =  // TODO Rq once TxSelector is ready
356		// s.zki.RqTxCompressedDataV2[s.i] = // TODO
357		// s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
358		// s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO
359		s.zki.S[s.i] = tx.Signature.S
360		s.zki.R8x[s.i] = tx.Signature.R8.X
361		s.zki.R8y[s.i] = tx.Signature.R8.Y
362	}
363
364	switch tx.Type {
365	case common.TxTypeTransfer:
366		// go to the MT account of sender and receiver, and update
367		// balance & nonce
368		err := s.applyTransfer(tx.Tx())
369		if err != nil {
370			return nil, nil, false, err
371		}
372	case common.TxTypeExit:
373		// execute exit flow
374		exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
375		if err != nil {
376			return nil, nil, false, err
377		}
378		return &tx.FromIdx, exitAccount, newExit, nil
379	default:
380	}
381	return nil, nil, false, nil
382}
383
384// applyCreateAccount creates a new account in the account of the depositer, it
385// stores the deposit value
386func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
387	account := &common.Account{
388		TokenID:   tx.TokenID,
389		Nonce:     0,
390		Balance:   tx.LoadAmount,
391		PublicKey: tx.FromBJJ,
392		EthAddr:   tx.FromEthAddr,
393	}
394
395	p, err := s.CreateAccount(common.Idx(s.idx+1), account)
396	if err != nil {
397		return err
398	}
399	if s.zki != nil {
400		s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
401		s.zki.Nonce1[s.i] = big.NewInt(0)
402		if babyjub.PointCoordSign(tx.FromBJJ.X) {
403			s.zki.Sign1[s.i] = big.NewInt(1)
404		}
405		s.zki.Ay1[s.i] = tx.FromBJJ.Y
406		s.zki.Balance1[s.i] = tx.LoadAmount
407		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
408		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
409		if p.IsOld0 {
410			s.zki.IsOld0_1[s.i] = big.NewInt(1)
411		}
412		s.zki.OldKey1[s.i] = p.OldKey.BigInt()
413		s.zki.OldValue1[s.i] = p.OldValue.BigInt()
414	}
415
416	s.idx = s.idx + 1
417	return s.setIdx(s.idx)
418}
419
420// applyDeposit updates the balance in the account of the depositer, if
421// andTransfer parameter is set to true, the method will also apply the
422// Transfer of the L1Tx/DepositTransfer
423func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
424	// deposit the tx.LoadAmount into the sender account
425	accSender, err := s.GetAccount(tx.FromIdx)
426	if err != nil {
427		return err
428	}
429	accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
430
431	// in case that the tx is a L1Tx>DepositTransfer
432	var accReceiver *common.Account
433	if transfer {
434		accReceiver, err = s.GetAccount(tx.ToIdx)
435		if err != nil {
436			return err
437		}
438		// subtract amount to the sender
439		accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
440		// add amount to the receiver
441		accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
442	}
443	// update sender account in localStateDB
444	p, err := s.UpdateAccount(tx.FromIdx, accSender)
445	if err != nil {
446		return err
447	}
448	if s.zki != nil {
449		s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
450		s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
451		if babyjub.PointCoordSign(accSender.PublicKey.X) {
452			s.zki.Sign1[s.i] = big.NewInt(1)
453		}
454		s.zki.Ay1[s.i] = accSender.PublicKey.Y
455		s.zki.Balance1[s.i] = accSender.Balance
456		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
457		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
458		// IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
459	}
460
461	// this is done after updating Sender Account (depositer)
462	if transfer {
463		// update receiver account in localStateDB
464		p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
465		if err != nil {
466			return err
467		}
468		if s.zki != nil {
469			s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
470			s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
471			if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
472				s.zki.Sign2[s.i] = big.NewInt(1)
473			}
474			s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
475			s.zki.Balance2[s.i] = accReceiver.Balance
476			s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
477			s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
478			// IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
479		}
480	}
481
482	return nil
483}
484
485// applyTransfer updates the balance & nonce in the account of the sender, and
486// the balance in the account of the receiver
487func (s *StateDB) applyTransfer(tx *common.Tx) error {
488	// get sender and receiver accounts from localStateDB
489	accSender, err := s.GetAccount(tx.FromIdx)
490	if err != nil {
491		return err
492	}
493	accReceiver, err := s.GetAccount(tx.ToIdx)
494	if err != nil {
495		return err
496	}
497
498	// increment nonce
499	accSender.Nonce++
500
501	// subtract amount to the sender
502	accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
503	// add amount to the receiver
504	accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
505
506	// update sender account in localStateDB
507	pSender, err := s.UpdateAccount(tx.FromIdx, accSender)
508	if err != nil {
509		return err
510	}
511	if s.zki != nil {
512		s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
513		s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
514		if babyjub.PointCoordSign(accSender.PublicKey.X) {
515			s.zki.Sign1[s.i] = big.NewInt(1)
516		}
517		s.zki.Ay1[s.i] = accSender.PublicKey.Y
518		s.zki.Balance1[s.i] = accSender.Balance
519		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
520		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings)
521	}
522
523	// update receiver account in localStateDB
524	pReceiver, err := s.UpdateAccount(tx.ToIdx, accReceiver)
525	if err != nil {
526		return err
527	}
528	if s.zki != nil {
529		s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
530		s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
531		if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
532			s.zki.Sign2[s.i] = big.NewInt(1)
533		}
534		s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
535		s.zki.Balance2[s.i] = accReceiver.Balance
536		s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
537		s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings)
538	}
539
540	return nil
541}
542
543// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
544// makes a deposit, and performs a transfer to another account
545func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
546	accSender := &common.Account{
547		TokenID:   tx.TokenID,
548		Nonce:     0,
549		Balance:   tx.LoadAmount,
550		PublicKey: tx.FromBJJ,
551		EthAddr:   tx.FromEthAddr,
552	}
553	accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
554	accReceiver, err := s.GetAccount(tx.ToIdx)
555	if err != nil {
556		return err
557	}
558	// subtract amount to the sender
559	accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
560	// add amount to the receiver
561	accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
562
563	// create Account of the Sender
564	p, err := s.CreateAccount(common.Idx(s.idx+1), accSender)
565	if err != nil {
566		return err
567	}
568	if s.zki != nil {
569		s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
570		s.zki.Nonce1[s.i] = big.NewInt(0)
571		if babyjub.PointCoordSign(tx.FromBJJ.X) {
572			s.zki.Sign1[s.i] = big.NewInt(1)
573		}
574		s.zki.Ay1[s.i] = tx.FromBJJ.Y
575		s.zki.Balance1[s.i] = tx.LoadAmount
576		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
577		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
578		if p.IsOld0 {
579			s.zki.IsOld0_1[s.i] = big.NewInt(1)
580		}
581		s.zki.OldKey1[s.i] = p.OldKey.BigInt()
582		s.zki.OldValue1[s.i] = p.OldValue.BigInt()
583	}
584
585	// update receiver account in localStateDB
586	p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
587	if err != nil {
588		return err
589	}
590	if s.zki != nil {
591		s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
592		s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
593		if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
594			s.zki.Sign2[s.i] = big.NewInt(1)
595		}
596		s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
597		s.zki.Balance2[s.i] = accReceiver.Balance
598		s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
599		s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
600	}
601
602	s.idx = s.idx + 1
603	return s.setIdx(s.idx)
604}
605
606// It returns the ExitAccount and a boolean determining if the Exit created a
607// new Leaf in the ExitTree.
608func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx *common.Tx) (*common.Account, bool, error) {
609	// 0. subtract tx.Amount from current Account in StateMT
610	// add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
611	acc, err := s.GetAccount(tx.FromIdx)
612	if err != nil {
613		return nil, false, err
614	}
615	acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
616	p, err := s.UpdateAccount(tx.FromIdx, acc)
617	if err != nil {
618		return nil, false, err
619	}
620	if s.zki != nil {
621		s.zki.TokenID1[s.i] = acc.TokenID.BigInt()
622		s.zki.Nonce1[s.i] = acc.Nonce.BigInt()
623		if babyjub.PointCoordSign(acc.PublicKey.X) {
624			s.zki.Sign1[s.i] = big.NewInt(1)
625		}
626		s.zki.Ay1[s.i] = acc.PublicKey.Y
627		s.zki.Balance1[s.i] = acc.Balance
628		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(acc.EthAddr)
629		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
630	}
631
632	exitAccount, err := getAccountInTreeDB(exitTree.DB(), tx.FromIdx)
633	if err == db.ErrNotFound {
634		// 1a. if idx does not exist in exitTree:
635		// add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance = exitAmount (exitAmount=tx.Amount)
636		exitAccount := &common.Account{
637			TokenID:   acc.TokenID,
638			Nonce:     common.Nonce(1),
639			Balance:   tx.Amount,
640			PublicKey: acc.PublicKey,
641			EthAddr:   acc.EthAddr,
642		}
643		_, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
644		return exitAccount, true, err
645	} else if err != nil {
646		return exitAccount, false, err
647	}
648
649	// 1b. if idx already exist in exitTree:
650	// update account, where account.Balance += exitAmount
651	exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
652	_, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
653	return exitAccount, false, err
654}
655
656// getIdx returns the stored Idx from the localStateDB, which is the last Idx
657// used for an Account in the localStateDB.
658func (s *StateDB) getIdx() (common.Idx, error) {
659	idxBytes, err := s.DB().Get(keyidx)
660	if err == db.ErrNotFound {
661		return 0, nil
662	}
663	if err != nil {
664		return 0, err
665	}
666	return common.IdxFromBytes(idxBytes[:4])
667}
668
669// setIdx stores Idx in the localStateDB
670func (s *StateDB) setIdx(idx common.Idx) error {
671	tx, err := s.DB().NewTx()
672	if err != nil {
673		return err
674	}
675	err = tx.Put(keyidx, idx.Bytes())
676	if err != nil {
677		return err
678	}
679	if err := tx.Commit(); err != nil {
680		return err
681	}
682	return nil
683}