Skip to content

Commit ee2fb78

Browse files
heemankvMohiiit
andauthored
Add --rpc-unsafe flag to protect dangerous admin RPC methods (#845)
Co-authored-by: mohiiit <[email protected]>
1 parent 92e603e commit ee2fb78

File tree

5 files changed

+37
-16
lines changed

5 files changed

+37
-16
lines changed

configs/args/config.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"rpc_external": false,
8383
"rpc_admin": false,
8484
"rpc_admin_external": false,
85+
"rpc_unsafe": false,
8586
"rpc_max_request_size": 15,
8687
"rpc_max_response_size": 15,
8788
"rpc_max_subscriptions_per_connection": 1024,

madara/crates/client/rpc/src/lib.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,7 @@ pub struct Starknet {
830830
storage_proof_config: StorageProofConfig,
831831
pub(crate) block_prod_handle: Option<mc_block_production::BlockProductionHandle>,
832832
pub ctx: ServiceContext,
833+
pub(crate) rpc_unsafe_enabled: bool,
833834
}
834835

835836
impl Starknet {
@@ -849,12 +850,17 @@ impl Starknet {
849850
block_prod_handle,
850851
ctx,
851852
pre_v0_9_preconfirmed_as_pending: false,
853+
rpc_unsafe_enabled: false,
852854
}
853855
}
854856

855857
pub fn set_pre_v0_9_preconfirmed_as_pending(&mut self, value: bool) {
856858
self.pre_v0_9_preconfirmed_as_pending = value;
857859
}
860+
861+
pub fn set_rpc_unsafe_enabled(&mut self, value: bool) {
862+
self.rpc_unsafe_enabled = value;
863+
}
858864
}
859865

860866
/// Returns the RpcModule merged with all the supported RPC versions.

madara/crates/client/rpc/src/versions/admin/v0_1_0/methods/write.rs

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use mp_rpc::v0_9_0::{
1111
};
1212
use mp_transactions::{L1HandlerTransactionResult, L1HandlerTransactionWithFee};
1313
use mp_block::header::CustomHeader;
14-
use mp_utils::service::MadaraServiceId;
1514

1615

1716
#[async_trait]
@@ -90,24 +89,24 @@ impl MadaraWriteRpcApiV0_1_0Server for Starknet {
9089
}
9190

9291
/// Force revert chain to a previous block by hash.
93-
/// Only works in full node mode.
92+
/// Only available when unsafe RPC methods are enabled.
9493
async fn revert_to(&self, block_hash: Felt) -> RpcResult<()> {
95-
// Only allow revert when in full node mode
96-
if self.ctx.service_status(MadaraServiceId::BlockProduction).is_off() {
97-
self.backend.revert_to(&block_hash).map_err(StarknetRpcApiError::from)?;
98-
// TODO(heemankv, 04-11-25): We should spend time in ruling out the two sources of truth problem for ChainTip
99-
// For now, we have to manually fetch Chain Tip from DB and update this in backend
100-
let fresh_chain_tip = self.backend.db.get_chain_tip().unwrap();
101-
let backend_chain_tip = mc_db::ChainTip::from_storage(fresh_chain_tip);
102-
self.backend.chain_tip.send_replace(backend_chain_tip);
103-
Ok(())
104-
} else {
105-
Err(StarknetRpcApiError::ErrUnexpectedError {
106-
error: "This method is only available in full node mode".to_string().into()
107-
})?
94+
// Check if unsafe RPC methods are enabled
95+
if !self.rpc_unsafe_enabled {
96+
return Err(StarknetRpcApiError::ErrUnexpectedError {
97+
error: "This method requires the --rpc-unsafe flag to be enabled".to_string().into()
98+
}.into());
10899
}
100+
101+
self.backend.revert_to(&block_hash).map_err(StarknetRpcApiError::from)?;
102+
let fresh_chain_tip = self.backend.db.get_chain_tip()
103+
.context("Failed to get chain tip after revert")
104+
.map_err(StarknetRpcApiError::from)?;
105+
let backend_chain_tip = mc_db::ChainTip::from_storage(fresh_chain_tip);
106+
self.backend.chain_tip.send_replace(backend_chain_tip);
107+
Ok(())
109108
}
110-
109+
111110
async fn add_l1_handler_message(
112111
&self,
113112
l1_handler_message: L1HandlerTransactionWithFee,
@@ -122,6 +121,13 @@ impl MadaraWriteRpcApiV0_1_0Server for Starknet {
122121
}
123122

124123
async fn set_block_header(&self, custom_block_headers: CustomHeader) -> RpcResult<()> {
124+
// Check if unsafe RPC methods are enabled
125+
if !self.rpc_unsafe_enabled {
126+
return Err(StarknetRpcApiError::ErrUnexpectedError {
127+
error: "This method requires the --rpc-unsafe flag to be enabled".to_string().into()
128+
}.into());
129+
}
130+
125131
self.backend.set_custom_header(custom_block_headers);
126132
Ok(())
127133
}

madara/node/src/cli/rpc.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ pub struct RpcParams {
9191
#[arg(env = "MADARA_RPC_ADMIN_EXTERNAL", long, default_value_t = false)]
9292
pub rpc_admin_external: bool,
9393

94+
/// Enables unsafe admin RPC methods. This includes dangerous methods like
95+
/// `revertTo` and `setCustomBlockHeader` that can modify the blockchain state.
96+
/// Use with extreme caution. Requires `--rpc-admin` to be enabled.
97+
#[arg(env = "MADARA_RPC_UNSAFE", long, default_value_t = false, requires = "rpc_admin")]
98+
pub rpc_unsafe: bool,
99+
94100
/// Set the maximum RPC request payload size for both HTTP and WebSockets in mebibytes.
95101
#[arg(env = "MADARA_RPC_MAX_REQUEST_SIZE", long, default_value_t = RPC_DEFAULT_MAX_REQUEST_SIZE_MIB)]
96102
pub rpc_max_request_size: u32,

madara/node/src/service/rpc/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ impl Service for RpcService {
7676
let block_prod_handle = self.block_prod_handle.clone();
7777

7878
let pre_v0_9_preconfirmed_as_pending = self.config.rpc_pre_v0_9_preconfirmed_as_pending;
79+
let rpc_unsafe_enabled = self.config.rpc_unsafe;
7980

8081
runner.service_loop(move |ctx| async move {
8182
let submit_tx = Arc::new(submit_tx_provider.make(ctx.clone()));
@@ -88,6 +89,7 @@ impl Service for RpcService {
8889
ctx.clone(),
8990
);
9091
starknet.set_pre_v0_9_preconfirmed_as_pending(pre_v0_9_preconfirmed_as_pending);
92+
starknet.set_rpc_unsafe_enabled(rpc_unsafe_enabled);
9193

9294
let metrics = RpcMetrics::register()?;
9395

0 commit comments

Comments
 (0)