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