Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ jobs:
- uses: rui314/setup-mold@v1
- uses: dtolnay/rust-toolchain@clippy
with:
toolchain: 'nightly-2026-01-05'
components: clippy
- uses: Swatinem/rust-cache@v2
with:
Expand All @@ -38,6 +39,7 @@ jobs:
- uses: rui314/setup-mold@v1
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: 'nightly-2026-01-05'
components: rustfmt
- name: Run fmt
run: cargo fmt --all --check
Expand All @@ -59,6 +61,8 @@ jobs:
- uses: actions/checkout@v6
- uses: rui314/setup-mold@v1
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: 'nightly-2026-01-05'
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
Expand Down Expand Up @@ -88,6 +92,8 @@ jobs:
- uses: actions/checkout@v6
- uses: rui314/setup-mold@v1
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: 'nightly-2026-01-05'
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
- uses: rui314/setup-mold@v1
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: 'nightly'
toolchain: 'nightly-2026-01-05'
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
Expand All @@ -43,7 +43,7 @@ jobs:
- uses: rui314/setup-mold@v1
- uses: dtolnay/rust-toolchain@nightly
with:
toolchain: 'nightly'
toolchain: 'nightly-2026-01-05'
- uses: Swatinem/rust-cache@v2
with:
cache-on-failure: true
Expand Down
12 changes: 7 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
NIGHTLY_TOOLCHAIN := nightly-2026-01-05

.PHONY: fmt
fmt:
cargo +nightly fmt
cargo +$(NIGHTLY_TOOLCHAIN) fmt

.PHONY: lint-toml
lint-toml: ensure-dprint
Expand All @@ -14,7 +16,7 @@ ensure-dprint:

.PHONY: clippy
clippy:
cargo +nightly clippy \
cargo +$(NIGHTLY_TOOLCHAIN) clippy \
--workspace \
--lib \
--examples \
Expand All @@ -25,7 +27,7 @@ clippy:

.PHONY: clippy-fix
clippy-fix:
cargo +nightly clippy \
cargo +$(NIGHTLY_TOOLCHAIN) clippy \
--workspace \
--lib \
--examples \
Expand All @@ -37,7 +39,7 @@ clippy-fix:

.PHONY: udeps
udeps:
cargo +nightly udeps --workspace --lib --examples --tests --benches --all-features --locked
cargo +$(NIGHTLY_TOOLCHAIN) udeps --workspace --lib --examples --tests --benches --all-features --locked

.PHONY: codespell
codespell: ensure-codespell
Expand All @@ -64,7 +66,7 @@ lint: fmt lint-toml clippy udeps codespell zepter

.PHONY: test
test:
cargo nextest run \
cargo +$(NIGHTLY_TOOLCHAIN) nextest run \
--workspace \
--locked \
--all-features \
Expand Down
55 changes: 42 additions & 13 deletions crates/network/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ impl<
// Filter the peers that have not seen this block hash.
let peers: Vec<FixedBytes<64>> = self
.scroll_wire
.state()
.block_received_state()
.iter()
.filter_map(|(peer_id, blocks)| (!blocks.contains(&hash)).then_some(*peer_id))
.collect();
Expand Down Expand Up @@ -227,7 +227,7 @@ impl<
// Announce block to the filtered set of peers
for peer_id in peers {
trace!(target: "scroll::network::manager", peer_id = %peer_id, block_number = %block.block.header.number, block_hash = %hash, "Announcing new block to peer");
self.scroll_wire.announce_block(peer_id, &block, hash);
self.scroll_wire.announce_block(peer_id, &block);
}
}

