json-rpc fixes
Some checks are pending
Deny / audit (push) Waiting to run

This commit is contained in:
hinto.janai 2024-12-19 20:41:50 -05:00
parent 114a5db52e
commit b2b7e93e4c
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
4 changed files with 115 additions and 82 deletions

25
Cargo.lock generated
View file

@ -885,6 +885,7 @@ dependencies = [
"bytes", "bytes",
"cuprate-fixed-bytes", "cuprate-fixed-bytes",
"cuprate-helper", "cuprate-helper",
"cuprate-hex",
"hex", "hex",
"paste", "paste",
"ref-cast", "ref-cast",
@ -939,6 +940,15 @@ dependencies = [
"windows", "windows",
] ]
[[package]]
name = "cuprate-hex"
version = "0.0.0"
dependencies = [
"hex",
"serde",
"serde_json",
]
[[package]] [[package]]
name = "cuprate-json-rpc" name = "cuprate-json-rpc"
version = "0.0.0" version = "0.0.0"
@ -1066,9 +1076,15 @@ version = "0.0.0"
dependencies = [ dependencies = [
"cuprate-epee-encoding", "cuprate-epee-encoding",
"cuprate-fixed-bytes", "cuprate-fixed-bytes",
"cuprate-helper",
"cuprate-hex",
"cuprate-p2p-core",
"cuprate-test-utils", "cuprate-test-utils",
"cuprate-types", "cuprate-types",
"hex",
"hex-literal",
"paste", "paste",
"pretty_assertions",
"serde", "serde",
"serde_json", "serde_json",
] ]
@ -1125,12 +1141,14 @@ dependencies = [
name = "cuprate-types" name = "cuprate-types"
version = "0.0.0" version = "0.0.0"
dependencies = [ dependencies = [
"bitflags 2.6.0",
"bytes", "bytes",
"cfg-if",
"cuprate-epee-encoding", "cuprate-epee-encoding",
"cuprate-fixed-bytes", "cuprate-fixed-bytes",
"cuprate-helper", "cuprate-helper",
"cuprate-hex",
"curve25519-dalek", "curve25519-dalek",
"hex",
"hex-literal", "hex-literal",
"monero-serai", "monero-serai",
"pretty_assertions", "pretty_assertions",
@ -1162,7 +1180,7 @@ name = "cuprate-zmq-types"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"assert-json-diff", "assert-json-diff",
"cuprate-types", "cuprate-hex",
"hex", "hex",
"serde", "serde",
"serde_json", "serde_json",
@ -1190,6 +1208,7 @@ dependencies = [
"cuprate-consensus", "cuprate-consensus",
"cuprate-consensus-context", "cuprate-consensus-context",
"cuprate-consensus-rules", "cuprate-consensus-rules",
"cuprate-constants",
"cuprate-cryptonight", "cuprate-cryptonight",
"cuprate-dandelion-tower", "cuprate-dandelion-tower",
"cuprate-database", "cuprate-database",
@ -1198,6 +1217,7 @@ dependencies = [
"cuprate-fast-sync", "cuprate-fast-sync",
"cuprate-fixed-bytes", "cuprate-fixed-bytes",
"cuprate-helper", "cuprate-helper",
"cuprate-hex",
"cuprate-json-rpc", "cuprate-json-rpc",
"cuprate-levin", "cuprate-levin",
"cuprate-p2p", "cuprate-p2p",
@ -1226,6 +1246,7 @@ dependencies = [
"serde", "serde",
"serde_bytes", "serde_bytes",
"serde_json", "serde_json",
"strum",
"thiserror", "thiserror",
"thread_local", "thread_local",
"tokio", "tokio",

View file

@ -54,7 +54,7 @@ use cuprate_rpc_types::{
}; };
use cuprate_types::{ use cuprate_types::{
rpc::{AuxPow, CoinbaseTxSum, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry}, rpc::{AuxPow, CoinbaseTxSum, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry},
BlockTemplate, HardFork, BlockTemplate, Chain, HardFork,
}; };
use crate::{ use crate::{
@ -228,12 +228,7 @@ async fn on_get_block_hash(
request: OnGetBlockHashRequest, request: OnGetBlockHashRequest,
) -> Result<OnGetBlockHashResponse, Error> { ) -> Result<OnGetBlockHashResponse, Error> {
let [height] = request.block_height; let [height] = request.block_height;
let hash = blockchain::block_hash( let hash = blockchain::block_hash(&mut state.blockchain_read, height, Chain::Main).await?;
&mut state.blockchain_read,
height,
todo!("access to `cuprated`'s Chain"),
)
.await?;
Ok(OnGetBlockHashResponse { Ok(OnGetBlockHashResponse {
block_hash: Hex(hash), block_hash: Hex(hash),
@ -428,7 +423,7 @@ async fn get_block(
let blob = HexVec(block.serialize()); let blob = HexVec(block.serialize());
let miner_tx_hash = Hex(block.miner_transaction.hash()); let miner_tx_hash = Hex(block.miner_transaction.hash());
let tx_hashes = block.transactions.iter().map(|a| Hex(*a)).collect(); let tx_hashes = block.transactions.iter().copied().map(Hex).collect();
let json = { let json = {
let block = cuprate_types::json::block::Block::from(block); let block = cuprate_types::json::block::Block::from(block);
serde_json::to_string_pretty(&block)? serde_json::to_string_pretty(&block)?
@ -467,8 +462,7 @@ async fn get_info(
let c = context.unchecked_blockchain_context(); let c = context.unchecked_blockchain_context();
let cumulative_difficulty = c.cumulative_difficulty; let cumulative_difficulty = c.cumulative_difficulty;
let adjusted_time = c.current_adjusted_timestamp_for_time_lock(); // TODO: is this correct? let adjusted_time = c.current_adjusted_timestamp_for_time_lock();
let c = &c.context_to_verify_block; let c = &c.context_to_verify_block;
let alt_blocks_count = if restricted { let alt_blocks_count = if restricted {
@ -476,76 +470,98 @@ async fn get_info(
} else { } else {
blockchain::alt_chain_count(&mut state.blockchain_read).await? blockchain::alt_chain_count(&mut state.blockchain_read).await?
}; };
let block_weight_limit = usize_to_u64(c.effective_median_weight); // TODO: is this correct?
let block_weight_median = usize_to_u64(c.median_weight_for_block_reward); // TODO: is this correct? let block_weight_limit = usize_to_u64(c.effective_median_weight);
let block_weight_median = usize_to_u64(c.median_weight_for_block_reward);
let block_size_limit = block_weight_limit; let block_size_limit = block_weight_limit;
let block_size_median = block_weight_median; let block_size_median = block_weight_median;
#[expect(clippy::if_same_then_else, reason = "TODO: support bootstrap")]
let (bootstrap_daemon_address, was_bootstrap_ever_used) = if restricted { let (bootstrap_daemon_address, was_bootstrap_ever_used) = if restricted {
(String::new(), false) (String::new(), false)
} else { } else {
todo!("support bootstrap daemon") (String::new(), false)
}; };
let busy_syncing = blockchain_manager::syncing(&mut state.blockchain_manager).await?; let busy_syncing = blockchain_manager::syncing(&mut state.blockchain_manager).await?;
let (cumulative_difficulty, cumulative_difficulty_top64) = let (cumulative_difficulty, cumulative_difficulty_top64) =
split_u128_into_low_high_bits(cumulative_difficulty); split_u128_into_low_high_bits(cumulative_difficulty);
let (database_size, free_space) = blockchain::database_size(&mut state.blockchain_read).await?; let (database_size, free_space) = blockchain::database_size(&mut state.blockchain_read).await?;
let (database_size, free_space) = if restricted { let (database_size, free_space) = if restricted {
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L131-L134> // <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L131-L134>
const fn round_up(value: u64, quantum: u64) -> u64 { const fn round_up(value: u64, quantum: u64) -> u64 {
value.div_ceil(quantum) value.div_ceil(quantum)
} }
let database_size = round_up(database_size, 5 * 1024 * 1024 * 1024); let database_size = round_up(database_size, 5 * 1024 * 1024 * 1024);
(database_size, u64::MAX) (database_size, u64::MAX)
} else { } else {
(database_size, free_space) (database_size, free_space)
}; };
let (difficulty, difficulty_top64) = split_u128_into_low_high_bits(c.next_difficulty); let (difficulty, difficulty_top64) = split_u128_into_low_high_bits(c.next_difficulty);
let height = usize_to_u64(c.chain_height); let height = usize_to_u64(c.chain_height);
let height_without_bootstrap = if restricted { 0 } else { height }; let height_without_bootstrap = if restricted { 0 } else { height };
let (incoming_connections_count, outgoing_connections_count) = if restricted { let (incoming_connections_count, outgoing_connections_count) = if restricted {
(0, 0) (0, 0)
} else { } else {
address_book::connection_count::<ClearNet>(&mut DummyAddressBook).await? address_book::connection_count::<ClearNet>(&mut DummyAddressBook).await?
}; };
let (mainnet, testnet, stagenet) = match todo!("access to `cuprated`'s `Network`") {
// TODO: This should be `cuprated`'s active network.
let network = Network::Mainnet;
let (mainnet, testnet, stagenet) = match network {
Network::Mainnet => (true, false, false), Network::Mainnet => (true, false, false),
Network::Testnet => (false, true, false), Network::Testnet => (false, true, false),
Network::Stagenet => (false, false, true), Network::Stagenet => (false, false, true),
}; };
// TODO: make sure this is:
// - the same case as `monerod` let nettype = network.to_string();
// - untagged (no `Network::`) // TODO: access to CLI/config's `--offline`
let nettype = todo!("access to `cuprated`'s `Network`").to_string(); let offline = false;
let offline = todo!("access to CLI/config's `--offline`");
let rpc_connections_count = if restricted { #[expect(
0 clippy::if_same_then_else,
} else { reason = "TODO: implement a connection counter in axum/RPC"
todo!("implement a connection counter in axum/RPC") )]
}; let rpc_connections_count = if restricted { 0 } else { 0 };
let start_time = if restricted { 0 } else { *START_INSTANT_UNIX }; 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(&mut state.blockchain_manager).await?;
let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?; let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?;
let target = blockchain_manager::target(&mut state.blockchain_manager) let target = blockchain_manager::target(&mut state.blockchain_manager)
.await? .await?
.as_secs(); .as_secs();
let top_block_hash = Hex(c.top_hash); let top_block_hash = Hex(c.top_hash);
let tx_count = blockchain::total_tx_count(&mut state.blockchain_read).await?; let tx_count = blockchain::total_tx_count(&mut state.blockchain_read).await?;
let tx_pool_size = txpool::size(&mut state.txpool_read, !restricted).await?; let tx_pool_size = txpool::size(&mut state.txpool_read, !restricted).await?;
let update_available = if restricted {
false #[expect(
} else { clippy::if_same_then_else,
todo!("implement an update checker for `cuprated`") clippy::needless_bool,
}; reason = "TODO: implement an update checker for `cuprated`?"
)]
let update_available = if restricted { false } else { false };
let version = if restricted { let version = if restricted {
String::new() String::new()
} else { } else {
VERSION_BUILD.to_string() VERSION_BUILD.to_string()
}; };
let (white_peerlist_size, grey_peerlist_size) = if restricted { let (white_peerlist_size, grey_peerlist_size) = if restricted {
(0, 0) (0, 0)
} else { } else {
address_book::peerlist_size::<ClearNet>(&mut DummyAddressBook).await? address_book::peerlist_size::<ClearNet>(&mut DummyAddressBook).await?
}; };
let wide_cumulative_difficulty = format!("{cumulative_difficulty:#x}"); let wide_cumulative_difficulty = format!("{cumulative_difficulty:#x}");
let wide_difficulty = format!("{:#x}", c.next_difficulty); let wide_difficulty = format!("{:#x}", c.next_difficulty);
@ -607,18 +623,12 @@ async fn hard_fork_info(
.current_hf .current_hf
}; };
let info = blockchain_context::hard_fork_info(&mut state.blockchain_context, hard_fork).await?; let hard_fork_info =
blockchain_context::hard_fork_info(&mut state.blockchain_context, hard_fork).await?;
Ok(HardForkInfoResponse { Ok(HardForkInfoResponse {
base: helper::access_response_base(false), base: helper::access_response_base(false),
earliest_height: info.earliest_height, hard_fork_info,
enabled: info.enabled,
state: info.state,
threshold: info.threshold,
version: info.version,
votes: info.votes,
voting: info.voting,
window: info.window,
}) })
} }
@ -1036,6 +1046,7 @@ async fn calc_pow(
// } // }
// TODO: will `CalculatePow` do the above checks? // TODO: will `CalculatePow` do the above checks?
let pow_hash = blockchain_context::calculate_pow( let pow_hash = blockchain_context::calculate_pow(
&mut state.blockchain_context, &mut state.blockchain_context,
hardfork, hardfork,
@ -1049,23 +1060,16 @@ async fn calc_pow(
}) })
} }
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3542-L3551>
async fn flush_cache(
state: CupratedRpcHandler,
request: FlushCacheRequest,
) -> Result<FlushCacheResponse, Error> {
// TODO: cuprated doesn't need this call; decide behavior.
Ok(FlushCacheResponse {
base: helper::response_base(false),
})
}
/// An async-friendly wrapper for [`add_aux_pow_inner`]. /// An async-friendly wrapper for [`add_aux_pow_inner`].
async fn add_aux_pow( async fn add_aux_pow(
state: CupratedRpcHandler, state: CupratedRpcHandler,
request: AddAuxPowRequest, request: AddAuxPowRequest,
) -> Result<AddAuxPowResponse, Error> { ) -> Result<AddAuxPowResponse, Error> {
// This method can be a bit heavy, so rate-limit restricted use.
if state.is_restricted() {
tokio::time::sleep(Duration::from_millis(100)).await;
}
tokio::task::spawn_blocking(|| add_aux_pow_inner(state, request)).await? tokio::task::spawn_blocking(|| add_aux_pow_inner(state, request)).await?
} }
@ -1261,16 +1265,25 @@ fn add_aux_pow_inner(
}) })
} }
//---------------------------------------------------------------------------------------------------- Unsupported RPC calls (for now)
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3553-L3627> /// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3553-L3627>
async fn get_tx_ids_loose( async fn get_tx_ids_loose(
state: CupratedRpcHandler, state: CupratedRpcHandler,
request: GetTxIdsLooseRequest, request: GetTxIdsLooseRequest,
) -> Result<GetTxIdsLooseResponse, Error> { ) -> Result<GetTxIdsLooseResponse, Error> {
// TODO: this RPC call is not yet in the v0.18 branch.
return Err(anyhow!("Not implemented"));
Ok(GetTxIdsLooseResponse { Ok(GetTxIdsLooseResponse {
base: helper::response_base(false), base: helper::response_base(false),
txids: todo!(), txids: todo!("this RPC call is not yet in the v0.18 branch."),
}) })
} }
//---------------------------------------------------------------------------------------------------- Unsupported RPC calls (forever)
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3542-L3551>
async fn flush_cache(
state: CupratedRpcHandler,
request: FlushCacheRequest,
) -> Result<FlushCacheResponse, Error> {
unreachable!()
}

View file

@ -59,7 +59,7 @@ pub async fn size(
Ok(usize_to_u64(size)) Ok(usize_to_u64(size))
} }
/// TODO /// [`TxpoolReadRequest::PoolInfo`]
pub async fn pool_info( pub async fn pool_info(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
@ -84,7 +84,7 @@ pub async fn pool_info(
Ok(pool_info) Ok(pool_info)
} }
/// TODO /// [`TxpoolReadRequest::TxsByHash`]
pub async fn txs_by_hash( pub async fn txs_by_hash(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
tx_hashes: Vec<[u8; 32]>, tx_hashes: Vec<[u8; 32]>,
@ -107,7 +107,7 @@ pub async fn txs_by_hash(
Ok(txs_in_pool) Ok(txs_in_pool)
} }
/// TODO /// [`TxpoolReadRequest::KeyImagesSpent`]
pub async fn key_images_spent( pub async fn key_images_spent(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
key_images: Vec<[u8; 32]>, key_images: Vec<[u8; 32]>,
@ -130,7 +130,7 @@ pub async fn key_images_spent(
Ok(status) Ok(status)
} }
/// TODO /// [`TxpoolReadRequest::Pool`]
pub async fn pool( pub async fn pool(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
@ -157,7 +157,7 @@ pub async fn pool(
Ok((txs, spent_key_images)) Ok((txs, spent_key_images))
} }
/// TODO /// [`TxpoolReadRequest::PoolStats`]
pub async fn pool_stats( pub async fn pool_stats(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
@ -178,7 +178,7 @@ pub async fn pool_stats(
Ok(txpool_stats) Ok(txpool_stats)
} }
/// TODO /// [`TxpoolReadRequest::AllHashes`]
pub async fn all_hashes( pub async fn all_hashes(
txpool_read: &mut TxpoolReadHandle, txpool_read: &mut TxpoolReadHandle,
include_sensitive_txs: bool, include_sensitive_txs: bool,
@ -199,19 +199,19 @@ pub async fn all_hashes(
Ok(hashes) Ok(hashes)
} }
/// TODO /// TODO: impl txpool manager.
pub async fn flush(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> { pub async fn flush(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> {
todo!(); todo!();
Ok(()) Ok(())
} }
/// TODO /// TODO: impl txpool manager.
pub async fn relay(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> { pub async fn relay(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> {
todo!(); todo!();
Ok(()) Ok(())
} }
/// TODO /// TODO: impl txpool manager.
pub async fn check_maybe_relay_local( pub async fn check_maybe_relay_local(
txpool_manager: &mut Infallible, txpool_manager: &mut Infallible,
tx: Transaction, tx: Transaction,

View file

@ -7,7 +7,9 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use cuprate_hex::{Hex, HexVec}; use cuprate_hex::{Hex, HexVec};
use cuprate_types::rpc::{AuxPow, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry}; use cuprate_types::rpc::{
AuxPow, GetMinerDataTxBacklogEntry, HardForkEntry, HardForkInfo, TxBacklogEntry,
};
use crate::{ use crate::{
base::{AccessResponseBase, ResponseBase}, base::{AccessResponseBase, ResponseBase},
@ -385,14 +387,9 @@ define_request_and_response! {
}, },
AccessResponseBase { AccessResponseBase {
earliest_height: u64, /// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
enabled: bool, #[cfg_attr(feature = "serde", serde(flatten))]
state: u32, hard_fork_info: HardForkInfo,
threshold: u32,
version: u8,
votes: u32,
voting: u8,
window: u32,
} }
} }
@ -1464,14 +1461,16 @@ mod test {
json::HARD_FORK_INFO_RESPONSE, json::HARD_FORK_INFO_RESPONSE,
HardForkInfoResponse { HardForkInfoResponse {
base: AccessResponseBase::OK, base: AccessResponseBase::OK,
earliest_height: 2689608, hard_fork_info: HardForkInfo {
enabled: true, earliest_height: 2689608,
state: 0, enabled: true,
threshold: 0, state: 0,
version: 16, threshold: 0,
votes: 10080, version: 16,
voting: 16, votes: 10080,
window: 10080, voting: 16,
window: 10080,
},
}, },
); );
} }