1mod auth_layer;
5mod channel;
6mod client;
7mod compression_layer;
8mod error;
9mod filter_layer;
10mod filter_list;
11pub mod json_validator;
12mod log_layer;
13mod metrics_layer;
14mod parallel_batch_layer;
15mod reflect;
16mod registry;
17mod request;
18mod segregation_layer;
19mod set_extension_layer;
20pub mod types;
21mod validation_layer;
22
23use crate::db::DbImpl;
24use crate::prelude::*;
25use crate::rpc::eth::types::RandomHexStringIdProvider;
26use crate::rpc::methods::eth::pubsub_trait::EthPubSubApiServer;
27use crate::shim::clock::ChainEpoch;
28use ahash::HashMap;
29use clap::ValueEnum as _;
30pub use client::Client;
31pub use error::ServerError;
32use eth::filter::EthEventHandler;
33use filter_layer::FilterLayer;
34pub use filter_list::FilterList;
35use futures::future::Either;
36use jsonrpsee::server::ServerConfig;
37use log_layer::LogLayer;
38pub use metrics_layer::MetricsMode;
39use parallel_batch_layer::ParallelBatchLayer;
40use reflect::Ctx;
41pub use reflect::{ApiPaths, Permission, RpcMethod, RpcMethodExt};
42pub use request::Request;
43use schemars::Schema;
44use segregation_layer::SegregationLayer;
45use set_extension_layer::SetExtensionLayer;
46
47pub use methods::*;
48
49pub use jsonrpsee::core::ClientError;
51
52pub const LOOKBACK_NO_LIMIT: ChainEpoch = -1;
54
55#[macro_export]
63macro_rules! for_each_rpc_method {
64 ($callback:path) => {
65 $callback!($crate::rpc::auth::AuthNew);
67 $callback!($crate::rpc::auth::AuthVerify);
68
69 $callback!($crate::rpc::beacon::BeaconGetEntry);
71
72 $callback!($crate::rpc::chain::ChainPruneSnapshot);
74 $callback!($crate::rpc::chain::ChainExport);
75 $callback!($crate::rpc::chain::ChainGetBlock);
76 $callback!($crate::rpc::chain::ChainGetBlockMessages);
77 $callback!($crate::rpc::chain::ChainGetEvents);
78 $callback!($crate::rpc::chain::ChainGetGenesis);
79 $callback!($crate::rpc::chain::ChainGetFinalizedTipset);
80 $callback!($crate::rpc::chain::ChainGetMessage);
81 $callback!($crate::rpc::chain::ChainGetMessagesInTipset);
82 $callback!($crate::rpc::chain::ChainGetMinBaseFee);
83 $callback!($crate::rpc::chain::ChainGetParentMessages);
84 $callback!($crate::rpc::chain::ChainGetParentReceipts);
85 $callback!($crate::rpc::chain::ChainGetPath);
86 $callback!($crate::rpc::chain::ChainGetTipSet);
87 $callback!($crate::rpc::chain::ChainGetTipSetV2);
88 $callback!($crate::rpc::chain::ChainGetTipSetFinalityStatus);
89 $callback!($crate::rpc::chain::ChainGetTipSetAfterHeight);
90 $callback!($crate::rpc::chain::ChainGetTipSetByHeight);
91 $callback!($crate::rpc::chain::ChainHasObj);
92 $callback!($crate::rpc::chain::ChainHead);
93 $callback!($crate::rpc::chain::ChainReadObj);
94 $callback!($crate::rpc::chain::ChainSetHead);
95 $callback!($crate::rpc::chain::ChainStatObj);
96 $callback!($crate::rpc::chain::ChainTipSetWeight);
97 $callback!($crate::rpc::chain::ForestChainExport);
98 $callback!($crate::rpc::chain::ForestChainExportDiff);
99 $callback!($crate::rpc::chain::ForestChainExportStatus);
100 $callback!($crate::rpc::chain::ForestChainExportCancel);
101 $callback!($crate::rpc::chain::ChainGetTipsetByParentState);
102
103 $callback!($crate::rpc::common::Session);
105 $callback!($crate::rpc::common::Shutdown);
106 $callback!($crate::rpc::common::StartTime);
107 $callback!($crate::rpc::common::Version);
108
109 $callback!($crate::rpc::eth::EthAccounts);
111 $callback!($crate::rpc::eth::EthAddressToFilecoinAddress);
112 $callback!($crate::rpc::eth::FilecoinAddressToEthAddress);
113 $callback!($crate::rpc::eth::EthBaseFee);
114 $callback!($crate::rpc::eth::BaseFeeByHeight);
115 $callback!($crate::rpc::eth::EthBlockNumber);
116 $callback!($crate::rpc::eth::EthCall);
117 $callback!($crate::rpc::eth::EthChainId);
118 $callback!($crate::rpc::eth::EthEstimateGas);
119 $callback!($crate::rpc::eth::EthFeeHistory);
120 $callback!($crate::rpc::eth::EthGasPrice);
121 $callback!($crate::rpc::eth::EthGetBalance);
122 $callback!($crate::rpc::eth::EthGetBlockByHash);
123 $callback!($crate::rpc::eth::EthGetBlockByNumber);
124 $callback!($crate::rpc::eth::EthGetBlockReceipts);
125 $callback!($crate::rpc::eth::EthGetBlockReceiptsLimited);
126 $callback!($crate::rpc::eth::EthGetBlockTransactionCountByHash);
127 $callback!($crate::rpc::eth::EthGetBlockTransactionCountByNumber);
128 $callback!($crate::rpc::eth::EthGetCode);
129 $callback!($crate::rpc::eth::EthGetLogs);
130 $callback!($crate::rpc::eth::EthGetFilterLogs);
131 $callback!($crate::rpc::eth::EthGetFilterChanges);
132 $callback!($crate::rpc::eth::EthGetMessageCidByTransactionHash);
133 $callback!($crate::rpc::eth::EthGetStorageAt);
134 $callback!($crate::rpc::eth::EthGetTransactionByHash);
135 $callback!($crate::rpc::eth::EthGetTransactionByHashLimited);
136 $callback!($crate::rpc::eth::EthGetTransactionCount);
137 $callback!($crate::rpc::eth::EthGetTransactionHashByCid);
138 $callback!($crate::rpc::eth::EthGetTransactionByBlockNumberAndIndex);
139 $callback!($crate::rpc::eth::EthGetTransactionByBlockHashAndIndex);
140 $callback!($crate::rpc::eth::EthMaxPriorityFeePerGas);
141 $callback!($crate::rpc::eth::EthProtocolVersion);
142 $callback!($crate::rpc::eth::EthGetTransactionReceipt);
143 $callback!($crate::rpc::eth::EthGetTransactionReceiptLimited);
144 $callback!($crate::rpc::eth::EthNewFilter);
145 $callback!($crate::rpc::eth::EthNewPendingTransactionFilter);
146 $callback!($crate::rpc::eth::EthNewBlockFilter);
147 $callback!($crate::rpc::eth::EthUninstallFilter);
148 $callback!($crate::rpc::eth::EthUnsubscribe);
149 $callback!($crate::rpc::eth::EthSubscribe);
150 $callback!($crate::rpc::eth::EthSyncing);
151 $callback!($crate::rpc::eth::EthTraceBlock);
152 $callback!($crate::rpc::eth::EthTraceCall);
153 $callback!($crate::rpc::eth::EthTraceFilter);
154 $callback!($crate::rpc::eth::EthTraceTransaction);
155 $callback!($crate::rpc::eth::EthDebugTraceTransaction);
156 $callback!($crate::rpc::eth::EthTraceReplayBlockTransactions);
157 $callback!($crate::rpc::eth::Web3ClientVersion);
158 $callback!($crate::rpc::eth::EthSendRawTransaction);
159 $callback!($crate::rpc::eth::EthSendRawTransactionUntrusted);
160
161 $callback!($crate::rpc::gas::GasEstimateFeeCap);
163 $callback!($crate::rpc::gas::GasEstimateGasLimit);
164 $callback!($crate::rpc::gas::GasEstimateGasPremium);
165 $callback!($crate::rpc::gas::GasEstimateMessageGas);
166
167 $callback!($crate::rpc::market::MarketAddBalance);
169
170 $callback!($crate::rpc::miner::MinerCreateBlock);
172 $callback!($crate::rpc::miner::MinerGetBaseInfo);
173
174 $callback!($crate::rpc::mpool::MpoolBatchPush);
176 $callback!($crate::rpc::mpool::MpoolBatchPushUntrusted);
177 $callback!($crate::rpc::mpool::MpoolGetConfig);
178 $callback!($crate::rpc::mpool::MpoolGetNonce);
179 $callback!($crate::rpc::mpool::MpoolPending);
180 $callback!($crate::rpc::mpool::MpoolPush);
181 $callback!($crate::rpc::mpool::MpoolPushMessage);
182 $callback!($crate::rpc::mpool::MpoolPushUntrusted);
183 $callback!($crate::rpc::mpool::MpoolSelect);
184
185 $callback!($crate::rpc::msig::MsigGetAvailableBalance);
187 $callback!($crate::rpc::msig::MsigGetPending);
188 $callback!($crate::rpc::msig::MsigGetVested);
189 $callback!($crate::rpc::msig::MsigGetVestingSchedule);
190
191 $callback!($crate::rpc::net::NetAddrsListen);
193 $callback!($crate::rpc::net::NetAgentVersion);
194 $callback!($crate::rpc::net::NetAutoNatStatus);
195 $callback!($crate::rpc::net::NetConnect);
196 $callback!($crate::rpc::net::NetDisconnect);
197 $callback!($crate::rpc::net::NetFindPeer);
198 $callback!($crate::rpc::net::NetInfo);
199 $callback!($crate::rpc::net::NetListening);
200 $callback!($crate::rpc::net::NetPeers);
201 $callback!($crate::rpc::net::NetProtectAdd);
202 $callback!($crate::rpc::net::NetProtectList);
203 $callback!($crate::rpc::net::NetProtectRemove);
204 $callback!($crate::rpc::net::NetVersion);
205 $callback!($crate::rpc::net::NetChainExchange);
206
207 $callback!($crate::rpc::node::NodeStatus);
209
210 $callback!($crate::rpc::state::StateAccountKey);
212 $callback!($crate::rpc::state::StateCall);
213 $callback!($crate::rpc::state::StateCirculatingSupply);
214 $callback!($crate::rpc::state::ForestStateCompute);
215 $callback!($crate::rpc::state::StateCompute);
216 $callback!($crate::rpc::state::StateDealProviderCollateralBounds);
217 $callback!($crate::rpc::state::StateFetchRoot);
218 $callback!($crate::rpc::state::StateGetActor);
219 $callback!($crate::rpc::state::StateGetActorV2);
220 $callback!($crate::rpc::state::StateGetID);
221 $callback!($crate::rpc::state::StateGetAllAllocations);
222 $callback!($crate::rpc::state::StateGetAllClaims);
223 $callback!($crate::rpc::state::StateGetAllocation);
224 $callback!($crate::rpc::state::StateGetAllocationForPendingDeal);
225 $callback!($crate::rpc::state::StateGetAllocationIdForPendingDeal);
226 $callback!($crate::rpc::state::StateGetAllocations);
227 $callback!($crate::rpc::state::StateGetBeaconEntry);
228 $callback!($crate::rpc::state::StateGetClaim);
229 $callback!($crate::rpc::state::StateGetClaims);
230 $callback!($crate::rpc::state::StateGetNetworkParams);
231 $callback!($crate::rpc::state::StateGetRandomnessDigestFromBeacon);
232 $callback!($crate::rpc::state::StateGetRandomnessDigestFromTickets);
233 $callback!($crate::rpc::state::StateGetRandomnessFromBeacon);
234 $callback!($crate::rpc::state::StateGetRandomnessFromTickets);
235 $callback!($crate::rpc::state::StateGetReceipt);
236 $callback!($crate::rpc::state::StateListActors);
237 $callback!($crate::rpc::state::StateListMessages);
238 $callback!($crate::rpc::state::StateListMiners);
239 $callback!($crate::rpc::state::StateLookupID);
240 $callback!($crate::rpc::state::StateLookupRobustAddress);
241 $callback!($crate::rpc::state::StateMarketBalance);
242 $callback!($crate::rpc::state::StateMarketDeals);
243 $callback!($crate::rpc::state::StateMarketParticipants);
244 $callback!($crate::rpc::state::StateMarketStorageDeal);
245 $callback!($crate::rpc::state::StateMinerActiveSectors);
246 $callback!($crate::rpc::state::StateMinerAllocated);
247 $callback!($crate::rpc::state::StateMinerAvailableBalance);
248 $callback!($crate::rpc::state::StateMinerDeadlines);
249 $callback!($crate::rpc::state::StateMinerFaults);
250 $callback!($crate::rpc::state::StateMinerInfo);
251 $callback!($crate::rpc::state::StateMinerInitialPledgeCollateral);
252 $callback!($crate::rpc::state::StateMinerPartitions);
253 $callback!($crate::rpc::state::StateMinerPower);
254 $callback!($crate::rpc::state::StateMinerPreCommitDepositForPower);
255 $callback!($crate::rpc::state::StateMinerProvingDeadline);
256 $callback!($crate::rpc::state::StateMinerRecoveries);
257 $callback!($crate::rpc::state::StateMinerSectorAllocated);
258 $callback!($crate::rpc::state::StateMinerSectorCount);
259 $callback!($crate::rpc::state::StateMinerSectors);
260 $callback!($crate::rpc::state::StateNetworkName);
261 $callback!($crate::rpc::state::StateNetworkVersion);
262 $callback!($crate::rpc::state::StateActorInfo);
263 $callback!($crate::rpc::state::StateReadState);
264 $callback!($crate::rpc::state::StateDecodeParams);
265 $callback!($crate::rpc::state::StateReplay);
266 $callback!($crate::rpc::state::StateSearchMsg);
267 $callback!($crate::rpc::state::StateSearchMsgLimited);
268 $callback!($crate::rpc::state::StateSectorExpiration);
269 $callback!($crate::rpc::state::StateSectorGetInfo);
270 $callback!($crate::rpc::state::StateSectorPartition);
271 $callback!($crate::rpc::state::StateSectorPreCommitInfo);
272 $callback!($crate::rpc::state::StateSectorPreCommitInfoV0);
273 $callback!($crate::rpc::state::StateVerifiedClientStatus);
274 $callback!($crate::rpc::state::StateVerifiedRegistryRootKey);
275 $callback!($crate::rpc::state::StateVerifierStatus);
276 $callback!($crate::rpc::state::StateVMCirculatingSupplyInternal);
277 $callback!($crate::rpc::state::StateWaitMsg);
278 $callback!($crate::rpc::state::StateWaitMsgV0);
279 $callback!($crate::rpc::state::StateMinerInitialPledgeForSector);
280
281 $callback!($crate::rpc::sync::SyncCheckBad);
283 $callback!($crate::rpc::sync::SyncMarkBad);
284 $callback!($crate::rpc::sync::SyncSnapshotProgress);
285 $callback!($crate::rpc::sync::SyncStatus);
286 $callback!($crate::rpc::sync::SyncSubmitBlock);
287
288 $callback!($crate::rpc::wallet::WalletBalance);
290 $callback!($crate::rpc::wallet::WalletDefaultAddress);
291 $callback!($crate::rpc::wallet::WalletDelete);
292 $callback!($crate::rpc::wallet::WalletExport);
293 $callback!($crate::rpc::wallet::WalletHas);
294 $callback!($crate::rpc::wallet::WalletImport);
295 $callback!($crate::rpc::wallet::WalletList);
296 $callback!($crate::rpc::wallet::WalletNew);
297 $callback!($crate::rpc::wallet::WalletSetDefault);
298 $callback!($crate::rpc::wallet::WalletSign);
299 $callback!($crate::rpc::wallet::WalletSignMessage);
300 $callback!($crate::rpc::wallet::WalletValidateAddress);
301 $callback!($crate::rpc::wallet::WalletVerify);
302
303 $callback!($crate::rpc::f3::GetRawNetworkName);
305 $callback!($crate::rpc::f3::F3GetCertificate);
306 $callback!($crate::rpc::f3::F3GetECPowerTable);
307 $callback!($crate::rpc::f3::F3GetF3PowerTable);
308 $callback!($crate::rpc::f3::F3GetF3PowerTableByInstance);
309 $callback!($crate::rpc::f3::F3IsRunning);
310 $callback!($crate::rpc::f3::F3GetProgress);
311 $callback!($crate::rpc::f3::F3GetManifest);
312 $callback!($crate::rpc::f3::F3ListParticipants);
313 $callback!($crate::rpc::f3::F3GetLatestCertificate);
314 $callback!($crate::rpc::f3::F3GetOrRenewParticipationTicket);
315 $callback!($crate::rpc::f3::F3Participate);
316 $callback!($crate::rpc::f3::F3ExportLatestSnapshot);
317 $callback!($crate::rpc::f3::GetHead);
318 $callback!($crate::rpc::f3::GetParent);
319 $callback!($crate::rpc::f3::GetParticipatingMinerIDs);
320 $callback!($crate::rpc::f3::GetPowerTable);
321 $callback!($crate::rpc::f3::GetTipset);
322 $callback!($crate::rpc::f3::GetTipsetByEpoch);
323 $callback!($crate::rpc::f3::Finalize);
324 $callback!($crate::rpc::f3::ProtectPeer);
325 $callback!($crate::rpc::f3::SignMessage);
326
327 $callback!($crate::rpc::misc::GetActorEventsRaw);
329 };
330}
331use compression_layer::{COMPRESS_MIN_BODY_SIZE, CompressionLayer};
332pub(crate) use for_each_rpc_method;
333use sync::SnapshotProgressTracker;
334use tower_http::sensitive_headers::SetSensitiveRequestHeadersLayer;
335
336#[allow(unused)]
337pub mod prelude {
349 use super::*;
350
351 pub use reflect::RpcMethodExt as _;
352
353 macro_rules! export {
354 ($ty:ty) => {
355 pub use $ty;
356 };
357 }
358
359 for_each_rpc_method!(export);
360}
361
362pub fn collect_rpc_method_info() -> Vec<(&'static str, Permission)> {
364 use crate::rpc::RpcMethod;
365
366 let mut methods = Vec::new();
367
368 macro_rules! add_method {
369 ($ty:ty) => {
370 methods.push((<$ty>::NAME, <$ty>::PERMISSION));
371 };
372 }
373
374 for_each_rpc_method!(add_method);
375
376 methods
377}
378
379mod methods {
416 pub mod auth;
417 pub mod beacon;
418 pub mod chain;
419 pub mod common;
420 pub mod eth;
421 pub mod f3;
422 pub mod gas;
423 pub mod market;
424 pub mod miner;
425 pub mod misc;
426 pub mod mpool;
427 pub mod msig;
428 pub mod net;
429 pub mod node;
430 pub mod state;
431 pub mod sync;
432 pub mod wallet;
433}
434
435use crate::rpc::auth_layer::{AuthLayer, resolve_claims};
436pub use crate::rpc::channel::CANCEL_METHOD_NAME;
437use crate::rpc::channel::RpcModule as FilRpcModule;
438use crate::rpc::eth::pubsub::EthPubSub;
439use crate::rpc::metrics_layer::MetricsLayer;
440use crate::{chain_sync::network_context::SyncNetworkContext, key_management::KeyStore};
441
442use crate::blocks::FullTipset;
443use crate::utils::misc::env::env_or_default;
444use jsonrpsee::{
445 Methods,
446 core::middleware::RpcServiceBuilder,
447 server::{RpcModule, Server, StopHandle, TowerServiceBuilder},
448};
449use parking_lot::RwLock;
450use std::env;
451use std::sync::{Arc, LazyLock};
452use std::time::Duration;
453use tokio::sync::mpsc;
454use tower::Service;
455
456use crate::rpc::sync::SnapshotProgressState;
457use openrpc_types::{self, ParamStructure};
458
459pub const DEFAULT_PORT: u16 = 2345;
460
461static DEFAULT_REQUEST_TIMEOUT: LazyLock<Duration> = LazyLock::new(|| {
463 env::var("FOREST_RPC_DEFAULT_TIMEOUT")
464 .ok()
465 .and_then(|it| Duration::from_secs(it.parse().ok()?).into())
466 .unwrap_or(Duration::from_secs(60))
467});
468
469pub fn default_max_connections() -> u32 {
475 static VALUE: LazyLock<u32> = LazyLock::new(|| {
476 env::var("FOREST_RPC_MAX_CONNECTIONS")
477 .ok()
478 .and_then(|it| it.parse().ok())
479 .unwrap_or(1000)
480 });
481 *VALUE
482}
483
484const MAX_REQUEST_BODY_SIZE: u32 = 64 * 1024 * 1024;
485
486static MAX_RESPONSE_BODY_SIZE: LazyLock<u32> =
493 LazyLock::new(|| env_or_default("FOREST_RPC_MAX_RESPONSE_BODY_SIZE", MAX_REQUEST_BODY_SIZE));
494
495pub struct RPCState {
498 pub keystore: Arc<RwLock<KeyStore>>,
499 pub state_manager: crate::state_manager::StateManager,
500 pub mpool: crate::message_pool::MessagePool<crate::chain::ChainStore>,
501 pub bad_blocks: Option<crate::chain_sync::BadBlockCache>,
502 pub sync_status: crate::chain_sync::SyncStatus,
503 pub eth_event_handler: Arc<EthEventHandler>,
504 pub eth_logs_feed: std::sync::OnceLock<eth::pubsub::LogsFeed>,
505 pub sync_network_context: SyncNetworkContext,
506 pub tipset_send: flume::Sender<FullTipset>,
507 pub start_time: chrono::DateTime<chrono::Utc>,
508 pub snapshot_progress_tracker: SnapshotProgressTracker,
509 pub shutdown: mpsc::Sender<()>,
510 pub mpool_locker: crate::message_pool::MpoolLocker,
511 pub nonce_tracker: crate::message_pool::NonceTracker,
512 pub temp_dir: Arc<std::path::PathBuf>,
513}
514
515impl RPCState {
516 pub fn beacon(&self) -> &Arc<crate::beacon::BeaconSchedule> {
517 self.state_manager.beacon_schedule()
518 }
519
520 pub fn chain_store(&self) -> &crate::chain::ChainStore {
521 self.state_manager.chain_store()
522 }
523
524 pub fn chain_index(&self) -> &crate::chain::index::ChainIndex {
525 self.chain_store().chain_index()
526 }
527
528 pub fn chain_config(&self) -> &Arc<crate::networks::ChainConfig> {
529 self.state_manager.chain_config()
530 }
531
532 pub fn db(&self) -> &DbImpl {
533 self.state_manager.db()
534 }
535
536 pub fn db_owned(&self) -> DbImpl {
537 self.state_manager.db_owned()
538 }
539
540 pub fn network_send(&self) -> &flume::Sender<crate::libp2p::NetworkMessage> {
541 self.sync_network_context.network_send()
542 }
543
544 pub fn get_snapshot_progress_tracker(&self) -> SnapshotProgressState {
545 self.snapshot_progress_tracker.state()
546 }
547}
548
549#[derive(Clone)]
550struct PerConnection<RpcMiddleware, HttpMiddleware> {
551 stop_handle: StopHandle,
552 svc_builder: Arc<TowerServiceBuilder<RpcMiddleware, HttpMiddleware>>,
553 keystore: Arc<RwLock<KeyStore>>,
554}
555
556fn bare_http_response<B: Default>(status: http::StatusCode) -> http::Response<B> {
558 http::Response::builder()
559 .status(status)
560 .body(B::default())
561 .unwrap_or_else(|_| http::Response::new(B::default()))
562}
563
564pub async fn start_rpc(
565 state: RPCState,
566 rpc_listener: tokio::net::TcpListener,
567 stop_handle: StopHandle,
568 filter_list: Option<Arc<FilterList>>,
569 metrics_mode: MetricsMode,
570) -> anyhow::Result<()> {
571 let filter_list = filter_list.unwrap_or_default();
572 let state = Arc::new(state);
574 let keystore = state.keystore.shallow_clone();
575 let mut modules = create_modules(state.shallow_clone());
576
577 let mut pubsub_module = FilRpcModule::default();
578 pubsub_module.register_channel("Filecoin.ChainNotify", {
579 let state_clone = state.shallow_clone();
580 move |params| chain::chain_notify(params, &state_clone)
581 })?;
582
583 for module in modules.values_mut() {
584 module.merge(EthPubSub::new(state.shallow_clone()).into_rpc())?;
586 module.merge(pubsub_module.clone())?;
587 }
588
589 let methods: Arc<HashMap<ApiPaths, Methods>> =
590 Arc::new(modules.into_iter().map(|(k, v)| (k, v.into())).collect());
591
592 let server_config = ServerConfig::builder()
593 .max_request_body_size(MAX_REQUEST_BODY_SIZE)
594 .max_response_body_size(*MAX_RESPONSE_BODY_SIZE)
596 .max_connections(default_max_connections())
597 .set_id_provider(RandomHexStringIdProvider::new())
598 .build();
599 let max_response_body_size = *MAX_RESPONSE_BODY_SIZE as usize;
600 let per_conn = PerConnection {
601 stop_handle: stop_handle.clone(),
602 svc_builder: Server::builder()
603 .set_config(server_config)
604 .set_http_middleware(
605 tower::ServiceBuilder::new()
606 .option_layer(COMPRESS_MIN_BODY_SIZE.map(CompressionLayer::new))
607 .layer(SetSensitiveRequestHeadersLayer::new(std::iter::once(
609 http::header::AUTHORIZATION,
610 ))),
611 )
612 .to_service_builder()
613 .into(),
614 keystore,
615 };
616 tracing::info!("Ready for RPC connections");
617 loop {
618 let sock = tokio::select! {
619 res = rpc_listener.accept() => {
620 match res {
621 Ok((stream, _remote_addr)) => {
622 let _ = stream.set_nodelay(true); stream
624 }
625 Err(e) => {
626 tracing::error!("failed to accept v4 connection: {:?}", e);
627 continue;
628 }
629 }
630 }
631 _ = per_conn.stop_handle.clone().shutdown() => break,
632 };
633
634 let svc = tower::service_fn({
635 let methods = methods.shallow_clone();
636 let per_conn = per_conn.clone();
637 let filter_list = filter_list.shallow_clone();
638 move |req: http::Request<_>| {
639 let svc_or_result = if let Ok(path) = ApiPaths::from_uri(req.uri()) {
640 let methods = methods.get(&path).cloned().unwrap_or_default();
641 let PerConnection {
642 stop_handle,
643 svc_builder,
644 keystore,
645 } = per_conn.clone();
646 match resolve_claims(&keystore, req.headers().get(http::header::AUTHORIZATION))
650 {
651 Ok(claims) => {
652 let rpc_middleware = RpcServiceBuilder::new()
655 .layer(SetExtensionLayer { path })
656 .layer(SegregationLayer)
657 .layer(FilterLayer::new(filter_list.shallow_clone()))
658 .layer(validation_layer::JsonValidationLayer)
659 .layer(AuthLayer::new(claims))
660 .layer(LogLayer::default())
661 .layer(ParallelBatchLayer::new(max_response_body_size))
665 .layer(MetricsLayer::new(metrics_mode));
666 Either::Left(
667 Arc::unwrap_or_clone(svc_builder)
668 .set_rpc_middleware(rpc_middleware)
669 .build(methods, stop_handle),
670 )
671 }
672 Err(reason) => {
673 tracing::debug!("rejecting unauthorized request: {reason}");
674 Either::Right(Ok(bare_http_response(http::StatusCode::UNAUTHORIZED)))
675 }
676 }
677 } else {
678 Either::Right(Ok(bare_http_response(http::StatusCode::NOT_FOUND)))
679 };
680 async move {
681 match svc_or_result {
682 Either::Left(mut svc) => {
683 svc.call(req).await.map_err(|e| anyhow::anyhow!("{:?}", e))
687 }
688 Either::Right(result) => result,
689 }
690 }
691 }
692 });
693
694 tokio::spawn(jsonrpsee::server::serve_with_graceful_shutdown(
695 sock,
696 svc,
697 stop_handle.clone().shutdown(),
698 ));
699 }
700
701 Ok(())
702}
703
704fn create_modules(state: Arc<RPCState>) -> HashMap<ApiPaths, RpcModule<RPCState>> {
705 let mut modules = HashMap::default();
706 for api_version in ApiPaths::value_variants() {
707 modules.insert(*api_version, RpcModule::from_arc(state.shallow_clone()));
708 }
709 macro_rules! register {
710 ($ty:ty) => {
711 if !<$ty>::SUBSCRIPTION {
714 <$ty>::register(&mut modules, ParamStructure::ByPosition).unwrap();
715 }
716 };
717 }
718 for_each_rpc_method!(register);
719 modules
720}
721
722pub fn openrpc(path: ApiPaths, include: Option<&[&str]>) -> openrpc_types::OpenRPC {
724 use schemars::generate::{SchemaGenerator, SchemaSettings};
725
726 let mut methods = vec![];
727 let mut settings = SchemaSettings::draft07();
729 settings.definitions_path = "#/components/schemas/".into();
731 let mut generator = SchemaGenerator::new(settings);
732 macro_rules! callback {
733 ($ty:ty) => {
734 if <$ty>::API_PATHS.contains(path) {
735 match include {
736 Some(include) => match include.contains(&<$ty>::NAME) {
737 true => {
738 methods.push(openrpc_types::ReferenceOr::Item(<$ty>::openrpc(
739 &mut generator,
740 ParamStructure::ByPosition,
741 &<$ty>::NAME,
742 )));
743 if let Some(alias) = &<$ty>::NAME_ALIAS {
744 methods.push(openrpc_types::ReferenceOr::Item(<$ty>::openrpc(
745 &mut generator,
746 ParamStructure::ByPosition,
747 &alias,
748 )));
749 }
750 }
751 false => {}
752 },
753 None => {
754 methods.push(openrpc_types::ReferenceOr::Item(<$ty>::openrpc(
755 &mut generator,
756 ParamStructure::ByPosition,
757 &<$ty>::NAME,
758 )));
759 if let Some(alias) = &<$ty>::NAME_ALIAS {
760 methods.push(openrpc_types::ReferenceOr::Item(<$ty>::openrpc(
761 &mut generator,
762 ParamStructure::ByPosition,
763 &alias,
764 )));
765 }
766 }
767 }
768 }
769 };
770 }
771 for_each_rpc_method!(callback);
772 openrpc_types::OpenRPC {
773 methods,
774 components: Some(openrpc_types::Components {
775 schemas: Some(
776 generator
777 .take_definitions(false)
778 .into_iter()
779 .filter_map(|(k, v)| {
780 if let Ok(v) = Schema::try_from(v) {
781 Some((k, v))
782 } else {
783 None
784 }
785 })
786 .collect(),
787 ),
788 ..Default::default()
789 }),
790 openrpc: openrpc_types::OPEN_RPC_SPECIFICATION_VERSION,
791 info: openrpc_types::Info {
792 title: String::from("forest"),
793 version: env!("CARGO_PKG_VERSION").into(),
794 ..Default::default()
795 },
796 ..Default::default()
797 }
798}
799
800#[cfg(test)]
801mod tests {
802 use super::*;
803 use crate::{
804 db::MemoryDB,
805 networks::NetworkChain,
806 rpc::{client::UrlClient, common::ShiftingVersion},
807 tool::offline_server::server::offline_rpc_state,
808 };
809 use jsonrpsee::{
810 core::{
811 client::{BatchResponse, ClientT},
812 params::BatchRequestBuilder,
813 },
814 server::stop_channel,
815 };
816 use std::net::{Ipv4Addr, SocketAddr};
817 use tokio::task::JoinSet;
818
819 #[test]
824 fn openrpc_v0() {
825 openrpc(ApiPaths::V0);
826 }
827
828 #[test]
829 fn openrpc_v1() {
830 openrpc(ApiPaths::V1);
831 }
832
833 #[test]
834 fn openrpc_v2() {
835 openrpc(ApiPaths::V2);
836 }
837
838 fn openrpc(path: ApiPaths) {
839 let spec = super::openrpc(path, None);
840 insta::assert_yaml_snapshot!(path.path(), spec);
841 }
842
843 #[test]
844 fn test_rpc_server() {
845 const TIMEOUT: Duration = Duration::from_secs(5);
846 let (done_tx, done_rx) = flume::bounded(1);
847 let rt = tokio::runtime::Builder::new_multi_thread()
848 .enable_all()
849 .build()
850 .unwrap();
851 rt.block_on(async move { test_rpc_server_inner(done_tx).await });
852 done_rx.recv().unwrap();
853 rt.shutdown_timeout(TIMEOUT);
855 }
856
857 async fn test_rpc_server_inner(done_tx: flume::Sender<()>) {
858 let chain = NetworkChain::Calibnet;
859 let db = Arc::new(MemoryDB::default());
860 let mut services = JoinSet::new();
861 let (state, mut shutdown_recv) = offline_rpc_state(chain, db, None, None, &mut services)
862 .await
863 .unwrap();
864 let block_delay_secs = state.chain_config().block_delay_secs;
865 let shutdown_send = state.shutdown.clone();
866 let jwt_read_permissions = vec!["read".to_owned()];
867 let jwt_read = super::methods::auth::AuthNew::create_token(
868 &state.keystore.read(),
869 chrono::Duration::hours(1),
870 jwt_read_permissions.clone(),
871 )
872 .unwrap();
873 let rpc_listener =
874 tokio::net::TcpListener::bind(SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 0))
875 .await
876 .unwrap();
877 let rpc_address = rpc_listener.local_addr().unwrap();
878 let (stop_handle, server_handle) = stop_channel();
879
880 let handle = tokio::spawn(start_rpc(
883 state,
884 rpc_listener,
885 stop_handle,
886 None,
887 MetricsMode::Enabled,
888 ));
889
890 println!("sending a few http requests");
891
892 let client = Client::from_url(
893 format!("http://{}:{}/", rpc_address.ip(), rpc_address.port())
894 .parse()
895 .unwrap(),
896 );
897
898 let response = super::methods::common::Version::call(&client, ())
899 .await
900 .unwrap();
901 assert_eq!(
902 &response.version,
903 &*crate::utils::version::FOREST_VERSION_STRING
904 );
905 assert_eq!(response.block_delay, block_delay_secs);
906 assert_eq!(response.api_version, ShiftingVersion::new(2, 3, 0));
907
908 let response = super::methods::auth::AuthVerify::call(&client, (jwt_read.clone(),))
909 .await
910 .unwrap();
911 assert_eq!(response, jwt_read_permissions);
912
913 super::methods::auth::AuthVerify::call(&client, (format!("Bearer {jwt_read}"),))
915 .await
916 .unwrap_err();
917
918 drop(client);
919
920 let http = reqwest::Client::new();
922 let rpc_url = format!("http://{}:{}/rpc/v1", rpc_address.ip(), rpc_address.port());
923 let jsonrpc_body = serde_json::json!({
924 "jsonrpc": "2.0",
925 "method": "Filecoin.Version",
926 "params": [],
927 "id": 0,
928 });
929
930 let bad_token = http
931 .post(&rpc_url)
932 .header(reqwest::header::AUTHORIZATION, "Bearer not-a-real-token")
933 .json(&jsonrpc_body)
934 .send()
935 .await
936 .unwrap();
937 assert_eq!(bad_token.status(), reqwest::StatusCode::UNAUTHORIZED);
938
939 let good_token = http
941 .post(&rpc_url)
942 .header(reqwest::header::AUTHORIZATION, format!("Bearer {jwt_read}"))
943 .json(&jsonrpc_body)
944 .send()
945 .await
946 .unwrap();
947 assert_eq!(good_token.status(), reqwest::StatusCode::OK);
948
949 println!("sending a few websocket requests");
950
951 let client = Client::from_url(
952 format!("ws://{}:{}/", rpc_address.ip(), rpc_address.port())
953 .parse()
954 .unwrap(),
955 );
956
957 let response = super::methods::auth::AuthVerify::call(&client, (jwt_read,))
958 .await
959 .unwrap();
960 assert_eq!(response, jwt_read_permissions);
961
962 drop(client);
963
964 let client = UrlClient::new(
966 format!("http://{}:{}/rpc/v1", rpc_address.ip(), rpc_address.port())
967 .parse()
968 .unwrap(),
969 None,
970 )
971 .await
972 .unwrap();
973 let mut batch_request_builder = BatchRequestBuilder::new();
974 let empty_payload: [(); 0] = [];
975 batch_request_builder
976 .insert("Filecoin.Version", empty_payload)
977 .unwrap();
978 batch_request_builder
979 .insert("eth_chainId", empty_payload)
980 .unwrap();
981 let batch_response: BatchResponse<serde_json::Value> =
982 client.batch_request(batch_request_builder).await.unwrap();
983 assert_eq!(batch_response.len(), 2);
984 assert_eq!(batch_response.num_successful_calls(), 2);
985 assert_eq!(batch_response.num_failed_calls(), 0);
986
987 let mut encoded = String::new();
991 prometheus_client::encoding::text::encode_registry(
992 &mut encoded,
993 &crate::metrics::default_registry(),
994 )
995 .unwrap();
996 let recorded = encoded.lines().any(|line| {
997 line.starts_with("rpc_processing_time_count{")
998 && line.contains(r#"method="eth_chainId""#)
999 && line
1000 .rsplit(' ')
1001 .next()
1002 .and_then(|v| v.parse::<u64>().ok())
1003 .is_some_and(|count| count == 1)
1004 });
1005 assert!(
1006 recorded,
1007 "batched method `eth_chainId` was not recorded in rpc_processing_time:\n{encoded}"
1008 );
1009
1010 println!("sending shutdown signal");
1012 shutdown_send.send(()).await.unwrap();
1013 println!("waiting on shutdown receiver");
1014 shutdown_recv.recv().await;
1015 println!("sending server stop signal");
1016 server_handle.stop().unwrap();
1017 println!("waiting on graceful shutdown");
1018 handle.await.unwrap().unwrap();
1019 println!("done");
1020 done_tx.send(()).unwrap();
1021 }
1022}