Expand All @@ -240,15 +240,30 @@ impl<
ScrollWireEvent::NewBlock { peer_id, block, signature } => {
let block_hash = block.hash_slow();
trace!(target: "scroll::network::manager", peer_id = ?peer_id, block = ?block_hash, signature = ?signature, "Received new block");

// Update the state of the peer cache i.e. peer has seen this block.
self.scroll_wire
.block_received_state_mut()
.entry(peer_id)
.or_insert_with(|| LruCache::new(LRU_CACHE_SIZE))
.insert(block_hash);

if self.blocks_seen.contains(&(block_hash, signature)) {
// Check if this peer has already sent this block to us, if so penalize it.
if self
.scroll_wire
.block_received_state()
.get(&peer_id)
.is_some_and(|cache| cache.contains(&block_hash))
{
trace!(target: "scroll::network::manager", peer_id = ?peer_id, block = ?block_hash, "Peer sent duplicate block, penalizing");
self.inner_network_handle.reputation_change(
peer_id,
reth_network_api::ReputationChangeKind::BadBlock,
);
}
None
} else {
// Update the state of the peer cache i.e. peer has seen this block.
self.scroll_wire
.state_mut()
.entry(peer_id)
.or_insert_with(|| LruCache::new(LRU_CACHE_SIZE))
.insert(block_hash);
// Update the state of the block cache i.e. we have seen this block.
self.blocks_seen.insert((block.hash_slow(), signature));

Expand Down Expand Up @@ -339,18 +354,32 @@ impl<
.and_then(|i| Signature::from_raw(&extra_data[i..]).ok())
{
let block_hash = block.hash_slow();
if self.blocks_seen.contains(&(block_hash, signature)) {
return None;
}
trace!(target: "scroll::bridge::import", peer_id = %peer_id, block_hash = %block_hash, signature = %signature.to_string(), extra_data = %extra_data.to_string(), "Received new block from eth-wire protocol");

// Update the state of the peer cache i.e. peer has seen this block.
self.scroll_wire
.state_mut()
.block_received_state_mut()
.entry(peer_id)
.or_insert_with(|| LruCache::new(LRU_CACHE_SIZE))
.insert(block_hash);

if self.blocks_seen.contains(&(block_hash, signature)) {
// Check if this peer has already sent this block to us, if so penalize it.
if self
.scroll_wire
.block_received_state()
.get(&peer_id)
.is_some_and(|cache| cache.contains(&block_hash))
{
trace!(target: "scroll::bridge::import", peer_id = ?peer_id, block = ?block_hash, "Peer sent duplicate block, penalizing");
self.inner_network_handle.reputation_change(
peer_id,
reth_network_api::ReputationChangeKind::BadBlock,
);
}
return None;
}
trace!(target: "scroll::bridge::import", peer_id = %peer_id, block_hash = %block_hash, signature = %signature.to_string(), extra_data = %extra_data.to_string(), "Received new block from eth-wire protocol");

// Update the state of the block cache i.e. we have seen this block.
self.blocks_seen.insert((block_hash, signature));
Some(ScrollNetworkManagerEvent::NewBlock(NewBlockWithPeer {
Expand Down
28 changes: 14 additions & 14 deletions crates/scroll-wire/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,45 +24,45 @@ pub struct ScrollWireManager {
/// A map of connections to peers.
connections: HashMap<PeerId, UnboundedSender<ScrollMessage>>,
/// A map of the state of the scroll wire protocol. Currently the state for each peer
/// is just a cache of the last 100 blocks seen by each peer.
state: HashMap<PeerId, LruCache<B256>>,
/// is just a cache of the last 100 blocks received from each peer.
block_received_state: HashMap<PeerId, LruCache<B256>>,
}

impl ScrollWireManager {
/// Creates a new [`ScrollWireManager`] instance.
pub fn new(events: UnboundedReceiver<ScrollWireEvent>) -> Self {
trace!(target: "scroll::wire::manager", "Creating new ScrollWireManager instance");
Self { events: events.into(), connections: HashMap::new(), state: HashMap::new() }
Self {
events: events.into(),
connections: HashMap::new(),
block_received_state: HashMap::new(),
}
}

/// Announces a new block to the specified peer.
pub fn announce_block(&mut self, peer_id: PeerId, block: &NewBlock, hash: B256) {
pub fn announce_block(&mut self, peer_id: PeerId, block: &NewBlock) {
if let Entry::Occupied(to_connection) = self.connections.entry(peer_id) {
// We send the block to the peer. If we receive an error we remove the peer from the
// connections map and delete its state as the connection is no longer valid.
if to_connection.get().send(ScrollMessage::new_block(block.clone())).is_err() {
trace!(target: "scroll::wire::manager", peer_id = %peer_id, "Failed to send block to peer - dropping peer.");
self.state.remove(&peer_id);
self.block_received_state.remove(&peer_id);
to_connection.remove();
} else {
// Upon successful sending of the block we update the state of the peer.
trace!(target: "scroll::wire::manager", peer_id = %peer_id, "Announced block to peer");
self.state
.entry(peer_id)
.or_insert_with(|| LruCache::new(LRU_CACHE_SIZE))
.insert(hash);
}
}
}

/// Returns the state of the `ScrollWire` protocol.
pub const fn state(&self) -> &HashMap<PeerId, LruCache<B256>> {
&self.state
pub const fn block_received_state(&self) -> &HashMap<PeerId, LruCache<B256>> {
&self.block_received_state
}

/// Returns a mutable reference to the state of the `ScrollWire` protocol.
pub const fn state_mut(&mut self) -> &mut HashMap<PeerId, LruCache<B256>> {
&mut self.state
pub const fn block_received_state_mut(&mut self) -> &mut HashMap<PeerId, LruCache<B256>> {
&mut self.block_received_state
}
}

Expand Down Expand Up @@ -94,7 +94,7 @@ impl Future for ScrollWireManager {
direction
);
this.connections.insert(peer_id, to_connection);
this.state.insert(peer_id, LruCache::new(100));
this.block_received_state.insert(peer_id, LruCache::new(100));
}
None => break,
}
Expand Down
Loading