arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/statedb/txprocessors.go
db/statedb/txprocessors.goRaw
  1package statedb
  2
  3import (
  4	"errors"
  5	"math/big"
  6
  7	"github.com/hermeznetwork/hermez-node/common"
  8	"github.com/hermeznetwork/hermez-node/log"
  9	"github.com/iden3/go-iden3-crypto/babyjub"
 10	"github.com/iden3/go-merkletree"
 11	"github.com/iden3/go-merkletree/db"
 12	"github.com/iden3/go-merkletree/db/memory"
 13)
 14
 15var (
 16	// keyidx is used as key in the db to store the current Idx
 17	keyidx = []byte("idx")
 18)
 19
 20func (s *StateDB) resetZKInputs() {
 21	s.zki = nil
 22	s.i = 0
 23}
 24
 25type processedExit struct {
 26	exit    bool
 27	newExit bool
 28	idx     common.Idx
 29	acc     common.Account
 30}
 31
 32// ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
 33// the StateDB depending on the transaction Type. Returns the common.ZKInputs
 34// to generate the SnarkProof later used by the BatchBuilder, and if
 35// cmpExitTree is set to true, returns common.ExitTreeLeaf that is later used
 36// by the Synchronizer to update the HistoryDB.
 37func (s *StateDB) ProcessTxs(cmpExitTree, cmpZKInputs bool, l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.PoolL2Tx) (*common.ZKInputs, []*common.ExitInfo, error) {
 38	var err error
 39	var exitTree *merkletree.MerkleTree
 40
 41	if s.zki != nil {
 42		return nil, nil, errors.New("Expected StateDB.zki==nil, something went wrong and it's not empty")
 43	}
 44	defer s.resetZKInputs()
 45
 46	nTx := len(l1usertxs) + len(l1coordinatortxs) + len(l2txs)
 47	if nTx == 0 {
 48		// TODO return ZKInputs of batch without txs
 49		return nil, nil, nil
 50	}
 51	exits := make([]processedExit, nTx)
 52
 53	if cmpZKInputs {
 54		s.zki = common.NewZKInputs(nTx, 24, 32) // TODO this values will be parameters of the function, taken from config file/coordinator call
 55		s.zki.OldLastIdx = (s.idx - 1).BigInt()
 56		s.zki.OldStateRoot = s.mt.Root().BigInt()
 57	}
 58
 59	// TBD if ExitTree is only in memory or stored in disk, for the moment
 60	// only needed in memory
 61	if cmpExitTree {
 62		exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels())
 63		if err != nil {
 64			return nil, nil, err
 65		}
 66	}
 67
 68	// assumption: l1usertx are sorted by L1Tx.Position
 69	for _, tx := range l1usertxs {
 70		exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, tx)
 71		if err != nil {
 72			return nil, nil, err
 73		}
 74		if exitIdx != nil && cmpExitTree {
 75			exits[s.i] = processedExit{
 76				exit:    true,
 77				newExit: newExit,
 78				idx:     *exitIdx,
 79				acc:     *exitAccount,
 80			}
 81		}
 82		if s.zki != nil {
 83			s.i++
 84		}
 85	}
 86	for _, tx := range l1coordinatortxs {
 87		exitIdx, exitAccount, newExit, err := s.processL1Tx(exitTree, tx)
 88		if err != nil {
 89			return nil, nil, err
 90		}
 91		if exitIdx != nil {
 92			log.Error("Unexpected Exit in L1CoordinatorTx")
 93		}
 94		if exitIdx != nil && cmpExitTree {
 95			exits[s.i] = processedExit{
 96				exit:    true,
 97				newExit: newExit,
 98				idx:     *exitIdx,
 99				acc:     *exitAccount,
100			}
101		}
102		if s.zki != nil {
103			s.i++
104		}
105	}
106	for _, tx := range l2txs {
107		exitIdx, exitAccount, newExit, err := s.processL2Tx(exitTree, tx)
108		if err != nil {
109			return nil, nil, err
110		}
111		if exitIdx != nil && cmpExitTree {
112			exits[s.i] = processedExit{
113				exit:    true,
114				newExit: newExit,
115				idx:     *exitIdx,
116				acc:     *exitAccount,
117			}
118		}
119		if s.zki != nil {
120			s.i++
121		}
122	}
123
124	if !cmpExitTree && !cmpZKInputs {
125		return nil, nil, nil
126	}
127
128	// once all txs processed (exitTree root frozen), for each Exit,
129	// generate common.ExitInfo data
130	var exitInfos []*common.ExitInfo
131	for i := 0; i < nTx; i++ {
132		if !exits[i].exit {
133			continue
134		}
135		exitIdx := exits[i].idx
136		exitAccount := exits[i].acc
137
138		// 0. generate MerkleProof
139		p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil)
140		if err != nil {
141			return nil, nil, err
142		}
143		// 1. generate common.ExitInfo
144		ei := &common.ExitInfo{
145			AccountIdx:  exitIdx,
146			MerkleProof: p,
147			Balance:     exitAccount.Balance,
148		}
149		exitInfos = append(exitInfos, ei)
150
151		if s.zki != nil {
152			s.zki.TokenID2[i] = exitAccount.TokenID.BigInt()
153			s.zki.Nonce2[i] = exitAccount.Nonce.BigInt()
154			if babyjub.PointCoordSign(exitAccount.PublicKey.X) {
155				s.zki.Sign2[i] = big.NewInt(1)
156			}
157			s.zki.Ay2[i] = exitAccount.PublicKey.Y
158			s.zki.Balance2[i] = exitAccount.Balance
159			s.zki.EthAddr2[i] = common.EthAddrToBigInt(exitAccount.EthAddr)
160			s.zki.Siblings2[i] = p.Siblings
161			if exits[i].newExit {
162				s.zki.NewExit[i] = big.NewInt(1)
163			}
164			if p.IsOld0 {
165				s.zki.IsOld0_2[i] = big.NewInt(1)
166			}
167			s.zki.OldKey2[i] = p.OldKey.BigInt()
168			s.zki.OldValue2[i] = p.OldValue.BigInt()
169		}
170	}
171	if !cmpZKInputs {
172		return nil, exitInfos, nil
173	}
174
175	// compute last ZKInputs parameters
176	s.zki.GlobalChainID = big.NewInt(0) // TODO, 0: ethereum, this will be get from config file
177	// zki.FeeIdxs = ? // TODO, this will be get from the config file
178	tokenIDs, err := s.getTokenIDsBigInt(l1usertxs, l1coordinatortxs, l2txs)
179	if err != nil {
180		return nil, nil, err
181	}
182	s.zki.FeePlanTokens = tokenIDs
183
184	// s.zki.ISInitStateRootFee = s.mt.Root().BigInt()
185
186	// TODO once the Node Config sets the Accounts where to send the Fees
187	// compute fees & update ZKInputs
188
189	// return exitInfos, so Synchronizer will be able to store it into
190	// HistoryDB for the concrete BatchNum
191	return s.zki, exitInfos, nil
192}
193
194// getTokenIDsBigInt returns the list of TokenIDs in *big.Int format
195func (s *StateDB) getTokenIDsBigInt(l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.PoolL2Tx) ([]*big.Int, error) {
196	tokenIDs := make(map[common.TokenID]bool)
197	for i := 0; i < len(l1usertxs); i++ {
198		tokenIDs[l1usertxs[i].TokenID] = true
199	}
200	for i := 0; i < len(l1coordinatortxs); i++ {
201		tokenIDs[l1coordinatortxs[i].TokenID] = true
202	}
203	for i := 0; i < len(l2txs); i++ {
204		// as L2Tx does not have parameter TokenID, get it from the
205		// AccountsDB (in the StateDB)
206		acc, err := s.GetAccount(l2txs[i].ToIdx)
207		if err != nil {
208			return nil, err
209		}
210		tokenIDs[acc.TokenID] = true
211	}
212	var tBI []*big.Int
213	for t := range tokenIDs {
214		tBI = append(tBI, t.BigInt())
215	}
216	return tBI, nil
217}
218
219// processL1Tx process the given L1Tx applying the needed updates to the
220// StateDB depending on the transaction Type. It returns the 3 parameters
221// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
222// the Exit created a new Leaf in the ExitTree.
223func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, bool, error) {
224	// ZKInputs
225	if s.zki != nil {
226		// Txs
227		// s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
228		s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
229		s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
230		s.zki.OnChain[s.i] = big.NewInt(1)
231
232		// L1Txs
233		s.zki.LoadAmountF[s.i] = tx.LoadAmount
234		s.zki.FromEthAddr[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
235		if tx.FromBJJ != nil {
236			s.zki.FromBJJCompressed[s.i] = BJJCompressedTo256BigInts(tx.FromBJJ.Compress())
237		}
238
239		// Intermediate States
240		s.zki.ISOnChain[s.i] = big.NewInt(1)
241	}
242
243	switch tx.Type {
244	case common.TxTypeForceTransfer, common.TxTypeTransfer:
245		// go to the MT account of sender and receiver, and update balance
246		// & nonce
247		err := s.applyTransfer(tx.Tx(), 0) // 0 for the parameter toIdx, as at L1Tx ToIdx can only be 0 in the Deposit type case.
248		if err != nil {
249			return nil, nil, false, err
250		}
251	case common.TxTypeCreateAccountDeposit:
252		// add new account to the MT, update balance of the MT account
253		err := s.applyCreateAccount(tx)
254		if err != nil {
255			return nil, nil, false, err
256		}
257
258		if s.zki != nil {
259			s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
260			s.zki.NewAccount[s.i] = big.NewInt(1)
261		}
262	case common.TxTypeDeposit:
263		// update balance of the MT account
264		err := s.applyDeposit(tx, false)
265		if err != nil {
266			return nil, nil, false, err
267		}
268	case common.TxTypeDepositTransfer:
269		// update balance in MT account, update balance & nonce of sender
270		// & receiver
271		err := s.applyDeposit(tx, true)
272		if err != nil {
273			return nil, nil, false, err
274		}
275	case common.TxTypeCreateAccountDepositTransfer:
276		// add new account to the merkletree, update balance in MT account,
277		// update balance & nonce of sender & receiver
278		err := s.applyCreateAccountDepositTransfer(tx)
279		if err != nil {
280			return nil, nil, false, err
281		}
282
283		if s.zki != nil {
284			s.zki.AuxFromIdx[s.i] = s.idx.BigInt() // last s.idx is the one used for creating the new account
285			s.zki.NewAccount[s.i] = big.NewInt(1)
286		}
287	case common.TxTypeExit:
288		// execute exit flow
289		exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
290		if err != nil {
291			return nil, nil, false, err
292		}
293		return &tx.FromIdx, exitAccount, newExit, nil
294	default:
295	}
296
297	return nil, nil, false, nil
298}
299
300// processL2Tx process the given L2Tx applying the needed updates to the
301// StateDB depending on the transaction Type. It returns the 3 parameters
302// related to the Exit (in case of): Idx, ExitAccount, boolean determining if
303// the Exit created a new Leaf in the ExitTree.
304func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2Tx) (*common.Idx, *common.Account, bool, error) {
305	var err error
306	var auxToIdx common.Idx
307	// if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
308	if tx.ToIdx == common.Idx(0) {
309		auxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ)
310		if err != nil {
311			log.Error(err)
312			return nil, nil, false, err
313		}
314	}
315
316	// ZKInputs
317	if s.zki != nil {
318		// Txs
319		// s.zki.TxCompressedData[s.i] = tx.TxCompressedData() // uncomment once L1Tx.TxCompressedData is ready
320		// s.zki.TxCompressedDataV2[s.i] = tx.TxCompressedDataV2() // uncomment once L2Tx.TxCompressedDataV2 is ready
321		s.zki.FromIdx[s.i] = tx.FromIdx.BigInt()
322		s.zki.ToIdx[s.i] = tx.ToIdx.BigInt()
323
324		// fill AuxToIdx if needed
325		if tx.ToIdx == common.Idx(0) {
326			// use toIdx that can have been filled by tx.ToIdx or
327			// if tx.Idx==0 (this case), toIdx is filled by the Idx
328			// from db by ToEthAddr&ToBJJ
329			s.zki.AuxToIdx[s.i] = auxToIdx.BigInt()
330		}
331
332		s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
333		s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
334
335		s.zki.OnChain[s.i] = big.NewInt(0)
336		s.zki.NewAccount[s.i] = big.NewInt(0)
337
338		// L2Txs
339		// s.zki.RqOffset[s.i] =  // TODO Rq once TxSelector is ready
340		// s.zki.RqTxCompressedDataV2[s.i] = // TODO
341		// s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
342		// s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO
343		s.zki.S[s.i] = tx.Signature.S
344		s.zki.R8x[s.i] = tx.Signature.R8.X
345		s.zki.R8y[s.i] = tx.Signature.R8.Y
346	}
347
348	switch tx.Type {
349	case common.TxTypeTransfer:
350		// go to the MT account of sender and receiver, and update
351		// balance & nonce
352		err = s.applyTransfer(tx.Tx(), auxToIdx)
353		if err != nil {
354			return nil, nil, false, err
355		}
356	case common.TxTypeExit:
357		// execute exit flow
358		exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
359		if err != nil {
360			return nil, nil, false, err
361		}
362		return &tx.FromIdx, exitAccount, newExit, nil
363	default:
364	}
365	return nil, nil, false, nil
366}
367
368// applyCreateAccount creates a new account in the account of the depositer, it
369// stores the deposit value
370func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
371	account := &common.Account{
372		TokenID:   tx.TokenID,
373		Nonce:     0,
374		Balance:   tx.LoadAmount,
375		PublicKey: tx.FromBJJ,
376		EthAddr:   tx.FromEthAddr,
377	}
378
379	p, err := s.CreateAccount(common.Idx(s.idx+1), account)
380	if err != nil {
381		return err
382	}
383	if s.zki != nil {
384		s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
385		s.zki.Nonce1[s.i] = big.NewInt(0)
386		if babyjub.PointCoordSign(tx.FromBJJ.X) {
387			s.zki.Sign1[s.i] = big.NewInt(1)
388		}
389		s.zki.Ay1[s.i] = tx.FromBJJ.Y
390		s.zki.Balance1[s.i] = tx.LoadAmount
391		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
392		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
393		if p.IsOld0 {
394			s.zki.IsOld0_1[s.i] = big.NewInt(1)
395		}
396		s.zki.OldKey1[s.i] = p.OldKey.BigInt()
397		s.zki.OldValue1[s.i] = p.OldValue.BigInt()
398	}
399
400	s.idx = s.idx + 1
401	return s.setIdx(s.idx)
402}
403
404// applyDeposit updates the balance in the account of the depositer, if
405// andTransfer parameter is set to true, the method will also apply the
406// Transfer of the L1Tx/DepositTransfer
407func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
408	// deposit the tx.LoadAmount into the sender account
409	accSender, err := s.GetAccount(tx.FromIdx)
410	if err != nil {
411		return err
412	}
413	accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
414
415	// in case that the tx is a L1Tx>DepositTransfer
416	var accReceiver *common.Account
417	if transfer {
418		accReceiver, err = s.GetAccount(tx.ToIdx)
419		if err != nil {
420			return err
421		}
422		// subtract amount to the sender
423		accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
424		// add amount to the receiver
425		accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
426	}
427	// update sender account in localStateDB
428	p, err := s.UpdateAccount(tx.FromIdx, accSender)
429	if err != nil {
430		return err
431	}
432	if s.zki != nil {
433		s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
434		s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
435		if babyjub.PointCoordSign(accSender.PublicKey.X) {
436			s.zki.Sign1[s.i] = big.NewInt(1)
437		}
438		s.zki.Ay1[s.i] = accSender.PublicKey.Y
439		s.zki.Balance1[s.i] = accSender.Balance
440		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
441		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
442		// IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
443	}
444
445	// this is done after updating Sender Account (depositer)
446	if transfer {
447		// update receiver account in localStateDB
448		p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
449		if err != nil {
450			return err
451		}
452		if s.zki != nil {
453			s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
454			s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
455			if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
456				s.zki.Sign2[s.i] = big.NewInt(1)
457			}
458			s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
459			s.zki.Balance2[s.i] = accReceiver.Balance
460			s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
461			s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
462			// IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
463		}
464	}
465
466	return nil
467}
468
469// applyTransfer updates the balance & nonce in the account of the sender, and
470// the balance in the account of the receiver.
471// Parameter 'toIdx' should be at 0 if the tx already has tx.ToIdx!=0, if
472// tx.ToIdx==0, then toIdx!=0, and will be used the toIdx parameter as Idx of
473// the receiver. This parameter is used when the tx.ToIdx is not specified and
474// the real ToIdx is found trhrough the ToEthAddr or ToBJJ.
475func (s *StateDB) applyTransfer(tx *common.Tx, auxToIdx common.Idx) error {
476	if auxToIdx == 0 {
477		auxToIdx = tx.ToIdx
478	}
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(auxToIdx)
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(auxToIdx, 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}