Skip to content

Refactor bridge implementation #19

@frisitano

Description

@frisitano

Overview

Currently, the bridge block import implementation wraps an inner_block_import. The bridge block import delegates to the inner_block_import and upon a poll invocation which returns ValidBlock/ValidHeader bridges a block over to the scroll wire protocol.

impl RethBlockImport<reth_scroll_primitives::ScrollBlock> for BridgeBlockImport {
/// This function is called when a new block is received from the network, it delegates the
/// block import to the inner block import.
fn on_new_block(
&mut self,
peer_id: PeerId,
incoming_block: reth_network::message::NewBlockMessage<
<ScrollNetworkPrimitives as NetworkPrimitives>::Block,
>,
) {
// We then delegate the block import to the inner block import.
self.inner.on_new_block(peer_id, incoming_block);
}
/// This function is called when the block import is polled.
///
/// If the block import is ready we check if the block is valid and if it is we send the block
/// to the scroll-wire protocol and then return the outcome.
fn poll(
&mut self,
cx: &mut Context<'_>,
) -> Poll<
reth_network::import::BlockImportOutcome<
<ScrollNetworkPrimitives as NetworkPrimitives>::Block,
>,
> {
if let Poll::Ready(outcome) = self.inner.poll(cx) {
match outcome.result {
Ok(BlockValidation::ValidBlock { ref block }) |
Ok(BlockValidation::ValidHeader { ref block }) => {
self.bridge_new_block_to_scroll_wire(outcome.peer, block.block.clone());
Poll::Ready(outcome)
}
Err(_) => Poll::Ready(outcome),
}
} else {
Poll::Pending
}
}
}

For the inner block import the current implementation uses the default block import provided via the Network configuration, this is ProofOfStakeBlockImport which is a noop. We should replace this and instead use ValidBlockImport from the e2e bridge integration.

/// A block import type that always returns a valid outcome.
#[derive(Debug, Default)]
pub struct ValidRethBlockImport {
/// A buffer for storing the blocks that are received.
blocks: VecDeque<(
PeerId,
reth_network::message::NewBlockMessage<reth_scroll_primitives::ScrollBlock>,
)>,
waker: Option<std::task::Waker>,
}
impl reth_network::import::BlockImport<reth_scroll_primitives::ScrollBlock>
for ValidRethBlockImport
{
fn on_new_block(
&mut self,
peer_id: PeerId,
incoming_block: reth_network::message::NewBlockMessage<
alloy_consensus::Block<reth_scroll_primitives::ScrollTransactionSigned>,
>,
) {
trace!(target: "network::import::ValidRethBlockImport", peer_id = %peer_id, block = ?incoming_block.block, "Received new block");
self.blocks.push_back((peer_id, incoming_block));
if let Some(waker) = self.waker.take() {
waker.wake();
}
}
fn poll(
&mut self,
cx: &mut Context<'_>,
) -> Poll<
reth_network::import::BlockImportOutcome<
alloy_consensus::Block<reth_scroll_primitives::ScrollTransactionSigned>,
>,
> {
// If there are blocks in the buffer we return the first block.
if let Some((peer, new_block)) = self.blocks.pop_front() {
Poll::Ready(reth_network::import::BlockImportOutcome {
peer,
result: Ok(reth_network::import::BlockValidation::ValidBlock { block: new_block }),
})
} else {
self.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}

block_import: Box::new(super::BridgeBlockImport::new(
new_block_tx,
self.block_import.unwrap_or(config.block_import),

This will result in a naive solution in which all blocks received over the eth-wire protocol will be bridged to scroll-wire and gossiped without performing any form of validation. In future implementations, we should validate gossiped blocks before rebroadcasting them, this can be done via the engine API.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions