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