arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/db/statedb/txprocessors.go
db/statedb/txprocessors.goRaw
  1package statedb
  2
  3import (
  4	"math/big"
  5
  6	"github.com/hermeznetwork/hermez-node/common"
  7	"github.com/iden3/go-merkletree/db"
  8)
  9
 10// keyidx is used as key in the db to store the current Idx
 11var keyidx = []byte("idx")
 12
 13// ProcessTxs process the given L1Txs & L2Txs applying the needed updates
 14// to the StateDB depending on the transaction Type. Returns the
 15// common.ZKInputs to generate the SnarkProof later used by the BatchBuilder,
 16// and returns common.ExitTreeLeaf that is later used by the Synchronizer to
 17// update the HistoryDB.
 18func (s *StateDB) ProcessTxs(l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.L2Tx) (*common.ZKInputs, []*common.ExitTreeLeaf, error) {
 19	for _, tx := range l1usertxs {
 20		err := s.processL1Tx(tx)
 21		if err != nil {
 22			return nil, nil, err
 23		}
 24	}
 25	for _, tx := range l1coordinatortxs {
 26		err := s.processL1Tx(tx)
 27		if err != nil {
 28			return nil, nil, err
 29		}
 30	}
 31	for _, tx := range l2txs {
 32		err := s.processL2Tx(tx)
 33		if err != nil {
 34			return nil, nil, err
 35		}
 36	}
 37
 38	return nil, nil, nil
 39}
 40
 41// processL2Tx process the given L2Tx applying the needed updates to
 42// the StateDB depending on the transaction Type.
 43func (s *StateDB) processL2Tx(tx *common.L2Tx) error {
 44	switch tx.Type {
 45	case common.TxTypeTransfer:
 46		// go to the MT account of sender and receiver, and update
 47		// balance & nonce
 48		err := s.applyTransfer(tx.Tx())
 49		if err != nil {
 50			return err
 51		}
 52	case common.TxTypeExit:
 53		// execute exit flow
 54	default:
 55	}
 56	return nil
 57}
 58
 59// processL1Tx process the given L1Tx applying the needed updates to the
 60// StateDB depending on the transaction Type.
 61func (s *StateDB) processL1Tx(tx *common.L1Tx) error {
 62	switch tx.Type {
 63	case common.TxTypeForceTransfer, common.TxTypeTransfer:
 64		// go to the MT account of sender and receiver, and update balance
 65		// & nonce
 66		err := s.applyTransfer(tx.Tx())
 67		if err != nil {
 68			return err
 69		}
 70	case common.TxTypeCreateAccountDeposit:
 71		// add new account to the MT, update balance of the MT account
 72		err := s.applyCreateAccount(tx)
 73		if err != nil {
 74			return err
 75		}
 76	case common.TxTypeDeposit:
 77		// update balance of the MT account
 78		err := s.applyDeposit(tx, false)
 79		if err != nil {
 80			return err
 81		}
 82	case common.TxTypeDepositTransfer:
 83		// update balance in MT account, update balance & nonce of sender
 84		// & receiver
 85		err := s.applyDeposit(tx, true)
 86		if err != nil {
 87			return err
 88		}
 89	case common.TxTypeCreateAccountDepositTransfer:
 90		// add new account to the merkletree, update balance in MT account,
 91		// update balance & nonce of sender & receiver
 92		err := s.applyCreateAccount(tx)
 93		if err != nil {
 94			return err
 95		}
 96		err = s.applyTransfer(tx.Tx())
 97		if err != nil {
 98			return err
 99		}
100	case common.TxTypeExit:
101		// execute exit flow
102	default:
103	}
104
105	return nil
106}
107
108// applyCreateAccount creates a new account in the account of the depositer, it
109// stores the deposit value
110func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
111	account := &common.Account{
112		TokenID:   tx.TokenID,
113		Nonce:     0,
114		Balance:   tx.LoadAmount,
115		PublicKey: tx.FromBJJ,
116		EthAddr:   tx.FromEthAddr,
117	}
118
119	_, err := s.CreateAccount(common.Idx(s.idx+1), account)
120	if err != nil {
121		return err
122	}
123
124	s.idx = s.idx + 1
125	return s.setIdx(s.idx)
126}
127
128// applyDeposit updates the balance in the account of the depositer, if
129// andTransfer parameter is set to true, the method will also apply the
130// Transfer of the L1Tx/DepositTransfer
131func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
132	// deposit the tx.LoadAmount into the sender account
133	accSender, err := s.GetAccount(tx.FromIdx)
134	if err != nil {
135		return err
136	}
137	accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
138
139	// in case that the tx is a L1Tx>DepositTransfer
140	if transfer {
141		accReceiver, err := s.GetAccount(tx.ToIdx)
142		if err != nil {
143			return err
144		}
145		// substract amount to the sender
146		accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
147		// add amount to the receiver
148		accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
149		// update receiver account in localStateDB
150		_, err = s.UpdateAccount(tx.ToIdx, accReceiver)
151		if err != nil {
152			return err
153		}
154	}
155	// update sender account in localStateDB
156	_, err = s.UpdateAccount(tx.FromIdx, accSender)
157	if err != nil {
158		return err
159	}
160	return nil
161}
162
163// applyTransfer updates the balance & nonce in the account of the sender, and
164// the balance in the account of the receiver
165func (s *StateDB) applyTransfer(tx *common.Tx) error {
166	// get sender and receiver accounts from localStateDB
167	accSender, err := s.GetAccount(tx.FromIdx)
168	if err != nil {
169		return err
170	}
171	accReceiver, err := s.GetAccount(tx.ToIdx)
172	if err != nil {
173		return err
174	}
175
176	// increment nonce
177	accSender.Nonce++
178
179	// substract amount to the sender
180	accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
181	// add amount to the receiver
182	accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
183
184	// update receiver account in localStateDB
185	_, err = s.UpdateAccount(tx.ToIdx, accReceiver)
186	if err != nil {
187		return err
188	}
189	// update sender account in localStateDB
190	_, err = s.UpdateAccount(tx.FromIdx, accSender)
191	if err != nil {
192		return err
193	}
194
195	return nil
196}
197
198// getIdx returns the stored Idx from the localStateDB, which is the last Idx
199// used for an Account in the localStateDB.
200func (s *StateDB) getIdx() (common.Idx, error) {
201	idxBytes, err := s.DB().Get(keyidx)
202	if err == db.ErrNotFound {
203		return 0, nil
204	}
205	if err != nil {
206		return 0, err
207	}
208	return common.IdxFromBytes(idxBytes[:4])
209}
210
211// setIdx stores Idx in the localStateDB
212func (s *StateDB) setIdx(idx common.Idx) error {
213	tx, err := s.DB().NewTx()
214	if err != nil {
215		return err
216	}
217	tx.Put(keyidx, idx.Bytes())
218	if err := tx.Commit(); err != nil {
219		return err
220	}
221	return nil
222}