review fixes
Some checks are pending
Deny / audit (push) Waiting to run

This commit is contained in:
hinto.janai 2025-01-16 20:14:30 -05:00
parent 4118af2f24
commit 0b3ff4e14c
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
7 changed files with 136 additions and 36 deletions

View file

@ -16,6 +16,7 @@ use cuprate_rpc_types::{
misc::BlockHeader,
};
use cuprate_types::HardFork;
use monero_serai::transaction::Timelock;
use crate::rpc::{
service::{blockchain, blockchain_context},
@ -170,6 +171,23 @@ pub(super) async fn top_height(state: &mut CupratedRpcHandler) -> Result<(u64, [
Ok((height, hash))
}
/// Returns `true` if the `timelock` is unlocked.
pub(super) async fn timelock_is_unlocked(
state: &mut CupratedRpcHandler,
timelock: Timelock,
) -> Result<bool, Error> {
let unlocked = match timelock {
Timelock::None => true,
Timelock::Block(height) => {
let (top_height, _) = top_height(state).await?;
top_height > usize_to_u64(height)
}
Timelock::Time(timestamp) => cuprate_helper::time::current_unix_timestamp() > timestamp,
};
Ok(unlocked)
}
/// TODO: impl bootstrap
pub const fn response_base(is_bootstrap: bool) -> ResponseBase {
if is_bootstrap {

View file

@ -467,8 +467,10 @@ async fn get_info(
blockchain::alt_chain_count(&mut state.blockchain_read).await?
};
let block_weight_limit = usize_to_u64(c.effective_median_weight);
let block_weight_median = usize_to_u64(c.median_weight_for_block_reward);
// TODO: these values are incorrectly calculated in `monerod` and copied in `cuprated`
// <https://github.com/Cuprate/cuprate/pull/355#discussion_r1906273007>
let block_weight_limit = usize_to_u64(c.effective_median_weight * 2);
let block_weight_median = usize_to_u64(c.effective_median_weight);
let block_size_limit = block_weight_limit;
let block_size_median = block_weight_median;
@ -969,9 +971,11 @@ async fn get_miner_data(
let major_version = c.current_hf.as_u8();
let height = usize_to_u64(c.chain_height);
let prev_id = Hex(c.top_hash);
let seed_hash = Hex(c.top_hash);
// TODO: RX seed hash <https://github.com/Cuprate/cuprate/pull/355#discussion_r1911814320>.
let seed_hash = Hex([0; 32]);
let difficulty = c.next_difficulty.hex_prefix();
let median_weight = usize_to_u64(c.median_weight_for_block_reward);
// TODO: <https://github.com/Cuprate/cuprate/pull/355#discussion_r1911821515>
let median_weight = usize_to_u64(c.effective_median_weight);
let already_generated_coins = c.already_generated_coins;
let tx_backlog = txpool::backlog(&mut state.txpool_read)
.await?
@ -1061,7 +1065,7 @@ async fn add_aux_pow(
tokio::time::sleep(Duration::from_millis(100)).await;
}
tokio::task::spawn_blocking(|| add_aux_pow_inner(state, request)).await?
cuprate_helper::asynch::rayon_spawn_async(|| add_aux_pow_inner(state, request)).await
}
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2072-L2207>

View file

@ -45,34 +45,22 @@ pub(super) async fn get_outs(
return Err(anyhow!("Too many outs requested"));
}
let outputs = {
let mut outputs = HashMap::<u64, HashSet<u64>>::with_capacity(request.outputs.len());
let outputs = blockchain::outputs_vec(&mut state.blockchain_read, request.outputs).await?;
let mut outs = Vec::<OutKeyBin>::with_capacity(outputs.len());
for out in request.outputs {
outputs
.entry(out.amount)
.and_modify(|set| {
set.insert(out.index);
})
.or_insert_with(|| HashSet::from([out.index]));
}
outputs
};
let outs = blockchain::outputs(&mut state.blockchain_read, outputs)
.await?
.into_iter()
.flat_map(|(amount, index_map)| {
index_map.into_values().map(|out| OutKeyBin {
for (_, index_vec) in outputs {
for (_, out) in index_vec {
let out_key = OutKeyBin {
key: out.key.map_or([0; 32], |e| e.compress().0),
mask: out.commitment.compress().0,
unlocked: matches!(out.time_lock, Timelock::None),
unlocked: helper::timelock_is_unlocked(&mut state, out.time_lock).await?,
height: usize_to_u64(out.height),
txid: if request.get_txid { out.txid } else { [0; 32] },
})
})
.collect::<Vec<OutKeyBin>>();
};
outs.push(out_key);
}
}
Ok(GetOutsResponse {
base: helper::access_response_base(false),

View file

@ -6,6 +6,7 @@ use std::{
};
use anyhow::Error;
use cuprate_rpc_types::misc::GetOutputsOut;
use monero_serai::block::Block;
use tower::{Service, ServiceExt};
@ -203,6 +204,28 @@ pub async fn outputs(
Ok(outputs)
}
/// [`BlockchainReadRequest::OutputsVec`]
pub async fn outputs_vec(
blockchain_read: &mut BlockchainReadHandle,
outputs: Vec<GetOutputsOut>,
) -> Result<Vec<(u64, Vec<(u64, OutputOnChain)>)>, Error> {
let outputs = outputs
.into_iter()
.map(|output| (output.amount, output.index))
.collect();
let BlockchainResponse::OutputsVec(outputs) = blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::OutputsVec(outputs))
.await?
else {
unreachable!();
};
Ok(outputs)
}
/// [`BlockchainReadRequest::NumberOutputsWithAmount`]
pub async fn number_outputs_with_amount(
blockchain_read: &mut BlockchainReadHandle,

View file

@ -119,8 +119,10 @@ fn map_request(
R::ChainHeight => chain_height(env),
R::GeneratedCoins(height) => generated_coins(env, height),
R::Outputs(map) => outputs(env, map),
R::OutputsVec(vec) => outputs_vec(env, vec),
R::NumberOutputsWithAmount(vec) => number_outputs_with_amount(env, vec),
R::KeyImagesSpent(set) => key_images_spent(env, set),
R::KeyImagesSpentVec(set) => key_images_spent_vec(env, set),
R::CompactChainHistory => compact_chain_history(env),
R::NextChainEntry(block_hashes, amount) => next_chain_entry(env, &block_hashes, amount),
R::FindFirstUnknown(block_ids) => find_first_unknown(env, &block_ids),
@ -487,6 +489,12 @@ fn outputs(env: &ConcreteEnv, outputs: HashMap<Amount, HashSet<AmountIndex>>) ->
Ok(BlockchainResponse::Outputs(map))
}
/// [`BlockchainReadRequest::OutputsVec`].
#[inline]
fn outputs_vec(env: &ConcreteEnv, outputs: Vec<(Amount, AmountIndex)>) -> ResponseResult {
Ok(BlockchainResponse::OutputsVec(todo!()))
}
/// [`BlockchainReadRequest::NumberOutputsWithAmount`].
#[inline]
fn number_outputs_with_amount(env: &ConcreteEnv, amounts: Vec<Amount>) -> ResponseResult {
@ -538,7 +546,43 @@ fn number_outputs_with_amount(env: &ConcreteEnv, amounts: Vec<Amount>) -> Respon
/// [`BlockchainReadRequest::KeyImagesSpent`].
#[inline]
fn key_images_spent(env: &ConcreteEnv, key_images: Vec<KeyImage>) -> ResponseResult {
fn key_images_spent(env: &ConcreteEnv, key_images: HashSet<KeyImage>) -> ResponseResult {
// Prepare tx/tables in `ThreadLocal`.
let env_inner = env.env_inner();
let tx_ro = thread_local(env);
let tables = thread_local(env);
// Key image check function.
let key_image_exists = |key_image| {
let tx_ro = tx_ro.get_or_try(|| env_inner.tx_ro())?;
let tables = get_tables!(env_inner, tx_ro, tables)?.as_ref();
key_image_exists(&key_image, tables.key_images())
};
// FIXME:
// Create/use `enum cuprate_types::Exist { Does, DoesNot }`
// or similar instead of `bool` for clarity.
// <https://github.com/Cuprate/cuprate/pull/113#discussion_r1581536526>
//
// Collect results using `rayon`.
match key_images
.into_par_iter()
.map(key_image_exists)
// If the result is either:
// `Ok(true)` => a key image was found, return early
// `Err` => an error was found, return early
//
// Else, `Ok(false)` will continue the iterator.
.find_any(|result| !matches!(result, Ok(false)))
{
None | Some(Ok(false)) => Ok(BlockchainResponse::KeyImagesSpent(false)), // Key image was NOT found.
Some(Ok(true)) => Ok(BlockchainResponse::KeyImagesSpent(true)), // Key image was found.
Some(Err(e)) => Err(e), // A database error occurred.
}
}
/// [`BlockchainReadRequest::KeyImagesSpentVec`].
fn key_images_spent_vec(env: &ConcreteEnv, key_images: Vec<KeyImage>) -> ResponseResult {
// Prepare tx/tables in `ThreadLocal`.
let env_inner = env.env_inner();
let tx_ro = thread_local(env);
@ -552,7 +596,7 @@ fn key_images_spent(env: &ConcreteEnv, key_images: Vec<KeyImage>) -> ResponseRes
};
// Collect results using `rayon`.
Ok(BlockchainResponse::KeyImagesSpent(
Ok(BlockchainResponse::KeyImagesSpentVec(
key_images
.into_par_iter()
.map(key_image_exists)

View file

@ -180,7 +180,7 @@ async fn test_template(
// Contains a fake non-spent key-image.
let ki_req = vec![[0; 32]];
let ki_resp = Ok(BlockchainResponse::KeyImagesSpent(vec![false]));
let ki_resp = Ok(BlockchainResponse::KeyImagesSpentVec(vec![false]));
//----------------------------------------------------------------------- Assert expected response
// Assert read requests lead to the expected responses.
@ -218,7 +218,7 @@ async fn test_template(
BlockchainReadRequest::NumberOutputsWithAmount(num_req),
num_resp,
),
(BlockchainReadRequest::KeyImagesSpent(ki_req), ki_resp),
(BlockchainReadRequest::KeyImagesSpentVec(ki_req), ki_resp),
] {
let response = reader.clone().oneshot(request).await;
println!("response: {response:#?}, expected_response: {expected_response:#?}");
@ -232,12 +232,12 @@ async fn test_template(
// Assert each key image we inserted comes back as "spent".
for key_image in tables.key_images_iter().keys().unwrap() {
let key_image = key_image.unwrap();
let request = BlockchainReadRequest::KeyImagesSpent(vec![key_image]);
let request = BlockchainReadRequest::KeyImagesSpentVec(vec![key_image]);
let response = reader.clone().oneshot(request).await;
println!("response: {response:#?}, key_image: {key_image:#?}");
assert_eq!(
response.unwrap(),
BlockchainResponse::KeyImagesSpent(vec![true])
BlockchainResponse::KeyImagesSpentVec(vec![true])
);
}

View file

@ -96,6 +96,13 @@ pub enum BlockchainReadRequest {
/// RCT output indices.
Outputs(HashMap<u64, HashSet<u64>>),
/// This is the same as [`BlockchainReadRequest::Outputs`] but with a [`Vec`] container.
///
/// The input [`Vec`] values are `(amount, amount_index)`.
///
/// The response will be in the same order as the request.
OutputsVec(Vec<(u64, u64)>),
/// Request the amount of outputs with a certain amount.
///
/// The input is a list of output amounts.
@ -104,7 +111,12 @@ pub enum BlockchainReadRequest {
/// Check the spend status of key images.
///
/// Input is a set of key images.
KeyImagesSpent(Vec<[u8; 32]>),
KeyImagesSpent(HashSet<[u8; 32]>),
/// Same as [`BlockchainReadRequest::KeyImagesSpent`] but with a [`Vec`].
///
/// The response will be in the same order as the request.
KeyImagesSpentVec(Vec<[u8; 32]>),
/// A request for the compact chain history.
CompactChainHistory,
@ -284,6 +296,9 @@ pub enum BlockchainResponse {
/// associated with their amount and amount index.
Outputs(HashMap<u64, HashMap<u64, OutputOnChain>>),
/// Response to [`BlockchainReadRequest::OutputsVec`].
OutputsVec(Vec<(u64, Vec<(u64, OutputOnChain)>)>),
/// Response to [`BlockchainReadRequest::NumberOutputsWithAmount`].
///
/// Inner value is a `HashMap` of all the outputs requested where:
@ -293,11 +308,19 @@ pub enum BlockchainResponse {
/// Response to [`BlockchainReadRequest::KeyImagesSpent`].
///
/// The inner value is `true` if _any_ of the key images
/// were spent (existed in the database already).
///
/// The inner value is `false` if _none_ of the key images were spent.
KeyImagesSpent(bool),
/// Response to [`BlockchainReadRequest::KeyImagesSpentVec`].
///
/// Inner value is a `Vec` the same length as the input.
///
/// The index of each entry corresponds with the request.
/// `true` means that the key image was spent.
KeyImagesSpent(Vec<bool>),
KeyImagesSpentVec(Vec<bool>),
/// Response to [`BlockchainReadRequest::CompactChainHistory`].
CompactChainHistory {