Files
cuprate-for-explorer/binaries/cuprated/src/rpc/server.rs
hinto-janai 97e539559a rpc: submit_block + /send_raw_transaction (#515)
* enable `submit_block` and `/send_raw_transaction`

* endpoint

* map

* not_relayed

* book

* log

* Update binaries/cuprated/src/rpc/service/tx_handler.rs

Co-authored-by: Boog900 <boog900@tutanota.com>

* review

* fix

---------

Co-authored-by: Boog900 <boog900@tutanota.com>
2025-07-17 00:34:33 +01:00

136 lines
3.7 KiB
Rust

//! RPC server initialization and main loop.
use std::{
net::{IpAddr, SocketAddr},
time::Duration,
};
use anyhow::Error;
use tokio::net::TcpListener;
use tower::limit::rate::RateLimitLayer;
use tower_http::limit::RequestBodyLimitLayer;
use tracing::{info, warn};
use cuprate_blockchain::service::BlockchainReadHandle;
use cuprate_consensus::BlockchainContextService;
use cuprate_rpc_interface::{RouterBuilder, RpcHandler};
use cuprate_txpool::service::TxpoolReadHandle;
use crate::{
config::RpcConfig,
rpc::{rpc_handler::BlockchainManagerHandle, CupratedRpcHandler},
txpool::IncomingTxHandler,
};
/// Initialize the RPC server(s).
///
/// # Panics
/// This function will panic if:
/// - the server(s) could not be started
/// - unrestricted RPC is started on non-local
/// address without override option
pub fn init_rpc_servers(
config: RpcConfig,
blockchain_read: BlockchainReadHandle,
blockchain_context: BlockchainContextService,
txpool_read: TxpoolReadHandle,
tx_handler: IncomingTxHandler,
) {
for ((enable, addr, request_byte_limit), restricted) in [
(
(
config.unrestricted.enable,
config.unrestricted.address,
config.unrestricted.request_byte_limit,
),
false,
),
(
(
config.restricted.enable,
config.restricted.address,
config.restricted.request_byte_limit,
),
true,
),
] {
if !enable {
info!(restricted, "Skipping RPC server");
continue;
}
if !restricted && !cuprate_helper::net::ip_is_local(addr.ip()) {
if config
.unrestricted
.i_know_what_im_doing_allow_public_unrestricted_rpc
{
warn!(
address = %addr,
"Starting unrestricted RPC on non-local address, this is dangerous!"
);
} else {
panic!("Refusing to start unrestricted RPC on a non-local address ({addr})");
}
}
let rpc_handler = CupratedRpcHandler::new(
restricted,
blockchain_read.clone(),
blockchain_context.clone(),
txpool_read.clone(),
tx_handler.clone(),
);
tokio::task::spawn(async move {
run_rpc_server(rpc_handler, restricted, addr, request_byte_limit)
.await
.unwrap();
});
}
}
/// This initializes and runs an RPC server.
///
/// The function will only return when the server itself returns or an error occurs.
async fn run_rpc_server(
rpc_handler: CupratedRpcHandler,
restricted: bool,
address: SocketAddr,
request_byte_limit: usize,
) -> Result<(), Error> {
info!(
restricted,
address = %address,
"Starting RPC server"
);
// TODO:
// - add functions that are `all()` but for restricted RPC
// - enable aliases automatically `other_get_height` + `other_getheight`?
let router = RouterBuilder::new()
.json_rpc()
.other_get_height()
.other_send_raw_transaction()
.other_sendrawtransaction()
.fallback()
.build()
.with_state(rpc_handler);
// Add restrictive layers if restricted RPC.
//
// TODO: <https://github.com/Cuprate/cuprate/issues/445>
let router = if request_byte_limit != 0 {
router.layer(RequestBodyLimitLayer::new(request_byte_limit))
} else {
router
};
// Start the server.
//
// TODO: impl custom server code, don't use axum.
let listener = TcpListener::bind(address).await?;
axum::serve(listener, router).await?;
Ok(())
}