Skip to content

Commit

Permalink
feat(ethexe): add more accurate gas estimation for commitments
Browse files Browse the repository at this point in the history
  • Loading branch information
StackOverflowExcept1on committed Jan 30, 2025
1 parent caf74e7 commit 68162b2
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 10 deletions.
3 changes: 3 additions & 0 deletions ethexe/contracts/src/IRouter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ import {Gear} from "./libraries/Gear.sol";
interface IRouter {
/// @custom:storage-location erc7201:router.storage.Router.
struct Storage {
/// @notice Reserved storage slot.
/// @dev This slot is reserved for gas estimation purposes. Must be zero.
uint256 reserved;
/// @notice Genesis block information for this router.
/// @dev This identifies the co-processor instance. To allow interactions with the router, after initialization, someone must call `lookupGenesisHash()`.
Gear.GenesisBlockInfo genesisBlock;
Expand Down
10 changes: 9 additions & 1 deletion ethexe/contracts/src/Router.sol
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,15 @@ contract Router is IRouter, OwnableUpgradeable, ReentrancyGuardTransient {
"invalid previous committed block hash"
);

require(Gear.blockIsPredecessor(_blockCommitment.predecessorBlock), "allowed predecessor block wasn't found");
/*
* @dev `router.reserved` is always `0` but can be overridden in an RPC request
* to estimate gas excluding `Gear.blockIsPredecessor()`.
*/
if (router.reserved == 0) {
require(
Gear.blockIsPredecessor(_blockCommitment.predecessorBlock), "allowed predecessor block wasn't found"
);
}

/*
* @dev SECURITY: this settlement should be performed before any other calls to avoid reentrancy.
Expand Down
2 changes: 1 addition & 1 deletion ethexe/ethereum/Mirror.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/MirrorProxy.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/Router.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion ethexe/ethereum/WrappedVara.json

Large diffs are not rendered by default.

62 changes: 57 additions & 5 deletions ethexe/ethereum/src/router/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ use crate::{
};
use alloy::{
consensus::{SidecarBuilder, SimpleCoder},
primitives::{Address, Bytes, U256},
primitives::{fixed_bytes, Address, Bytes, U256},
providers::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider},
rpc::types::Filter,
rpc::types::{eth::state::AccountOverride, Filter},
transports::BoxTransport,
};
use anyhow::{anyhow, Result};
Expand All @@ -38,7 +38,7 @@ use events::signatures;
use futures::StreamExt;
use gear_core::ids::{prelude::CodeIdExt as _, ProgramId};
use gprimitives::{ActorId, CodeId, H256};
use std::sync::Arc;
use std::{collections::HashMap, sync::Arc};

pub mod events;

Expand Down Expand Up @@ -74,6 +74,11 @@ pub struct Router {
}

impl Router {
/// `Gear.blockIsPredecessor(hash)` can consume up to 30_000 gas
const GEAR_BLOCK_IS_PREDECESSOR_GAS: u64 = 30_000;
/// Huge gas limit is necessary so that the transaction is more likely to be picked up
const HUGE_GAS_LIMIT: u64 = 10_000_000;

pub(crate) fn new(
address: Address,
wvara_address: Address,
Expand Down Expand Up @@ -198,8 +203,29 @@ impl Router {
.map(|signature| Bytes::copy_from_slice(signature.as_ref()))
.collect(),
);

let mut state_diff = HashMap::default();
state_diff.insert(
// keccak256(abi.encode(uint256(keccak256(bytes("router.storage.RouterV1"))) - 1)) & ~bytes32(uint256(0xff))
fixed_bytes!("e3d827fd4fed52666d49a0df00f9cc2ac79f0f2378fc627e62463164801b6500"),
fixed_bytes!("0000000000000000000000000000000000000000000000000000000000000001"),
);

let mut state = HashMap::default();
state.insert(
*self.instance.address(),
AccountOverride {
state_diff: Some(state_diff),
..Default::default()
},
);

let estimate_gas_builder = builder.clone().state(state);
let gas_limit = Self::HUGE_GAS_LIMIT
.max(estimate_gas_builder.estimate_gas().await? + Self::GEAR_BLOCK_IS_PREDECESSOR_GAS);

let receipt = builder
.gas(10_000_000)
.gas(gas_limit)
.send()
.await?
.try_get_receipt()
Expand All @@ -220,7 +246,33 @@ impl Router {
.map(|signature| Bytes::copy_from_slice(signature.as_ref()))
.collect(),
);
let receipt = builder.send().await?.try_get_receipt().await?;

let mut state_diff = HashMap::default();
state_diff.insert(
// keccak256(abi.encode(uint256(keccak256(bytes("router.storage.RouterV1"))) - 1)) & ~bytes32(uint256(0xff))
fixed_bytes!("e3d827fd4fed52666d49a0df00f9cc2ac79f0f2378fc627e62463164801b6500"),
fixed_bytes!("0000000000000000000000000000000000000000000000000000000000000001"),
);

let mut state = HashMap::default();
state.insert(
*self.instance.address(),
AccountOverride {
state_diff: Some(state_diff),
..Default::default()
},
);

let estimate_gas_builder = builder.clone().state(state);
let gas_limit = Self::HUGE_GAS_LIMIT
.max(estimate_gas_builder.estimate_gas().await? + Self::GEAR_BLOCK_IS_PREDECESSOR_GAS);

let receipt = builder
.gas(gas_limit)
.send()
.await?
.try_get_receipt()
.await?;
Ok(H256(receipt.transaction_hash.0))
}
}
Expand Down

0 comments on commit 68162b2

Please sign in to comment.