mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(net): add NetworkMode to enforce POS rules (#215)
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
import::{BlockImport, NoopBlockImport},
|
import::{BlockImport, ProofOfStakeBlockImport},
|
||||||
peers::PeersConfig,
|
peers::PeersConfig,
|
||||||
session::SessionsConfig,
|
session::SessionsConfig,
|
||||||
};
|
};
|
||||||
@ -36,6 +36,8 @@ pub struct NetworkConfig<C> {
|
|||||||
pub genesis_hash: H256,
|
pub genesis_hash: H256,
|
||||||
/// The block importer type.
|
/// The block importer type.
|
||||||
pub block_import: Box<dyn BlockImport>,
|
pub block_import: Box<dyn BlockImport>,
|
||||||
|
/// The default mode of the network.
|
||||||
|
pub network_mode: NetworkMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
// === impl NetworkConfig ===
|
// === impl NetworkConfig ===
|
||||||
@ -90,6 +92,8 @@ pub struct NetworkConfigBuilder<C> {
|
|||||||
genesis_hash: H256,
|
genesis_hash: H256,
|
||||||
/// The block importer type.
|
/// The block importer type.
|
||||||
block_import: Box<dyn BlockImport>,
|
block_import: Box<dyn BlockImport>,
|
||||||
|
/// The default mode of the network.
|
||||||
|
network_mode: NetworkMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
// === impl NetworkConfigBuilder ===
|
// === impl NetworkConfigBuilder ===
|
||||||
@ -108,7 +112,8 @@ impl<C> NetworkConfigBuilder<C> {
|
|||||||
fork_id: None,
|
fork_id: None,
|
||||||
chain: Chain::Named(reth_primitives::rpc::Chain::Mainnet),
|
chain: Chain::Named(reth_primitives::rpc::Chain::Mainnet),
|
||||||
genesis_hash: Default::default(),
|
genesis_hash: Default::default(),
|
||||||
block_import: Box::<NoopBlockImport>::default(),
|
block_import: Box::<ProofOfStakeBlockImport>::default(),
|
||||||
|
network_mode: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +143,7 @@ impl<C> NetworkConfigBuilder<C> {
|
|||||||
chain,
|
chain,
|
||||||
genesis_hash,
|
genesis_hash,
|
||||||
block_import,
|
block_import,
|
||||||
|
network_mode,
|
||||||
} = self;
|
} = self;
|
||||||
NetworkConfig {
|
NetworkConfig {
|
||||||
client,
|
client,
|
||||||
@ -155,6 +161,30 @@ impl<C> NetworkConfigBuilder<C> {
|
|||||||
chain,
|
chain,
|
||||||
genesis_hash,
|
genesis_hash,
|
||||||
block_import,
|
block_import,
|
||||||
|
network_mode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Describes the mode of the network wrt. POS or POW.
|
||||||
|
///
|
||||||
|
/// This affects block propagation in the `eth` sub-protocol [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p)
|
||||||
|
///
|
||||||
|
/// In POS `NewBlockHashes` and `NewBlock` messages become invalid.
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
|
||||||
|
pub enum NetworkMode {
|
||||||
|
/// Network is in proof-of-work mode.
|
||||||
|
Work,
|
||||||
|
/// Network is in proof-of-stake mode
|
||||||
|
#[default]
|
||||||
|
Stake,
|
||||||
|
}
|
||||||
|
|
||||||
|
// === impl NetworkMode ===
|
||||||
|
|
||||||
|
impl NetworkMode {
|
||||||
|
/// Returns true if network has entered proof-of-stake
|
||||||
|
pub fn is_stake(&self) -> bool {
|
||||||
|
matches!(self, NetworkMode::Stake)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -50,12 +50,14 @@ pub enum BlockImportError {
|
|||||||
Consensus(#[from] reth_interfaces::consensus::Error),
|
Consensus(#[from] reth_interfaces::consensus::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An implementation of `BlockImport` that does nothing
|
/// An implementation of `BlockImport` used in Proof-of-Stake consensus that does nothing.
|
||||||
|
///
|
||||||
|
/// Block propagation over devp2p is invalid in POS: [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p)
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
pub struct NoopBlockImport;
|
pub struct ProofOfStakeBlockImport;
|
||||||
|
|
||||||
impl BlockImport for NoopBlockImport {
|
impl BlockImport for ProofOfStakeBlockImport {
|
||||||
fn on_new_block(&mut self, _peer_id: PeerId, _incoming_block: NewBlockMessage) {}
|
fn on_new_block(&mut self, _peer_id: PeerId, _incoming_block: NewBlockMessage) {}
|
||||||
|
|
||||||
fn poll(&mut self, _cx: &mut Context<'_>) -> Poll<BlockImportOutcome> {
|
fn poll(&mut self, _cx: &mut Context<'_>) -> Poll<BlockImportOutcome> {
|
||||||
|
|||||||
@ -115,6 +115,7 @@ where
|
|||||||
sessions_config,
|
sessions_config,
|
||||||
genesis_hash,
|
genesis_hash,
|
||||||
block_import,
|
block_import,
|
||||||
|
network_mode,
|
||||||
..
|
..
|
||||||
} = config;
|
} = config;
|
||||||
|
|
||||||
@ -142,6 +143,7 @@ where
|
|||||||
to_manager_tx,
|
to_manager_tx,
|
||||||
local_node_id,
|
local_node_id,
|
||||||
peers_handle,
|
peers_handle,
|
||||||
|
network_mode,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
@ -211,18 +213,40 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Enforces [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p) consensus rules for the network protocol
|
||||||
|
///
|
||||||
|
/// Depending on the mode of the network:
|
||||||
|
/// - disconnect peer if in POS
|
||||||
|
/// - execute the closure if in POW
|
||||||
|
fn within_pow_or_disconnect<F>(&mut self, peer_id: PeerId, only_pow: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self),
|
||||||
|
{
|
||||||
|
// reject message in POS
|
||||||
|
if self.handle.mode().is_stake() {
|
||||||
|
// connections to peers which send invalid messages should be terminated
|
||||||
|
self.swarm.sessions_mut().disconnect(peer_id);
|
||||||
|
} else {
|
||||||
|
only_pow(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles a received Message from the peer.
|
/// Handles a received Message from the peer.
|
||||||
fn on_peer_message(&mut self, peer_id: PeerId, msg: PeerMessage) {
|
fn on_peer_message(&mut self, peer_id: PeerId, msg: PeerMessage) {
|
||||||
match msg {
|
match msg {
|
||||||
PeerMessage::NewBlockHashes(hashes) => {
|
PeerMessage::NewBlockHashes(hashes) => {
|
||||||
let hashes = Arc::try_unwrap(hashes).unwrap_or_else(|arc| (*arc).clone());
|
self.within_pow_or_disconnect(peer_id, |this| {
|
||||||
// update peer's state, to track what blocks this peer has seen
|
let hashes = Arc::try_unwrap(hashes).unwrap_or_else(|arc| (*arc).clone());
|
||||||
self.swarm.state_mut().on_new_block_hashes(peer_id, hashes.0)
|
// update peer's state, to track what blocks this peer has seen
|
||||||
|
this.swarm.state_mut().on_new_block_hashes(peer_id, hashes.0)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
PeerMessage::NewBlock(block) => {
|
PeerMessage::NewBlock(block) => {
|
||||||
self.swarm.state_mut().on_new_block(peer_id, block.hash);
|
self.within_pow_or_disconnect(peer_id, move |this| {
|
||||||
// start block import process
|
this.swarm.state_mut().on_new_block(peer_id, block.hash);
|
||||||
self.block_import.on_new_block(peer_id, block);
|
// start block import process
|
||||||
|
this.block_import.on_new_block(peer_id, block);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
PeerMessage::PooledTransactions(msg) => {
|
PeerMessage::PooledTransactions(msg) => {
|
||||||
self.event_listeners
|
self.event_listeners
|
||||||
@ -245,6 +269,10 @@ where
|
|||||||
self.event_listeners.listeners.push(tx);
|
self.event_listeners.listeners.push(tx);
|
||||||
}
|
}
|
||||||
NetworkHandleMessage::AnnounceBlock(block, hash) => {
|
NetworkHandleMessage::AnnounceBlock(block, hash) => {
|
||||||
|
if self.handle.mode().is_stake() {
|
||||||
|
error!(target = "net", "Block propagation is not supported in POS - [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p)");
|
||||||
|
return
|
||||||
|
}
|
||||||
let msg = NewBlockMessage { hash, block: Arc::new(block) };
|
let msg = NewBlockMessage { hash, block: Arc::new(block) };
|
||||||
self.swarm.state_mut().announce_new_block(msg);
|
self.swarm.state_mut().announce_new_block(msg);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::{manager::NetworkEvent, message::PeerRequest, peers::PeersHandle};
|
use crate::{config::NetworkMode, manager::NetworkEvent, message::PeerRequest, peers::PeersHandle};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use reth_eth_wire::{NewBlock, NewPooledTransactionHashes, Transactions};
|
use reth_eth_wire::{NewBlock, NewPooledTransactionHashes, Transactions};
|
||||||
use reth_primitives::{PeerId, H256};
|
use reth_primitives::{PeerId, H256};
|
||||||
@ -27,6 +27,7 @@ impl NetworkHandle {
|
|||||||
to_manager_tx: UnboundedSender<NetworkHandleMessage>,
|
to_manager_tx: UnboundedSender<NetworkHandleMessage>,
|
||||||
local_node_id: PeerId,
|
local_node_id: PeerId,
|
||||||
peers: PeersHandle,
|
peers: PeersHandle,
|
||||||
|
network_mode: NetworkMode,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let inner = NetworkInner {
|
let inner = NetworkInner {
|
||||||
num_active_peers,
|
num_active_peers,
|
||||||
@ -34,6 +35,7 @@ impl NetworkHandle {
|
|||||||
listener_address,
|
listener_address,
|
||||||
local_node_id,
|
local_node_id,
|
||||||
peers,
|
peers,
|
||||||
|
network_mode,
|
||||||
};
|
};
|
||||||
Self { inner: Arc::new(inner) }
|
Self { inner: Arc::new(inner) }
|
||||||
}
|
}
|
||||||
@ -49,6 +51,11 @@ impl NetworkHandle {
|
|||||||
rx
|
rx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the mode of the network, either pow, or pos
|
||||||
|
pub fn mode(&self) -> &NetworkMode {
|
||||||
|
&self.inner.network_mode
|
||||||
|
}
|
||||||
|
|
||||||
/// Sends a [`NetworkHandleMessage`] to the manager
|
/// Sends a [`NetworkHandleMessage`] to the manager
|
||||||
pub(crate) fn send_message(&self, msg: NetworkHandleMessage) {
|
pub(crate) fn send_message(&self, msg: NetworkHandleMessage) {
|
||||||
let _ = self.inner.to_manager_tx.send(msg);
|
let _ = self.inner.to_manager_tx.send(msg);
|
||||||
@ -71,6 +78,8 @@ struct NetworkInner {
|
|||||||
local_node_id: PeerId,
|
local_node_id: PeerId,
|
||||||
/// Access to the all the nodes
|
/// Access to the all the nodes
|
||||||
peers: PeersHandle,
|
peers: PeersHandle,
|
||||||
|
/// The mode of the network
|
||||||
|
network_mode: NetworkMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal messages that can be passed to the [`NetworkManager`](crate::NetworkManager).
|
/// Internal messages that can be passed to the [`NetworkManager`](crate::NetworkManager).
|
||||||
|
|||||||
Reference in New Issue
Block a user