feat: add optimism canyon engine tests (#6107)

This commit is contained in:
Dan Cline
2024-01-17 15:54:00 -05:00
committed by GitHub
parent 43167eabda
commit aeee4486eb
4 changed files with 289 additions and 11 deletions

View File

@ -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 }

View File

@ -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");
}
}