mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore: use new aquamarine macro (#5785)
This commit is contained in:
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -332,16 +332,16 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
|
||||
|
||||
[[package]]
|
||||
name = "aquamarine"
|
||||
version = "0.3.2"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df752953c49ce90719c7bf1fc587bc8227aed04732ea0c0f85e5397d7fdbd1a1"
|
||||
checksum = "074b80d14d0240b6ce94d68f059a2d26a5d77280ae142662365a21ef6e2594ef"
|
||||
dependencies = [
|
||||
"include_dir",
|
||||
"itertools 0.10.5",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -157,7 +157,7 @@ boa_engine = "0.17"
|
||||
boa_gc = "0.17"
|
||||
|
||||
# misc
|
||||
aquamarine = "0.3"
|
||||
aquamarine = "0.4"
|
||||
bytes = "1.5"
|
||||
bitflags = "2.4"
|
||||
clap = "4"
|
||||
|
||||
@ -37,40 +37,25 @@ use tracing::{debug, error, info, instrument, trace, warn};
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// A Tree of chains.
|
||||
///
|
||||
/// Mermaid flowchart represents all the states a block can have inside the blockchaintree.
|
||||
/// Green blocks belong to canonical chain and are saved inside then database, they are our main
|
||||
/// chain. Pending blocks and sidechains are found in memory inside [`BlockchainTree`].
|
||||
/// Both pending and sidechains have same mechanisms only difference is when they get committed to
|
||||
/// the database. For pending it is an append operation but for sidechains they need to move current
|
||||
/// canonical blocks to BlockchainTree and commit the sidechain to the database to become canonical
|
||||
/// chain (reorg). ```mermaid
|
||||
/// flowchart BT
|
||||
/// subgraph canonical chain
|
||||
/// CanonState:::state
|
||||
/// block0canon:::canon -->block1canon:::canon -->block2canon:::canon -->block3canon:::canon -->
|
||||
/// block4canon:::canon --> block5canon:::canon end
|
||||
/// block5canon --> block6pending1:::pending
|
||||
/// block5canon --> block6pending2:::pending
|
||||
/// subgraph sidechain2
|
||||
/// S2State:::state
|
||||
/// block3canon --> block4s2:::sidechain --> block5s2:::sidechain
|
||||
/// end
|
||||
/// subgraph sidechain1
|
||||
/// S1State:::state
|
||||
/// block2canon --> block3s1:::sidechain --> block4s1:::sidechain --> block5s1:::sidechain -->
|
||||
/// block6s1:::sidechain end
|
||||
/// classDef state fill:#1882C4
|
||||
/// classDef canon fill:#8AC926
|
||||
/// classDef pending fill:#FFCA3A
|
||||
/// classDef sidechain fill:#FF595E
|
||||
/// ```
|
||||
/// The flowchart represents all the states a block can have inside the tree.
|
||||
///
|
||||
/// - Green blocks belong to the canonical chain and are saved inside the database.
|
||||
/// - Pending blocks and sidechains are found in-memory inside [`BlockchainTree`].
|
||||
///
|
||||
/// main functions:
|
||||
/// * [BlockchainTree::insert_block]: Connect block to chain, execute it and if valid insert block
|
||||
/// into the tree.
|
||||
/// * [BlockchainTree::finalize_block]: Remove chains that are branch off the now finalized block.
|
||||
/// * [BlockchainTree::make_canonical]: Check if we have the hash of block that is the current
|
||||
/// Both pending chains and sidechains have the same mechanisms, the only difference is when they
|
||||
/// get committed to the database.
|
||||
///
|
||||
/// For pending, it is an append operation, but for sidechains they need to move the current
|
||||
/// canonical blocks to the tree (by removing them from the database), and commit the sidechain
|
||||
/// blocks to the database to become the canonical chain (reorg).
|
||||
///
|
||||
/// include_mmd!("docs/mermaid/tree.mmd")
|
||||
///
|
||||
/// # Main functions
|
||||
/// * [BlockchainTree::insert_block]: Connect a block to a chain, execute it, and if valid, insert
|
||||
/// the block into the tree.
|
||||
/// * [BlockchainTree::finalize_block]: Remove chains that branch off of the now finalized block.
|
||||
/// * [BlockchainTree::make_canonical]: Check if we have the hash of a block that is the current
|
||||
/// canonical head and commit it to db.
|
||||
#[derive(Debug)]
|
||||
pub struct BlockchainTree<DB: Database, EF: ExecutorFactory> {
|
||||
|
||||
@ -18,44 +18,13 @@ use std::sync::{
|
||||
};
|
||||
use tokio::sync::{mpsc::UnboundedSender, oneshot};
|
||||
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// Front-end API for fetching data from the network.
|
||||
///
|
||||
/// Following diagram illustrates how a request, See [`HeadersClient::get_headers`] and
|
||||
/// [`BodiesClient::get_block_bodies`] is handled internally.
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// ```mermaid
|
||||
/// sequenceDiagram
|
||||
// participant Client as FetchClient
|
||||
// participant Fetcher as StateFetcher
|
||||
// participant State as NetworkState
|
||||
// participant Session as Active Peer Session
|
||||
// participant Peers as PeerManager
|
||||
// loop Send Request, retry if retriable and remaining retries
|
||||
// Client->>Fetcher: DownloadRequest{GetHeaders, GetBodies}
|
||||
// Note over Client,Fetcher: Request and oneshot Sender sent via `request_tx` channel
|
||||
// loop Process buffered requests
|
||||
// State->>Fetcher: poll action
|
||||
// Fetcher->>Fetcher: Select Available Peer
|
||||
// Note over Fetcher: Peer is available if it's currently idle, no inflight requests
|
||||
// Fetcher->>State: FetchAction::BlockDownloadRequest
|
||||
// State->>Session: Delegate Request
|
||||
// Note over State,Session: Request and oneshot Sender sent via `to_session_tx` channel
|
||||
// end
|
||||
// Session->>Session: Send Request to remote
|
||||
// Session->>Session: Enforce Request timeout
|
||||
// Session-->>State: Send Response Result via channel
|
||||
// State->>Fetcher: Delegate Response
|
||||
// Fetcher-->>Client: Send Response via channel
|
||||
// opt Bad Response
|
||||
// Client->>Peers: Penalize Peer
|
||||
// end
|
||||
// Peers->>Peers: Apply Reputation Change
|
||||
// opt reputation dropped below threshold
|
||||
// Peers->>State: Disconnect Session
|
||||
// State->>Session: Delegate Disconnect
|
||||
// end
|
||||
// end
|
||||
/// ```
|
||||
///
|
||||
/// include_mmd!("docs/mermaid/fetch-client.mmd")
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FetchClient {
|
||||
/// Sender half of the request channel.
|
||||
|
||||
@ -60,34 +60,14 @@ use tokio::sync::mpsc::{self, error::TrySendError};
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
use tracing::{debug, error, trace, warn};
|
||||
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// Manages the _entire_ state of the network.
|
||||
///
|
||||
/// This is an endless [`Future`] that consistently drives the state of the entire network forward.
|
||||
///
|
||||
/// The [`NetworkManager`] is the container type for all parts involved with advancing the network.
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// ```mermaid
|
||||
/// graph TB
|
||||
/// handle(NetworkHandle)
|
||||
/// events(NetworkEvents)
|
||||
/// transactions(Transactions Task)
|
||||
/// ethrequest(ETH Request Task)
|
||||
/// discovery(Discovery Task)
|
||||
/// subgraph NetworkManager
|
||||
/// direction LR
|
||||
/// subgraph Swarm
|
||||
/// direction TB
|
||||
/// B1[(Session Manager)]
|
||||
/// B2[(Connection Lister)]
|
||||
/// B3[(Network State)]
|
||||
/// end
|
||||
/// end
|
||||
/// handle <--> |request response channel| NetworkManager
|
||||
/// NetworkManager --> |Network events| events
|
||||
/// transactions <--> |transactions| NetworkManager
|
||||
/// ethrequest <--> |ETH request handing| NetworkManager
|
||||
/// discovery --> |Discovered peers| NetworkManager
|
||||
/// ```
|
||||
///
|
||||
/// include_mmd!("docs/mermaid/network-manager.mmd")
|
||||
#[derive(Debug)]
|
||||
#[must_use = "The NetworkManager does nothing unless polled"]
|
||||
pub struct NetworkManager<C> {
|
||||
@ -543,7 +523,7 @@ where
|
||||
if self.handle.mode().is_stake() {
|
||||
// See [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#devp2p)
|
||||
warn!(target: "net", "Peer performed block propagation, but it is not supported in proof of stake (EIP-3675)");
|
||||
return
|
||||
return;
|
||||
}
|
||||
let msg = NewBlockMessage { hash, block: Arc::new(block) };
|
||||
self.swarm.state_mut().announce_new_block(msg);
|
||||
@ -638,7 +618,7 @@ where
|
||||
// This is only possible if the channel was deliberately closed since we always
|
||||
// have an instance of `NetworkHandle`
|
||||
error!("Network message channel closed.");
|
||||
return Poll::Ready(())
|
||||
return Poll::Ready(());
|
||||
}
|
||||
Poll::Ready(Some(msg)) => this.on_handle_message(msg),
|
||||
};
|
||||
@ -909,7 +889,7 @@ where
|
||||
if budget == 0 {
|
||||
// make sure we're woken up again
|
||||
cx.waker().wake_by_ref();
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ use std::{
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// Contains the connectivity related state of the network.
|
||||
///
|
||||
/// A swarm emits [`SwarmEvent`]s when polled.
|
||||
@ -44,24 +45,8 @@ use tracing::trace;
|
||||
/// request channel for the created session and sends requests it receives from the
|
||||
/// [`StateFetcher`], which receives request objects from the client interfaces responsible for
|
||||
/// downloading headers and bodies.
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// ```mermaid
|
||||
/// graph TB
|
||||
/// connections(TCP Listener)
|
||||
/// Discovery[(Discovery)]
|
||||
/// fetchRequest(Client Interfaces)
|
||||
/// Sessions[(SessionManager)]
|
||||
/// SessionTask[(Peer Session)]
|
||||
/// State[(State)]
|
||||
/// StateFetch[(State Fetcher)]
|
||||
/// connections --> |incoming| Sessions
|
||||
/// State --> |initiate outgoing| Sessions
|
||||
/// Discovery --> |update peers| State
|
||||
/// Sessions --> |spawns| SessionTask
|
||||
/// SessionTask <--> |handle state requests| State
|
||||
/// fetchRequest --> |request Headers, Bodies| StateFetch
|
||||
/// State --> |poll pending requests| StateFetch
|
||||
/// ```
|
||||
///
|
||||
/// include_mmd!("docs/mermaid/swarm.mmd")
|
||||
#[derive(Debug)]
|
||||
#[must_use = "Swarm does nothing unless polled"]
|
||||
pub(crate) struct Swarm<C> {
|
||||
@ -207,7 +192,7 @@ where
|
||||
ListenerEvent::Incoming { stream, remote_addr } => {
|
||||
// Reject incoming connection if node is shutting down.
|
||||
if self.is_shutting_down() {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
// ensure we can handle an incoming connection from this address
|
||||
if let Err(err) =
|
||||
@ -225,13 +210,13 @@ where
|
||||
);
|
||||
}
|
||||
}
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
|
||||
match self.sessions.on_incoming(stream, remote_addr) {
|
||||
Ok(session_id) => {
|
||||
trace!(target: "net", ?remote_addr, "Incoming connection");
|
||||
return Some(SwarmEvent::IncomingTcpConnection { session_id, remote_addr })
|
||||
return Some(SwarmEvent::IncomingTcpConnection { session_id, remote_addr });
|
||||
}
|
||||
Err(err) => {
|
||||
trace!(target: "net", ?err, "Incoming connection rejected, capacity already reached.");
|
||||
@ -250,7 +235,7 @@ where
|
||||
match event {
|
||||
StateAction::Connect { remote_addr, peer_id } => {
|
||||
self.dial_outbound(remote_addr, peer_id);
|
||||
return Some(SwarmEvent::OutgoingTcpConnection { remote_addr, peer_id })
|
||||
return Some(SwarmEvent::OutgoingTcpConnection { remote_addr, peer_id });
|
||||
}
|
||||
StateAction::Disconnect { peer_id, reason } => {
|
||||
self.sessions.disconnect(peer_id, reason);
|
||||
@ -268,7 +253,7 @@ where
|
||||
StateAction::DiscoveredNode { peer_id, socket_addr, fork_id } => {
|
||||
// Don't try to connect to peer if node is shutting down
|
||||
if self.is_shutting_down() {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
// Insert peer only if no fork id or a valid fork id
|
||||
if fork_id.map_or_else(|| true, |f| self.sessions.is_valid_fork_id(f)) {
|
||||
@ -317,7 +302,7 @@ where
|
||||
loop {
|
||||
while let Poll::Ready(action) = this.state.poll(cx) {
|
||||
if let Some(event) = this.on_state_action(action) {
|
||||
return Poll::Ready(Some(event))
|
||||
return Poll::Ready(Some(event));
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,9 +311,9 @@ where
|
||||
Poll::Pending => {}
|
||||
Poll::Ready(event) => {
|
||||
if let Some(event) = this.on_session_event(event) {
|
||||
return Poll::Ready(Some(event))
|
||||
return Poll::Ready(Some(event));
|
||||
}
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -337,13 +322,13 @@ where
|
||||
Poll::Pending => {}
|
||||
Poll::Ready(event) => {
|
||||
if let Some(event) = this.on_connection(event) {
|
||||
return Poll::Ready(Some(event))
|
||||
return Poll::Ready(Some(event));
|
||||
}
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return Poll::Pending
|
||||
return Poll::Pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,39 +49,7 @@ pub type PipelineWithResult<DB> = (Pipeline<DB>, Result<ControlFlow, PipelineErr
|
||||
/// After the entire pipeline has been run, it will run again unless asked to stop (see
|
||||
/// [Pipeline::set_max_block]).
|
||||
///
|
||||
/// ```mermaid
|
||||
/// graph TB
|
||||
/// Start[Start]
|
||||
/// Done[Done]
|
||||
/// Error[Error]
|
||||
/// subgraph Unwind
|
||||
/// StartUnwind(Unwind in reverse order of execution)
|
||||
/// UnwindStage(Unwind stage)
|
||||
/// NextStageToUnwind(Next stage)
|
||||
/// end
|
||||
/// subgraph Single loop
|
||||
/// RunLoop(Run loop)
|
||||
/// NextStage(Next stage)
|
||||
/// LoopDone(Loop done)
|
||||
/// subgraph Stage Execution
|
||||
/// Execute(Execute stage)
|
||||
/// end
|
||||
/// end
|
||||
/// Start --> RunLoop --> NextStage
|
||||
/// NextStage --> |No stages left| LoopDone
|
||||
/// NextStage --> |Next stage| Execute
|
||||
/// Execute --> |Not done| Execute
|
||||
/// Execute --> |Unwind requested| StartUnwind
|
||||
/// Execute --> |Done| NextStage
|
||||
/// Execute --> |Error| Error
|
||||
/// StartUnwind --> NextStageToUnwind
|
||||
/// NextStageToUnwind --> |Next stage| UnwindStage
|
||||
/// NextStageToUnwind --> |No stages left| RunLoop
|
||||
/// UnwindStage --> |Error| Error
|
||||
/// UnwindStage --> |Unwound| NextStageToUnwind
|
||||
/// LoopDone --> |Target block reached| Done
|
||||
/// LoopDone --> |Target block not reached| RunLoop
|
||||
/// ```
|
||||
/// include_mmd!("docs/mermaid/pipeline.mmd")
|
||||
///
|
||||
/// # Unwinding
|
||||
///
|
||||
@ -193,7 +161,7 @@ where
|
||||
max_block = ?self.max_block,
|
||||
"Terminating pipeline."
|
||||
);
|
||||
return Ok(())
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,7 +197,7 @@ where
|
||||
ControlFlow::Continue { block_number } => self.progress.update(block_number),
|
||||
ControlFlow::Unwind { target, bad_block } => {
|
||||
self.unwind(target, Some(bad_block.number))?;
|
||||
return Ok(ControlFlow::Unwind { target, bad_block })
|
||||
return Ok(ControlFlow::Unwind { target, bad_block });
|
||||
}
|
||||
}
|
||||
|
||||
@ -272,7 +240,7 @@ where
|
||||
"Unwind point too far for stage"
|
||||
);
|
||||
self.listeners.notify(PipelineEvent::Skipped { stage_id });
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
debug!(
|
||||
@ -317,7 +285,7 @@ where
|
||||
}
|
||||
Err(err) => {
|
||||
self.listeners.notify(PipelineEvent::Error { stage_id });
|
||||
return Err(PipelineError::Stage(StageError::Fatal(Box::new(err))))
|
||||
return Err(PipelineError::Stage(StageError::Fatal(Box::new(err))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -357,7 +325,7 @@ where
|
||||
// We reached the maximum block, so we skip the stage
|
||||
return Ok(ControlFlow::NoProgress {
|
||||
block_number: prev_checkpoint.map(|progress| progress.block_number),
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
let exec_input = ExecInput { target, checkpoint: prev_checkpoint };
|
||||
@ -412,7 +380,7 @@ where
|
||||
ControlFlow::Continue { block_number }
|
||||
} else {
|
||||
ControlFlow::NoProgress { block_number: Some(block_number) }
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
@ -421,7 +389,7 @@ where
|
||||
if let Some(ctrl) =
|
||||
on_stage_error(&self.provider_factory, stage_id, prev_checkpoint, err)?
|
||||
{
|
||||
return Ok(ctrl)
|
||||
return Ok(ctrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,45 +32,12 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// A pool that manages transactions.
|
||||
///
|
||||
/// This pool maintains the state of all transactions and stores them accordingly.
|
||||
|
||||
#[cfg_attr(doc, aquamarine::aquamarine)]
|
||||
/// ```mermaid
|
||||
/// graph TB
|
||||
/// subgraph TxPool
|
||||
/// direction TB
|
||||
/// pool[(All Transactions)]
|
||||
/// subgraph Subpools
|
||||
/// direction TB
|
||||
/// B3[(Queued)]
|
||||
/// B1[(Pending)]
|
||||
/// B2[(Basefee)]
|
||||
/// B4[(Blob)]
|
||||
/// end
|
||||
/// end
|
||||
/// discard([discard])
|
||||
/// production([Block Production])
|
||||
/// new([New Block])
|
||||
/// A[Incoming Tx] --> B[Validation] -->|insert| pool
|
||||
/// pool --> |if ready + blobfee too low| B4
|
||||
/// pool --> |if ready| B1
|
||||
/// pool --> |if ready + basfee too low| B2
|
||||
/// pool --> |nonce gap or lack of funds| B3
|
||||
/// pool --> |update| pool
|
||||
/// B1 --> |best| production
|
||||
/// B2 --> |worst| discard
|
||||
/// B3 --> |worst| discard
|
||||
/// B4 --> |worst| discard
|
||||
/// B1 --> |increased blob fee| B4
|
||||
/// B4 --> |decreased blob fee| B1
|
||||
/// B1 --> |increased base fee| B2
|
||||
/// B2 --> |decreased base fee| B1
|
||||
/// B3 --> |promote| B1
|
||||
/// B3 --> |promote| B2
|
||||
/// new --> |apply state changes| pool
|
||||
/// ```
|
||||
///
|
||||
/// include_mmd!("docs/mermaid/txpool.mmd")
|
||||
pub struct TxPool<T: TransactionOrdering> {
|
||||
/// Contains the currently known information about the senders.
|
||||
sender_info: FnvHashMap<SenderId, SenderInfo>,
|
||||
@ -509,7 +476,7 @@ impl<T: TransactionOrdering> TxPool<T> {
|
||||
on_chain_nonce: u64,
|
||||
) -> PoolResult<AddedTransaction<T::Transaction>> {
|
||||
if self.contains(tx.hash()) {
|
||||
return Err(PoolError::new(*tx.hash(), PoolErrorKind::AlreadyImported))
|
||||
return Err(PoolError::new(*tx.hash(), PoolErrorKind::AlreadyImported));
|
||||
}
|
||||
|
||||
// Update sender info with balance and nonce
|
||||
@ -737,7 +704,7 @@ impl<T: TransactionOrdering> TxPool<T> {
|
||||
}
|
||||
id = descendant;
|
||||
} else {
|
||||
return
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -964,7 +931,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
let count = entry.get_mut();
|
||||
if *count == 1 {
|
||||
entry.remove();
|
||||
return
|
||||
return;
|
||||
}
|
||||
*count -= 1;
|
||||
}
|
||||
@ -1024,7 +991,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
($iter:ident) => {
|
||||
'this: while let Some((peek, _)) = iter.peek() {
|
||||
if peek.sender != id.sender {
|
||||
break 'this
|
||||
break 'this;
|
||||
}
|
||||
iter.next();
|
||||
}
|
||||
@ -1043,7 +1010,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
current: tx.subpool,
|
||||
destination: Destination::Discard,
|
||||
});
|
||||
continue 'transactions
|
||||
continue 'transactions;
|
||||
}
|
||||
|
||||
let ancestor = TransactionId::ancestor(id.nonce, info.state_nonce, id.sender);
|
||||
@ -1066,7 +1033,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
// If there's a nonce gap, we can shortcircuit, because there's nothing to update yet.
|
||||
if tx.state.has_nonce_gap() {
|
||||
next_sender!(iter);
|
||||
continue 'transactions
|
||||
continue 'transactions;
|
||||
}
|
||||
|
||||
// Since this is the first transaction of the sender, it has no parked ancestors
|
||||
@ -1086,13 +1053,13 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
while let Some((peek, ref mut tx)) = iter.peek_mut() {
|
||||
if peek.sender != id.sender {
|
||||
// Found the next sender
|
||||
continue 'transactions
|
||||
continue 'transactions;
|
||||
}
|
||||
|
||||
// can short circuit
|
||||
if tx.state.has_nonce_gap() {
|
||||
next_sender!(iter);
|
||||
continue 'transactions
|
||||
continue 'transactions;
|
||||
}
|
||||
|
||||
// update cumulative cost
|
||||
@ -1254,7 +1221,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
fn contains_conflicting_transaction(&self, tx: &ValidPoolTransaction<T>) -> bool {
|
||||
let mut iter = self.txs_iter(tx.transaction_id.sender);
|
||||
if let Some((_, existing)) = iter.next() {
|
||||
return tx.tx_type_conflicts_with(&existing.transaction)
|
||||
return tx.tx_type_conflicts_with(&existing.transaction);
|
||||
}
|
||||
// no existing transaction for this sender
|
||||
false
|
||||
@ -1278,7 +1245,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
if current_txs >= self.max_account_slots {
|
||||
return Err(InsertErr::ExceededSenderTransactionsCapacity {
|
||||
transaction: Arc::new(transaction),
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
if transaction.gas_limit() > self.block_gas_limit {
|
||||
@ -1286,12 +1253,12 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
block_gas_limit: self.block_gas_limit,
|
||||
tx_gas_limit: transaction.gas_limit(),
|
||||
transaction: Arc::new(transaction),
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if self.contains_conflicting_transaction(&transaction) {
|
||||
// blob vs non blob transactions are mutually exclusive for the same sender
|
||||
return Err(InsertErr::TxTypeConflict { transaction: Arc::new(transaction) })
|
||||
return Err(InsertErr::TxTypeConflict { transaction: Arc::new(transaction) });
|
||||
}
|
||||
|
||||
Ok(transaction)
|
||||
@ -1311,12 +1278,12 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
if let Some(ancestor) = ancestor {
|
||||
let Some(ancestor_tx) = self.txs.get(&ancestor) else {
|
||||
// ancestor tx is missing, so we can't insert the new blob
|
||||
return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) })
|
||||
return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) });
|
||||
};
|
||||
if ancestor_tx.state.has_nonce_gap() {
|
||||
// the ancestor transaction already has a nonce gap, so we can't insert the new
|
||||
// blob
|
||||
return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) })
|
||||
return Err(InsertErr::BlobTxHasNonceGap { transaction: Arc::new(new_blob_tx) });
|
||||
}
|
||||
|
||||
// the max cost executing this transaction requires
|
||||
@ -1325,7 +1292,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
// check if the new blob would go into overdraft
|
||||
if cumulative_cost > on_chain_balance {
|
||||
// the transaction would go into overdraft
|
||||
return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
|
||||
return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) });
|
||||
}
|
||||
|
||||
// ensure that a replacement would not shift already propagated blob transactions into
|
||||
@ -1342,14 +1309,14 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
cumulative_cost += tx.transaction.cost();
|
||||
if tx.transaction.is_eip4844() && cumulative_cost > on_chain_balance {
|
||||
// the transaction would shift
|
||||
return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
|
||||
return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if new_blob_tx.cost() > on_chain_balance {
|
||||
// the transaction would go into overdraft
|
||||
return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) })
|
||||
return Err(InsertErr::Overdraft { transaction: Arc::new(new_blob_tx) });
|
||||
}
|
||||
|
||||
Ok(new_blob_tx)
|
||||
@ -1369,7 +1336,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
if maybe_replacement.max_fee_per_gas() <=
|
||||
existing_transaction.max_fee_per_gas() * price_bump_multiplier
|
||||
{
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
let existing_max_priority_fee_per_gas =
|
||||
@ -1382,7 +1349,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
existing_max_priority_fee_per_gas != 0 &&
|
||||
replacement_max_priority_fee_per_gas != 0
|
||||
{
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
// check max blob fee per gas
|
||||
@ -1395,7 +1362,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
if replacement_max_blob_fee_per_gas <=
|
||||
existing_max_blob_fee_per_gas * price_bump_multiplier
|
||||
{
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1484,7 +1451,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
let fee_cap = transaction.max_fee_per_gas();
|
||||
|
||||
if fee_cap < self.minimal_protocol_basefee as u128 {
|
||||
return Err(InsertErr::FeeCapBelowMinimumProtocolFeeCap { transaction, fee_cap })
|
||||
return Err(InsertErr::FeeCapBelowMinimumProtocolFeeCap { transaction, fee_cap });
|
||||
}
|
||||
if fee_cap >= self.pending_fees.base_fee as u128 {
|
||||
state.insert(TxState::ENOUGH_FEE_CAP_BLOCK);
|
||||
@ -1523,7 +1490,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
return Err(InsertErr::Underpriced {
|
||||
transaction: pool_tx.transaction,
|
||||
existing: *entry.get().transaction.hash(),
|
||||
})
|
||||
});
|
||||
}
|
||||
let new_hash = *pool_tx.transaction.hash();
|
||||
let new_transaction = pool_tx.transaction.clone();
|
||||
@ -1566,7 +1533,7 @@ impl<T: PoolTransaction> AllTransactions<T> {
|
||||
|
||||
// If there's a nonce gap, we can shortcircuit
|
||||
if next_nonce != id.nonce {
|
||||
break
|
||||
break;
|
||||
}
|
||||
|
||||
// close the nonce gap
|
||||
|
||||
31
docs/mermaid/fetch-client.mmd
Normal file
31
docs/mermaid/fetch-client.mmd
Normal file
@ -0,0 +1,31 @@
|
||||
sequenceDiagram
|
||||
participant Client as FetchClient
|
||||
participant Fetcher as StateFetcher
|
||||
participant State as NetworkState
|
||||
participant Session as Active Peer Session
|
||||
participant Peers as PeerManager
|
||||
loop Send Request, retry if retriable and remaining retries
|
||||
Client->>Fetcher: DownloadRequest{GetHeaders, GetBodies}
|
||||
Note over Client,Fetcher: Request and oneshot Sender sent via `request_tx` channel
|
||||
loop Process buffered requests
|
||||
State->>Fetcher: poll action
|
||||
Fetcher->>Fetcher: Select Available Peer
|
||||
Note over Fetcher: Peer is available if it's currently idle, no inflight requests
|
||||
Fetcher->>State: FetchAction::BlockDownloadRequest
|
||||
State->>Session: Delegate Request
|
||||
Note over State,Session: Request and oneshot Sender sent via `to_session_tx` channel
|
||||
end
|
||||
Session->>Session: Send Request to remote
|
||||
Session->>Session: Enforce Request timeout
|
||||
Session-->>State: Send Response Result via channel
|
||||
State->>Fetcher: Delegate Response
|
||||
Fetcher-->>Client: Send Response via channel
|
||||
opt Bad Response
|
||||
Client->>Peers: Penalize Peer
|
||||
end
|
||||
Peers->>Peers: Apply Reputation Change
|
||||
opt reputation dropped below threshold
|
||||
Peers->>State: Disconnect Session
|
||||
State->>Session: Delegate Disconnect
|
||||
end
|
||||
end
|
||||
20
docs/mermaid/network-manager.mmd
Normal file
20
docs/mermaid/network-manager.mmd
Normal file
@ -0,0 +1,20 @@
|
||||
graph TB
|
||||
handle(NetworkHandle)
|
||||
events(NetworkEvents)
|
||||
transactions(Transactions Task)
|
||||
ethrequest(ETH Request Task)
|
||||
discovery(Discovery Task)
|
||||
subgraph NetworkManager
|
||||
direction LR
|
||||
subgraph Swarm
|
||||
direction TB
|
||||
B1[(Session Manager)]
|
||||
B2[(Connection Lister)]
|
||||
B3[(Network State)]
|
||||
end
|
||||
end
|
||||
handle <--> |request response channel| NetworkManager
|
||||
NetworkManager --> |Network events| events
|
||||
transactions <--> |transactions| NetworkManager
|
||||
ethrequest <--> |ETH request handing| NetworkManager
|
||||
discovery --> |Discovered peers| NetworkManager
|
||||
31
docs/mermaid/pipeline.mmd
Normal file
31
docs/mermaid/pipeline.mmd
Normal file
@ -0,0 +1,31 @@
|
||||
graph TB
|
||||
Start[Start]
|
||||
Done[Done]
|
||||
Error[Error]
|
||||
subgraph Unwind
|
||||
StartUnwind(Unwind in reverse order of execution)
|
||||
UnwindStage(Unwind stage)
|
||||
NextStageToUnwind(Next stage)
|
||||
end
|
||||
subgraph Single loop
|
||||
RunLoop(Run loop)
|
||||
NextStage(Next stage)
|
||||
LoopDone(Loop done)
|
||||
subgraph Stage Execution
|
||||
Execute(Execute stage)
|
||||
end
|
||||
end
|
||||
Start --> RunLoop --> NextStage
|
||||
NextStage --> |No stages left| LoopDone
|
||||
NextStage --> |Next stage| Execute
|
||||
Execute --> |Not done| Execute
|
||||
Execute --> |Unwind requested| StartUnwind
|
||||
Execute --> |Done| NextStage
|
||||
Execute --> |Error| Error
|
||||
StartUnwind --> NextStageToUnwind
|
||||
NextStageToUnwind --> |Next stage| UnwindStage
|
||||
NextStageToUnwind --> |No stages left| RunLoop
|
||||
UnwindStage --> |Error| Error
|
||||
UnwindStage --> |Unwound| NextStageToUnwind
|
||||
LoopDone --> |Target block reached| Done
|
||||
LoopDone --> |Target block not reached| RunLoop
|
||||
15
docs/mermaid/swarm.mmd
Normal file
15
docs/mermaid/swarm.mmd
Normal file
@ -0,0 +1,15 @@
|
||||
graph TB
|
||||
connections(TCP Listener)
|
||||
Discovery[(Discovery)]
|
||||
fetchRequest(Client Interfaces)
|
||||
Sessions[(SessionManager)]
|
||||
SessionTask[(Peer Session)]
|
||||
State[(State)]
|
||||
StateFetch[(State Fetcher)]
|
||||
connections --> |incoming| Sessions
|
||||
State --> |initiate outgoing| Sessions
|
||||
Discovery --> |update peers| State
|
||||
Sessions --> |spawns| SessionTask
|
||||
SessionTask <--> |handle state requests| State
|
||||
fetchRequest --> |request Headers, Bodies| StateFetch
|
||||
State --> |poll pending requests| StateFetch
|
||||
21
docs/mermaid/tree.mmd
Normal file
21
docs/mermaid/tree.mmd
Normal file
@ -0,0 +1,21 @@
|
||||
flowchart BT
|
||||
subgraph canonical chain
|
||||
CanonState:::state
|
||||
block0canon:::canon -->block1canon:::canon -->block2canon:::canon -->block3canon:::canon -->
|
||||
block4canon:::canon --> block5canon:::canon
|
||||
end
|
||||
block5canon --> block6pending1:::pending
|
||||
block5canon --> block6pending2:::pending
|
||||
subgraph sidechain2
|
||||
S2State:::state
|
||||
block3canon --> block4s2:::sidechain --> block5s2:::sidechain
|
||||
end
|
||||
subgraph sidechain1
|
||||
S1State:::state
|
||||
block2canon --> block3s1:::sidechain --> block4s1:::sidechain --> block5s1:::sidechain -->
|
||||
block6s1:::sidechain
|
||||
end
|
||||
classDef state fill:#1882C4
|
||||
classDef canon fill:#8AC926
|
||||
classDef pending fill:#FFCA3A
|
||||
classDef sidechain fill:#FF595E
|
||||
32
docs/mermaid/txpool.mmd
Normal file
32
docs/mermaid/txpool.mmd
Normal file
@ -0,0 +1,32 @@
|
||||
graph TB
|
||||
subgraph TxPool
|
||||
direction TB
|
||||
pool[(All Transactions)]
|
||||
subgraph Subpools
|
||||
direction TB
|
||||
B3[(Queued)]
|
||||
B1[(Pending)]
|
||||
B2[(Basefee)]
|
||||
B4[(Blob)]
|
||||
end
|
||||
end
|
||||
discard([discard])
|
||||
production([Block Production])
|
||||
new([New Block])
|
||||
A[Incoming Tx] --> B[Validation] -->|insert| pool
|
||||
pool --> |if ready + blobfee too low| B4
|
||||
pool --> |if ready| B1
|
||||
pool --> |if ready + basfee too low| B2
|
||||
pool --> |nonce gap or lack of funds| B3
|
||||
pool --> |update| pool
|
||||
B1 --> |best| production
|
||||
B2 --> |worst| discard
|
||||
B3 --> |worst| discard
|
||||
B4 --> |worst| discard
|
||||
B1 --> |increased blob fee| B4
|
||||
B4 --> |decreased blob fee| B1
|
||||
B1 --> |increased base fee| B2
|
||||
B2 --> |decreased base fee| B1
|
||||
B3 --> |promote| B1
|
||||
B3 --> |promote| B2
|
||||
new --> |apply state changes| pool
|
||||
Reference in New Issue
Block a user