From de7abfc3f004673f4e1fb0fd38545af78ccad90d Mon Sep 17 00:00:00 2001 From: "hinto.janai" Date: Mon, 25 Nov 2024 20:52:18 -0500 Subject: [PATCH] `helper::block_header` --- binaries/cuprated/src/rpc/helper.rs | 130 +++++++++++------- .../src/rpc/request/blockchain_context.rs | 19 +++ 2 files changed, 97 insertions(+), 52 deletions(-) diff --git a/binaries/cuprated/src/rpc/helper.rs b/binaries/cuprated/src/rpc/helper.rs index 48434a45..5ee42444 100644 --- a/binaries/cuprated/src/rpc/helper.rs +++ b/binaries/cuprated/src/rpc/helper.rs @@ -9,35 +9,93 @@ use anyhow::{anyhow, Error}; use monero_serai::block::Block; use cuprate_consensus::{BlockChainContext, BlockChainContextService}; -use cuprate_helper::{cast::usize_to_u64, map::split_u128_into_low_high_bits}; +use cuprate_helper::{ + cast::{u64_to_usize, usize_to_u64}, + map::split_u128_into_low_high_bits, +}; use cuprate_rpc_types::misc::{BlockHeader, KeyImageSpentStatus}; -use cuprate_types::ExtendedBlockHeader; +use cuprate_types::{ExtendedBlockHeader, HardFork}; use crate::{ rpc::request::{blockchain, blockchain_context}, rpc::CupratedRpcHandler, }; -pub(super) fn into_block_header( +/// Map some data into a [`BlockHeader`]. +/// +/// Sort of equivalent to: +/// . +pub(super) async fn block_header( + state: &mut CupratedRpcHandler, height: u64, - top_height: u64, fill_pow_hash: bool, - block: Block, - header: ExtendedBlockHeader, -) -> BlockHeader { +) -> Result { + let block = blockchain::block(&mut state.blockchain_read, height).await?; + let header = blockchain::block_extended_header(&mut state.blockchain_read, height).await?; + let hardfork = HardFork::from_vote(header.vote); + let (top_height, _) = top_height(state).await?; + + // TODO: if the request block is not on the main chain, + // we must get the alt block and this variable will be `true`. + let orphan_status = false; + + // FIXME: is there a cheaper way to get this? + let difficulty = blockchain_context::batch_get_difficulties( + &mut state.blockchain_context, + vec![(height, hardfork)], + ) + .await? + .first() + .copied() + .ok_or_else(|| anyhow!("Failed to get block difficulty"))?; + + 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 pow_hash = blockchain_context::calculate_pow( + &mut state.blockchain_context, + hardfork, + block, + seed_hash, + ) + .await?; + + hex::encode(pow_hash) + } else { + String::new() + }; + let block_weight = usize_to_u64(header.block_weight); let depth = top_height.saturating_sub(height); + let (cumulative_difficulty_top64, cumulative_difficulty) = split_u128_into_low_high_bits(header.cumulative_difficulty); + let (difficulty_top64, difficulty) = split_u128_into_low_high_bits(difficulty); + let wide_difficulty = hex::encode(difficulty.to_ne_bytes()); - BlockHeader { + let reward = block + .miner_transaction + .prefix() + .outputs + .iter() + .map(|o| o.amount.expect("coinbase is transparent")) + .sum::(); + + Ok(BlockHeader { block_size: block_weight, block_weight, cumulative_difficulty_top64, cumulative_difficulty, depth, - difficulty_top64: todo!(), - difficulty: todo!(), + difficulty_top64, + difficulty, hash: hex::encode(block.hash()), height, long_term_weight: usize_to_u64(header.long_term_weight), @@ -46,33 +104,14 @@ pub(super) fn into_block_header( minor_version: header.vote, nonce: block.header.nonce, num_txes: usize_to_u64(block.transactions.len()), - orphan_status: todo!(), - pow_hash: if fill_pow_hash { - todo!() - } else { - String::new() - }, + orphan_status, + pow_hash, prev_hash: hex::encode(block.header.previous), - reward: todo!(), + reward, timestamp: block.header.timestamp, wide_cumulative_difficulty: hex::encode(u128::to_le_bytes(header.cumulative_difficulty)), - wide_difficulty: todo!(), - } -} - -/// Get a [`VerifiedBlockInformation`] and map it to a [`BlockHeader`]. -pub(super) async fn block_header( - state: &mut CupratedRpcHandler, - height: u64, - fill_pow_hash: bool, -) -> Result { - let (top_height, _) = top_height(state).await?; - let block = blockchain::block(&mut state.blockchain_read, height).await?; - let header = blockchain::block_extended_header(&mut state.blockchain_read, height).await?; - - let block_header = into_block_header(height, top_height, fill_pow_hash, block, header); - - Ok(block_header) + wide_difficulty, + }) } /// Same as [`block_header`] but with the block's hash. @@ -81,24 +120,11 @@ pub(super) async fn block_header_by_hash( hash: [u8; 32], fill_pow_hash: bool, ) -> Result { - let (top_height, _) = top_height(state).await?; - let block = blockchain::block_by_hash(&mut state.blockchain_read, hash).await?; - let header: ExtendedBlockHeader = todo!(); //blockchain::block_extended_header_by_hash(state.blockchain_read, hash).await?; + let (_, height) = blockchain::find_block(&mut state.blockchain_read, hash) + .await? + .ok_or_else(|| anyhow!("Block did not exist."))?; - let block_header = into_block_header(todo!(), top_height, fill_pow_hash, block, header); - - Ok(block_header) -} - -/// TODO -pub(super) async fn top_block_header( - state: &mut CupratedRpcHandler, - fill_pow_hash: bool, -) -> Result { - let block: Block = todo!(); - let header: ExtendedBlockHeader = todo!(); - - let block_header = into_block_header(todo!(), todo!(), fill_pow_hash, block, header); + let block_header = block_header(state, usize_to_u64(height), fill_pow_hash).await?; Ok(block_header) } @@ -145,7 +171,7 @@ pub(super) async fn top_height(state: &mut CupratedRpcHandler) -> Result<(u64, [ Ok((height, hash)) } -/// TODO +/// Check if a key image is spent. pub(super) async fn key_image_spent( state: &mut CupratedRpcHandler, key_image: [u8; 32], diff --git a/binaries/cuprated/src/rpc/request/blockchain_context.rs b/binaries/cuprated/src/rpc/request/blockchain_context.rs index f0990afb..099c6c61 100644 --- a/binaries/cuprated/src/rpc/request/blockchain_context.rs +++ b/binaries/cuprated/src/rpc/request/blockchain_context.rs @@ -100,3 +100,22 @@ pub(crate) async fn calculate_pow( Ok(hash) } + +/// [`BlockChainContextRequest::BatchGetDifficulties`] +pub(crate) async fn batch_get_difficulties( + blockchain_context: &mut BlockChainContextService, + difficulties: Vec<(u64, HardFork)>, +) -> Result, Error> { + let BlockChainContextResponse::BatchDifficulties(resp) = blockchain_context + .ready() + .await + .map_err(|e| anyhow!(e))? + .call(BlockChainContextRequest::BatchGetDifficulties(difficulties)) + .await + .map_err(|e| anyhow!(e))? + else { + unreachable!(); + }; + + Ok(resp) +}