github.com/0xPolygon/supernets2-node@v0.0.0-20230711153321-2fe574524eaa/sequencer/addrqueue.go (about) 1 package sequencer 2 3 import ( 4 "math/big" 5 "time" 6 7 "github.com/0xPolygon/supernets2-node/log" 8 "github.com/0xPolygon/supernets2-node/state" 9 "github.com/0xPolygon/supernets2-node/state/runtime" 10 "github.com/ethereum/go-ethereum/common" 11 ) 12 13 // addrQueue is a struct that stores the ready and notReady txs for a specific from address 14 type addrQueue struct { 15 from common.Address 16 fromStr string 17 currentNonce uint64 18 currentBalance *big.Int 19 readyTx *TxTracker 20 notReadyTxs map[uint64]*TxTracker 21 } 22 23 // newAddrQueue creates and init a addrQueue 24 func newAddrQueue(addr common.Address, nonce uint64, balance *big.Int) *addrQueue { 25 return &addrQueue{ 26 from: addr, 27 fromStr: addr.String(), 28 currentNonce: nonce, 29 currentBalance: balance, 30 readyTx: nil, 31 notReadyTxs: make(map[uint64]*TxTracker), 32 } 33 } 34 35 // addTx adds a tx to the addrQueue and updates the ready a notReady Txs 36 func (a *addrQueue) addTx(tx *TxTracker) (newReadyTx, prevReadyTx *TxTracker, dropReason error) { 37 if a.currentNonce == tx.Nonce { // Is a possible readyTx 38 // We set the tx as readyTx if we do not have one assigned or if the gasPrice is better or equal than the current readyTx 39 if a.readyTx == nil || ((a.readyTx != nil) && (tx.GasPrice.Cmp(a.readyTx.GasPrice) >= 0)) { 40 oldReadyTx := a.readyTx 41 if a.currentBalance.Cmp(tx.Cost) >= 0 { // 42 a.readyTx = tx 43 return tx, oldReadyTx, nil 44 } else { // If there is not enough balance we set the new tx as notReadyTxs 45 a.readyTx = nil 46 a.notReadyTxs[tx.Nonce] = tx 47 return nil, oldReadyTx, nil 48 } 49 } 50 } else if a.currentNonce > tx.Nonce { 51 return nil, nil, runtime.ErrIntrinsicInvalidNonce 52 } 53 54 nrTx, found := a.notReadyTxs[tx.Nonce] 55 if !found || ((found) && (tx.GasPrice.Cmp(nrTx.GasPrice) >= 0)) { 56 a.notReadyTxs[tx.Nonce] = tx 57 } 58 59 return nil, nil, nil 60 } 61 62 // ExpireTransactions removes the txs that have been in the queue for more than maxTime 63 func (a *addrQueue) ExpireTransactions(maxTime time.Duration) ([]*TxTracker, *TxTracker) { 64 var ( 65 txs []*TxTracker 66 prevReadyTx *TxTracker 67 ) 68 69 for _, txTracker := range a.notReadyTxs { 70 if txTracker.ReceivedAt.Add(maxTime).Before(time.Now()) { 71 txs = append(txs, txTracker) 72 delete(a.notReadyTxs, txTracker.Nonce) 73 log.Debugf("Deleting notReadyTx %s from addrQueue %s", txTracker.HashStr, a.fromStr) 74 } 75 } 76 77 if a.readyTx != nil && a.readyTx.ReceivedAt.Add(maxTime).Before(time.Now()) { 78 prevReadyTx = a.readyTx 79 txs = append(txs, a.readyTx) 80 a.readyTx = nil 81 log.Debugf("Deleting notReadyTx %s from addrQueue %s", prevReadyTx.HashStr, a.fromStr) 82 } 83 84 return txs, prevReadyTx 85 } 86 87 // IsEmpty returns true if the addrQueue is empty 88 func (a *addrQueue) IsEmpty() bool { 89 return a.readyTx == nil && len(a.notReadyTxs) == 0 90 } 91 92 // deleteTx deletes the tx from the addrQueue 93 func (a *addrQueue) deleteTx(txHash common.Hash) (deletedReadyTx *TxTracker) { 94 txHashStr := txHash.String() 95 96 if (a.readyTx != nil) && (a.readyTx.HashStr == txHashStr) { 97 log.Infof("Deleting readyTx %s from addrQueue %s", txHashStr, a.fromStr) 98 prevReadyTx := a.readyTx 99 a.readyTx = nil 100 return prevReadyTx 101 } else { 102 for _, txTracker := range a.notReadyTxs { 103 if txTracker.HashStr == txHashStr { 104 log.Infof("Deleting notReadyTx %s from addrQueue %s", txHashStr, a.fromStr) 105 delete(a.notReadyTxs, txTracker.Nonce) 106 } 107 } 108 return nil 109 } 110 } 111 112 // updateCurrentNonceBalance updates the nonce and balance of the addrQueue and updates the ready and notReady txs 113 func (a *addrQueue) updateCurrentNonceBalance(nonce *uint64, balance *big.Int) (newReadyTx, prevReadyTx *TxTracker, toDelete []*TxTracker) { 114 var oldReadyTx *TxTracker = nil 115 txsToDelete := make([]*TxTracker, 0) 116 117 if balance != nil { 118 log.Infof("Updating balance for addrQueue %s from %s to %s", a.fromStr, a.currentBalance.String(), balance.String()) 119 a.currentBalance = balance 120 } 121 122 if nonce != nil { 123 if a.currentNonce != *nonce { 124 a.currentNonce = *nonce 125 for _, txTracker := range a.notReadyTxs { 126 if txTracker.Nonce < a.currentNonce { 127 reason := runtime.ErrIntrinsicInvalidNonce.Error() 128 txTracker.FailedReason = &reason 129 txsToDelete = append(txsToDelete, txTracker) 130 } 131 } 132 for _, txTracker := range txsToDelete { 133 log.Infof("Deleting notReadyTx with nonce %d from addrQueue %s", txTracker.Nonce, a.fromStr) 134 delete(a.notReadyTxs, txTracker.Nonce) 135 } 136 } 137 } 138 139 if a.readyTx != nil { 140 // If readyTX.nonce is not the currentNonce or currentBalance is less that the readyTx.Cost 141 // set readyTx=nil. Later we will move the tx to notReadyTxs 142 if (a.readyTx.Nonce != a.currentNonce) || (a.currentBalance.Cmp(a.readyTx.Cost) < 0) { 143 oldReadyTx = a.readyTx 144 a.readyTx = nil 145 } 146 } 147 148 // We check if we have a new readyTx from the notReadyTxs (at this point, to optmize the code, 149 // we are not including the oldReadyTx in notReadyTxs, as it can match again if the nonce has not changed) 150 if a.readyTx == nil { 151 nrTx, found := a.notReadyTxs[a.currentNonce] 152 if found { 153 if a.currentBalance.Cmp(nrTx.Cost) >= 0 { 154 a.readyTx = nrTx 155 log.Infof("Moving notReadyTx %s to readyTx for addrQueue %s", nrTx.HashStr, a.fromStr) 156 delete(a.notReadyTxs, a.currentNonce) 157 } 158 } 159 } 160 161 // We add the oldReadyTx to notReadyTxs (if it has a valid nonce) at this point to avoid check it again in the previous if statement 162 if oldReadyTx != nil && oldReadyTx.Nonce > a.currentNonce { 163 log.Infof("Marking readyTx %s as notReadyTx from addrQueue %s", oldReadyTx.HashStr, a.fromStr) 164 a.notReadyTxs[oldReadyTx.Nonce] = oldReadyTx 165 } 166 167 return a.readyTx, oldReadyTx, txsToDelete 168 } 169 170 // UpdateTxZKCounters updates the ZKCounters for the given tx (txHash) 171 // If the updated tx is the readyTx it returns a copy of the previous readyTx, nil otherwise 172 func (a *addrQueue) UpdateTxZKCounters(txHash common.Hash, counters state.ZKCounters, constraints batchConstraintsFloat64, weights batchResourceWeights) (newReadyTx, prevReadyTx *TxTracker) { 173 txHashStr := txHash.String() 174 175 if (a.readyTx != nil) && (a.readyTx.HashStr == txHashStr) { 176 // We need to assign the new readyTx as a new TxTracker copy of the previous one with the updated efficiency 177 // We need to do in this way because the efficiency value is changed and we use this value as key field to 178 // add/delete TxTrackers in the efficiencyList 179 prevReadyTx := a.readyTx 180 newReadyTx := *a.readyTx 181 newReadyTx.updateZKCounters(counters, constraints, weights) 182 a.readyTx = &newReadyTx 183 log.Debugf("Updating readyTx %s with new ZKCounters from addrQueue %s", txHashStr, a.fromStr) 184 return a.readyTx, prevReadyTx 185 } else { 186 txHashStr := txHash.String() 187 for _, txTracker := range a.notReadyTxs { 188 if txTracker.HashStr == txHashStr { 189 log.Debugf("Updating notReadyTx %s with new ZKCounters from addrQueue %s", txHashStr, a.fromStr) 190 txTracker.updateZKCounters(counters, constraints, weights) 191 break 192 } 193 } 194 return nil, nil 195 } 196 }