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