mirror of
https://github.com/hinto-janai/cuprate.git
synced 2025-01-21 10:14:30 +00:00
This commit is contained in:
parent
4118af2f24
commit
0b3ff4e14c
7 changed files with 136 additions and 36 deletions
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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])
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue