hermez-node/txselector/txselector.go
txselector/txselector.goRaw
1package txselector
2
3import (
4 "sort"
5
6 "github.com/hermeznetwork/hermez-node/txselector/common"
7 "github.com/hermeznetwork/hermez-node/txselector/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}