Skip to content

POC: simplify SDK #15593

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

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
Draft

POC: simplify SDK #15593

wants to merge 15 commits into from

Conversation

emhane
Copy link
Member

@emhane emhane commented Apr 7, 2025

Ref #13951

BlockReader is trait aggregating a lot of stateful behaviour, however it's used as trait bound in type definitions just in order to access the associated data primitive types. A more intentional way to do this, is to make use of the stateless base trait NodePrimitives in the type definition.

/// Container type `EthApi`
#[expect(missing_debug_implementations)]
pub struct EthApiInner<Provider: BlockReader, Pool, Network, EvmConfig> {
/// The transaction pool.
pool: Pool,
/// The provider that can interact with the chain.
provider: Provider,
/// An interface to interact with the network
network: Network,
/// All configured Signers
signers: parking_lot::RwLock<Vec<Box<dyn EthSigner<Provider::Transaction>>>>,
/// The async cache frontend for eth related data
eth_cache: EthStateCache<Provider::Block, Provider::Receipt>,
/// The async gas oracle frontend for gas price suggestions
gas_oracle: GasPriceOracle<Provider>,
/// Maximum gas limit for `eth_call` and call tracing RPC methods.
gas_cap: u64,
/// Maximum number of blocks for `eth_simulateV1`.
max_simulate_blocks: u64,
/// The maximum number of blocks into the past for generating state proofs.
eth_proof_window: u64,
/// The block number at which the node started
starting_block: U256,
/// The type that can spawn tasks which would otherwise block.
task_spawner: Box<dyn TaskSpawner>,
/// Cached pending block if any
pending_block: Mutex<Option<PendingBlock<Provider::Block, Provider::Receipt>>>,
/// A pool dedicated to CPU heavy blocking tasks.
blocking_task_pool: BlockingTaskPool,
/// Cache for block fees history
fee_history_cache: FeeHistoryCache,
/// The type that defines how to configure the EVM
evm_config: EvmConfig,
/// Guard for getproof calls
blocking_task_guard: BlockingTaskGuard,
/// Transaction broadcast channel
raw_tx_sender: broadcast::Sender<Bytes>,
}

Since NodePrimitives is stateless, it can effortlessly become supertrait of any provider trait and removes the need for adding the same associated types again explicitly to the provider traits.

All provider traits read to and from the same database so there is no need to separately configure and therefore to define new associated types TransactionProvider::Transaction, HeaderProvider::Header, etc. creating overhead as we need to link them to the rest of the node, e.g. TransactionProvider::Transaction == <N as NodePrimitives>::SignedTx. It also saves the need for the trait NodePrimitivesProvider, hereby removing an extra complexity layer.

/// Client trait for fetching `Header` related data.
#[auto_impl::auto_impl(&, Arc)]
pub trait HeaderProvider: Send + Sync {
/// The header type this provider supports.
type Header: BlockHeader;

Alt approaches: creating a new trait NodePrimitivesBase, identical associated types as NodePrimitives but without trait bounds on the associated types and using this as super trait instead and in type defs, similar as RpcNodeCore. This approach was out-ruled because it adds more code, whereas the PR aims to remove redundancy and create stronger cohesion in the SDK abstraction to its origin in NodePrimitives.

@emhane emhane added C-debt A clean up/refactor of existing code A-sdk Related to reth's use as a library labels Apr 7, 2025
@emhane emhane marked this pull request as draft April 7, 2025 16:09
@emhane emhane removed the request for review from fgimenez April 7, 2025 16:09
@emhane emhane requested review from gakonst and removed request for shekhirin, onbjerg, rakita and rkrasiuk April 7, 2025 16:09
impl<C, N> CanonStateSubscriptions for NoopProvider<C, N>
where
C: Send + Sync,
N: NodePrimitives + Unpin + Default + Clone + 'static,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

places that require trait bounds like these can be collapsed into some helper trait eventually HalfFullNodePrimitives or smthg. NodePrimitives can't be static for example in order to be supertrait of traits of T that should be implemented on &T also. @mattsse

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

alt, we can upgrade the trait bound everywhere where it needs to be static/Clone/etc. to FullNodePrimitives. it works quite nicely with the MaybeCompact and other Maybe- traits in reth-primitives-traits to just include the trait bound everywhere, even where Compact isn't needed, without any overhead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-sdk Related to reth's use as a library C-debt A clean up/refactor of existing code
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

1 participant