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