-
Notifications
You must be signed in to change notification settings - Fork 3
feat(e2e tests): invalid block penalizes peer #228
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
base: main
Are you sure you want to change the base?
Changes from all commits
4f6fde6
a6c531e
a953318
319e7a9
d3d743b
320770d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,20 @@ | ||
use super::{RollupManagerEvent, RollupManagerStatus}; | ||
|
||
use reth_network_api::FullNetwork; | ||
use reth_scroll_node::ScrollNetworkPrimitives; | ||
use reth_tokio_util::EventStream; | ||
use scroll_network::ScrollNetworkHandle; | ||
use tokio::sync::oneshot; | ||
|
||
/// The commands that can be sent to the rollup manager. | ||
#[derive(Debug)] | ||
pub enum RollupManagerCommand { | ||
pub enum RollupManagerCommand<N: FullNetwork<Primitives = ScrollNetworkPrimitives>> { | ||
/// Command to build a new block. | ||
BuildBlock, | ||
/// Returns an event stream for rollup manager events. | ||
EventListener(oneshot::Sender<EventStream<RollupManagerEvent>>), | ||
/// Report the current status of the manager via the oneshot channel. | ||
Status(oneshot::Sender<RollupManagerStatus>), | ||
/// Returns the network handle. | ||
NetworkHandle(oneshot::Sender<ScrollNetworkHandle<N>>), | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,10 +3,11 @@ | |
use alloy_eips::BlockNumberOrTag; | ||
use alloy_primitives::{address, b256, Address, Bytes, Signature, B256, U256}; | ||
use futures::StreamExt; | ||
use reth_network::{NetworkConfigBuilder, PeersInfo}; | ||
use reth_network::{NetworkConfigBuilder, Peers, PeersInfo}; | ||
use reth_rpc_api::EthApiServer; | ||
use reth_scroll_chainspec::SCROLL_DEV; | ||
use reth_scroll_node::ScrollNetworkPrimitives; | ||
use reth_scroll_primitives::ScrollBlock; | ||
use reth_tokio_util::EventStream; | ||
use rollup_node::{ | ||
test_utils::{ | ||
|
@@ -16,16 +17,19 @@ use rollup_node::{ | |
BeaconProviderArgs, DatabaseArgs, EngineDriverArgs, GasPriceOracleArgs, L1ProviderArgs, | ||
NetworkArgs as ScrollNetworkArgs, ScrollRollupNodeConfig, SequencerArgs, | ||
}; | ||
use rollup_node_manager::{RollupManagerCommand, RollupManagerEvent, RollupManagerHandle}; | ||
use rollup_node_manager::{RollupManagerCommand, RollupManagerEvent}; | ||
use rollup_node_primitives::BatchCommitData; | ||
use rollup_node_providers::BlobSource; | ||
use rollup_node_sequencer::L1MessageInclusionMode; | ||
use rollup_node_watcher::L1Notification; | ||
use scroll_alloy_consensus::TxL1Message; | ||
use scroll_network::{NewBlockWithPeer, SCROLL_MAINNET}; | ||
use scroll_wire::{ScrollWireConfig, ScrollWireProtocolHandler}; | ||
use std::{path::PathBuf, sync::Arc}; | ||
use tokio::sync::{oneshot, Mutex}; | ||
use std::{path::PathBuf, sync::Arc, time::Duration}; | ||
use tokio::{ | ||
sync::{oneshot, Mutex}, | ||
time, | ||
}; | ||
use tracing::trace; | ||
|
||
#[tokio::test] | ||
|
@@ -57,7 +61,7 @@ async fn can_bridge_l1_messages() -> eyre::Result<()> { | |
let (mut nodes, _tasks, _wallet) = setup_engine(node_args, 1, chain_spec, false, false).await?; | ||
let node = nodes.pop().unwrap(); | ||
|
||
let rnm_handle: RollupManagerHandle = node.inner.add_ons_handle.rollup_manager_handle.clone(); | ||
let rnm_handle = node.inner.add_ons_handle.rollup_manager_handle.clone(); | ||
let mut rnm_events = rnm_handle.get_event_listener().await?; | ||
let l1_watcher_tx = node.inner.add_ons_handle.l1_watcher_tx.clone().unwrap(); | ||
|
||
|
@@ -164,6 +168,93 @@ async fn can_sequence_and_gossip_blocks() { | |
} | ||
} | ||
|
||
#[tokio::test] | ||
async fn can_penalize_peer_for_invalid_block() { | ||
reth_tracing::init_test_tracing(); | ||
|
||
// create 2 nodes | ||
let chain_spec = (*SCROLL_DEV).clone(); | ||
let rollup_manager_args = ScrollRollupNodeConfig { | ||
test: true, | ||
network_args: ScrollNetworkArgs { | ||
enable_eth_scroll_wire_bridge: true, | ||
enable_scroll_wire: true, | ||
sequencer_url: None, | ||
}, | ||
database_args: DatabaseArgs { path: Some(PathBuf::from("sqlite::memory:")) }, | ||
l1_provider_args: L1ProviderArgs::default(), | ||
engine_driver_args: EngineDriverArgs::default(), | ||
sequencer_args: SequencerArgs { | ||
sequencer_enabled: true, | ||
block_time: 0, | ||
max_l1_messages_per_block: 4, | ||
l1_message_inclusion_mode: L1MessageInclusionMode::BlockDepth(0), | ||
payload_building_duration: 1000, | ||
..SequencerArgs::default() | ||
}, | ||
beacon_provider_args: BeaconProviderArgs { | ||
blob_source: BlobSource::Mock, | ||
..Default::default() | ||
}, | ||
signer_args: Default::default(), | ||
gas_price_oracle_args: GasPriceOracleArgs::default(), | ||
}; | ||
|
||
let (nodes, _tasks, _) = | ||
setup_engine(rollup_manager_args, 2, chain_spec, false, false).await.unwrap(); | ||
|
||
let node0_rmn_handle = nodes[0].inner.add_ons_handle.rollup_manager_handle.clone(); | ||
let node0_network_handle = node0_rmn_handle.get_network_handle().await.unwrap(); | ||
let node0_id = node0_network_handle.inner().peer_id(); | ||
|
||
let node1_rnm_handle = nodes[1].inner.add_ons_handle.rollup_manager_handle.clone(); | ||
let node1_network_handle = node1_rnm_handle.get_network_handle().await.unwrap(); | ||
Comment on lines
+206
to
+211
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I might be mistaking but isn't it possible to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. checked and we could just use let block = NewBlock {
block: ScrollBlock {
header: Header {
extra_data: Signature::new(U256::ONE, U256::ONE, false).as_bytes().into(),
..Default::default()
},
..Default::default()
},
..Default::default()
}; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The pattern that @greged93 described will only gossip over the |
||
|
||
// get initial reputation of node0 from pov of node1 | ||
let initial_reputation = | ||
node1_network_handle.inner().reputation_by_id(*node0_id).await.unwrap().unwrap(); | ||
assert_eq!(initial_reputation, 0); | ||
|
||
// create invalid block | ||
let block = ScrollBlock::default(); | ||
|
||
// send invalid block from node0 to node1. We don't care about the signature here since we use a | ||
// NoopConsensus in the test. | ||
node0_network_handle.announce_block(block, Signature::new(U256::from(1), U256::from(1), false)); | ||
|
||
eventually( | ||
Duration::from_secs(100), | ||
Duration::from_millis(10000), | ||
"Peer0 reputation should be lower after sending invalid block", | ||
|| async { | ||
// check that the node0 is penalized on node1 | ||
let slashed_reputation = | ||
node1_network_handle.inner().reputation_by_id(*node0_id).await.unwrap().unwrap(); | ||
slashed_reputation < initial_reputation | ||
}, | ||
) | ||
.await; | ||
} | ||
|
||
/// Helper function to wait until a predicate is true or a timeout occurs. | ||
pub async fn eventually<F, Fut>(timeout: Duration, tick: Duration, message: &str, mut predicate: F) | ||
where | ||
F: FnMut() -> Fut, | ||
Fut: std::future::Future<Output = bool>, | ||
{ | ||
let mut interval = time::interval(tick); | ||
let start = time::Instant::now(); | ||
loop { | ||
if predicate().await { | ||
return; | ||
} | ||
|
||
assert!(start.elapsed() <= timeout, "Timeout while waiting for condition: {message}"); | ||
|
||
interval.tick().await; | ||
} | ||
} | ||
|
||
#[allow(clippy::large_stack_frames)] | ||
#[tokio::test] | ||
async fn can_sequence_and_gossip_transactions() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: we do comments then derive