mirror of
https://github.com/MAGICGrants/cuprate-for-explorer.git
synced 2026-01-09 19:47:59 -05:00
cuprated: CupratedRpcHandler, enable certain endpoints (#450)
* add rpc server * add init fn * add layers * docs * comments * move * warn * split config * split * fix toml * impl p2p port * fix tests * docs * doc * remove (de)compression * init rpc servers with handlers * add `rpc.md` * typo * sort * revert cargo.lock diff * 🟣 * not_available() * `advertise` * Update binaries/cuprated/src/config/rpc.rs Co-authored-by: Boog900 <boog900@tutanota.com> * update tracing * `tracing::field::display` * fix * typo * docs * clippy * remove comment_out * add test for `cuprate_helper::net::ip_is_local` * fix args * `/get_outs`, `/get_height` * enable methods * apply * block fn * fix * clippy * book * add warning * update * typos * Update binaries/cuprated/src/rpc/handlers/helper.rs Co-authored-by: Boog900 <boog900@tutanota.com> * fmt --------- Co-authored-by: Boog900 <boog900@tutanota.com>
This commit is contained in:
@@ -133,7 +133,7 @@ fn main() {
|
||||
let tx_handler = IncomingTxHandler::init(
|
||||
network_interfaces.clearnet_network_interface.clone(),
|
||||
txpool_write_handle.clone(),
|
||||
txpool_read_handle,
|
||||
txpool_read_handle.clone(),
|
||||
context_svc.clone(),
|
||||
blockchain_read_handle.clone(),
|
||||
);
|
||||
@@ -149,15 +149,20 @@ fn main() {
|
||||
blockchain::init_blockchain_manager(
|
||||
network_interfaces.clearnet_network_interface,
|
||||
blockchain_write_handle,
|
||||
blockchain_read_handle,
|
||||
txpool_write_handle,
|
||||
blockchain_read_handle.clone(),
|
||||
txpool_write_handle.clone(),
|
||||
context_svc.clone(),
|
||||
config.block_downloader_config(),
|
||||
)
|
||||
.await;
|
||||
|
||||
// Initialize the RPC server(s).
|
||||
rpc::init_rpc_servers(config.rpc);
|
||||
rpc::init_rpc_servers(
|
||||
config.rpc,
|
||||
blockchain_read_handle,
|
||||
context_svc.clone(),
|
||||
txpool_read_handle,
|
||||
);
|
||||
|
||||
// Start the command listener.
|
||||
if std::io::IsTerminal::is_terminal(&std::io::stdin()) {
|
||||
|
||||
@@ -30,7 +30,7 @@ use cuprate_types::{
|
||||
};
|
||||
|
||||
use crate::rpc::{
|
||||
handlers::{helper, shared},
|
||||
handlers::{helper, shared, shared::not_available},
|
||||
service::{blockchain, txpool},
|
||||
CupratedRpcHandler,
|
||||
};
|
||||
@@ -44,17 +44,13 @@ pub async fn map_request(
|
||||
use BinResponse as Resp;
|
||||
|
||||
Ok(match request {
|
||||
Req::GetBlocks(r) => Resp::GetBlocks(get_blocks(state, r).await?),
|
||||
Req::GetBlocksByHeight(r) => Resp::GetBlocksByHeight(get_blocks_by_height(state, r).await?),
|
||||
Req::GetHashes(r) => Resp::GetHashes(get_hashes(state, r).await?),
|
||||
Req::GetOutputIndexes(r) => Resp::GetOutputIndexes(get_output_indexes(state, r).await?),
|
||||
Req::GetOuts(r) => Resp::GetOuts(get_outs(state, r).await?),
|
||||
Req::GetTransactionPoolHashes(r) => {
|
||||
Resp::GetTransactionPoolHashes(get_transaction_pool_hashes(state, r).await?)
|
||||
}
|
||||
Req::GetOutputDistribution(r) => {
|
||||
Resp::GetOutputDistribution(get_output_distribution(state, r).await?)
|
||||
}
|
||||
Req::GetBlocks(r) => Resp::GetBlocks(not_available()?),
|
||||
Req::GetBlocksByHeight(r) => Resp::GetBlocksByHeight(not_available()?),
|
||||
Req::GetHashes(r) => Resp::GetHashes(not_available()?),
|
||||
Req::GetOutputIndexes(r) => Resp::GetOutputIndexes(not_available()?),
|
||||
Req::GetOuts(r) => Resp::GetOuts(not_available()?),
|
||||
Req::GetTransactionPoolHashes(r) => Resp::GetTransactionPoolHashes(not_available()?),
|
||||
Req::GetOutputDistribution(r) => Resp::GetOutputDistribution(not_available()?),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ use cuprate_rpc_types::{
|
||||
base::{AccessResponseBase, ResponseBase},
|
||||
misc::BlockHeader,
|
||||
};
|
||||
use cuprate_types::HardFork;
|
||||
use cuprate_types::{Chain, HardFork};
|
||||
use monero_serai::transaction::Timelock;
|
||||
|
||||
use crate::rpc::{
|
||||
@@ -55,18 +55,15 @@ pub(super) async fn block_header(
|
||||
let pow_hash = if fill_pow_hash {
|
||||
let seed_height =
|
||||
cuprate_consensus_rules::blocks::randomx_seed_height(u64_to_usize(height));
|
||||
let seed_hash = blockchain::block_hash(
|
||||
&mut state.blockchain_read,
|
||||
height,
|
||||
todo!("access to `cuprated`'s Chain"),
|
||||
)
|
||||
.await?;
|
||||
let seed_hash =
|
||||
blockchain::block_hash(&mut state.blockchain_read, height, Chain::Main).await?;
|
||||
|
||||
Some(
|
||||
blockchain_context::calculate_pow(
|
||||
&mut state.blockchain_context,
|
||||
hardfork,
|
||||
block,
|
||||
// TODO: expensive clone
|
||||
block.clone(),
|
||||
seed_hash,
|
||||
)
|
||||
.await?,
|
||||
|
||||
@@ -61,7 +61,7 @@ use crate::{
|
||||
constants::VERSION_BUILD,
|
||||
rpc::{
|
||||
constants::{FIELD_NOT_SUPPORTED, UNSUPPORTED_RPC_CALL},
|
||||
handlers::{helper, shared},
|
||||
handlers::{helper, shared, shared::not_available},
|
||||
service::{address_book, blockchain, blockchain_context, blockchain_manager, txpool},
|
||||
CupratedRpcHandler,
|
||||
},
|
||||
@@ -77,11 +77,11 @@ pub async fn map_request(
|
||||
use JsonRpcResponse as Resp;
|
||||
|
||||
Ok(match request {
|
||||
Req::GetBlockTemplate(r) => Resp::GetBlockTemplate(get_block_template(state, r).await?),
|
||||
Req::GetBlockTemplate(r) => Resp::GetBlockTemplate(not_available()?),
|
||||
Req::GetBlockCount(r) => Resp::GetBlockCount(get_block_count(state, r).await?),
|
||||
Req::OnGetBlockHash(r) => Resp::OnGetBlockHash(on_get_block_hash(state, r).await?),
|
||||
Req::SubmitBlock(r) => Resp::SubmitBlock(submit_block(state, r).await?),
|
||||
Req::GenerateBlocks(r) => Resp::GenerateBlocks(generate_blocks(state, r).await?),
|
||||
Req::SubmitBlock(r) => Resp::SubmitBlock(not_available()?),
|
||||
Req::GenerateBlocks(r) => Resp::GenerateBlocks(not_available()?),
|
||||
Req::GetLastBlockHeader(r) => {
|
||||
Resp::GetLastBlockHeader(get_last_block_header(state, r).await?)
|
||||
}
|
||||
@@ -95,33 +95,25 @@ pub async fn map_request(
|
||||
Resp::GetBlockHeadersRange(get_block_headers_range(state, r).await?)
|
||||
}
|
||||
Req::GetBlock(r) => Resp::GetBlock(get_block(state, r).await?),
|
||||
Req::GetConnections(r) => Resp::GetConnections(get_connections(state, r).await?),
|
||||
Req::GetInfo(r) => Resp::GetInfo(get_info(state, r).await?),
|
||||
Req::HardForkInfo(r) => Resp::HardForkInfo(hard_fork_info(state, r).await?),
|
||||
Req::SetBans(r) => Resp::SetBans(set_bans(state, r).await?),
|
||||
Req::GetBans(r) => Resp::GetBans(get_bans(state, r).await?),
|
||||
Req::Banned(r) => Resp::Banned(banned(state, r).await?),
|
||||
Req::FlushTransactionPool(r) => {
|
||||
Resp::FlushTransactionPool(flush_transaction_pool(state, r).await?)
|
||||
}
|
||||
Req::GetOutputHistogram(r) => {
|
||||
Resp::GetOutputHistogram(get_output_histogram(state, r).await?)
|
||||
}
|
||||
Req::GetCoinbaseTxSum(r) => Resp::GetCoinbaseTxSum(get_coinbase_tx_sum(state, r).await?),
|
||||
Req::GetVersion(r) => Resp::GetVersion(get_version(state, r).await?),
|
||||
Req::GetFeeEstimate(r) => Resp::GetFeeEstimate(get_fee_estimate(state, r).await?),
|
||||
Req::GetAlternateChains(r) => {
|
||||
Resp::GetAlternateChains(get_alternate_chains(state, r).await?)
|
||||
}
|
||||
Req::RelayTx(r) => Resp::RelayTx(relay_tx(state, r).await?),
|
||||
Req::SyncInfo(r) => Resp::SyncInfo(sync_info(state, r).await?),
|
||||
Req::GetTransactionPoolBacklog(r) => {
|
||||
Resp::GetTransactionPoolBacklog(get_transaction_pool_backlog(state, r).await?)
|
||||
}
|
||||
Req::GetMinerData(r) => Resp::GetMinerData(get_miner_data(state, r).await?),
|
||||
Req::PruneBlockchain(r) => Resp::PruneBlockchain(prune_blockchain(state, r).await?),
|
||||
Req::CalcPow(r) => Resp::CalcPow(calc_pow(state, r).await?),
|
||||
Req::AddAuxPow(r) => Resp::AddAuxPow(add_aux_pow(state, r).await?),
|
||||
Req::GetConnections(r) => Resp::GetConnections(not_available()?),
|
||||
Req::GetInfo(r) => Resp::GetInfo(not_available()?),
|
||||
Req::HardForkInfo(r) => Resp::HardForkInfo(not_available()?),
|
||||
Req::SetBans(r) => Resp::SetBans(not_available()?),
|
||||
Req::GetBans(r) => Resp::GetBans(not_available()?),
|
||||
Req::Banned(r) => Resp::Banned(not_available()?),
|
||||
Req::FlushTransactionPool(r) => Resp::FlushTransactionPool(not_available()?),
|
||||
Req::GetOutputHistogram(r) => Resp::GetOutputHistogram(not_available()?),
|
||||
Req::GetCoinbaseTxSum(r) => Resp::GetCoinbaseTxSum(not_available()?),
|
||||
Req::GetVersion(r) => Resp::GetVersion(not_available()?),
|
||||
Req::GetFeeEstimate(r) => Resp::GetFeeEstimate(not_available()?),
|
||||
Req::GetAlternateChains(r) => Resp::GetAlternateChains(not_available()?),
|
||||
Req::RelayTx(r) => Resp::RelayTx(not_available()?),
|
||||
Req::SyncInfo(r) => Resp::SyncInfo(not_available()?),
|
||||
Req::GetTransactionPoolBacklog(r) => Resp::GetTransactionPoolBacklog(not_available()?),
|
||||
Req::GetMinerData(r) => Resp::GetMinerData(not_available()?),
|
||||
Req::PruneBlockchain(r) => Resp::PruneBlockchain(not_available()?),
|
||||
Req::CalcPow(r) => Resp::CalcPow(not_available()?),
|
||||
Req::AddAuxPow(r) => Resp::AddAuxPow(not_available()?),
|
||||
|
||||
// Unsupported RPC calls.
|
||||
Req::GetTxIdsLoose(_) | Req::FlushCache(_) => return Err(anyhow!(UNSUPPORTED_RPC_CALL)),
|
||||
@@ -172,7 +164,7 @@ async fn get_block_template(
|
||||
seed_hash,
|
||||
next_seed_hash,
|
||||
} = *blockchain_manager::create_block_template(
|
||||
&mut state.blockchain_manager,
|
||||
todo!(),
|
||||
prev_block,
|
||||
request.wallet_address,
|
||||
request.extra_nonce.0,
|
||||
@@ -242,7 +234,7 @@ async fn submit_block(
|
||||
let block_id = Hex(block.hash());
|
||||
|
||||
// Attempt to relay the block.
|
||||
blockchain_manager::relay_block(&mut state.blockchain_manager, Box::new(block)).await?;
|
||||
blockchain_manager::relay_block(todo!(), Box::new(block)).await?;
|
||||
|
||||
Ok(SubmitBlockResponse {
|
||||
base: helper::response_base(false),
|
||||
@@ -269,7 +261,7 @@ async fn generate_blocks(
|
||||
};
|
||||
|
||||
let (blocks, height) = blockchain_manager::generate_blocks(
|
||||
&mut state.blockchain_manager,
|
||||
todo!(),
|
||||
request.amount_of_blocks,
|
||||
prev_block,
|
||||
request.starting_nonce,
|
||||
@@ -479,7 +471,7 @@ async fn get_info(
|
||||
(String::new(), false)
|
||||
};
|
||||
|
||||
let busy_syncing = blockchain_manager::syncing(&mut state.blockchain_manager).await?;
|
||||
let busy_syncing = blockchain_manager::syncing(todo!()).await?;
|
||||
|
||||
let (cumulative_difficulty, cumulative_difficulty_top64) =
|
||||
split_u128_into_low_high_bits(cumulative_difficulty);
|
||||
@@ -524,12 +516,10 @@ async fn get_info(
|
||||
let rpc_connections_count = if restricted { 0 } else { 0 };
|
||||
|
||||
let start_time = if restricted { 0 } else { *START_INSTANT_UNIX };
|
||||
let synchronized = blockchain_manager::synced(&mut state.blockchain_manager).await?;
|
||||
let synchronized = blockchain_manager::synced(todo!()).await?;
|
||||
|
||||
let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?;
|
||||
let target = blockchain_manager::target(&mut state.blockchain_manager)
|
||||
.await?
|
||||
.as_secs();
|
||||
let target_height = blockchain_manager::target_height(todo!()).await?;
|
||||
let target = blockchain_manager::target(todo!()).await?.as_secs();
|
||||
let top_block_hash = Hex(c.top_hash);
|
||||
|
||||
let tx_count = blockchain::total_tx_count(&mut state.blockchain_read).await?;
|
||||
@@ -738,7 +728,7 @@ async fn flush_transaction_pool(
|
||||
.map(|h| h.0)
|
||||
.collect::<Vec<[u8; 32]>>();
|
||||
|
||||
txpool::flush(&mut state.txpool_manager, tx_hashes).await?;
|
||||
txpool::flush(todo!(), tx_hashes).await?;
|
||||
|
||||
Ok(FlushTransactionPoolResponse { status: Status::Ok })
|
||||
}
|
||||
@@ -807,7 +797,7 @@ async fn get_version(
|
||||
_: GetVersionRequest,
|
||||
) -> Result<GetVersionResponse, Error> {
|
||||
let current_height = helper::top_height(&mut state).await?.0;
|
||||
let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?;
|
||||
let target_height = blockchain_manager::target_height(todo!()).await?;
|
||||
|
||||
let mut hard_forks = Vec::with_capacity(HardFork::COUNT);
|
||||
|
||||
@@ -880,7 +870,7 @@ async fn relay_tx(
|
||||
.map(|h| h.0)
|
||||
.collect::<Vec<[u8; 32]>>();
|
||||
|
||||
txpool::relay(&mut state.txpool_manager, tx_hashes).await?;
|
||||
txpool::relay(todo!(), tx_hashes).await?;
|
||||
|
||||
Ok(RelayTxResponse { status: Status::Ok })
|
||||
}
|
||||
@@ -892,7 +882,7 @@ async fn sync_info(
|
||||
) -> Result<SyncInfoResponse, Error> {
|
||||
let height = usize_to_u64(state.blockchain_context.blockchain_context().chain_height);
|
||||
|
||||
let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?;
|
||||
let target_height = blockchain_manager::target_height(todo!()).await?;
|
||||
|
||||
let peers = address_book::connection_info::<ClearNet>(&mut DummyAddressBook)
|
||||
.await?
|
||||
@@ -900,12 +890,11 @@ async fn sync_info(
|
||||
.map(|info| SyncInfoPeer { info })
|
||||
.collect();
|
||||
|
||||
let next_needed_pruning_seed =
|
||||
blockchain_manager::next_needed_pruning_seed(&mut state.blockchain_manager)
|
||||
.await?
|
||||
.compress();
|
||||
let next_needed_pruning_seed = blockchain_manager::next_needed_pruning_seed(todo!())
|
||||
.await?
|
||||
.compress();
|
||||
|
||||
let spans = blockchain_manager::spans::<ClearNet>(&mut state.blockchain_manager).await?;
|
||||
let spans = blockchain_manager::spans::<ClearNet>(todo!()).await?;
|
||||
|
||||
// <https://github.com/Cuprate/cuprate/pull/320#discussion_r1811063772>
|
||||
let overview = String::from(FIELD_NOT_SUPPORTED);
|
||||
@@ -994,10 +983,8 @@ async fn prune_blockchain(
|
||||
mut state: CupratedRpcHandler,
|
||||
request: PruneBlockchainRequest,
|
||||
) -> Result<PruneBlockchainResponse, Error> {
|
||||
let pruned = blockchain_manager::pruned(&mut state.blockchain_manager).await?;
|
||||
let pruning_seed = blockchain_manager::prune(&mut state.blockchain_manager)
|
||||
.await?
|
||||
.compress();
|
||||
let pruned = blockchain_manager::pruned(todo!()).await?;
|
||||
let pruning_seed = blockchain_manager::prune(todo!()).await?.compress();
|
||||
|
||||
Ok(PruneBlockchainResponse {
|
||||
base: helper::response_base(false),
|
||||
|
||||
@@ -49,7 +49,7 @@ use cuprate_types::{
|
||||
use crate::{
|
||||
rpc::{
|
||||
constants::UNSUPPORTED_RPC_CALL,
|
||||
handlers::{helper, shared},
|
||||
handlers::{helper, shared, shared::not_available},
|
||||
service::{address_book, blockchain, blockchain_context, blockchain_manager, txpool},
|
||||
CupratedRpcHandler,
|
||||
},
|
||||
@@ -66,36 +66,26 @@ pub async fn map_request(
|
||||
|
||||
Ok(match request {
|
||||
Req::GetHeight(r) => Resp::GetHeight(get_height(state, r).await?),
|
||||
Req::GetTransactions(r) => Resp::GetTransactions(get_transactions(state, r).await?),
|
||||
Req::GetAltBlocksHashes(r) => {
|
||||
Resp::GetAltBlocksHashes(get_alt_blocks_hashes(state, r).await?)
|
||||
}
|
||||
Req::IsKeyImageSpent(r) => Resp::IsKeyImageSpent(is_key_image_spent(state, r).await?),
|
||||
Req::SendRawTransaction(r) => {
|
||||
Resp::SendRawTransaction(send_raw_transaction(state, r).await?)
|
||||
}
|
||||
Req::SaveBc(r) => Resp::SaveBc(save_bc(state, r).await?),
|
||||
Req::GetPeerList(r) => Resp::GetPeerList(get_peer_list(state, r).await?),
|
||||
Req::SetLogLevel(r) => Resp::SetLogLevel(set_log_level(state, r).await?),
|
||||
Req::SetLogCategories(r) => Resp::SetLogCategories(set_log_categories(state, r).await?),
|
||||
Req::GetTransactionPool(r) => {
|
||||
Resp::GetTransactionPool(get_transaction_pool(state, r).await?)
|
||||
}
|
||||
Req::GetTransactionPoolStats(r) => {
|
||||
Resp::GetTransactionPoolStats(get_transaction_pool_stats(state, r).await?)
|
||||
}
|
||||
Req::StopDaemon(r) => Resp::StopDaemon(stop_daemon(state, r).await?),
|
||||
Req::GetLimit(r) => Resp::GetLimit(get_limit(state, r).await?),
|
||||
Req::SetLimit(r) => Resp::SetLimit(set_limit(state, r).await?),
|
||||
Req::OutPeers(r) => Resp::OutPeers(out_peers(state, r).await?),
|
||||
Req::InPeers(r) => Resp::InPeers(in_peers(state, r).await?),
|
||||
Req::GetNetStats(r) => Resp::GetNetStats(get_net_stats(state, r).await?),
|
||||
Req::GetOuts(r) => Resp::GetOuts(get_outs(state, r).await?),
|
||||
Req::PopBlocks(r) => Resp::PopBlocks(pop_blocks(state, r).await?),
|
||||
Req::GetTransactionPoolHashes(r) => {
|
||||
Resp::GetTransactionPoolHashes(get_transaction_pool_hashes(state, r).await?)
|
||||
}
|
||||
Req::GetPublicNodes(r) => Resp::GetPublicNodes(get_public_nodes(state, r).await?),
|
||||
Req::GetTransactions(r) => Resp::GetTransactions(not_available()?),
|
||||
Req::GetAltBlocksHashes(r) => Resp::GetAltBlocksHashes(not_available()?),
|
||||
Req::IsKeyImageSpent(r) => Resp::IsKeyImageSpent(not_available()?),
|
||||
Req::SendRawTransaction(r) => Resp::SendRawTransaction(not_available()?),
|
||||
Req::SaveBc(r) => Resp::SaveBc(not_available()?),
|
||||
Req::GetPeerList(r) => Resp::GetPeerList(not_available()?),
|
||||
Req::SetLogLevel(r) => Resp::SetLogLevel(not_available()?),
|
||||
Req::SetLogCategories(r) => Resp::SetLogCategories(not_available()?),
|
||||
Req::GetTransactionPool(r) => Resp::GetTransactionPool(not_available()?),
|
||||
Req::GetTransactionPoolStats(r) => Resp::GetTransactionPoolStats(not_available()?),
|
||||
Req::StopDaemon(r) => Resp::StopDaemon(not_available()?),
|
||||
Req::GetLimit(r) => Resp::GetLimit(not_available()?),
|
||||
Req::SetLimit(r) => Resp::SetLimit(not_available()?),
|
||||
Req::OutPeers(r) => Resp::OutPeers(not_available()?),
|
||||
Req::InPeers(r) => Resp::InPeers(not_available()?),
|
||||
Req::GetNetStats(r) => Resp::GetNetStats(not_available()?),
|
||||
Req::GetOuts(r) => Resp::GetOuts(not_available()?),
|
||||
Req::PopBlocks(r) => Resp::PopBlocks(not_available()?),
|
||||
Req::GetTransactionPoolHashes(r) => Resp::GetTransactionPoolHashes(not_available()?),
|
||||
Req::GetPublicNodes(r) => Resp::GetPublicNodes(not_available()?),
|
||||
|
||||
// Unsupported requests.
|
||||
Req::SetBootstrapDaemon(_)
|
||||
@@ -452,9 +442,9 @@ async fn send_raw_transaction(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: handle to txpool service.
|
||||
let tx_relay_checks =
|
||||
txpool::check_maybe_relay_local(&mut state.txpool_manager, tx, !request.do_not_relay)
|
||||
.await?;
|
||||
txpool::check_maybe_relay_local(todo!(), tx, !request.do_not_relay).await?;
|
||||
|
||||
if tx_relay_checks.is_empty() {
|
||||
return Ok(resp);
|
||||
@@ -496,7 +486,7 @@ async fn send_raw_transaction(
|
||||
|
||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L1525-L1535>
|
||||
async fn save_bc(mut state: CupratedRpcHandler, _: SaveBcRequest) -> Result<SaveBcResponse, Error> {
|
||||
blockchain_manager::sync(&mut state.blockchain_manager).await?;
|
||||
blockchain_manager::sync(todo!()).await?;
|
||||
|
||||
Ok(SaveBcResponse {
|
||||
base: ResponseBase::OK,
|
||||
@@ -554,7 +544,7 @@ async fn stop_daemon(
|
||||
mut state: CupratedRpcHandler,
|
||||
_: StopDaemonRequest,
|
||||
) -> Result<StopDaemonResponse, Error> {
|
||||
blockchain_manager::stop(&mut state.blockchain_manager).await?;
|
||||
blockchain_manager::stop(todo!()).await?;
|
||||
Ok(StopDaemonResponse { status: Status::Ok })
|
||||
}
|
||||
|
||||
@@ -658,8 +648,7 @@ async fn pop_blocks(
|
||||
mut state: CupratedRpcHandler,
|
||||
request: PopBlocksRequest,
|
||||
) -> Result<PopBlocksResponse, Error> {
|
||||
let height =
|
||||
blockchain_manager::pop_blocks(&mut state.blockchain_manager, request.nblocks).await?;
|
||||
let height = blockchain_manager::pop_blocks(todo!(), request.nblocks).await?;
|
||||
|
||||
Ok(PopBlocksResponse {
|
||||
base: helper::response_base(false),
|
||||
|
||||
@@ -128,3 +128,11 @@ pub(super) async fn get_output_distribution(
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
/// Always returns an [`Error`].
|
||||
///
|
||||
/// This is a temporary function used for RPC method/endpoints
|
||||
/// that are not yet ready - it should be removed when all are ready.
|
||||
pub(super) fn not_available<T>() -> Result<T, Error> {
|
||||
Err(anyhow!("Not available"))
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ pub type BlockchainManagerHandle = cuprate_database_service::DatabaseReadService
|
||||
BlockchainManagerResponse,
|
||||
>;
|
||||
|
||||
/// TODO
|
||||
/// cuprated's RPC handler service.
|
||||
#[derive(Clone)]
|
||||
pub struct CupratedRpcHandler {
|
||||
/// Should this RPC server be [restricted](RpcHandler::is_restricted)?
|
||||
@@ -167,14 +167,9 @@ pub struct CupratedRpcHandler {
|
||||
/// Handle to the blockchain context service.
|
||||
pub blockchain_context: BlockchainContextService,
|
||||
|
||||
/// Handle to the blockchain manager.
|
||||
pub blockchain_manager: BlockchainManagerHandle,
|
||||
|
||||
/// Read handle to the transaction pool database.
|
||||
pub txpool_read: TxpoolReadHandle,
|
||||
|
||||
/// TODO: handle to txpool service.
|
||||
pub txpool_manager: std::convert::Infallible,
|
||||
// TODO: handle to txpool service.
|
||||
}
|
||||
|
||||
impl CupratedRpcHandler {
|
||||
@@ -183,17 +178,13 @@ impl CupratedRpcHandler {
|
||||
restricted: bool,
|
||||
blockchain_read: BlockchainReadHandle,
|
||||
blockchain_context: BlockchainContextService,
|
||||
blockchain_manager: BlockchainManagerHandle,
|
||||
txpool_read: TxpoolReadHandle,
|
||||
txpool_manager: std::convert::Infallible,
|
||||
) -> Self {
|
||||
Self {
|
||||
restricted,
|
||||
blockchain_read,
|
||||
blockchain_context,
|
||||
blockchain_manager,
|
||||
txpool_read,
|
||||
txpool_manager,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,11 +9,17 @@ use anyhow::Error;
|
||||
use tokio::net::TcpListener;
|
||||
use tower::limit::rate::RateLimitLayer;
|
||||
use tower_http::limit::RequestBodyLimitLayer;
|
||||
use tracing::{field::display, info, warn};
|
||||
use tracing::{info, warn};
|
||||
|
||||
use cuprate_rpc_interface::{RouterBuilder, RpcHandlerDummy};
|
||||
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::CupratedRpcHandler};
|
||||
use crate::{
|
||||
config::RpcConfig,
|
||||
rpc::{rpc_handler::BlockchainManagerHandle, CupratedRpcHandler},
|
||||
};
|
||||
|
||||
/// Initialize the RPC server(s).
|
||||
///
|
||||
@@ -22,7 +28,12 @@ use crate::{config::RpcConfig, rpc::CupratedRpcHandler};
|
||||
/// - 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) {
|
||||
pub fn init_rpc_servers(
|
||||
config: RpcConfig,
|
||||
blockchain_read: BlockchainReadHandle,
|
||||
blockchain_context: BlockchainContextService,
|
||||
txpool_read: TxpoolReadHandle,
|
||||
) {
|
||||
for ((enable, addr, request_byte_limit), restricted) in [
|
||||
(
|
||||
(
|
||||
@@ -52,7 +63,7 @@ pub fn init_rpc_servers(config: RpcConfig) {
|
||||
.i_know_what_im_doing_allow_public_unrestricted_rpc
|
||||
{
|
||||
warn!(
|
||||
address = display(addr),
|
||||
address = %addr,
|
||||
"Starting unrestricted RPC on non-local address, this is dangerous!"
|
||||
);
|
||||
} else {
|
||||
@@ -60,8 +71,15 @@ pub fn init_rpc_servers(config: RpcConfig) {
|
||||
}
|
||||
}
|
||||
|
||||
let rpc_handler = CupratedRpcHandler::new(
|
||||
restricted,
|
||||
blockchain_read.clone(),
|
||||
blockchain_context.clone(),
|
||||
txpool_read.clone(),
|
||||
);
|
||||
|
||||
tokio::task::spawn(async move {
|
||||
run_rpc_server(restricted, addr, request_byte_limit)
|
||||
run_rpc_server(rpc_handler, restricted, addr, request_byte_limit)
|
||||
.await
|
||||
.unwrap();
|
||||
});
|
||||
@@ -72,28 +90,26 @@ pub fn init_rpc_servers(config: RpcConfig) {
|
||||
///
|
||||
/// 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 = display(&address),
|
||||
address = %address,
|
||||
"Starting RPC server"
|
||||
);
|
||||
|
||||
// Create the router.
|
||||
//
|
||||
// TODO: impl more layers, rate-limiting, configuration, etc.
|
||||
let state = RpcHandlerDummy { restricted };
|
||||
// TODO:
|
||||
// - add functions that are `all()` but for restricted RPC
|
||||
// - enable aliases automatically `other_get_height` + `other_getheight`?
|
||||
//
|
||||
// FIXME:
|
||||
// - `json_rpc` is 1 endpoint; `RouterBuilder` operates at the
|
||||
// level endpoint; we can't selectively enable certain `json_rpc` methods
|
||||
let router = RouterBuilder::new().fallback().build().with_state(state);
|
||||
let router = RouterBuilder::new()
|
||||
.json_rpc()
|
||||
.other_get_height()
|
||||
.fallback()
|
||||
.build()
|
||||
.with_state(rpc_handler);
|
||||
|
||||
// Add restrictive layers if restricted RPC.
|
||||
//
|
||||
|
||||
@@ -15,14 +15,16 @@
|
||||
- [Command line](cli.md)
|
||||
|
||||
- [Resources](resources/intro.md)
|
||||
- [Address](resources/address.md)
|
||||
- [Disk](resources/disk.md)
|
||||
- [Ports](resources/ports.md)
|
||||
- [IP](resources/ip.md)
|
||||
|
||||
- [Deployment](deployment/intro.md)
|
||||
- [systemd](deployment/systemd.md)
|
||||
|
||||
- [RPC](rpc.md)
|
||||
|
||||
- [Platform support](platform.md)
|
||||
|
||||
- [License](license.md)
|
||||
|
||||
<!-- TODO: - [Glossary](glossary/intro.md) or maybe a wiki? -->
|
||||
|
||||
@@ -52,6 +52,7 @@ Cuprate's node (`cuprated`) can currently:
|
||||
- Sync the blockchain and transaction pool
|
||||
- Broadcast and relay blocks and transactions
|
||||
- Help other peers sync their blockchain
|
||||
- Respond to certain [daemon RPC](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html) requests
|
||||
|
||||
## How fast does `cuprated` sync?
|
||||
The current full verification sync timings are around ~7.5x faster than `monerod`.
|
||||
@@ -91,7 +92,7 @@ The database `cuprated` generates and uses cannot directly be used by `monerod`
|
||||
## Can I connect a wallet to `cuprated`?
|
||||
Not yet.
|
||||
|
||||
Wallets require the [daemon RPC API](https://docs.getmonero.org/rpc-library/monerod-rpc). This is actively being worked on to be backwards compatible with `monerod`, although this is not yet available.
|
||||
Wallets require the [daemon RPC API](https://docs.getmonero.org/rpc-library/monerod-rpc). This is actively being worked on to be backwards compatible with `monerod`, see the [RPC section](rpc.md) for more information.
|
||||
|
||||
## Can `cuprated` be used with an anonymity network like Tor?
|
||||
Not yet (directly).
|
||||
|
||||
19
books/user/src/resources/address.md
Normal file
19
books/user/src/resources/address.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Address
|
||||
IP addresses and ports used by `cuprated`.
|
||||
|
||||
### P2P
|
||||
`cuprated` can bind to a [IPv4](https://en.wikipedia.org/wiki/IPv4) or [IPv6](https://en.wikipedia.org/wiki/IPv6) address for P2P connections.
|
||||
|
||||
By default, this address is `0.0.0.0:18080`, which will bind to all available interfaces.
|
||||
|
||||
See the [`listen_on` and `p2p_port` option in the config file](../config.md) to manually set this address.
|
||||
|
||||
Setting the port to `0` will disable incoming P2P connections.
|
||||
|
||||
### RPC
|
||||
By default, the:
|
||||
|
||||
- unrestricted RPC server is enabled and binds to `127.0.0.1:18081`
|
||||
- restricted RPC server is disabled and binds to `0.0.0.0:18089`
|
||||
|
||||
See the [`address` option in the config file](../config.md) to manually set the addresses.
|
||||
@@ -1,5 +0,0 @@
|
||||
# IP
|
||||
`cuprated` currently binds to a single [IPv4 address](https://en.wikipedia.org/wiki/IPv4) for P2P connections.
|
||||
|
||||
By default, this IP address is `0.0.0.0`, which will bind to all available interfaces.
|
||||
See the [`listen_on` option in the config file](../config.md) to manually set this IP address.
|
||||
@@ -1,7 +0,0 @@
|
||||
# Ports
|
||||
`cuprated` currently uses a single port to accept incoming P2P connections.
|
||||
|
||||
By default, this port is `18080`.
|
||||
See the [`p2p_port` option in the config file](../config.md) to manually set this port.
|
||||
|
||||
Setting the port to `0` will disable incoming P2P connections.
|
||||
106
books/user/src/rpc.md
Normal file
106
books/user/src/rpc.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# RPC
|
||||
|
||||
> **⚠️ Warning ⚠️**
|
||||
>
|
||||
> Cuprate is still experimental software.
|
||||
>
|
||||
> Consider sandboxing `cuprated` before publicly exposing restricted RPC.
|
||||
|
||||
`monerod`'s daemon RPC has 3 kinds of interfaces:
|
||||
1. [JSON-RPC 2.0](https://www.jsonrpc.org) methods called at the `/json_rpc` endpoint, e.g. [`get_block`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_block)
|
||||
1. JSON endpoints, e.g. [`/get_height`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_height)
|
||||
1. Binary endpoints, e.g. [`/get_blocks.bin`](https://www.getmonero.org/resources/developer-guides/daemon-rpc.html#get_blocksbin)
|
||||
|
||||
<!-- TODO: explain the binary format -->
|
||||
|
||||
`cuprated`'s RPC aims to mirror `monerod`'s as much as it can. The end-goal is compatibility with common use-cases such as wallet software.
|
||||
|
||||
This section contains the development status of endpoints/methods in `cuprated`.
|
||||
|
||||
| Status | Meaning |
|
||||
|--------|---------|
|
||||
| 🟢 | Enabled and tested
|
||||
| 🟣 | Enabled but has differences waiting to be resolved
|
||||
| 🟠 | Enabled but not fully tested
|
||||
| ⚪ | Not enabled yet
|
||||
| ⚫ | Not planned to be supported
|
||||
|
||||
<!-- NOTE: Sort methods/endpoints A-Z -->
|
||||
|
||||
## JSON-RPC methods
|
||||
| Method | Status | Notes |
|
||||
|--------------------------------|--------|---------|
|
||||
| `add_aux_pow` | ⚪ |
|
||||
| `banned` | ⚪ |
|
||||
| `calc_pow` | ⚪ |
|
||||
| `flush_cache` | ⚫ | `cuprated` does not require this method
|
||||
| `flush_txpool` | ⚪ |
|
||||
| `generateblocks` | ⚪ |
|
||||
| `get_alternate_chains` | ⚪ |
|
||||
| `get_bans` | ⚪ |
|
||||
| `get_block` | 🟠 |
|
||||
| `get_block_count` | 🟠 |
|
||||
| `get_block_header_by_hash` | 🟠 |
|
||||
| `get_block_header_by_height` | 🟠 |
|
||||
| `get_block_headers_range` | 🟠 |
|
||||
| `get_block_template` | ⚪ |
|
||||
| `get_coinbase_tx_sum` | ⚪ |
|
||||
| `get_connections` | ⚪ |
|
||||
| `get_fee_estimate` | ⚪ |
|
||||
| `get_info` | ⚪ |
|
||||
| `get_last_block_header` | ⚪ |
|
||||
| `get_miner_data` | ⚪ |
|
||||
| `get_output_distribution` | ⚪ |
|
||||
| `get_output_histogram` | ⚪ |
|
||||
| `get_tx_ids_loose` | ⚪ | Not implemented in `monerod` release branch yet
|
||||
| `get_txpool_backlog` | ⚪ |
|
||||
| `get_version` | ⚪ |
|
||||
| `hard_fork_info` | ⚪ |
|
||||
| `on_get_block_hash` | 🟠 |
|
||||
| `prune_blockchain` | ⚫ |
|
||||
| `relay_tx` | ⚪ |
|
||||
| `set_bans` | ⚪ |
|
||||
| `submit_block` | ⚪ |
|
||||
| `sync_info` | ⚪ |
|
||||
|
||||
## JSON endpoints
|
||||
| Endpoint | Status | Notes |
|
||||
|--------------------------------|--------|---------|
|
||||
| `/get_alt_blocks_hashes` | ⚪ |
|
||||
| `/get_height` | 🟠 |
|
||||
| `/get_limit` | ⚪ |
|
||||
| `/get_net_stats` | ⚪ |
|
||||
| `/get_outs` | ⚪ |
|
||||
| `/get_peer_list` | ⚪ |
|
||||
| `/get_public_nodes` | ⚪ |
|
||||
| `/get_transaction_pool` | ⚪ |
|
||||
| `/get_transaction_pool_hashes` | ⚪ |
|
||||
| `/get_transaction_pool_stats` | ⚪ |
|
||||
| `/get_transactions` | ⚪ |
|
||||
| `/in_peers` | ⚪ |
|
||||
| `/is_key_image_spent` | ⚪ |
|
||||
| `/mining_status` | ⚫ | `cuprated` does not mine
|
||||
| `/out_peers` | ⚪ |
|
||||
| `/pop_blocks` | ⚪ |
|
||||
| `/save_bc` | ⚪ |
|
||||
| `/send_raw_transaction` | ⚪ |
|
||||
| `/set_bootstrap_daemon` | ⚪ | Requires bootstrap implementation
|
||||
| `/set_limit` | ⚪ |
|
||||
| `/set_log_categories` | ⚪ | Could be re-purposed to use `tracing` filters
|
||||
| `/set_log_hash_rate` | ⚫ | `cuprated` does not mine
|
||||
| `/set_log_level` | ⚪ | Will use `tracing` levels
|
||||
| `/start_mining` | ⚫ | `cuprated` does not mine
|
||||
| `/stop_daemon` | ⚪ |
|
||||
| `/stop_mining` | ⚫ | `cuprated` does not mine
|
||||
| `/update` | ⚫ |
|
||||
|
||||
## Binary endpoints
|
||||
| Endpoint | Status | Notes |
|
||||
|------------------------------------|--------|---------|
|
||||
| `/get_blocks.bin` | ⚪ |
|
||||
| `/get_blocks_by_height.bin` | ⚪ |
|
||||
| `/get_hashes.bin` | ⚪ |
|
||||
| `/get_output_distribution.bin` | ⚪ |
|
||||
| `/get_output_indexes.bin` | ⚪ |
|
||||
| `/get_outs.bin` | ⚪ |
|
||||
| `/get_transaction_pool_hashes.bin` | ⚪ |
|
||||
@@ -354,6 +354,33 @@ pub fn get_block_extended_header_top(
|
||||
Ok((header, height))
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Block
|
||||
/// Retrieve a [`Block`] via its [`BlockHeight`].
|
||||
#[doc = doc_error!()]
|
||||
#[inline]
|
||||
pub fn get_block(tables: &impl Tables, block_height: &BlockHeight) -> DbResult<Block> {
|
||||
let header_blob = tables.block_header_blobs().get(block_height)?.0;
|
||||
let header = BlockHeader::read(&mut header_blob.as_slice())?;
|
||||
|
||||
let transactions = tables.block_txs_hashes().get(block_height)?.0;
|
||||
let miner_tx_id = tables.block_infos().get(block_height)?.mining_tx_index;
|
||||
let miner_transaction = crate::ops::tx::get_tx_from_id(&miner_tx_id, tables.tx_blobs())?;
|
||||
|
||||
Ok(Block {
|
||||
header,
|
||||
miner_transaction,
|
||||
transactions,
|
||||
})
|
||||
}
|
||||
|
||||
/// Retrieve a [`Block`] via its [`BlockHash`].
|
||||
#[doc = doc_error!()]
|
||||
#[inline]
|
||||
pub fn get_block_by_hash(tables: &impl Tables, block_hash: &BlockHash) -> DbResult<Block> {
|
||||
let block_height = tables.block_heights().get(block_hash)?;
|
||||
get_block(tables, &block_height)
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Misc
|
||||
/// Retrieve a [`BlockInfo`] via its [`BlockHeight`].
|
||||
#[doc = doc_error!()]
|
||||
|
||||
@@ -41,9 +41,9 @@ use crate::{
|
||||
get_alt_chain_history_ranges,
|
||||
},
|
||||
block::{
|
||||
block_exists, get_block_blob_with_tx_indexes, get_block_complete_entry,
|
||||
get_block_complete_entry_from_height, get_block_extended_header_from_height,
|
||||
get_block_height, get_block_info,
|
||||
block_exists, get_block, get_block_blob_with_tx_indexes, get_block_by_hash,
|
||||
get_block_complete_entry, get_block_complete_entry_from_height,
|
||||
get_block_extended_header_from_height, get_block_height, get_block_info,
|
||||
},
|
||||
blockchain::{cumulative_generated_coins, find_split_point, top_block_height},
|
||||
key_image::key_image_exists,
|
||||
@@ -888,12 +888,28 @@ fn alt_blocks_in_chain(env: &ConcreteEnv, chain_id: ChainId) -> ResponseResult {
|
||||
|
||||
/// [`BlockchainReadRequest::Block`]
|
||||
fn block(env: &ConcreteEnv, block_height: BlockHeight) -> ResponseResult {
|
||||
Ok(BlockchainResponse::Block(todo!()))
|
||||
// Single-threaded, no `ThreadLocal` required.
|
||||
let env_inner = env.env_inner();
|
||||
let tx_ro = env_inner.tx_ro()?;
|
||||
let tables = env_inner.open_tables(&tx_ro)?;
|
||||
|
||||
Ok(BlockchainResponse::Block(get_block(
|
||||
&tables,
|
||||
&block_height,
|
||||
)?))
|
||||
}
|
||||
|
||||
/// [`BlockchainReadRequest::BlockByHash`]
|
||||
fn block_by_hash(env: &ConcreteEnv, block_hash: BlockHash) -> ResponseResult {
|
||||
Ok(BlockchainResponse::Block(todo!()))
|
||||
// Single-threaded, no `ThreadLocal` required.
|
||||
let env_inner = env.env_inner();
|
||||
let tx_ro = env_inner.tx_ro()?;
|
||||
let tables = env_inner.open_tables(&tx_ro)?;
|
||||
|
||||
Ok(BlockchainResponse::Block(get_block_by_hash(
|
||||
&tables,
|
||||
&block_hash,
|
||||
)?))
|
||||
}
|
||||
|
||||
/// [`BlockchainReadRequest::TotalTxCount`]
|
||||
|
||||
Reference in New Issue
Block a user