DB messages, map header using (Block, ExtendedBlockHeader)

This commit is contained in:
hinto.janai 2024-09-12 18:00:20 -04:00
parent 0d0a544e68
commit 726a9f244b
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
9 changed files with 259 additions and 46 deletions

View file

@ -8,6 +8,7 @@
unused_variables,
clippy::needless_pass_by_value,
clippy::unused_async,
clippy::diverging_sub_expression,
unreachable_code,
reason = "TODO: remove after v1.0.0"
)]

View file

@ -8,6 +8,7 @@ use std::{
use anyhow::{anyhow, Error};
use futures::StreamExt;
use monero_serai::block::Block;
use tower::{Service, ServiceExt};
use cuprate_consensus::BlockchainResponse;
@ -43,7 +44,7 @@ pub(super) async fn chain_height(
pub(super) async fn block(
state: &mut CupratedRpcHandlerState,
height: u64,
) -> Result<VerifiedBlockInformation, Error> {
) -> Result<Block, Error> {
let BlockchainResponse::Block(block) = state
.blockchain_read
.ready()
@ -61,7 +62,7 @@ pub(super) async fn block(
pub(super) async fn block_by_hash(
state: &mut CupratedRpcHandlerState,
hash: [u8; 32],
) -> Result<VerifiedBlockInformation, Error> {
) -> Result<Block, Error> {
let BlockchainResponse::BlockByHash(block) = state
.blockchain_read
.ready()
@ -113,6 +114,23 @@ pub(super) async fn block_extended_header_by_hash(
Ok(header)
}
/// [`BlockchainResponse::TopBlockFull`].
pub(super) async fn top_block_full(
state: &mut CupratedRpcHandlerState,
) -> Result<(Block, ExtendedBlockHeader), Error> {
let BlockchainResponse::TopBlockFull(block, header) = state
.blockchain_read
.ready()
.await?
.call(BlockchainReadRequest::TopBlockFull)
.await?
else {
unreachable!();
};
Ok((block, header))
}
/// [`BlockchainResponse::BlockHash`] with [`Chain::Main`].
pub(super) async fn block_hash(
state: &mut CupratedRpcHandlerState,

View file

@ -27,18 +27,61 @@ use crate::{
rpc::{CupratedRpcHandlerState, RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE},
};
fn into_block_header(
height: u64,
top_height: u64,
fill_pow_hash: bool,
block: Block,
header: ExtendedBlockHeader,
) -> BlockHeader {
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);
BlockHeader {
block_size: block_weight,
block_weight,
cumulative_difficulty_top64,
cumulative_difficulty,
depth,
difficulty_top64: todo!(),
difficulty: todo!(),
hash: hex::encode(block.hash()),
height,
long_term_weight: usize_to_u64(header.long_term_weight),
major_version: header.version.as_u8(),
miner_tx_hash: hex::encode(block.miner_transaction.hash()),
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()
},
prev_hash: hex::encode(block.header.previous),
reward: todo!(),
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 CupratedRpcHandlerState,
height: u64,
fill_pow_hash: bool,
) -> Result<(VerifiedBlockInformation, BlockHeader), Error> {
) -> Result<BlockHeader, Error> {
let (top_height, _) = top_height(state).await?;
let block = blockchain::block(state, height).await?;
let mut block_header = BlockHeader::from(&block);
if !fill_pow_hash {
block_header.pow_hash = String::new();
}
Ok((block, block_header))
let header = blockchain::block_extended_header(state, height).await?;
let block_header = into_block_header(height, top_height, fill_pow_hash, block, header);
Ok(block_header)
}
/// Same as [`block_header`] but with the block's hash.
@ -46,13 +89,27 @@ pub(super) async fn block_header_by_hash(
state: &mut CupratedRpcHandlerState,
hash: [u8; 32],
fill_pow_hash: bool,
) -> Result<(VerifiedBlockInformation, BlockHeader), Error> {
) -> Result<BlockHeader, Error> {
let (top_height, _) = top_height(state).await?;
let block = blockchain::block_by_hash(state, hash).await?;
let mut block_header = BlockHeader::from(&block);
if !fill_pow_hash {
block_header.pow_hash = String::new();
}
Ok((block, block_header))
let header = blockchain::block_extended_header_by_hash(state, hash).await?;
let block_header = into_block_header(header.height, top_height, fill_pow_hash, block, header);
Ok(block_header)
}
/// TODO
pub(super) async fn top_block_header(
state: &mut CupratedRpcHandlerState,
fill_pow_hash: bool,
) -> Result<BlockHeader, Error> {
let (block, header) = blockchain::top_block_full(state).await?;
let block_header =
into_block_header(header.height, header.height, fill_pow_hash, block, header);
Ok(block_header)
}
/// Check if `height` is greater than the [`top_height`].

View file

@ -1,4 +1,3 @@
use core::slice::SlicePattern;
use std::sync::Arc;
use anyhow::{anyhow, Error};
@ -174,7 +173,7 @@ async fn get_last_block_header(
request: GetLastBlockHeaderRequest,
) -> Result<GetLastBlockHeaderResponse, Error> {
let (height, _) = helper::top_height(&mut state).await?;
let (_, block_header) = helper::block_header(&mut state, height, request.fill_pow_hash).await?;
let block_header = helper::block_header(&mut state, height, request.fill_pow_hash).await?;
Ok(GetLastBlockHeaderResponse {
base: AccessResponseBase::ok(),
@ -199,7 +198,7 @@ async fn get_block_header_by_hash(
fill_pow_hash: bool,
) -> Result<BlockHeader, Error> {
let hash = helper::hex_to_hash(hex)?;
let (_, block_header) = helper::block_header_by_hash(state, hash, fill_pow_hash).await?;
let block_header = helper::block_header_by_hash(state, hash, fill_pow_hash).await?;
Ok(block_header)
}
@ -225,7 +224,7 @@ async fn get_block_header_by_height(
request: GetBlockHeaderByHeightRequest,
) -> Result<GetBlockHeaderByHeightResponse, Error> {
helper::check_height(&mut state, request.height).await?;
let (_, block_header) =
let block_header =
helper::block_header(&mut state, request.height, request.fill_pow_hash).await?;
Ok(GetBlockHeaderByHeightResponse {
@ -272,7 +271,8 @@ async fn get_block_headers_range(
let BlockchainResponse::Block(header) = task.await?? else {
unreachable!();
};
headers.push((&header).into());
// headers.push((&header).into());
headers.push(todo!());
}
Ok(GetBlockHeadersRangeResponse {
@ -294,23 +294,25 @@ async fn get_block(
blockchain::block_by_hash(&mut state, hash).await?
};
let block_header = (&block).into();
let blob = hex::encode(block.block_blob);
let miner_tx_hash = hex::encode(block.block.miner_transaction.hash());
let tx_hashes = block
.txs
.into_iter()
.map(|tx| hex::encode(tx.tx_hash))
.collect();
Ok(todo!())
Ok(GetBlockResponse {
base: AccessResponseBase::ok(),
blob,
json: todo!(), // TODO: make `JSON` type in `cuprate_rpc_types`
miner_tx_hash,
tx_hashes,
block_header,
})
// let block_header = (&block).into();
// let blob = hex::encode(block.block_blob);
// let miner_tx_hash = hex::encode(block.block.miner_transaction.hash());
// let tx_hashes = block
// .txs
// .into_iter()
// .map(|tx| hex::encode(tx.tx_hash))
// .collect();
// Ok(GetBlockResponse {
// base: AccessResponseBase::ok(),
// blob,
// json: todo!(), // TODO: make `JSON` type in `cuprate_rpc_types`
// miner_tx_hash,
// tx_hashes,
// block_header,
// })
}
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2729-L2738>

View file

@ -56,6 +56,9 @@ pub struct DummyBlockExtendedHeader {
pub block_weight: Option<usize>,
#[proptest(strategy = "any::<usize>().prop_map(|x| Some(x % 100_000_000))")]
pub long_term_weight: Option<usize>,
#[proptest(strategy = "any::<u64>().prop_map(Some)")]
pub height: Option<u64>,
}
impl From<DummyBlockExtendedHeader> for ExtendedBlockHeader {
@ -67,6 +70,7 @@ impl From<DummyBlockExtendedHeader> for ExtendedBlockHeader {
cumulative_difficulty: value.cumulative_difficulty.unwrap_or_default(),
block_weight: value.block_weight.unwrap_or_default(),
long_term_weight: value.long_term_weight.unwrap_or_default(),
height: value.height.unwrap_or_default(),
}
}
}

View file

@ -17,10 +17,12 @@ use crate::{
output::get_rct_num_outputs,
tx::{add_tx, remove_tx},
},
tables::{BlockHeights, BlockInfos, Tables, TablesMut},
tables::{BlockBlobs, BlockHeights, BlockInfos, Tables, TablesMut},
types::{BlockHash, BlockHeight, BlockInfo},
};
use super::blockchain::top_block_height;
//---------------------------------------------------------------------------------------------------- `add_block_*`
/// Add a [`VerifiedBlockInformation`] to the database.
///
@ -162,6 +164,53 @@ pub fn pop_block(
Ok((block_height, block_hash, block))
}
//---------------------------------------------------------------------------------------------------- `get_block_*`
/// Retrieve a [`Block`] via its [`BlockHeight`].
#[doc = doc_error!()]
#[inline]
pub fn get_block(
block_height: &BlockHeight,
table_block_blobs: &impl DatabaseRo<BlockBlobs>,
) -> Result<Block, RuntimeError> {
let block_blob = table_block_blobs.get(block_height)?;
Ok(Block::read(&mut block_blob.0.as_slice())?)
}
/// Retrieve a [`Block`] via its [`BlockHash`].
#[doc = doc_error!()]
#[inline]
pub fn get_block_by_hash(
block_hash: &BlockHash,
table_block_heights: &impl DatabaseRo<BlockHeights>,
table_block_blobs: &impl DatabaseRo<BlockBlobs>,
) -> Result<Block, RuntimeError> {
let block_height = table_block_heights.get(block_hash)?;
get_block(&block_height, table_block_blobs)
}
/// Retrieve the top [`Block`].
#[doc = doc_error!()]
#[inline]
pub fn get_top_block(
table_block_heights: &impl DatabaseRo<BlockHeights>,
table_block_blobs: &impl DatabaseRo<BlockBlobs>,
) -> Result<Block, RuntimeError> {
let top_height = top_block_height(table_block_heights)?;
get_block(&top_height, table_block_blobs)
}
/// [`get_top_block`] and [`get_block_extended_header_top`].
#[doc = doc_error!()]
#[inline]
pub fn get_top_block_full(
tables: &impl Tables,
) -> Result<(Block, ExtendedBlockHeader), RuntimeError> {
let (header, _) = get_block_extended_header_top(tables)?;
let block = get_top_block(tables.block_heights(), tables.block_blobs())?;
Ok((block, header))
}
//---------------------------------------------------------------------------------------------------- `get_block_extended_header_*`
/// Retrieve a [`ExtendedBlockHeader`] from the database.
///
@ -207,6 +256,7 @@ pub fn get_block_extended_header_from_height(
timestamp: block.header.timestamp,
block_weight: block_info.weight as usize,
long_term_weight: block_info.long_term_weight as usize,
height: *block_height as u64,
})
}

View file

@ -6,6 +6,7 @@ use std::{
sync::Arc,
};
use monero_serai::block::Block;
use rayon::{
iter::{IntoParallelIterator, ParallelIterator},
ThreadPool,
@ -23,10 +24,11 @@ use cuprate_types::{
use crate::{
ops::{
block::{
block_exists, get_block_extended_header, get_block_extended_header_from_height,
get_block_height, get_block_info,
block_exists, get_block, get_block_by_hash, get_block_extended_header,
get_block_extended_header_from_height, get_block_extended_header_top, get_block_height,
get_block_info, get_top_block, get_top_block_full,
},
blockchain::{cumulative_generated_coins, top_block_height},
blockchain::{self, cumulative_generated_coins, top_block_height},
key_image::key_image_exists,
output::id_to_output_on_chain,
},
@ -34,7 +36,7 @@ use crate::{
free::{compact_history_genesis_not_included, compact_history_index_to_height_offset},
types::{BlockchainReadHandle, ResponseResult},
},
tables::{BlockHeights, BlockInfos, KeyImages, OpenTables, Tables},
tables::{BlockBlobs, BlockHeights, BlockInfos, KeyImages, OpenTables, Tables},
types::{Amount, AmountIndex, BlockHash, BlockHeight, KeyImage, PreRctOutputId},
};
@ -88,8 +90,11 @@ fn map_request(
match request {
R::Block(height) => block(env, height),
R::BlockByHash(hash) => block_by_hash(env, hash),
R::TopBlock => top_block(env),
R::BlockExtendedHeader(height) => block_extended_header(env, height),
R::BlockExtendedHeaderByHash(hash) => block_extended_header_by_hash(env, hash),
R::TopBlockExtendedHeader => top_block_extended_header_by_hash(env),
R::TopBlockFull => top_block_full(env),
R::BlockHash(height, chain) => block_hash(env, height, chain),
R::FindBlock(_) => todo!("Add alt blocks to DB"),
R::FilterUnknownHashes(hashes) => filter_unknown_hashes(env, hashes),
@ -187,9 +192,12 @@ fn block(env: &ConcreteEnv, block_height: BlockHeight) -> ResponseResult {
// 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)?;
let table_block_blobs = env_inner.open_db_ro::<BlockBlobs>(&tx_ro)?;
Ok(BlockchainResponse::Block(todo!()))
Ok(BlockchainResponse::Block(get_block(
&block_height,
&table_block_blobs,
)?))
}
/// [`BlockchainReadRequest::BlockByHash`].
@ -198,9 +206,29 @@ fn block_by_hash(env: &ConcreteEnv, block_hash: BlockHash) -> ResponseResult {
// 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)?;
let table_block_heights = env_inner.open_db_ro::<BlockHeights>(&tx_ro)?;
let table_block_blobs = env_inner.open_db_ro::<BlockBlobs>(&tx_ro)?;
Ok(BlockchainResponse::BlockByHash(todo!()))
Ok(BlockchainResponse::BlockByHash(get_block_by_hash(
&block_hash,
&table_block_heights,
&table_block_blobs,
)?))
}
/// [`BlockchainReadRequest::TopBlock`].
#[inline]
fn top_block(env: &ConcreteEnv) -> ResponseResult {
// Single-threaded, no `ThreadLocal` required.
let env_inner = env.env_inner();
let tx_ro = env_inner.tx_ro()?;
let table_block_heights = env_inner.open_db_ro::<BlockHeights>(&tx_ro)?;
let table_block_blobs = env_inner.open_db_ro::<BlockBlobs>(&tx_ro)?;
Ok(BlockchainResponse::TopBlock(get_top_block(
&table_block_heights,
&table_block_blobs,
)?))
}
/// [`BlockchainReadRequest::BlockExtendedHeader`].
@ -229,6 +257,32 @@ fn block_extended_header_by_hash(env: &ConcreteEnv, block_hash: BlockHash) -> Re
))
}
/// [`BlockchainReadRequest::TopBlockExtendedHeader`].
#[inline]
fn top_block_extended_header_by_hash(env: &ConcreteEnv) -> ResponseResult {
// 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::TopBlockExtendedHeader(
get_block_extended_header_top(&tables)?.0,
))
}
/// [`BlockchainReadRequest::TopBlockFull`].
#[inline]
fn top_block_full(env: &ConcreteEnv) -> ResponseResult {
// 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)?;
let (block, header) = get_top_block_full(&tables)?;
Ok(BlockchainResponse::TopBlockFull(block, header))
}
/// [`BlockchainReadRequest::BlockHash`].
#[inline]
fn block_hash(env: &ConcreteEnv, block_height: BlockHeight, chain: Chain) -> ResponseResult {
@ -547,6 +601,7 @@ fn find_first_unknown(env: &ConcreteEnv, block_ids: &[BlockHash]) -> ResponseRes
}
/// [`BlockchainReadRequest::CumulativeBlockWeightLimit`]
#[allow(clippy::diverging_sub_expression, reason = "TODO")]
fn cumulative_block_weight_limit(env: &ConcreteEnv) -> ResponseResult {
let env_inner = env.env_inner();
let tx_ro = env_inner.tx_ro()?;

View file

@ -9,6 +9,8 @@ use std::{
ops::Range,
};
use monero_serai::block::Block;
use crate::types::{Chain, ExtendedBlockHeader, OutputOnChain, VerifiedBlockInformation};
//---------------------------------------------------------------------------------------------------- ReadRequest
@ -32,6 +34,9 @@ pub enum BlockchainReadRequest {
/// The input is the block's hash.
BlockByHash([u8; 32]),
/// TODO
TopBlock,
/// Request a block's extended header.
///
/// The input is the block's height.
@ -42,6 +47,12 @@ pub enum BlockchainReadRequest {
/// The input is the block's hash.
BlockExtendedHeaderByHash([u8; 32]),
/// TODO
TopBlockExtendedHeader,
/// TODO
TopBlockFull,
/// Request a block's hash.
///
/// The input is the block's height and the chain it is on.
@ -152,10 +163,13 @@ pub enum BlockchainWriteRequest {
pub enum BlockchainResponse {
//------------------------------------------------------ Reads
/// Response to [`BlockchainReadRequest::Block`].
Block(VerifiedBlockInformation),
Block(Block),
/// Response to [`BlockchainReadRequest::BlockByHash`].
BlockByHash(VerifiedBlockInformation),
BlockByHash(Block),
/// Response to [`BlockchainReadRequest::TopBlock`].
TopBlock(Block),
/// Response to [`BlockchainReadRequest::BlockExtendedHeader`].
///
@ -167,6 +181,16 @@ pub enum BlockchainResponse {
/// Inner value is the extended headed of the requested block.
BlockExtendedHeaderByHash(ExtendedBlockHeader),
/// Response to [`BlockchainReadRequest::TopBlockExtendedHeader`].
///
/// Inner value is the extended headed of the requested block.
TopBlockExtendedHeader(ExtendedBlockHeader),
/// Response to [`BlockchainReadRequest::TopBlockFull`].
///
/// Inner value is TODO.
TopBlockFull(Block, ExtendedBlockHeader),
/// Response to [`BlockchainReadRequest::BlockHash`].
///
/// Inner value is the hash of the requested block.

View file

@ -33,6 +33,8 @@ pub struct ExtendedBlockHeader {
pub block_weight: usize,
/// The long term block weight, based on the median weight of the preceding `100_000` blocks.
pub long_term_weight: usize,
/// TODO
pub height: u64,
}
//---------------------------------------------------------------------------------------------------- VerifiedTransactionInformation