Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect block gas limit in gasEstimate buffer #2353

Merged
merged 4 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/contracts/artifacts/FetchBlock.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"}],"bytecode":"0x6080604052348015600f57600080fd5b506000804311601e5760006027565b60276001436084565b9050804060008260375760006042565b60406001846084565b405b604080516020810186905290810184905260608101829052426080820181905291925060009060a0016040516020818303038152906040529050805181602001f35b8181038181111560a457634e487b7160e01b600052601160045260246000fd5b9291505056fe","deployedBytecode":"0x6080604052600080fdfea164736f6c6343000811000a","devdoc":{"methods":{}},"userdoc":{"methods":{}}}
{"abi":[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"}],"bytecode":"0x6080604052348015600f57600080fd5b506000804311601e5760006027565b6027600143608e565b9050804060008260375760006042565b6040600184608e565b405b60408051602081018690529081018490526060810182905242608082018190524560a08301819052929350919060009060c0016040516020818303038152906040529050805181602001f35b8181038181111560ae57634e487b7160e01b600052601160045260246000fd5b9291505056fe","deployedBytecode":"0x6080604052600080fdfea164736f6c6343000811000a","devdoc":{"methods":{}},"userdoc":{"methods":{}}}
3 changes: 2 additions & 1 deletion crates/contracts/solidity/FetchBlock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ contract FetchBlock {
? blockhash(blockNumber - 1)
: bytes32(0);
uint timestamp = block.timestamp;
uint gasLimit = block.gaslimit;

bytes memory result = abi.encode(blockNumber, blockHash, parentHash, timestamp);
bytes memory result = abi.encode(blockNumber, blockHash, parentHash, timestamp, gasLimit);
assembly {
return(add(32, result), mload(result))
}
Expand Down
9 changes: 4 additions & 5 deletions crates/driver/src/domain/competition/solution/settlement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ pub struct Settlement {
pub access_list: eth::AccessList,
/// The gas parameters used by the settlement.
pub gas: Gas,

/// See the [`Settlement::solutions`] method.
solutions: HashMap<solution::Id, Solution>,
}
Expand Down Expand Up @@ -135,7 +134,7 @@ impl Settlement {
)
.await?;
let price = eth.gas_price().await?;
let gas = Gas::new(gas, price);
let gas = Gas::new(gas, eth.gas_limit(), price);

// Ensure that the solver has sufficient balance for the settlement to be mined.
if eth.balance(settlement.solver).await? < gas.required_balance() {
Expand Down Expand Up @@ -374,21 +373,21 @@ pub struct Gas {
impl Gas {
/// Computes settlement gas parameters given estimates for gas and gas
/// price.
pub fn new(estimate: eth::Gas, price: eth::GasPrice) -> Self {
pub fn new(estimate: eth::Gas, limit: eth::Gas, price: eth::GasPrice) -> Self {
// Specify a different gas limit than the estimated gas when executing a
// settlement transaction. This allows the transaction to be resilient
// to small variations in actual gas usage.
// Also, some solutions can have significant gas refunds that are refunded at
// the end of execution, so we want to increase gas limit enough so
// those solutions don't revert with out of gas error.
const GAS_LIMIT_FACTOR: f64 = 2.0;
let limit =
let estimate_with_buffer =
eth::U256::from_f64_lossy(eth::U256::to_f64_lossy(estimate.into()) * GAS_LIMIT_FACTOR)
.into();

Self {
estimate,
limit,
limit: std::cmp::min(limit, estimate_with_buffer),
price,
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/driver/src/domain/eth/gas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use {
///
/// The amount of Ether that is paid in transaction fees is proportional to this
/// amount as well as the transaction's [`EffectiveGasPrice`].
#[derive(Debug, Default, Clone, Copy)]
#[derive(Debug, Default, Clone, Copy, Ord, Eq, PartialOrd, PartialEq)]
pub struct Gas(pub U256);

impl From<U256> for Gas {
Expand Down
4 changes: 4 additions & 0 deletions crates/driver/src/infra/blockchain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,10 @@ impl Ethereum {
self.gas.estimate().await
}

pub fn gas_limit(&self) -> eth::Gas {
self.current_block.borrow().gas_limit.into()
}

/// Returns the current [`eth::Ether`] balance of the specified account.
pub async fn balance(&self, address: eth::Address) -> Result<eth::Ether, Error> {
self.web3
Expand Down
17 changes: 17 additions & 0 deletions crates/driver/src/tests/cases/settle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,20 @@ async fn private_rpc_with_high_risk_solution() {
let err = test.settle().await.err();
err.kind("FailedToSubmit");
}

/// Checks that we can settle transactions that have a gas limit higher than
/// half the block size
#[tokio::test]
#[ignore]
async fn high_gas_limit() {
let test = tests::setup()
.name("high gas limit")
.pool(ab_pool())
.order(ab_order())
.solution(ab_solution().increase_gas(15_000_000))
.done()
.await;

test.solve().await.ok();
test.settle().await.ok().await;
}
2 changes: 2 additions & 0 deletions crates/driver/src/tests/setup/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,8 @@ impl Node {
.arg("0") // use 0 to let `anvil` use any open port
.arg("--balance")
.arg("1000000")
.arg("--gas-limit")
.arg("30000000")
.stdout(std::process::Stdio::piped())
.spawn()
.unwrap();
Expand Down
23 changes: 20 additions & 3 deletions crates/driver/src/tests/setup/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,9 +350,9 @@ pub struct Setup {
pub enum Calldata {
/// Set up the solver to return a solution with valid calldata.
Valid {
/// Include additional meaningless bytes appended to the calldata. This
/// is useful for lowering the solution score in a controlled
/// way.
/// Include additional meaningless non-zero bytes appended to the
/// calldata. This is useful for lowering the solution score in
/// a controlled way.
additional_bytes: usize,
},
/// Set up the solver to return a solution with bogus calldata.
Expand Down Expand Up @@ -380,6 +380,23 @@ impl Solution {
}
}

/// Increase the solution gas consumption by at least `units`.
pub fn increase_gas(self, units: usize) -> Self {
// non-zero bytes costs 16 gas
let additional_bytes = (units / 16) + 1;
Self {
calldata: match self.calldata {
Calldata::Valid {
additional_bytes: existing,
} => Calldata::Valid {
additional_bytes: existing + additional_bytes,
},
Calldata::Invalid => Calldata::Invalid,
},
..self
}
}

/// Make the solution return invalid calldata.
pub fn invalid(self) -> Self {
Self {
Expand Down
4 changes: 3 additions & 1 deletion crates/ethrpc/src/current_block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ pub mod retriever;
use {
crate::Web3,
anyhow::{anyhow, ensure, Context as _, Result},
primitive_types::H256,
primitive_types::{H256, U256},
std::{sync::Arc, time::Duration},
tokio::sync::watch,
tokio_stream::wrappers::WatchStream,
Expand Down Expand Up @@ -52,6 +52,7 @@ pub struct BlockInfo {
pub hash: H256,
pub parent_hash: H256,
pub timestamp: u64,
pub gas_limit: U256,
}

impl TryFrom<Block<H256>> for BlockInfo {
Expand All @@ -63,6 +64,7 @@ impl TryFrom<Block<H256>> for BlockInfo {
hash: value.hash.context("block missing hash")?,
parent_hash: value.parent_hash,
timestamp: value.timestamp.as_u64(),
gas_limit: value.gas_limit,
})
}
}
Expand Down
5 changes: 4 additions & 1 deletion crates/ethrpc/src/current_block/retriever.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ impl BlockRetrieving for BlockRetriever {
hash: fetch.parent_hash,
timestamp: fetch.timestamp,
parent_hash: call.hash,
gas_limit: fetch.gas_limit,
})
} else {
bail!("large differential between eth_getBlock {fetch:?} and eth_call {call:?}");
Expand All @@ -94,19 +95,21 @@ impl BlockRetrieving for BlockRetriever {
}

/// Decodes the return data from the `FetchBlock` contract.
fn decode(return_data: [u8; 128]) -> Result<BlockInfo> {
fn decode(return_data: [u8; 160]) -> Result<BlockInfo> {
let number = u64::try_from(U256::from_big_endian(&return_data[0..32]))
.ok()
.context("block number overflows u64")?;
let hash = H256::from_slice(&return_data[32..64]);
let parent_hash = H256::from_slice(&return_data[64..96]);
let timestamp = U256::from_big_endian(&return_data[96..128]).as_u64();
let gas_limit = U256::from_big_endian(&return_data[128..160]);

Ok(BlockInfo {
number,
hash,
parent_hash,
timestamp,
gas_limit,
})
}

Expand Down
Loading