Skip to content

Commit 8c1f7d1

Browse files
authored
feat: improve rpc namespace (#454)
* feat: improve rpc namespace * feat: improve rpc namespace * add --rpc.rollup-node-admin to test * address comment * fix: ci docker
1 parent 562f46d commit 8c1f7d1

File tree

13 files changed

+151
-66
lines changed

13 files changed

+151
-66
lines changed

book/src/running-a-node.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ These can be used as reliable blob sources without requiring your own beacon nod
130130

131131
#### Rollup Node RPC
132132

133-
- `--rpc.rollup-node`: Enable the rollup node RPC namespace (provides rollup-specific methods)
133+
- `--rpc.rollup-node=false`: Disable the rollup node basic RPC namespace(default: enabled) (provides rollup-specific methods)
134+
- `--rpc.rollup-node-admin`: Enable the rollup node admin RPC namespace (provides rollup-specific methods)
134135

135136
### Example Configurations
136137

crates/node/src/add_ons/mod.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,16 @@ use reth_scroll_primitives::ScrollPrimitives;
2727
use reth_scroll_rpc::{eth::ScrollEthApiBuilder, ScrollEthApiError};
2828
use scroll_alloy_evm::ScrollTransactionIntoTxEnv;
2929
use scroll_wire::ScrollWireEvent;
30+
use std::sync::Arc;
3031

3132
mod handle;
3233
pub use handle::ScrollAddOnsHandle;
3334

3435
mod rpc;
35-
pub use rpc::{RollupNodeExtApiClient, RollupNodeExtApiServer, RollupNodeRpcExt};
36+
pub use rpc::{
37+
RollupNodeAdminApiClient, RollupNodeAdminApiServer, RollupNodeApiClient, RollupNodeApiServer,
38+
RollupNodeRpcExt,
39+
};
3640

3741
mod rollup;
3842
pub use rollup::IsDevChain;
@@ -128,20 +132,34 @@ where
128132
);
129133

130134
let (tx, rx) = tokio::sync::oneshot::channel();
131-
let rollup_node_rpc_ext = RollupNodeRpcExt::<N::Network>::new(rx);
132-
if rollup_node_manager_addon.config().rpc_args.enabled {
133-
rpc_add_ons = rpc_add_ons.extend_rpc_modules(move |ctx| {
134-
ctx.modules.merge_configured(rollup_node_rpc_ext.into_rpc())?;
135-
Ok(())
136-
});
137-
}
135+
let rpc_config = rollup_node_manager_addon.config().rpc_args.clone();
136+
137+
// Register rollupNode API and rollupNodeAdmin API if enabled
138+
let rollup_node_rpc_ext = Arc::new(RollupNodeRpcExt::<N::Network>::new(rx));
139+
140+
rpc_add_ons = rpc_add_ons.extend_rpc_modules(move |ctx| {
141+
// Always register rollupNode API (read-only operations)
142+
if rpc_config.basic_enabled {
143+
ctx.modules
144+
.merge_configured(RollupNodeApiServer::into_rpc(rollup_node_rpc_ext.clone()))?;
145+
}
146+
// Only register rollupNodeAdmin API if enabled (administrative operations)
147+
if rpc_config.admin_enabled {
148+
ctx.modules
149+
.merge_configured(RollupNodeAdminApiServer::into_rpc(rollup_node_rpc_ext))?;
150+
}
151+
Ok(())
152+
});
138153

139154
let rpc_handle = rpc_add_ons.launch_add_ons_with(ctx.clone(), |_| Ok(())).await?;
140155
let (rollup_manager_handle, l1_watcher_tx) =
141156
rollup_node_manager_addon.launch(ctx.clone(), rpc_handle.clone()).await?;
142157

143-
tx.send(rollup_manager_handle.clone())
144-
.map_err(|_| eyre::eyre!("failed to send rollup manager handle"))?;
158+
// Only send handle if RPC is enabled
159+
if rpc_config.basic_enabled || rpc_config.admin_enabled {
160+
tx.send(rollup_manager_handle.clone())
161+
.map_err(|_| eyre::eyre!("failed to send rollup manager handle"))?;
162+
}
145163

