Skip to content

Commit

Permalink
RPC: Fix state override support in estimate gas (DeFiCh#2806)
Browse files Browse the repository at this point in the history
* Add state override support in estimate gas RPC

---------

Co-authored-by: Jouzo <[email protected]>
  • Loading branch information
sieniven and Jouzo authored Jan 29, 2024
1 parent 6b97eb8 commit 5864373
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 26 deletions.
16 changes: 11 additions & 5 deletions lib/ain-grpc/src/rpc/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -811,11 +811,17 @@ impl MetachainRPCServer for MetachainRPCModule {

// Recap the highest gas allowance with account's balance
if call.from.is_some() {
let balance = self
.handler
.core
.get_balance(caller, block.header.state_root)
.map_err(to_custom_err)?;
let balance = if let Some(balance) = overlay
.as_ref()
.and_then(|o| o.get_account(&caller).map(|acc| acc.balance))
{
balance
} else {
self.handler
.core
.get_balance(caller, block.header.state_root)
.map_err(to_custom_err)?
};
let mut available = balance;
if let Some(value) = call.value {
if balance < value {
Expand Down
144 changes: 123 additions & 21 deletions test/functional/feature_evm_gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,115 +104,144 @@ def setup(self):
self.nodes[0].generate(1)
self.start_height = self.nodes[0].getblockcount()

def generate_test_txs(self, address):
dict_txs = dict()
# Eth call for balance transfer with gas specified
self.valid_balance_transfer_tx_with_gas = {
"from": self.ethAddress,
valid_balance_transfer_tx_with_gas = {
"from": address,
"to": self.toAddress,
"value": "0xDE0B6B3A7640000", # 1 DFI
"gas": "0x7a120",
"gasPrice": "0x37E11D600", # 15_000_000_000
}
dict_txs["valid_balance_transfer_tx_with_gas"] = (
valid_balance_transfer_tx_with_gas
)

# Eth call for balance transfer with exact gas specified
self.valid_balance_transfer_tx_with_exact_gas = {
"from": self.ethAddress,
valid_balance_transfer_tx_with_exact_gas = {
"from": address,
"to": self.toAddress,
"value": "0xDE0B6B3A7640000", # 1 DFI
"gas": "0x5208",
"gasPrice": "0x37E11D600", # 15_000_000_000
}
dict_txs["valid_balance_transfer_tx_with_exact_gas"] = (
valid_balance_transfer_tx_with_exact_gas
)

# Valid eth call for balance transfer without gas specified
self.valid_balance_transfer_tx_without_gas = {
"from": self.ethAddress,
valid_balance_transfer_tx_without_gas = {
"from": address,
"to": self.toAddress,
"value": "0xDE0B6B3A7640000", # 1 DFI
"gasPrice": "0x37E11D600", # 15_000_000_000
}
dict_txs["valid_balance_transfer_tx_without_gas"] = (
valid_balance_transfer_tx_without_gas
)

# Invalid eth call for balance transfer with both gasPrice and maxFeePerGas specified
self.invalid_balance_transfer_tx_specified_gas_1 = {
"from": self.ethAddress,
invalid_balance_transfer_tx_specified_gas_1 = {
"from": address,
"to": self.toAddress,
"value": "0xDE0B6B3A7640000", # 1 DFI
"gasPrice": "0x37E11D600", # 15_000_000_000
"maxFeePerGas": "0x37E11D600", # 15_000_000_000
}
dict_txs["invalid_balance_transfer_tx_specified_gas_1"] = (
invalid_balance_transfer_tx_specified_gas_1
)

# Invalid eth call for balance transfer with both gasPrice and priorityFeePerGas specified
self.invalid_balance_transfer_tx_specified_gas_2 = {
"from": self.ethAddress,
invalid_balance_transfer_tx_specified_gas_2 = {
"from": address,
"to": self.toAddress,
"value": "0xDE0B6B3A7640000", # 1 DFI
"gasPrice": "0x37E11D600", # 15_000_000_000
"maxPriorityFeePerGas": "0x37E11D600", # 15_000_000_000
}
dict_txs["invalid_balance_transfer_tx_specified_gas_2"] = (
invalid_balance_transfer_tx_specified_gas_2
)

# Invalid eth call for balance transfer with both data and input fields specified
self.invalid_balance_transfer_tx_specified_data_and_input = {
"from": self.ethAddress,
invalid_balance_transfer_tx_specified_data_and_input = {
"from": address,
"to": self.toAddress,
"value": "0xDE0B6B3A7640000", # 1 DFI
"gasPrice": "0x37E11D600", # 15_000_000_000
"data": "0xffffffffffffffff",
"input": "0xffffffffffffffff",
}
dict_txs["invalid_balance_transfer_tx_specified_data_and_input"] = (
invalid_balance_transfer_tx_specified_data_and_input
)

# Invalid eth call from insufficient balance for balance transfer
self.invalid_balance_transfer_tx_insufficient_funds = {
"from": self.ethAddress,
invalid_balance_transfer_tx_insufficient_funds = {
"from": address,
"to": self.toAddress,
"value": "0x152D02C7E14AF6800000", # 100_000 DFI
"gasPrice": "0x37E11D600", # 15_000_000_000
}
dict_txs["invalid_balance_transfer_tx_insufficient_funds"] = (
invalid_balance_transfer_tx_insufficient_funds
)
return dict_txs

def test_estimate_gas_balance_transfer(self):
self.rollback_to(self.start_height)
dict_txs = self.generate_test_txs(self.ethAddress)

# Test valid estimateGas call for transfer tx with gas specified
gas = self.nodes[0].eth_estimateGas(self.valid_balance_transfer_tx_with_gas)
gas = self.nodes[0].eth_estimateGas(
dict_txs["valid_balance_transfer_tx_with_gas"]
)
assert_equal(gas, "0x5208")

# Test valid estimateGas call for transfer tx with exact gas specified
gas = self.nodes[0].eth_estimateGas(
self.valid_balance_transfer_tx_with_exact_gas
dict_txs["valid_balance_transfer_tx_with_exact_gas"],
)
assert_equal(gas, "0x5208")

# Test valid estimateGas call for transfer tx without gas specified
gas = self.nodes[0].eth_estimateGas(self.valid_balance_transfer_tx_without_gas)
gas = self.nodes[0].eth_estimateGas(
dict_txs["valid_balance_transfer_tx_without_gas"]
)
assert_equal(gas, "0x5208")

# Test invalid estimateGas call, both gasPrice and maxFeePerGas specified
assert_raises_rpc_error(
-32001,
"both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified",
self.nodes[0].eth_estimateGas,
self.invalid_balance_transfer_tx_specified_gas_1,
dict_txs["invalid_balance_transfer_tx_specified_gas_1"],
)

# Test invalid estimateGas call, both gasPrice and maxPriorityFeePerGas specified
assert_raises_rpc_error(
-32001,
"Custom error: both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified",
self.nodes[0].eth_estimateGas,
self.invalid_balance_transfer_tx_specified_gas_2,
dict_txs["invalid_balance_transfer_tx_specified_gas_2"],
)

# Test invalid estimateGas call, both data and input field specified
assert_raises_rpc_error(
-32001,
"Custom error: data and input fields are mutually exclusive",
self.nodes[0].eth_estimateGas,
self.invalid_balance_transfer_tx_specified_data_and_input,
dict_txs["invalid_balance_transfer_tx_specified_data_and_input"],
)

# Test invalid estimateGas call, insufficient funds
assert_raises_rpc_error(
-32001,
"Custom error: insufficient funds for transfer",
self.nodes[0].eth_estimateGas,
self.invalid_balance_transfer_tx_insufficient_funds,
dict_txs["invalid_balance_transfer_tx_insufficient_funds"],
)

def test_estimate_gas_contract(self):
Expand Down Expand Up @@ -355,6 +384,77 @@ def test_estimate_gas_revert(self):
contract.functions.value_check(0).estimate_gas,
)

def test_estimate_gas_state_override(self):
self.rollback_to(self.start_height)

emptyAddress = self.nodes[0].getnewaddress("", "erc55")
self.nodes[0].generate(1)
balance = self.nodes[0].eth_getBalance(emptyAddress, "latest")
assert_equal(int(balance[2:], 16), 0)

dict_txs = self.generate_test_txs(emptyAddress)
state_override = {emptyAddress: {"balance": "0x8AC7230489E80000"}} # 10 DFI

# Test valid estimateGas call for transfer tx with gas specified and state override
gas = self.nodes[0].eth_estimateGas(
dict_txs["valid_balance_transfer_tx_with_gas"], "latest", state_override
)
assert_equal(gas, "0x5208")

# Test valid estimateGas call for transfer tx with exact gas specified and state override
gas = self.nodes[0].eth_estimateGas(
dict_txs["valid_balance_transfer_tx_with_exact_gas"],
"latest",
state_override,
)
assert_equal(gas, "0x5208")

# Test valid estimateGas call for transfer tx without gas specified and state override
gas = self.nodes[0].eth_estimateGas(
dict_txs["valid_balance_transfer_tx_without_gas"], "latest", state_override
)
assert_equal(gas, "0x5208")

# Test invalid estimateGas call, both gasPrice and maxFeePerGas specified and state override
assert_raises_rpc_error(
-32001,
"both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified",
self.nodes[0].eth_estimateGas,
dict_txs["invalid_balance_transfer_tx_specified_gas_1"],
"latest",
state_override,
)

# Test invalid estimateGas call, both gasPrice and maxPriorityFeePerGas specified and state override
assert_raises_rpc_error(
-32001,
"Custom error: both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified",
self.nodes[0].eth_estimateGas,
dict_txs["invalid_balance_transfer_tx_specified_gas_2"],
"latest",
state_override,
)

# Test invalid estimateGas call, both data and input field specified and state override
assert_raises_rpc_error(
-32001,
"Custom error: data and input fields are mutually exclusive",
self.nodes[0].eth_estimateGas,
dict_txs["invalid_balance_transfer_tx_specified_data_and_input"],
"latest",
state_override,
)

# Test invalid estimateGas call, insufficient funds and state override
assert_raises_rpc_error(
-32001,
"Custom error: insufficient funds for transfer",
self.nodes[0].eth_estimateGas,
dict_txs["invalid_balance_transfer_tx_insufficient_funds"],
"latest",
state_override,
)

def run_test(self):
self.setup()

Expand All @@ -366,6 +466,8 @@ def run_test(self):

self.test_estimate_gas_revert()

self.test_estimate_gas_state_override()


if __name__ == "__main__":
EVMGasTest().main()

0 comments on commit 5864373

Please sign in to comment.