Skip to content

Commit

Permalink
feat: add hardhat config RPC methods (#4596)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wodann authored Nov 18, 2023
1 parent e8fc578 commit 4c1e5fa
Show file tree
Hide file tree
Showing 14 changed files with 213 additions and 42 deletions.
8 changes: 5 additions & 3 deletions crates/edr_eth/src/remote/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -823,8 +823,10 @@ impl RpcClient {
}

/// Calls `net_version`.
pub async fn network_id(&self) -> Result<U256, RpcClientError> {
self.call(MethodInvocation::NetVersion()).await
pub async fn network_id(&self) -> Result<u64, RpcClientError> {
self.call::<U64>(MethodInvocation::NetVersion())
.await
.map(|network_id| network_id.as_limbs()[0])
}
}

Expand Down Expand Up @@ -1935,7 +1937,7 @@ mod tests {
.await
.expect("should have succeeded");

assert_eq!(version, U256::from(1));
assert_eq!(version, 1);
}

#[tokio::test]
Expand Down
3 changes: 3 additions & 0 deletions crates/edr_evm/src/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ pub trait Blockchain {
/// Retrieves the last block number in the blockchain.
fn last_block_number(&self) -> u64;

/// Retrieves the network ID of the blockchain.
fn network_id(&self) -> u64;

/// Retrieves the receipt of the transaction with the provided hash, if it
/// exists.
fn receipt_by_transaction_hash(
Expand Down
8 changes: 6 additions & 2 deletions crates/edr_evm/src/blockchain/forked.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub struct ForkedBlockchain {
fork_state: ForkState,
fork_block_number: u64,
chain_id: u64,
_network_id: U256,
network_id: u64,
spec_id: SpecId,
hardfork_activations: Option<HardforkActivations>,
}
Expand Down Expand Up @@ -157,7 +157,7 @@ impl ForkedBlockchain {
fork_state,
fork_block_number,
chain_id,
_network_id: network_id,
network_id,
spec_id,
hardfork_activations,
})
Expand Down Expand Up @@ -284,6 +284,10 @@ impl Blockchain for ForkedBlockchain {
self.local_storage.last_block_number()
}

fn network_id(&self) -> u64 {
self.network_id
}

#[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
fn receipt_by_transaction_hash(
&self,
Expand Down
4 changes: 4 additions & 0 deletions crates/edr_evm/src/blockchain/local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ impl Blockchain for LocalBlockchain {
self.storage.last_block_number()
}

fn network_id(&self) -> u64 {
self.chain_id
}

#[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
fn receipt_by_transaction_hash(
&self,
Expand Down
79 changes: 64 additions & 15 deletions crates/edr_provider/src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,17 @@ use edr_evm::{
KECCAK_EMPTY,
};
use indexmap::IndexMap;
use rpc_hardhat::ForkMetadata;
use tokio::runtime;

use self::account::{create_accounts, InitialAccounts};
use crate::{filter::Filter, logger::Logger, ProviderConfig, ProviderError};

#[derive(Debug, thiserror::Error)]
pub enum CreationError {
/// A blockchain error
#[error(transparent)]
Blockchain(BlockchainError),
/// An error that occurred while constructing a forked blockchain.
#[error(transparent)]
ForkedBlockchainCreation(#[from] ForkedCreationError),
Expand All @@ -56,6 +60,9 @@ pub struct ProviderData {
min_gas_price: U256,
prevrandao_generator: RandomHashGenerator,
block_time_offset_seconds: u64,
fork_metadata: Option<ForkMetadata>,
instance_id: B256,
next_block_base_fee_per_gas: Option<U256>,
next_block_timestamp: Option<u64>,
allow_blocks_with_same_timestamp: bool,
allow_unlimited_contract_size: bool,
Expand All @@ -77,8 +84,11 @@ impl ProviderData {
genesis_accounts,
} = create_accounts(config);

let BlockchainAndState { state, blockchain } =
create_blockchain_and_state(runtime, config, genesis_accounts).await?;
let BlockchainAndState {
blockchain,
state,
fork_metadata,
} = create_blockchain_and_state(runtime, config, genesis_accounts).await?;

let prevrandao_generator = RandomHashGenerator::with_seed("randomMixHashSeed");

Expand All @@ -93,6 +103,9 @@ impl ProviderData {
min_gas_price: U256::from(1),
prevrandao_generator,
block_time_offset_seconds: block_time_offset_seconds(config)?,
fork_metadata,
instance_id: B256::random(),
next_block_base_fee_per_gas: None,
next_block_timestamp: None,
allow_blocks_with_same_timestamp: config.allow_blocks_with_same_timestamp,
allow_unlimited_contract_size: config.allow_unlimited_contract_size,
Expand Down Expand Up @@ -120,7 +133,20 @@ impl ProviderData {
})?
}

pub fn block_number(&self) -> u64 {
/// Returns the metadata of the forked blockchain, if it exists.
pub fn fork_metadata(&self) -> Option<&ForkMetadata> {
self.fork_metadata.as_ref()
}

/// Returns the last block in the blockchain.
pub fn last_block(
&self,
) -> Result<Arc<dyn SyncBlock<Error = BlockchainError>>, BlockchainError> {
self.blockchain.last_block()
}

/// Returns the number of the last block in the blockchain.
pub fn last_block_number(&self) -> u64 {
self.blockchain.last_block_number()
}

Expand Down Expand Up @@ -260,6 +286,10 @@ impl ProviderData {
self.block_time_offset_seconds
}

pub fn instance_id(&self) -> &B256 {
&self.instance_id
}

pub fn logger(&self) -> &Logger {
&self.logger
}
Expand All @@ -281,6 +311,9 @@ impl ProviderData {
self.block_time_offset_seconds = new_offset;
}

// Reset the next block base fee per gas upon successful execution
self.next_block_base_fee_per_gas.take();

// Reset next block time stamp
self.next_block_timestamp.take();

Expand Down Expand Up @@ -402,6 +435,16 @@ impl ProviderData {
Ok(())
}

/// Sets the coinbase.
pub fn set_coinbase(&mut self, coinbase: Address) {
self.beneficiary = coinbase;
}

/// Sets the next block's base fee per gas.
pub fn set_next_block_base_fee_per_gas(&mut self, base_fee_per_gas: U256) {
self.next_block_base_fee_per_gas = Some(base_fee_per_gas);
}

/// Set the next block timestamp.
pub fn set_next_block_timestamp(&mut self, timestamp: u64) -> Result<u64, ProviderError> {
use std::cmp::Ordering;
Expand All @@ -424,6 +467,11 @@ impl ProviderData {
}
}

/// Sets the next block's prevrandao.
pub fn set_next_prev_randao(&mut self, prev_randao: B256) {
self.prevrandao_generator.set_next(prev_randao);
}

pub fn set_nonce(&mut self, address: Address, nonce: u64) -> Result<(), ProviderError> {
self.state.modify_account(
address,
Expand Down Expand Up @@ -562,12 +610,6 @@ impl ProviderData {
timestamp: u64,
prevrandao: Option<B256>,
) -> Result<MineBlockResultAndState<StateError>, ProviderError> {
// TODO: when we support hardhat_setNextBlockBaseFeePerGas, incorporate
// the last-passed value here. (but don't .take() it yet, because we only
// want to clear it if the block mining is successful.
// https://github.com/NomicFoundation/edr/issues/145
let base_fee = None;

// TODO: https://github.com/NomicFoundation/edr/issues/156
let reward = U256::ZERO;

Expand All @@ -584,15 +626,11 @@ impl ProviderData {
// TODO: make this configurable (https://github.com/NomicFoundation/edr/issues/111)
MineOrdering::Fifo,
reward,
base_fee,
self.next_block_base_fee_per_gas,
prevrandao,
None,
)?;

// TODO: when we support hardhat_setNextBlockBaseFeePerGas, reset the user
// provided next block base fee per gas to `None`
// https://github.com/NomicFoundation/edr/issues/145

Ok(result)
}

Expand Down Expand Up @@ -758,6 +796,7 @@ fn block_time_offset_seconds(config: &ProviderConfig) -> Result<u64, CreationErr

struct BlockchainAndState {
blockchain: Box<dyn SyncBlockchain<BlockchainError, StateError>>,
fork_metadata: Option<ForkMetadata>,
state: Box<dyn SyncState<StateError>>,
}

Expand Down Expand Up @@ -793,6 +832,15 @@ async fn create_blockchain_and_state(

Ok(BlockchainAndState {
state: Box::new(state),
fork_metadata: Some(ForkMetadata {
chain_id: blockchain.chain_id(),
fork_block_number,
fork_block_hash: *blockchain
.block_by_number(fork_block_number)
.map_err(CreationError::Blockchain)?
.expect("Fork block must exist")
.hash(),
}),
blockchain: Box::new(blockchain),
})
} else {
Expand All @@ -818,6 +866,7 @@ async fn create_blockchain_and_state(

Ok(BlockchainAndState {
state,
fork_metadata: None,
blockchain: Box::new(blockchain),
})
}
Expand Down Expand Up @@ -1013,7 +1062,7 @@ mod tests {

// Mine a block to make sure we're not getting the genesis block
fixture.provider_data.mine_and_commit_block(None)?;
let last_block_number = fixture.provider_data.block_number();
let last_block_number = fixture.provider_data.last_block_number();
// Sanity check
assert!(last_block_number > 0);

Expand Down
5 changes: 4 additions & 1 deletion crates/edr_provider/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::time::SystemTimeError;

use edr_eth::{
remote::{filter::SubscriptionType, jsonrpc, BlockSpec},
Address, U256,
Address, SpecId, U256,
};
use edr_evm::{
blockchain::BlockchainError, state::StateError, MineBlockError, MinerTransactionError,
Expand Down Expand Up @@ -72,4 +72,7 @@ pub enum ProviderError {
/// The address is not owned by this node.
#[error("{address} is not owned by this node")]
UnknownAddress { address: Address },
/// Minimum required hardfork not met
#[error("Feature is only available in post-{minimum:?} hardforks, the current hardfork is {actual:?}")]
UnmetHardfork { actual: SpecId, minimum: SpecId },
}
17 changes: 12 additions & 5 deletions crates/edr_provider/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@ fn handle_hardhat_request(
rpc_hardhat::Request::IntervalMine() => {
hardhat::handle_interval_mine_request(data).and_then(to_json)
}
rpc_hardhat::Request::Metadata() => Err(ProviderError::Unimplemented("".to_string())),
rpc_hardhat::Request::Metadata() => {
hardhat::handle_metadata_request(data).and_then(to_json)
}
rpc_hardhat::Request::Mine(_, _) => Err(ProviderError::Unimplemented("".to_string())),
rpc_hardhat::Request::Reset(_) => Err(ProviderError::Unimplemented("".to_string())),
rpc_hardhat::Request::SetBalance(address, balance) => {
Expand All @@ -246,20 +248,25 @@ fn handle_hardhat_request(
rpc_hardhat::Request::SetCode(address, code) => {
hardhat::handle_set_code(data, address, code).and_then(to_json)
}
rpc_hardhat::Request::SetCoinbase(_) => Err(ProviderError::Unimplemented("".to_string())),
rpc_hardhat::Request::SetCoinbase(coinbase) => {
hardhat::handle_set_coinbase_request(data, coinbase).and_then(to_json)
}
rpc_hardhat::Request::SetLoggingEnabled(_) => {
Err(ProviderError::Unimplemented("".to_string()))
}
rpc_hardhat::Request::SetMinGasPrice(_) => {
Err(ProviderError::Unimplemented("".to_string()))
}
rpc_hardhat::Request::SetNextBlockBaseFeePerGas(_) => {
Err(ProviderError::Unimplemented("".to_string()))
rpc_hardhat::Request::SetNextBlockBaseFeePerGas(base_fee_per_gas) => {
hardhat::handle_set_next_block_base_fee_per_gas_request(data, base_fee_per_gas)
.and_then(to_json)
}
rpc_hardhat::Request::SetNonce(address, nonce) => {
hardhat::handle_set_nonce(data, address, nonce).and_then(to_json)
}
rpc_hardhat::Request::SetPrevRandao(_) => Err(ProviderError::Unimplemented("".to_string())),
rpc_hardhat::Request::SetPrevRandao(prev_randao) => {
hardhat::handle_set_prev_randao_request(data, prev_randao).and_then(to_json)
}
rpc_hardhat::Request::SetStorageAt(address, index, value) => {
hardhat::handle_set_storage_at(data, address, index, value).and_then(to_json)
}
Expand Down
2 changes: 1 addition & 1 deletion crates/edr_provider/src/requests/eth/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use edr_eth::{remote::BlockSpec, Address, U256, U64};
use crate::{data::ProviderData, ProviderError};

pub fn handle_block_number_request(data: &ProviderData) -> Result<U64, ProviderError> {
Ok(U64::from(data.block_number()))
Ok(U64::from(data.last_block_number()))
}

pub fn handle_chain_id_request(data: &ProviderData) -> Result<U64, ProviderError> {
Expand Down
10 changes: 7 additions & 3 deletions crates/edr_provider/src/requests/eth/web3.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ use sha3::{Digest, Keccak256};

use crate::ProviderError;

pub fn handle_web3_client_version_request() -> Result<String, ProviderError> {
Ok(format!(
pub fn client_version() -> String {
format!(
"edr/{}/revm/{}",
env!("CARGO_PKG_VERSION"),
env!("REVM_VERSION"),
))
)
}

pub fn handle_web3_client_version_request() -> Result<String, ProviderError> {
Ok(client_version())
}

pub fn handle_web3_sha3_request(message: ZeroXPrefixedBytes) -> Result<B256, ProviderError> {
Expand Down
3 changes: 2 additions & 1 deletion crates/edr_provider/src/requests/hardhat.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod accounts;
mod config;
mod miner;
mod state;

pub use self::{accounts::*, miner::*, state::*};
pub use self::{accounts::*, config::*, miner::*, state::*};
Loading

0 comments on commit 4c1e5fa

Please sign in to comment.