arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/txselector/txselector.go
txselector/txselector.goRaw
  1package txselector
  2
  3import (
  4	"sort"
  5
  6	"github.com/hermeznetwork/hermez-node/tx-selector/common"
  7	"github.com/hermeznetwork/hermez-node/tx-selector/mock"
  8)
  9
 10// txs implements the interface Sort for an array of Tx
 11type txs []common.Tx
 12
 13func (t txs) Len() int {
 14	return len(t)
 15}
 16func (t txs) Swap(i, j int) {
 17	t[i], t[j] = t[j], t[i]
 18}
 19func (t txs) Less(i, j int) bool {
 20	return t[i].UserFeeAbsolute > t[j].UserFeeAbsolute
 21}
 22
 23type TxSelector struct {
 24	// NMax is the maximum L1-user-tx for a batch
 25	NMax uint64
 26	// MMax is the maximum L1-operator-tx for a batch
 27	MMax uint64
 28	// PMax is the maximum L2-tx for a batch
 29	PMax uint64
 30	// DB is a pointer to the database interface
 31	DB *mock.MockDB
 32}
 33
 34func NewTxSelector(db *mock.MockDB, nMax, mMax, pMax uint64) *TxSelector {
 35	return &TxSelector{
 36		NMax: nMax,
 37		MMax: mMax,
 38		PMax: pMax,
 39		DB:   db,
 40	}
 41}
 42
 43func (txsel *TxSelector) updateLocalAccountDB(batchId uint64) error {
 44	// if batchID > max(localAccountDB.BatchID) + 1
 45	//     make a checkpoint of AccountDB at BatchID to a localAccountDB
 46	// use localAccountDB[inputBatchID-1]
 47
 48	return nil
 49}
 50
 51func (txsel *TxSelector) GetL2TxSelection(batchID uint64) ([]common.Tx, error) {
 52	err := txsel.updateLocalAccountDB(batchID)
 53	if err != nil {
 54		return nil, err
 55	}
 56
 57	// get pending l2-tx from tx-pool
 58	txsRaw := txsel.DB.GetTxs(batchID)
 59
 60	// discard the txs that don't have an Account in the AccountDB
 61	var validTxs txs
 62	for _, tx := range txsRaw {
 63		accountID := getAccountID(tx.ToEthAddr, tx.TokenID)
 64		if _, ok := txsel.DB.AccountDB[accountID]; ok {
 65			validTxs = append(validTxs, tx)
 66		}
 67	}
 68
 69	// get most profitable L2-tx (len<NMax)
 70	txs := txsel.getL2Profitable(validTxs)
 71
 72	// apply L2-tx to local AccountDB, make checkpoint tagged with BatchID
 73	//     update balances
 74	//     update nonces
 75
 76	// return selected txs
 77	return txs, nil
 78}
 79
 80func (txsel *TxSelector) GetL1L2TxSelection(batchID uint64, l1txs []common.Tx) ([]common.Tx, []common.Tx, []common.Tx, error) {
 81	err := txsel.updateLocalAccountDB(batchID)
 82	if err != nil {
 83		return nil, nil, nil, err
 84	}
 85
 86	// apply l1-user-tx to localAccountDB
 87	//     create new leaves
 88	//     update balances
 89	//     update nonces
 90
 91	// get pending l2-tx from tx-pool
 92	txsRaw := txsel.DB.GetTxs(batchID)
 93
 94	// discard the txs that don't have an Account in the AccountDB
 95	// neither appear in the PendingRegistersDB
 96	var validTxs txs
 97	for _, tx := range txsRaw {
 98		accountID := getAccountID(tx.ToEthAddr, tx.TokenID)
 99		exist := txsel.checkIfAccountExist(accountID)
100		if exist {
101			validTxs = append(validTxs, tx)
102		}
103	}
104
105	// get most profitable L2-tx (len<NMax)
106	l2txs := txsel.getL2Profitable(validTxs)
107
108	// prepare (from the selected l2txs) pending to register from the PendingRegistersDB
109	var pendingRegisters []common.Account
110	for _, tx := range l2txs {
111		accountID := getAccountID(tx.ToEthAddr, tx.TokenID)
112		if toRegister, ok := txsel.DB.PendingRegistersDB[accountID]; ok {
113			pendingRegisters = append(pendingRegisters, toRegister)
114		}
115	}
116
117	// create L1-operator-tx for each L2-tx selected in which the recipient does not have account
118	l1OperatorTxs := txsel.createL1OperatorTxForL2Tx(pendingRegisters) // only with the L2-tx selected ones
119
120	return l1txs, l2txs, l1OperatorTxs, nil
121}
122
123func (txsel *TxSelector) checkIfAccountExist(accountID [36]byte) bool {
124	// check if account exist in AccountDB
125	if _, ok := txsel.DB.AccountDB[accountID]; ok {
126		return true
127	}
128	// check if account is pending to register
129	if _, ok := txsel.DB.PendingRegistersDB[accountID]; ok {
130		return true
131	}
132	return false
133}
134
135func (txsel *TxSelector) getL2Profitable(txs txs) txs {
136	sort.Sort(txs)
137	return txs[:txsel.PMax]
138}
139func (txsel *TxSelector) createL1OperatorTxForL2Tx(accounts []common.Account) txs {
140	//
141	return txs{}
142}