|
9 | 9 | CONTRACTS, |
10 | 10 | KEYS, |
11 | 11 | deploy_contract, |
| 12 | + get_account_nonce, |
| 13 | + replace_transaction, |
| 14 | + send_transaction, |
12 | 15 | send_txs, |
13 | 16 | sign_transaction, |
14 | 17 | wait_for_new_blocks, |
@@ -138,3 +141,88 @@ def send_with_nonce(nonce): |
138 | 141 | sender |
139 | 142 | ) |
140 | 143 | assert orig_nonce + 4 + i == local_nonce |
| 144 | + |
| 145 | + |
| 146 | +@pytest.mark.flaky(max_runs=3) |
| 147 | +def test_tx_replacement(cronos_mempool): |
| 148 | + w3 = cronos_mempool.w3 |
| 149 | + base_fee = w3.eth.get_block("latest")["baseFeePerGas"] |
| 150 | + priority_fee = w3.eth.max_priority_fee |
| 151 | + nonce = get_account_nonce(w3) |
| 152 | + # replace with less than 10% bump, should fail |
| 153 | + with pytest.raises(ValueError) as exc: |
| 154 | + _ = replace_transaction( |
| 155 | + w3, |
| 156 | + { |
| 157 | + "to": ADDRS["community"], |
| 158 | + "value": 1, |
| 159 | + "maxFeePerGas": base_fee + priority_fee, |
| 160 | + "maxPriorityFeePerGas": priority_fee, |
| 161 | + "nonce": nonce, |
| 162 | + "from": ADDRS["validator"], |
| 163 | + }, |
| 164 | + { |
| 165 | + "to": ADDRS["community"], |
| 166 | + "value": 2, |
| 167 | + "maxFeePerGas": int((base_fee + priority_fee) * 1.05), # +5% bump |
| 168 | + "maxPriorityFeePerGas": int(priority_fee * 1.05), |
| 169 | + "nonce": nonce, |
| 170 | + "from": ADDRS["validator"], |
| 171 | + }, |
| 172 | + KEYS["validator"], |
| 173 | + )["transactionHash"] |
| 174 | + assert "tx doesn't fit the replacement rule" in str(exc) |
| 175 | + |
| 176 | + wait_for_new_blocks(cronos_mempool.cosmos_cli(), 1) |
| 177 | + nonce = get_account_nonce(w3) |
| 178 | + initial_balance = w3.eth.get_balance(ADDRS["community"]) |
| 179 | + # replace with more than 10% bump, should succeed |
| 180 | + txhash = replace_transaction( |
| 181 | + w3, |
| 182 | + { |
| 183 | + "to": ADDRS["community"], |
| 184 | + "value": 3, |
| 185 | + "maxFeePerGas": base_fee + priority_fee, |
| 186 | + "maxPriorityFeePerGas": priority_fee, |
| 187 | + "nonce": nonce, |
| 188 | + "from": ADDRS["validator"], |
| 189 | + }, |
| 190 | + { |
| 191 | + "to": ADDRS["community"], |
| 192 | + "value": 5, |
| 193 | + "maxFeePerGas": int((base_fee + priority_fee) * 1.15), # +15% bump |
| 194 | + "maxPriorityFeePerGas": int(priority_fee * 1.15), |
| 195 | + "nonce": nonce, |
| 196 | + "from": ADDRS["validator"], |
| 197 | + }, |
| 198 | + KEYS["validator"], |
| 199 | + )["transactionHash"] |
| 200 | + tx1 = w3.eth.get_transaction(txhash) |
| 201 | + assert tx1["transactionIndex"] == 0 |
| 202 | + assert w3.eth.get_balance(ADDRS["community"]) == initial_balance + 5 |
| 203 | + |
| 204 | + # check that already accepted transaction cannot be replaced |
| 205 | + txhash_noreplacemenet = send_transaction( |
| 206 | + w3, |
| 207 | + { |
| 208 | + "to": ADDRS["community"], |
| 209 | + "value": 10, |
| 210 | + "maxFeePerGas": base_fee + priority_fee, |
| 211 | + "maxPriorityFeePerGas": priority_fee, |
| 212 | + }, |
| 213 | + KEYS["validator"], |
| 214 | + )["transactionHash"] |
| 215 | + tx2 = w3.eth.get_transaction(txhash_noreplacemenet) |
| 216 | + assert tx2["transactionIndex"] == 0 |
| 217 | + |
| 218 | + with pytest.raises(ValueError) as exc: |
| 219 | + w3.eth.replace_transaction( |
| 220 | + txhash_noreplacemenet, |
| 221 | + { |
| 222 | + "to": ADDRS["community"], |
| 223 | + "value": 15, |
| 224 | + "maxFeePerGas": int((base_fee + priority_fee) * 1.15), # +15% bump |
| 225 | + "maxPriorityFeePerGas": int(priority_fee * 1.15), |
| 226 | + }, |
| 227 | + ) |
| 228 | + assert "has already been mined" in str(exc) |
0 commit comments