146164
Ok(ScrollAddOnsHandle {
147165
rollup_manager_handle,

crates/node/src/add_ons/rpc.rs

Lines changed: 102 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@ use tokio::sync::{oneshot, Mutex, OnceCell};
1313

1414
/// RPC extension for rollup node management operations.
1515
///
16-
/// This struct provides a custom JSON-RPC namespace (`rollupNode`) that exposes
17-
/// rollup management functionality to RPC clients. It manages a connection to the
16+
/// This struct provides custom JSON-RPC namespaces (`rollupNode` and `rollupNodeAdmin`)
17+
/// that expose rollup management functionality to RPC clients. It manages a connection to the
1818
/// rollup manager through a handle that is initialized lazily via a oneshot channel.
19+
///
20+
/// Both `RollupNodeApiServer` and `RollupNodeAdminApiServer` traits are implemented.
21+
/// You can control which APIs to expose by selectively registering them in the RPC modules.
1922
#[derive(Debug)]
2023
pub struct RollupNodeRpcExt<N>
2124
where
@@ -32,6 +35,9 @@ where
3235
N: FullNetwork<Primitives = ScrollNetworkPrimitives>,
3336
{
3437
/// Creates a new RPC extension with a receiver for the rollup manager handle.
38+
///
39+
/// This struct implements both `RollupNodeApiServer` and `RollupNodeAdminApiServer`.
40+
/// Control which APIs are exposed by selectively registering them when extending RPC modules.
3541
pub fn new(rx: oneshot::Receiver<ChainOrchestratorHandle<N>>) -> Self {
3642
Self { rx: Mutex::new(Some(rx)), handle: OnceCell::new() }
3743
}
@@ -53,31 +59,22 @@ where
5359
}
5460
}
5561

56-
/// Defines the `rollupNode` JSON-RPC namespace for rollup management operations.
62+
/// Defines the `rollupNode` JSON-RPC namespace for basic operations.
5763
///
58-
/// This trait provides a custom RPC namespace that exposes rollup node management
59-
/// functionality to external clients. The namespace is exposed as `rollupNode` and
60-
/// provides methods for controlling automatic sequencing behavior.
64+
/// This trait provides a custom RPC namespace that exposes rollup node status
65+
/// and query functionality to external clients. The namespace is exposed as `rollupNode`.
6166
///
6267
/// # Usage
6368
/// These methods can be called via JSON-RPC using the `rollupNode` namespace:
6469
/// ```json
65-
/// {"jsonrpc": "2.0", "method": "rollupNode_enableAutomaticSequencing", "params": [], "id": 1}
70+
/// {"jsonrpc": "2.0", "method": "rollupNode_status", "params": [], "id": 1}
6671
/// ```
6772
/// or using cast:
6873
/// ```bash
69-
/// cast rpc rollupNode_enableAutomaticSequencing
74+
/// cast rpc rollupNode_status
7075
/// ```
7176
#[rpc(server, client, namespace = "rollupNode")]
72-
pub trait RollupNodeExtApi {
73-
/// Enables automatic sequencing in the rollup node.
74-
#[method(name = "enableAutomaticSequencing")]
75-
async fn enable_automatic_sequencing(&self) -> RpcResult<bool>;
76-
77-
/// Disables automatic sequencing in the rollup node.
78-
#[method(name = "disableAutomaticSequencing")]
79-
async fn disable_automatic_sequencing(&self) -> RpcResult<bool>;
80-
77+
pub trait RollupNodeApi {
8178
/// Returns the current status of the rollup node.
8279
#[method(name = "status")]
8380
async fn status(&self) -> RpcResult<ChainOrchestratorStatus>;
@@ -94,12 +91,38 @@ pub trait RollupNodeExtApi {
9491
) -> RpcResult<Option<L1MessageEnvelope>>;
9592
}
9693

94+
/// Defines the `rollupNodeAdmin` JSON-RPC namespace for administrative operations.
95+
///
96+
/// This trait provides a custom RPC namespace that exposes rollup node administrative
97+
/// functionality to external clients. The namespace is exposed as `rollupNodeAdmin` and
98+
/// requires the `--rpc.rollup-node-admin` flag to be enabled.
99+
///
100+
/// # Usage
101+
/// These methods can be called via JSON-RPC using the `rollupNodeAdmin` namespace:
102+
/// ```json
103+
/// {"jsonrpc": "2.0", "method": "rollupNodeAdmin_enableAutomaticSequencing", "params": [], "id": 1}
104+
/// ```
105+
/// or using cast:
106+
/// ```bash
107+
/// cast rpc rollupNodeAdmin_enableAutomaticSequencing
108+
/// ```
109+
#[rpc(server, client, namespace = "rollupNodeAdmin")]
110+
pub trait RollupNodeAdminApi {
111+
/// Enables automatic sequencing in the rollup node.
112+
#[method(name = "enableAutomaticSequencing")]
113+
async fn enable_automatic_sequencing(&self) -> RpcResult<bool>;
114+
115+
/// Disables automatic sequencing in the rollup node.
116+
#[method(name = "disableAutomaticSequencing")]
117+
async fn disable_automatic_sequencing(&self) -> RpcResult<bool>;
118+
}
119+
97120
#[async_trait]
98-
impl<N> RollupNodeExtApiServer for RollupNodeRpcExt<N>
121+
impl<N> RollupNodeApiServer for RollupNodeRpcExt<N>
99122
where
100123
N: FullNetwork<Primitives = ScrollNetworkPrimitives>,
101124
{
102-
async fn enable_automatic_sequencing(&self) -> RpcResult<bool> {
125+
async fn status(&self) -> RpcResult<ChainOrchestratorStatus> {
103126
let handle = self.rollup_manager_handle().await.map_err(|e| {
104127
ErrorObjectOwned::owned(
105128
error::INTERNAL_ERROR_CODE,
@@ -108,16 +131,16 @@ where
108131
)
109132
})?;
110133

111-
handle.enable_automatic_sequencing().await.map_err(|e| {
134+
handle.status().await.map_err(|e| {
112135
ErrorObjectOwned::owned(
113136
error::INTERNAL_ERROR_CODE,
114-
format!("Failed to enable automatic sequencing: {}", e),
137+
format!("Failed to get rollup node status: {}", e),
115138
None::<()>,
116139
)
117140
})
118141
}
119142

120-
async fn disable_automatic_sequencing(&self) -> RpcResult<bool> {
143+
async fn get_l1_message_by_index(&self, index: u64) -> RpcResult<Option<L1MessageEnvelope>> {
121144
let handle = self.rollup_manager_handle().await.map_err(|e| {
122145
ErrorObjectOwned::owned(
123146
error::INTERNAL_ERROR_CODE,
@@ -126,16 +149,19 @@ where
126149
)
127150
})?;
128151

129-
handle.disable_automatic_sequencing().await.map_err(|e| {
152+
handle.get_l1_message_by_key(L1MessageKey::from_queue_index(index)).await.map_err(|e| {
130153
ErrorObjectOwned::owned(
131154
error::INTERNAL_ERROR_CODE,
132-
format!("Failed to disable automatic sequencing: {}", e),
155+
format!("Failed to get L1 message by index: {}", e),
133156
None::<()>,
134157
)
135158
})
136159
}
137160

138-
async fn status(&self) -> RpcResult<ChainOrchestratorStatus> {
161+
async fn get_l1_message_by_key(
162+
&self,
163+
l1_message_key: L1MessageKey,
164+
) -> RpcResult<Option<L1MessageEnvelope>> {
139165
let handle = self.rollup_manager_handle().await.map_err(|e| {
140166
ErrorObjectOwned::owned(
141167
error::INTERNAL_ERROR_CODE,
@@ -144,16 +170,22 @@ where
144170
)
145171
})?;
146172

147-
handle.status().await.map_err(|e| {
173+
handle.get_l1_message_by_key(l1_message_key).await.map_err(|e| {
148174
ErrorObjectOwned::owned(
149175
error::INTERNAL_ERROR_CODE,
150-
format!("Failed to get rollup node status: {}", e),
176+
format!("Failed to get L1 message by key: {}", e),
151177
None::<()>,
152178
)
153179
})
154180
}
181+
}
155182

156-
async fn get_l1_message_by_index(&self, index: u64) -> RpcResult<Option<L1MessageEnvelope>> {
183+
#[async_trait]
184+
impl<N> RollupNodeAdminApiServer for RollupNodeRpcExt<N>
185+
where
186+
N: FullNetwork<Primitives = ScrollNetworkPrimitives>,
187+
{
188+
async fn enable_automatic_sequencing(&self) -> RpcResult<bool> {
157189
let handle = self.rollup_manager_handle().await.map_err(|e| {
158190
ErrorObjectOwned::owned(
159191
error::INTERNAL_ERROR_CODE,
@@ -162,19 +194,16 @@ where
162194
)
163195
})?;
164196

165-
handle.get_l1_message_by_key(L1MessageKey::from_queue_index(index)).await.map_err(|e| {
197+
handle.enable_automatic_sequencing().await.map_err(|e| {
166198
ErrorObjectOwned::owned(
167199
error::INTERNAL_ERROR_CODE,
168-
format!("Failed to get L1 message by index: {}", e),
200+
format!("Failed to enable automatic sequencing: {}", e),
169201
None::<()>,
170202
)
171203
})
172204
}
173205

174-
async fn get_l1_message_by_key(
175-
&self,
176-
l1_message_key: L1MessageKey,
177-
) -> RpcResult<Option<L1MessageEnvelope>> {
206+
async fn disable_automatic_sequencing(&self) -> RpcResult<bool> {
178207
let handle = self.rollup_manager_handle().await.map_err(|e| {
179208
ErrorObjectOwned::owned(
180209
error::INTERNAL_ERROR_CODE,
@@ -183,12 +212,49 @@ where
183212
)
184213
})?;
185214

186-
handle.get_l1_message_by_key(l1_message_key).await.map_err(|e| {
215+
handle.disable_automatic_sequencing().await.map_err(|e| {
187216
ErrorObjectOwned::owned(
188217
error::INTERNAL_ERROR_CODE,
189-
format!("Failed to get L1 message by key: {}", e),
218+
format!("Failed to disable automatic sequencing: {}", e),
190219
None::<()>,
191220
)
192221
})
193222
}
194223
}
224+
225+
// Implement RollupNodeApiServer for Arc<RollupNodeRpcExt<N>> to allow shared ownership
226+
#[async_trait]
227+
impl<N> RollupNodeApiServer for std::sync::Arc<RollupNodeRpcExt<N>>
228+
where
229+
N: FullNetwork<Primitives = ScrollNetworkPrimitives>,
230+
{
231+
async fn status(&self) -> RpcResult<ChainOrchestratorStatus> {
232+
(**self).status().await
233+
}
234+
235+
async fn get_l1_message_by_index(&self, index: u64) -> RpcResult<Option<L1MessageEnvelope>> {
236+
(**self).get_l1_message_by_index(index).await
237+
}
238+
239+
async fn get_l1_message_by_key(
240+
&self,
241+
l1_message_key: L1MessageKey,
242+
) -> RpcResult<Option<L1MessageEnvelope>> {
243+
(**self).get_l1_message_by_key(l1_message_key).await
244+
}
245+
}
246+
247+
// Implement RollupNodeAdminApiServer for Arc<RollupNodeRpcExt<N>> to allow shared ownership
248+
#[async_trait]
249+
impl<N> RollupNodeAdminApiServer for std::sync::Arc<RollupNodeRpcExt<N>>
250+
where
251+
N: FullNetwork<Primitives = ScrollNetworkPrimitives>,
252+
{
253+
async fn enable_automatic_sequencing(&self) -> RpcResult<bool> {
254+
(**self).enable_automatic_sequencing().await
255+
}
256+
257+
async fn disable_automatic_sequencing(&self) -> RpcResult<bool> {
258+
(**self).disable_automatic_sequencing().await
259+
}
260+
}

crates/node/src/args.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -751,9 +751,12 @@ pub struct SignerArgs {
751751
/// The arguments for the rpc.
752752
#[derive(Debug, Default, Clone, clap::Args)]
753753
pub struct RpcArgs {
754-
/// A boolean to represent if the rollup node rpc should be enabled.
755-
#[arg(long = "rpc.rollup-node", help = "Enable the rollup node RPC namespace")]
756-
pub enabled: bool,
754+
/// A boolean to represent if the rollup node basic rpc should be enabled.
755+
#[arg(long = "rpc.rollup-node", default_value_t = true, action = ArgAction::Set, help = "Enable the rollup node basic RPC namespace(default: true)")]
756+
pub basic_enabled: bool,
757+
/// A boolean to represent if the rollup node admin rpc should be enabled.
758+
#[arg(long = "rpc.rollup-node-admin", help = "Enable the rollup node admin RPC namespace")]
759+
pub admin_enabled: bool,
757760
}
758761

759762
impl SignerArgs {

crates/node/src/test_utils/fixture.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ impl TestFixtureBuilder {
253253
gas_price_oracle_args: RollupNodeGasPriceOracleArgs::default(),
254254
consensus_args: ConsensusArgs::noop(),
255255
database: None,
256-
rpc_args: RpcArgs { enabled: true },
256+
rpc_args: RpcArgs { basic_enabled: true, admin_enabled: true },
257257
}
258258
}
259259

crates/node/src/test_utils/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ pub fn default_test_scroll_rollup_node_config() -> ScrollRollupNodeConfig {
239239
gas_price_oracle_args: crate::RollupNodeGasPriceOracleArgs::default(),
240240
consensus_args: ConsensusArgs::noop(),
241241
database: None,
242-
rpc_args: RpcArgs { enabled: true },
242+
rpc_args: RpcArgs { basic_enabled: true, admin_enabled: true },
243243
}
244244
}
245245

@@ -279,6 +279,6 @@ pub fn default_sequencer_test_scroll_rollup_node_config() -> ScrollRollupNodeCon
279279
gas_price_oracle_args: crate::RollupNodeGasPriceOracleArgs::default(),
280280
consensus_args: ConsensusArgs::noop(),
281281
database: None,
282-
rpc_args: RpcArgs { enabled: true },
282+
rpc_args: RpcArgs { basic_enabled: true, admin_enabled: true },
283283
}
284284
}

crates/node/tests/e2e.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rollup_node::{
2222
generate_tx, setup_engine, EventAssertions, NetworkHelperProvider, ReputationChecks,
2323
TestFixture,
2424
},
25-
RollupNodeContext, RollupNodeExtApiClient,
25+
RollupNodeAdminApiClient, RollupNodeContext,
2626
};
2727
use rollup_node_chain_orchestrator::ChainOrchestratorEvent;
2828
use rollup_node_primitives::{sig_encode_hash, BatchCommitData, BlockInfo};
@@ -1504,7 +1504,7 @@ async fn can_rpc_enable_disable_sequencing() -> eyre::Result<()> {
15041504

15051505
// Disable automatic sequencing via RPC
15061506
let client = fixture.sequencer().node.rpc_client().expect("Should have rpc client");
1507-
let result = RollupNodeExtApiClient::disable_automatic_sequencing(&client).await?;
1507+
let result = RollupNodeAdminApiClient::disable_automatic_sequencing(&client).await?;
15081508
assert!(result, "Disable automatic sequencing should return true");
15091509

15101510
// Wait a bit and verify no more blocks are produced automatically.
@@ -1532,7 +1532,7 @@ async fn can_rpc_enable_disable_sequencing() -> eyre::Result<()> {
15321532
fixture.expect_event_on(1).chain_extended(block_num_after_wait + 1).await?;
15331533

15341534
// Enable sequencing again
1535-
let result = RollupNodeExtApiClient::enable_automatic_sequencing(&client).await?;
1535+
let result = RollupNodeAdminApiClient::enable_automatic_sequencing(&client).await?;
15361536
assert!(result, "Enable automatic sequencing should return true");
15371537

15381538
// Make sure automatic sequencing resumes

0 commit comments

Comments
 (0)