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