mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: add optimism canyon engine tests (#6107)
This commit is contained in:
@ -116,6 +116,10 @@ itertools.workspace = true
|
||||
rayon.workspace = true
|
||||
futures-util.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
jsonrpsee.workspace = true
|
||||
assert_matches = "1.5.0"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
jemallocator = { version = "0.5.0", optional = true }
|
||||
jemalloc-ctl = { version = "0.5.0", optional = true }
|
||||
|
||||
@ -278,9 +278,9 @@ impl NodeConfig {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the chain for the node
|
||||
pub fn with_chain(mut self, chain: Arc<ChainSpec>) -> Self {
|
||||
self.chain = chain;
|
||||
/// Set the [ChainSpec] for the node
|
||||
pub fn with_chain(mut self, chain: impl Into<Arc<ChainSpec>>) -> Self {
|
||||
self.chain = chain.into();
|
||||
self
|
||||
}
|
||||
|
||||
@ -296,12 +296,6 @@ impl NodeConfig {
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the [ChainSpec] for the node
|
||||
pub fn with_chain_spec(mut self, chain: Arc<ChainSpec>) -> Self {
|
||||
self.chain = chain;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the trusted setup file for the node
|
||||
pub fn with_trusted_setup_file(mut self, trusted_setup_file: impl Into<PathBuf>) -> Self {
|
||||
self.trusted_setup_file = Some(trusted_setup_file.into());
|
||||
@ -1371,7 +1365,6 @@ impl NodeHandle {
|
||||
/// Waits for the node to exit, if it was configured to exit.
|
||||
pub async fn wait_for_node_exit(self) -> eyre::Result<()> {
|
||||
self.consensus_engine_rx.await??;
|
||||
info!(target: "reth::cli", "Consensus engine has exited.");
|
||||
|
||||
if self.terminate {
|
||||
Ok(())
|
||||
@ -1459,4 +1452,276 @@ mod tests {
|
||||
handles.push(handle);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[tokio::test]
|
||||
async fn optimism_pre_canyon_no_withdrawals_valid() {
|
||||
reth_tracing::init_test_tracing();
|
||||
use alloy_chains::Chain;
|
||||
use jsonrpsee::http_client::HttpClient;
|
||||
use reth_primitives::Genesis;
|
||||
use reth_rpc_api::EngineApiClient;
|
||||
use reth_rpc_types::engine::{
|
||||
ForkchoiceState, OptimismPayloadAttributes, PayloadAttributes,
|
||||
};
|
||||
|
||||
// this launches a test node with http
|
||||
let rpc_args = RpcServerArgs::default().with_http();
|
||||
|
||||
// create optimism genesis with canyon at block 2
|
||||
let spec = ChainSpec::builder()
|
||||
.chain(Chain::optimism_mainnet())
|
||||
.genesis(Genesis::default())
|
||||
.regolith_activated()
|
||||
.build();
|
||||
|
||||
let genesis_hash = spec.genesis_hash();
|
||||
|
||||
// create node config
|
||||
let node_config = NodeConfig::test().with_rpc(rpc_args).with_instance(7).with_chain(spec);
|
||||
|
||||
let (handle, _manager) = spawn_node(node_config).await.unwrap();
|
||||
|
||||
// call a function on the node
|
||||
let client = handle.rpc_server_handles().auth.http_client();
|
||||
let block_number = client.block_number().await.unwrap();
|
||||
|
||||
// it should be zero, since this is an ephemeral test node
|
||||
assert_eq!(block_number, U256::ZERO);
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let forkchoice_state = ForkchoiceState {
|
||||
head_block_hash: genesis_hash,
|
||||
safe_block_hash: genesis_hash,
|
||||
finalized_block_hash: genesis_hash,
|
||||
};
|
||||
|
||||
let payload_attributes = OptimismPayloadAttributes {
|
||||
payload_attributes: PayloadAttributes {
|
||||
timestamp: 1,
|
||||
prev_randao: Default::default(),
|
||||
suggested_fee_recipient: Default::default(),
|
||||
// canyon is _not_ in the chain spec, so this should cause the engine call to fail
|
||||
withdrawals: None,
|
||||
parent_beacon_block_root: None,
|
||||
},
|
||||
no_tx_pool: None,
|
||||
gas_limit: Some(1),
|
||||
transactions: None,
|
||||
};
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let res = <HttpClient as EngineApiClient<OptimismEngineTypes>>::fork_choice_updated_v2(
|
||||
&client,
|
||||
forkchoice_state,
|
||||
Some(payload_attributes),
|
||||
)
|
||||
.await;
|
||||
res.expect("pre-canyon engine call without withdrawals should succeed");
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[tokio::test]
|
||||
async fn optimism_pre_canyon_withdrawals_invalid() {
|
||||
reth_tracing::init_test_tracing();
|
||||
use alloy_chains::Chain;
|
||||
use assert_matches::assert_matches;
|
||||
use jsonrpsee::{core::Error, http_client::HttpClient, types::error::INVALID_PARAMS_CODE};
|
||||
use reth_primitives::Genesis;
|
||||
use reth_rpc_api::EngineApiClient;
|
||||
use reth_rpc_types::engine::{
|
||||
ForkchoiceState, OptimismPayloadAttributes, PayloadAttributes,
|
||||
};
|
||||
|
||||
// this launches a test node with http
|
||||
let rpc_args = RpcServerArgs::default().with_http();
|
||||
|
||||
// create optimism genesis with canyon at block 2
|
||||
let spec = ChainSpec::builder()
|
||||
.chain(Chain::optimism_mainnet())
|
||||
.genesis(Genesis::default())
|
||||
.regolith_activated()
|
||||
.build();
|
||||
|
||||
let genesis_hash = spec.genesis_hash();
|
||||
|
||||
// create node config
|
||||
let node_config = NodeConfig::test().with_rpc(rpc_args).with_instance(8).with_chain(spec);
|
||||
|
||||
let (handle, _manager) = spawn_node(node_config).await.unwrap();
|
||||
|
||||
// call a function on the node
|
||||
let client = handle.rpc_server_handles().auth.http_client();
|
||||
let block_number = client.block_number().await.unwrap();
|
||||
|
||||
// it should be zero, since this is an ephemeral test node
|
||||
assert_eq!(block_number, U256::ZERO);
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let forkchoice_state = ForkchoiceState {
|
||||
head_block_hash: genesis_hash,
|
||||
safe_block_hash: genesis_hash,
|
||||
finalized_block_hash: genesis_hash,
|
||||
};
|
||||
|
||||
let payload_attributes = OptimismPayloadAttributes {
|
||||
payload_attributes: PayloadAttributes {
|
||||
timestamp: 1,
|
||||
prev_randao: Default::default(),
|
||||
suggested_fee_recipient: Default::default(),
|
||||
// canyon is _not_ in the chain spec, so this should cause the engine call to fail
|
||||
withdrawals: Some(vec![]),
|
||||
parent_beacon_block_root: None,
|
||||
},
|
||||
no_tx_pool: None,
|
||||
gas_limit: Some(1),
|
||||
transactions: None,
|
||||
};
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let res = <HttpClient as EngineApiClient<OptimismEngineTypes>>::fork_choice_updated_v2(
|
||||
&client,
|
||||
forkchoice_state,
|
||||
Some(payload_attributes),
|
||||
)
|
||||
.await;
|
||||
let err = res.expect_err("pre-canyon engine call with withdrawals should fail");
|
||||
assert_matches!(err, Error::Call(ref object) if object.code() == INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[tokio::test]
|
||||
async fn optimism_post_canyon_no_withdrawals_invalid() {
|
||||
reth_tracing::init_test_tracing();
|
||||
use alloy_chains::Chain;
|
||||
use assert_matches::assert_matches;
|
||||
use jsonrpsee::{core::Error, http_client::HttpClient, types::error::INVALID_PARAMS_CODE};
|
||||
use reth_primitives::Genesis;
|
||||
use reth_rpc_api::EngineApiClient;
|
||||
use reth_rpc_types::engine::{
|
||||
ForkchoiceState, OptimismPayloadAttributes, PayloadAttributes,
|
||||
};
|
||||
|
||||
// this launches a test node with http
|
||||
let rpc_args = RpcServerArgs::default().with_http();
|
||||
|
||||
// create optimism genesis with canyon at block 2
|
||||
let spec = ChainSpec::builder()
|
||||
.chain(Chain::optimism_mainnet())
|
||||
.genesis(Genesis::default())
|
||||
.canyon_activated()
|
||||
.build();
|
||||
|
||||
let genesis_hash = spec.genesis_hash();
|
||||
|
||||
// create node config
|
||||
let node_config = NodeConfig::test().with_rpc(rpc_args).with_instance(9).with_chain(spec);
|
||||
|
||||
let (handle, _manager) = spawn_node(node_config).await.unwrap();
|
||||
|
||||
// call a function on the node
|
||||
let client = handle.rpc_server_handles().auth.http_client();
|
||||
let block_number = client.block_number().await.unwrap();
|
||||
|
||||
// it should be zero, since this is an ephemeral test node
|
||||
assert_eq!(block_number, U256::ZERO);
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let forkchoice_state = ForkchoiceState {
|
||||
head_block_hash: genesis_hash,
|
||||
safe_block_hash: genesis_hash,
|
||||
finalized_block_hash: genesis_hash,
|
||||
};
|
||||
|
||||
let payload_attributes = OptimismPayloadAttributes {
|
||||
payload_attributes: PayloadAttributes {
|
||||
timestamp: 1,
|
||||
prev_randao: Default::default(),
|
||||
suggested_fee_recipient: Default::default(),
|
||||
// canyon is _not_ in the chain spec, so this should cause the engine call to fail
|
||||
withdrawals: None,
|
||||
parent_beacon_block_root: None,
|
||||
},
|
||||
no_tx_pool: None,
|
||||
gas_limit: Some(1),
|
||||
transactions: None,
|
||||
};
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let res = <HttpClient as EngineApiClient<OptimismEngineTypes>>::fork_choice_updated_v2(
|
||||
&client,
|
||||
forkchoice_state,
|
||||
Some(payload_attributes),
|
||||
)
|
||||
.await;
|
||||
let err = res.expect_err("post-canyon engine call with no withdrawals should fail");
|
||||
assert_matches!(err, Error::Call(ref object) if object.code() == INVALID_PARAMS_CODE);
|
||||
}
|
||||
|
||||
#[cfg(feature = "optimism")]
|
||||
#[tokio::test]
|
||||
async fn optimism_post_canyon_withdrawals_valid() {
|
||||
reth_tracing::init_test_tracing();
|
||||
use alloy_chains::Chain;
|
||||
use jsonrpsee::http_client::HttpClient;
|
||||
use reth_primitives::Genesis;
|
||||
use reth_rpc_api::EngineApiClient;
|
||||
use reth_rpc_types::engine::{
|
||||
ForkchoiceState, OptimismPayloadAttributes, PayloadAttributes,
|
||||
};
|
||||
|
||||
// this launches a test node with http
|
||||
let rpc_args = RpcServerArgs::default().with_http();
|
||||
|
||||
// create optimism genesis with canyon at block 2
|
||||
let spec = ChainSpec::builder()
|
||||
.chain(Chain::optimism_mainnet())
|
||||
.genesis(Genesis::default())
|
||||
.canyon_activated()
|
||||
.build();
|
||||
|
||||
let genesis_hash = spec.genesis_hash();
|
||||
|
||||
// create node config
|
||||
let node_config = NodeConfig::test().with_rpc(rpc_args).with_instance(10).with_chain(spec);
|
||||
|
||||
let (handle, _manager) = spawn_node(node_config).await.unwrap();
|
||||
|
||||
// call a function on the node
|
||||
let client = handle.rpc_server_handles().auth.http_client();
|
||||
let block_number = client.block_number().await.unwrap();
|
||||
|
||||
// it should be zero, since this is an ephemeral test node
|
||||
assert_eq!(block_number, U256::ZERO);
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let forkchoice_state = ForkchoiceState {
|
||||
head_block_hash: genesis_hash,
|
||||
safe_block_hash: genesis_hash,
|
||||
finalized_block_hash: genesis_hash,
|
||||
};
|
||||
|
||||
let payload_attributes = OptimismPayloadAttributes {
|
||||
payload_attributes: PayloadAttributes {
|
||||
timestamp: 1,
|
||||
prev_randao: Default::default(),
|
||||
suggested_fee_recipient: Default::default(),
|
||||
// canyon is _not_ in the chain spec, so this should cause the engine call to fail
|
||||
withdrawals: Some(vec![]),
|
||||
parent_beacon_block_root: None,
|
||||
},
|
||||
no_tx_pool: None,
|
||||
gas_limit: Some(1),
|
||||
transactions: None,
|
||||
};
|
||||
|
||||
// call the engine_forkchoiceUpdated function with payload attributes
|
||||
let res = <HttpClient as EngineApiClient<OptimismEngineTypes>>::fork_choice_updated_v2(
|
||||
&client,
|
||||
forkchoice_state,
|
||||
Some(payload_attributes),
|
||||
)
|
||||
.await;
|
||||
res.expect("post-canyon engine call with withdrawals should succeed");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user