feat(ante, evm): set priority for eth transactions (#1214)

* Set priority for eth transactions

Set the tx priority to the lowest priority in the messages.

fix unit tests

code cleanup and spec

update spec

fix go lint

add priority integration test

add python linter job

add access list tx type

fix gas limit

remove ledger tag, so no need to replace hid dependency

fix earlier check

ibc-go v5.0.0-beta1

* fix pruned node integration test

* Update x/feemarket/spec/09_antehandlers.md

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
yihuang
2022-08-05 15:00:31 +02:00
committed by GitHub
co-authored by Federico Kunze Küllmer
parent 53f160cbb0
commit e1560849dd
25 changed files with 307 additions and 63 deletions
@@ -1,8 +1,18 @@
{
dotenv: '../../../scripts/.env',
'ethermintd_777-1': {
'ethermint_9000-1': {
cmd: 'ethermintd',
'start-flags': '--trace',
config: {
consensus: {
// larger timeout for more stable mempool tests
timeout_commit: '10s',
},
mempool: {
// use v1 mempool to enable tx prioritization
version: 'v1',
},
},
'app-config': {
'minimum-gas-prices': '0aphoton',
'index-events': ['ethereum_tx.ethereumTxHash'],
+2 -2
View File
@@ -4,7 +4,6 @@ import signal
import subprocess
from pathlib import Path
import tomlkit
import web3
from pystarport import ports
from web3.middleware import geth_poa_middleware
@@ -61,9 +60,10 @@ class Geth:
def setup_ethermint(path, base_port):
cfg = Path(__file__).parent / "../../scripts/ethermint-devnet.yaml"
cfg = Path(__file__).parent / "configs/default.jsonnet"
yield from setup_custom_ethermint(path, base_port, cfg)
def setup_geth(path, base_port):
with (path / "geth.log").open("w") as logfile:
cmd = [
+114
View File
@@ -0,0 +1,114 @@
from .network import Ethermint
from .utils import KEYS, sign_transaction
PRIORITY_REDUCTION = 1000000
def effective_gas_price(tx, base_fee):
if "maxFeePerGas" in tx:
# dynamic fee tx
return min(base_fee + tx["maxPriorityFeePerGas"], tx["maxFeePerGas"])
else:
# legacy tx
return tx["gasPrice"]
def tx_priority(tx, base_fee):
if "maxFeePerGas" in tx:
# dynamic fee tx
return (
min(tx["maxPriorityFeePerGas"], tx["maxFeePerGas"] - base_fee)
// PRIORITY_REDUCTION
)
else:
# legacy tx
return (tx["gasPrice"] - base_fee) // PRIORITY_REDUCTION
def test_priority(ethermint: Ethermint):
"""
test priorities of different tx types
"""
w3 = ethermint.w3
amount = 10000
base_fee = w3.eth.get_block("latest").baseFeePerGas
# [ ( sender, tx ), ... ]
# use different senders to avoid nonce conflicts
test_cases = [
(
"validator",
{
"to": "0x0000000000000000000000000000000000000000",
"value": amount,
"gas": 21000,
"maxFeePerGas": base_fee + PRIORITY_REDUCTION * 6,
"maxPriorityFeePerGas": 0,
},
),
(
"community",
{
"to": "0x0000000000000000000000000000000000000000",
"value": amount,
"gas": 21000,
"gasPrice": base_fee + PRIORITY_REDUCTION * 2,
},
),
(
"signer2",
{
"to": "0x0000000000000000000000000000000000000000",
"value": amount,
"gasPrice": base_fee + PRIORITY_REDUCTION * 4,
"accessList": [
{
"address": "0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae",
"storageKeys": (
"0x00000000000000000000000000000000000000000000000000000000"
"00000003",
"0x00000000000000000000000000000000000000000000000000000000"
"00000007",
),
}
],
},
),
(
"signer1",
{
"to": "0x0000000000000000000000000000000000000000",
"value": amount,
"gas": 21000,
"maxFeePerGas": base_fee + PRIORITY_REDUCTION * 6,
"maxPriorityFeePerGas": PRIORITY_REDUCTION * 6,
},
),
]
# test cases are ordered by priority
priorities = [tx_priority(tx, base_fee) for _, tx in test_cases]
assert all(a < b for a, b in zip(priorities, priorities[1:]))
signed = [sign_transaction(w3, tx, key=KEYS[sender]) for sender, tx in test_cases]
# send the txs from low priority to high,
# but the later sent txs should be included earlier.
txhashes = [w3.eth.send_raw_transaction(tx.rawTransaction) for tx in signed]
receipts = [w3.eth.wait_for_transaction_receipt(txhash) for txhash in txhashes]
print(receipts)
assert all(receipt.status == 1 for receipt in receipts), "expect all txs success"
# the later txs should be included earlier because of higher priority
# FIXME there's some non-deterministics due to mempool logic
assert all(included_earlier(r2, r1) for r1, r2 in zip(receipts, receipts[1:]))
def included_earlier(receipt1, receipt2):
"returns true if receipt1 is earlier than receipt2"
if receipt1.blockNumber < receipt2.blockNumber:
return True
elif receipt1.blockNumber == receipt2.blockNumber:
return receipt1.transactionIndex < receipt2.transactionIndex
else:
return False
+34
View File
@@ -1,6 +1,22 @@
import os
import socket
import time
from eth_account import Account
from web3._utils.transactions import fill_nonce, fill_transaction_defaults
Account.enable_unaudited_hdwallet_features()
ACCOUNTS = {
"validator": Account.from_mnemonic(os.getenv("VALIDATOR1_MNEMONIC")),
"community": Account.from_mnemonic(os.getenv("COMMUNITY_MNEMONIC")),
"signer1": Account.from_mnemonic(os.getenv("SIGNER1_MNEMONIC")),
"signer2": Account.from_mnemonic(os.getenv("SIGNER2_MNEMONIC")),
}
KEYS = {name: account.key for name, account in ACCOUNTS.items()}
ADDRS = {name: account.address for name, account in ACCOUNTS.items()}
def wait_for_port(port, host="127.0.0.1", timeout=40.0):
start_time = time.perf_counter()
while True:
@@ -14,3 +30,21 @@ def wait_for_port(port, host="127.0.0.1", timeout=40.0):
"Waited too long for the port {} on host {} to start accepting "
"connections.".format(port, host)
) from ex
def fill_defaults(w3, tx):
return fill_nonce(w3, fill_transaction_defaults(w3, tx))
def sign_transaction(w3, tx, key=KEYS["validator"]):
"fill default fields and sign"
acct = Account.from_key(key)
tx["from"] = acct.address
tx = fill_defaults(w3, tx)
return acct.sign_transaction(tx)
def send_transaction(w3, tx, key=KEYS["validator"]):
signed = sign_transaction(w3, tx, key)
txhash = w3.eth.send_raw_transaction(signed.rawTransaction)
return w3.eth.wait_for_transaction_receipt(txhash)