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					return nil, nil, false, ErrToIdxNotFound
323				}
324			} else if !bytes.Equal(tx.ToEthAddr.Bytes(), common.EmptyAddr.Bytes()) && tx.ToBJJ != nil {
325				// case ToEthAddr!=0 && ToBJJ!=0
326				idx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ)
327				if err != nil {
328					return nil, nil, false, ErrToIdxNotFound
329				}
330			} else {
331				// rest of cases (included case ToEthAddr==0) are not possible
332				return nil, nil, false, ErrToIdxNotFound
333			}
334			s.zki.AuxToIdx[s.i] = idx.BigInt()
335		}
336		s.zki.ToBJJAy[s.i] = tx.ToBJJ.Y
337		s.zki.ToEthAddr[s.i] = common.EthAddrToBigInt(tx.ToEthAddr)
338
339		s.zki.OnChain[s.i] = big.NewInt(0)
340		s.zki.NewAccount[s.i] = big.NewInt(0)
341
342		// L2Txs
343		// s.zki.RqOffset[s.i] =  // TODO Rq once TxSelector is ready
344		// s.zki.RqTxCompressedDataV2[s.i] = // TODO
345		// s.zki.RqToEthAddr[s.i] = common.EthAddrToBigInt(tx.RqToEthAddr) // TODO
346		// s.zki.RqToBJJAy[s.i] = tx.ToBJJ.Y // TODO
347		s.zki.S[s.i] = tx.Signature.S
348		s.zki.R8x[s.i] = tx.Signature.R8.X
349		s.zki.R8y[s.i] = tx.Signature.R8.Y
350	}
351
352	switch tx.Type {
353	case common.TxTypeTransfer:
354		// go to the MT account of sender and receiver, and update
355		// balance & nonce
356		err = s.applyTransfer(tx.Tx())
357		if err != nil {
358			return nil, nil, false, err
359		}
360	case common.TxTypeExit:
361		// execute exit flow
362		exitAccount, newExit, err := s.applyExit(exitTree, tx.Tx())
363		if err != nil {
364			return nil, nil, false, err
365		}
366		return &tx.FromIdx, exitAccount, newExit, nil
367	default:
368	}
369	return nil, nil, false, nil
370}
371
372// applyCreateAccount creates a new account in the account of the depositer, it
373// stores the deposit value
374func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
375	account := &common.Account{
376		TokenID:   tx.TokenID,
377		Nonce:     0,
378		Balance:   tx.LoadAmount,
379		PublicKey: tx.FromBJJ,
380		EthAddr:   tx.FromEthAddr,
381	}
382
383	p, err := s.CreateAccount(common.Idx(s.idx+1), account)
384	if err != nil {
385		return err
386	}
387	if s.zki != nil {
388		s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
389		s.zki.Nonce1[s.i] = big.NewInt(0)
390		if babyjub.PointCoordSign(tx.FromBJJ.X) {
391			s.zki.Sign1[s.i] = big.NewInt(1)
392		}
393		s.zki.Ay1[s.i] = tx.FromBJJ.Y
394		s.zki.Balance1[s.i] = tx.LoadAmount
395		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
396		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
397		if p.IsOld0 {
398			s.zki.IsOld0_1[s.i] = big.NewInt(1)
399		}
400		s.zki.OldKey1[s.i] = p.OldKey.BigInt()
401		s.zki.OldValue1[s.i] = p.OldValue.BigInt()
402	}
403
404	s.idx = s.idx + 1
405	return s.setIdx(s.idx)
406}
407
408// applyDeposit updates the balance in the account of the depositer, if
409// andTransfer parameter is set to true, the method will also apply the
410// Transfer of the L1Tx/DepositTransfer
411func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
412	// deposit the tx.LoadAmount into the sender account
413	accSender, err := s.GetAccount(tx.FromIdx)
414	if err != nil {
415		return err
416	}
417	accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
418
419	// in case that the tx is a L1Tx>DepositTransfer
420	var accReceiver *common.Account
421	if transfer {
422		accReceiver, err = s.GetAccount(tx.ToIdx)
423		if err != nil {
424			return err
425		}
426		// subtract amount to the sender
427		accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
428		// add amount to the receiver
429		accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
430	}
431	// update sender account in localStateDB
432	p, err := s.UpdateAccount(tx.FromIdx, accSender)
433	if err != nil {
434		return err
435	}
436	if s.zki != nil {
437		s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
438		s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
439		if babyjub.PointCoordSign(accSender.PublicKey.X) {
440			s.zki.Sign1[s.i] = big.NewInt(1)
441		}
442		s.zki.Ay1[s.i] = accSender.PublicKey.Y
443		s.zki.Balance1[s.i] = accSender.Balance
444		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
445		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
446		// IsOld0_1, OldKey1, OldValue1 not needed as this is not an insert
447	}
448
449	// this is done after updating Sender Account (depositer)
450	if transfer {
451		// update receiver account in localStateDB
452		p, err := s.UpdateAccount(tx.ToIdx, accReceiver)
453		if err != nil {
454			return err
455		}
456		if s.zki != nil {
457			s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
458			s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
459			if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
460				s.zki.Sign2[s.i] = big.NewInt(1)
461			}
462			s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
463			s.zki.Balance2[s.i] = accReceiver.Balance
464			s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
465			s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
466			// IsOld0_2, OldKey2, OldValue2 not needed as this is not an insert
467		}
468	}
469
470	return nil
471}
472
473// applyTransfer updates the balance & nonce in the account of the sender, and
474// the balance in the account of the receiver
475func (s *StateDB) applyTransfer(tx *common.Tx) error {
476	// get sender and receiver accounts from localStateDB
477	accSender, err := s.GetAccount(tx.FromIdx)
478	if err != nil {
479		return err
480	}
481	accReceiver, err := s.GetAccount(tx.ToIdx)
482	if err != nil {
483		return err
484	}
485
486	// increment nonce
487	accSender.Nonce++
488
489	// subtract amount to the sender
490	accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
491	// add amount to the receiver
492	accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
493
494	// update sender account in localStateDB
495	pSender, err := s.UpdateAccount(tx.FromIdx, accSender)
496	if err != nil {
497		return err
498	}
499	if s.zki != nil {
500		s.zki.TokenID1[s.i] = accSender.TokenID.BigInt()
501		s.zki.Nonce1[s.i] = accSender.Nonce.BigInt()
502		if babyjub.PointCoordSign(accSender.PublicKey.X) {
503			s.zki.Sign1[s.i] = big.NewInt(1)
504		}
505		s.zki.Ay1[s.i] = accSender.PublicKey.Y
506		s.zki.Balance1[s.i] = accSender.Balance
507		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(accSender.EthAddr)
508		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(pSender.Siblings)
509	}
510
511	// update receiver account in localStateDB
512	pReceiver, err := s.UpdateAccount(tx.ToIdx, accReceiver)
513	if err != nil {
514		return err
515	}
516	if s.zki != nil {
517		s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
518		s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
519		if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
520			s.zki.Sign2[s.i] = big.NewInt(1)
521		}
522		s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
523		s.zki.Balance2[s.i] = accReceiver.Balance
524		s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
525		s.zki.Siblings2[s.i] = siblingsToZKInputFormat(pReceiver.Siblings)
526	}
527
528	return nil
529}
530
531// applyCreateAccountDepositTransfer, in a single tx, creates a new account,
532// makes a deposit, and performs a transfer to another account
533func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
534	accSender := &common.Account{
535		TokenID:   tx.TokenID,
536		Nonce:     0,
537		Balance:   tx.LoadAmount,
538		PublicKey: tx.FromBJJ,
539		EthAddr:   tx.FromEthAddr,
540	}
541	accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
542	accReceiver, err := s.GetAccount(tx.ToIdx)
543	if err != nil {
544		return err
545	}
546	// subtract amount to the sender
547	accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
548	// add amount to the receiver
549	accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
550
551	// create Account of the Sender
552	p, err := s.CreateAccount(common.Idx(s.idx+1), accSender)
553	if err != nil {
554		return err
555	}
556	if s.zki != nil {
557		s.zki.TokenID1[s.i] = tx.TokenID.BigInt()
558		s.zki.Nonce1[s.i] = big.NewInt(0)
559		if babyjub.PointCoordSign(tx.FromBJJ.X) {
560			s.zki.Sign1[s.i] = big.NewInt(1)
561		}
562		s.zki.Ay1[s.i] = tx.FromBJJ.Y
563		s.zki.Balance1[s.i] = tx.LoadAmount
564		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(tx.FromEthAddr)
565		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
566		if p.IsOld0 {
567			s.zki.IsOld0_1[s.i] = big.NewInt(1)
568		}
569		s.zki.OldKey1[s.i] = p.OldKey.BigInt()
570		s.zki.OldValue1[s.i] = p.OldValue.BigInt()
571	}
572
573	// update receiver account in localStateDB
574	p, err = s.UpdateAccount(tx.ToIdx, accReceiver)
575	if err != nil {
576		return err
577	}
578	if s.zki != nil {
579		s.zki.TokenID2[s.i] = accReceiver.TokenID.BigInt()
580		s.zki.Nonce2[s.i] = accReceiver.Nonce.BigInt()
581		if babyjub.PointCoordSign(accReceiver.PublicKey.X) {
582			s.zki.Sign2[s.i] = big.NewInt(1)
583		}
584		s.zki.Ay2[s.i] = accReceiver.PublicKey.Y
585		s.zki.Balance2[s.i] = accReceiver.Balance
586		s.zki.EthAddr2[s.i] = common.EthAddrToBigInt(accReceiver.EthAddr)
587		s.zki.Siblings2[s.i] = siblingsToZKInputFormat(p.Siblings)
588	}
589
590	s.idx = s.idx + 1
591	return s.setIdx(s.idx)
592}
593
594// It returns the ExitAccount and a boolean determining if the Exit created a
595// new Leaf in the ExitTree.
596func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx *common.Tx) (*common.Account, bool, error) {
597	// 0. subtract tx.Amount from current Account in StateMT
598	// add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
599	acc, err := s.GetAccount(tx.FromIdx)
600	if err != nil {
601		return nil, false, err
602	}
603	acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
604	p, err := s.UpdateAccount(tx.FromIdx, acc)
605	if err != nil {
606		return nil, false, err
607	}
608	if s.zki != nil {
609		s.zki.TokenID1[s.i] = acc.TokenID.BigInt()
610		s.zki.Nonce1[s.i] = acc.Nonce.BigInt()
611		if babyjub.PointCoordSign(acc.PublicKey.X) {
612			s.zki.Sign1[s.i] = big.NewInt(1)
613		}
614		s.zki.Ay1[s.i] = acc.PublicKey.Y
615		s.zki.Balance1[s.i] = acc.Balance
616		s.zki.EthAddr1[s.i] = common.EthAddrToBigInt(acc.EthAddr)
617		s.zki.Siblings1[s.i] = siblingsToZKInputFormat(p.Siblings)
618	}
619
620	if exitTree == nil {
621		return nil, false, nil
622	}
623	exitAccount, err := getAccountInTreeDB(exitTree.DB(), tx.FromIdx)
624	if err == db.ErrNotFound {
625		// 1a. if idx does not exist in exitTree:
626		// add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance = exitAmount (exitAmount=tx.Amount)
627		exitAccount := &common.Account{
628			TokenID:   acc.TokenID,
629			Nonce:     common.Nonce(1),
630			Balance:   tx.Amount,
631			PublicKey: acc.PublicKey,
632			EthAddr:   acc.EthAddr,
633		}
634		_, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
635		return exitAccount, true, err
636	} else if err != nil {
637		return exitAccount, false, err
638	}
639
640	// 1b. if idx already exist in exitTree:
641	// update account, where account.Balance += exitAmount
642	exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
643	_, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
644	return exitAccount, false, err
645}
646
647// getIdx returns the stored Idx from the localStateDB, which is the last Idx
648// used for an Account in the localStateDB.
649func (s *StateDB) getIdx() (common.Idx, error) {
650	idxBytes, err := s.DB().Get(keyidx)
651	if err == db.ErrNotFound {
652		return 0, nil
653	}
654	if err != nil {
655		return 0, err
656	}
657	return common.IdxFromBytes(idxBytes[:4])
658}
659
660// setIdx stores Idx in the localStateDB
661func (s *StateDB) setIdx(idx common.Idx) error {
662	tx, err := s.DB().NewTx()
663	if err != nil {
664		return err
665	}
666	idxBytes, err := idx.Bytes()
667	if err != nil {
668		return err
669	}
670	err = tx.Put(keyidx, idxBytes[:])
671	if err != nil {
672		return err
673	}
674	if err := tx.Commit(); err != nil {
675		return err
676	}
677	return nil
678}