diff --git a/Cargo.toml b/Cargo.toml index c0eb9b04..cfe42d92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ rustdoc-args = ["--cfg", "docsrs"] maili-protocol = { version = "0.1.0", path = "crates/protocol", default-features = false } maili-provider = { version = "0.1.0", path = "crates/provider", default-features = false } maili-registry = { version = "0.1.0", path = "crates/registry", default-features = false } +maili-rpc-jsonrpsee = { version = "0.1.0", path = "crates/rpc-jsonrpsee", default-features = false } maili-rpc-types-engine = { version = "0.1.0", path = "crates/rpc-types-engine", default-features = false } # OP-Alloy @@ -46,7 +47,6 @@ op-alloy-genesis = { version = "0.9.1", default-features = false } op-alloy-consensus = { version = "0.9.1", default-features = false } op-alloy-network = { version = "0.9.1", default-features = false } op-alloy-rpc-types = { version = "0.9.1", default-features = false } -op-alloy-rpc-jsonrpsee = { version = "0.9.1", default-features = false } op-alloy-rpc-types-engine = { version = "0.9.1", default-features = false } # Alloy diff --git a/crates/rpc-jsonrpsee/Cargo.toml b/crates/rpc-jsonrpsee/Cargo.toml new file mode 100644 index 00000000..fa213134 --- /dev/null +++ b/crates/rpc-jsonrpsee/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "maili-rpc-jsonrpsee" +description = "Optimism RPC Client" + +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +authors.workspace = true +repository.workspace = true +exclude.workspace = true + +[lints] +workspace = true + +[dependencies] +# Workspace +maili-protocol = { workspace = true, default-features = false, features = ["serde"] } +maili-rpc-types-engine = { workspace = true, default-features = false, features = ["serde"] } + +# OP-Alloy +op-alloy-rpc-types.workspace = true + +# Alloy +alloy-eips.workspace = true +alloy-primitives.workspace = true + +# rpc +jsonrpsee.workspace = true + +[features] +default = ["std"] +std = [ + "maili-protocol/std", + "maili-rpc-types-engine/std", + "op-alloy-rpc-types/std", + "alloy-eips/std", + "alloy-primitives/std", +] +client = [ + "jsonrpsee/client", + "jsonrpsee/async-client", +] diff --git a/crates/rpc-jsonrpsee/README.md b/crates/rpc-jsonrpsee/README.md new file mode 100644 index 00000000..e66295a8 --- /dev/null +++ b/crates/rpc-jsonrpsee/README.md @@ -0,0 +1,10 @@ +## `maili-rpc-jsonrpsee` + +CI +maili-rpc-jsonrpsee crate +MIT License +Apache License +Book + + +Low-level Optimism JSON-RPC server and client implementations. diff --git a/crates/rpc-jsonrpsee/src/lib.rs b/crates/rpc-jsonrpsee/src/lib.rs new file mode 100644 index 00000000..dd08fe38 --- /dev/null +++ b/crates/rpc-jsonrpsee/src/lib.rs @@ -0,0 +1,12 @@ +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg", + html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico" +)] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +pub mod traits; diff --git a/crates/rpc-jsonrpsee/src/traits.rs b/crates/rpc-jsonrpsee/src/traits.rs new file mode 100644 index 00000000..7eacba13 --- /dev/null +++ b/crates/rpc-jsonrpsee/src/traits.rs @@ -0,0 +1,162 @@ +#![allow(missing_docs)] + +//! Rollup Node + +use alloc::{boxed::Box, string::String, vec::Vec}; +use core::net::IpAddr; + +use alloy_eips::BlockNumberOrTag; +use alloy_primitives::{B256, U64}; +use jsonrpsee::{core::RpcResult, proc_macros::rpc}; +use maili_protocol::{ExecutingMessage, SafetyLevel}; +use maili_rpc_types_engine::{ProtocolVersion, SuperchainSignal}; +use op_alloy_rpc_types::{ + OutputResponse, PeerDump, PeerInfo, PeerStats, RollupConfig, SafeHeadResponse, SyncStatus, +}; + +/// Optimism specified rpc interface. +/// +/// https://docs.optimism.io/builders/node-operators/json-rpc +/// https://github.com/ethereum-optimism/optimism/blob/8dd17a7b114a7c25505cd2e15ce4e3d0f7e3f7c1/op-node/node/api.go#L114 +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "optimism"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "optimism"))] +pub trait RollupNode { + /// Get the output root at a specific block. + #[method(name = "outputAtBlock")] + async fn op_output_at_block(&self, block_number: BlockNumberOrTag) + -> RpcResult; + + /// Gets the safe head at an L1 block height. + #[method(name = "safeHeadAtL1Block")] + async fn op_safe_head_at_l1_block( + &self, + block_number: BlockNumberOrTag, + ) -> RpcResult; + + /// Get the synchronization status. + #[method(name = "syncStatus")] + async fn op_sync_status(&self) -> RpcResult; + + /// Get the rollup configuration parameters. + #[method(name = "rollupConfig")] + async fn op_rollup_config(&self) -> RpcResult; + + /// Get the software version. + #[method(name = "version")] + async fn op_version(&self) -> RpcResult; +} + +/// The opp2p namespace handles peer interactions. +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "opp2p"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "opp2p"))] +pub trait OpP2PApi { + /// Returns information of node + #[method(name = "self")] + async fn opp2p_self(&self) -> RpcResult; + + #[method(name = "peers")] + async fn opp2p_peers(&self) -> RpcResult; + + #[method(name = "peerStats")] + async fn opp2p_peer_stats(&self) -> RpcResult; + + #[method(name = "discoveryTable")] + async fn opp2p_discovery_table(&self) -> RpcResult>; + + #[method(name = "blockPeer")] + async fn opp2p_block_peer(&self, peer: String) -> RpcResult<()>; + + #[method(name = "listBlockedPeers")] + async fn opp2p_list_blocked_peers(&self) -> RpcResult>; + + #[method(name = "blocAddr")] + async fn opp2p_block_addr(&self, ip: IpAddr) -> RpcResult<()>; + + #[method(name = "unblockAddr")] + async fn opp2p_unblock_addr(&self, ip: IpAddr) -> RpcResult<()>; + + #[method(name = "listBlockedAddrs")] + async fn opp2p_list_blocked_addrs(&self) -> RpcResult>; + + /// todo: should be IPNet? + #[method(name = "blockSubnet")] + async fn opp2p_block_subnet(&self, subnet: String) -> RpcResult<()>; + + /// todo: should be IPNet? + #[method(name = "unblockSubnet")] + async fn opp2p_unblock_subnet(&self, subnet: String) -> RpcResult<()>; + + /// todo: should be IPNet? + #[method(name = "listBlockedSubnets")] + async fn opp2p_list_blocked_subnets(&self) -> RpcResult>; + + #[method(name = "protectPeer")] + async fn opp2p_protect_peer(&self, peer: String) -> RpcResult<()>; + + #[method(name = "unprotectPeer")] + async fn opp2p_unprotect_peer(&self, peer: String) -> RpcResult<()>; + + #[method(name = "connectPeer")] + async fn opp2p_connect_peer(&self, peer: String) -> RpcResult<()>; + + #[method(name = "disconnectPeer")] + async fn opp2p_disconnect_peer(&self, peer: String) -> RpcResult<()>; +} + +/// The admin namespace endpoints +/// https://github.com/ethereum-optimism/optimism/blob/c7ad0ebae5dca3bf8aa6f219367a95c15a15ae41/op-node/node/api.go#L28-L36 +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "admin"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "admin"))] +pub trait OpAdminApi { + #[method(name = "resetDerivationPipeline")] + async fn admin_reset_derivation_pipeline(&self) -> RpcResult<()>; + + #[method(name = "startSequencer")] + async fn admin_start_sequencer(&self, block_hash: B256) -> RpcResult<()>; + + #[method(name = "stopSequencer")] + async fn admin_stop_sequencer(&self) -> RpcResult; + + #[method(name = "sequencerActive")] + async fn admin_sequencer_active(&self) -> RpcResult; +} + +/// Engine API extension for Optimism superchain signaling +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "engine"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "engine"))] +pub trait EngineApiExt { + /// Signal superchain v1 message + /// + /// The execution engine SHOULD warn when the recommended version is newer than the current + /// version. The execution engine SHOULD take safety precautions if it does not meet + /// the required version. + /// + /// # Returns + /// The latest supported OP-Stack protocol version of the execution engine. + /// + /// See: + #[method(name = "signalSuperchainV1")] + async fn signal_superchain_v1(&self, signal: SuperchainSignal) -> RpcResult; +} + +/// Op API extension for controlling the miner. +#[cfg_attr(not(feature = "client"), rpc(server, namespace = "miner"))] +#[cfg_attr(feature = "client", rpc(server, client, namespace = "miner"))] +pub trait MinerApiExt { + /// Sets the maximum data availability size of any tx allowed in a block, and the total max l1 + /// data size of the block. 0 means no maximum. + #[method(name = "setMaxDASize")] + async fn set_max_da_size(&self, max_tx_size: U64, max_block_size: U64) -> RpcResult; +} + +/// Supervisor API for interop. +#[rpc(client, namespace = "supervisor")] +pub trait SupervisorApi { + /// Checks if the given messages meet the given minimum safety level. + #[method(name = "checkMessages")] + async fn check_messages( + &self, + messages: Vec, + min_safety: SafetyLevel, + ) -> RpcResult<()>; +}