Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 92 additions & 40 deletions binaries/cuprated/src/rpc/handlers/bin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ use std::num::NonZero;
use anyhow::{anyhow, Error};
use bytes::Bytes;

use cuprate_constants::rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_TRANSACTIONS_COUNT};
use cuprate_constants::rpc::{
GET_BLOCKS_BIN_MAX_BLOCK_COUNT, RESTRICTED_BLOCK_COUNT, RESTRICTED_TRANSACTIONS_COUNT,
};
use cuprate_fixed_bytes::ByteArrayVec;
use cuprate_helper::cast::{u64_to_usize, usize_to_u64};
use cuprate_rpc_interface::RpcHandler;
Expand All @@ -22,15 +24,15 @@ use cuprate_rpc_types::{
GetTransactionPoolHashesRequest, GetTransactionPoolHashesResponse,
},
json::{GetOutputDistributionRequest, GetOutputDistributionResponse},
misc::RequestedInfo,
misc::{RequestedInfo, Status},
};
use cuprate_types::{
rpc::{PoolInfo, PoolInfoExtent},
rpc::{BlockOutputIndices, PoolInfoExtent, TxOutputIndices},
BlockCompleteEntry,
};

use crate::rpc::{
handlers::{helper, shared, shared::not_available},
handlers::{helper, shared},
service::{blockchain, txpool},
CupratedRpcHandler,
};
Expand All @@ -44,7 +46,7 @@ pub async fn map_request(
use BinResponse as Resp;

Ok(match request {
Req::GetBlocks(r) => Resp::GetBlocks(not_available()?),
Req::GetBlocks(r) => Resp::GetBlocks(get_blocks(state, r).await?),
Req::GetBlocksByHeight(r) => Resp::GetBlocksByHeight(get_blocks_by_height(state, r).await?),
Req::GetHashes(r) => Resp::GetHashes(get_hashes(state, r).await?),
Req::GetOutputIndexes(r) => Resp::GetOutputIndexes(get_output_indexes(state, r).await?),
Expand Down Expand Up @@ -74,12 +76,13 @@ async fn get_blocks(
prune,
no_miner_tx,
pool_info_since,
max_block_count,
} = request;

let block_hashes: Vec<[u8; 32]> = (&block_ids).into();
drop(block_ids);

let Some(requested_info) = RequestedInfo::from_u8(request.requested_info) else {
let Some(requested_info) = RequestedInfo::from_u8(requested_info) else {
return Err(anyhow!("Wrong requested info"));
};

Expand All @@ -89,71 +92,120 @@ async fn get_blocks(
RequestedInfo::PoolOnly => (false, true),
};

let pool_info_extent = PoolInfoExtent::None;
let (pool_info_extent, added_pool_txs, remaining_added_pool_txids, removed_pool_txids);

let pool_info = if get_pool {
if get_pool {
let is_restricted = state.is_restricted();
let include_sensitive_txs = !is_restricted;

let max_tx_count = if is_restricted {
RESTRICTED_TRANSACTIONS_COUNT
} else {
usize::MAX
};

txpool::pool_info(
&mut state.txpool_read,
include_sensitive_txs,
max_tx_count,
NonZero::new(u64_to_usize(request.pool_info_since)),
)
.await?
let pool_since =
txpool::pool_info_since(&state.tx_handler.txpool_manager, pool_info_since).await?;

let (to_send, remaining): (&[[u8; 32]], &[[u8; 32]]) =
if pool_since.added.len() > max_tx_count {
pool_since.added.split_at(max_tx_count)
} else {
(&pool_since.added, &[])
};

added_pool_txs = txpool::tx_blobs_by_hash(&mut state.txpool_read, to_send, prune).await?;
remaining_added_pool_txids = remaining.to_vec().into();
removed_pool_txids = pool_since.removed.into();

pool_info_extent = if pool_since.full_required {
PoolInfoExtent::Full
} else {
PoolInfoExtent::Incremental
};
} else {
PoolInfo::None
};
pool_info_extent = PoolInfoExtent::None;
added_pool_txs = vec![];
remaining_added_pool_txids = ByteArrayVec::default();
removed_pool_txids = ByteArrayVec::default();
}

let resp = GetBlocksResponse {
base: helper::access_response_base(false),
blocks: vec![],
start_height: 0,
current_height: 0,
top_block_hash: [0; 32],
output_indices: vec![],
daemon_time,
pool_info,
pool_info_extent,
added_pool_txs,
remaining_added_pool_txids,
removed_pool_txids,
};

if !get_blocks {
return Ok(resp);
}

if let Some(block_id) = block_hashes.first() {
let (height, hash) = helper::top_height(&mut state).await?;

if hash == *block_id {
return Ok(GetBlocksResponse {
current_height: height + 1,
..resp
});
}
}
let len = u64_to_usize(if max_block_count > 0 {
max_block_count.min(GET_BLOCKS_BIN_MAX_BLOCK_COUNT)
} else {
GET_BLOCKS_BIN_MAX_BLOCK_COUNT
});

let (block_hashes, start_height, _) =
blockchain::next_chain_entry(&mut state.blockchain_read, block_hashes).await?;
let req_start_height = if start_height > 0 {
Some(u64_to_usize(start_height))
} else {
None
};

if start_height.is_none() {
return Err(anyhow!("Block IDs were not sorted properly"));
if req_start_height.is_none() && block_hashes.is_empty() {
return Ok(GetBlocksResponse {
base: AccessResponseBase {
response_base: ResponseBase {
status: Status::Failed,
untrusted: false,
},
credits: 0,
top_hash: String::new(),
},
..resp
});
}

let (blocks, missing_hashes, height) =
blockchain::block_complete_entries(&mut state.blockchain_read, block_hashes).await?;

if !missing_hashes.is_empty() {
return Err(anyhow!("Missing blocks"));
let (top_height, top_hash) = helper::top_height(&mut state);
if start_height > top_height || block_hashes.first() == Some(&top_hash) {
return Ok(GetBlocksResponse {
current_height: top_height + 1,
top_block_hash: top_hash,
..resp
});
}

let (blocks, chain_height, actual_start_height, output_indices, top_hash) =
blockchain::block_complete_entries_above_split_point(
&mut state.blockchain_read,
block_hashes,
req_start_height,
no_miner_tx,
len,
prune,
)
.await?;

Ok(GetBlocksResponse {
blocks,
current_height: usize_to_u64(height),
current_height: usize_to_u64(chain_height),
start_height: usize_to_u64(actual_start_height),
top_block_hash: top_hash,
output_indices: output_indices
.into_iter()
.map(|block| BlockOutputIndices {
indices: block
.into_iter()
.map(|indices| TxOutputIndices { indices })
.collect(),
})
.collect(),
..resp
})
}
Expand Down
17 changes: 7 additions & 10 deletions binaries/cuprated/src/rpc/handlers/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub(super) async fn block_header(
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?;
let (top_height, _) = top_height(state);

// TODO: if the request block is not on the main chain,
// we must get the alt block and this variable will be `true`.
Expand Down Expand Up @@ -132,11 +132,8 @@ pub(super) async fn block_header_by_hash(
/// # Errors
/// This returns the [`top_height`] on [`Ok`] and
/// returns [`Error`] if `height` is greater than [`top_height`].
pub(super) async fn check_height(
state: &mut CupratedRpcHandler,
height: u64,
) -> Result<u64, Error> {
let (top_height, _) = top_height(state).await?;
pub(super) fn check_height(state: &mut CupratedRpcHandler, height: u64) -> Result<u64, Error> {
let (top_height, _) = top_height(state);

if height > top_height {
return Err(anyhow!(
Expand Down Expand Up @@ -164,10 +161,10 @@ pub(super) fn hex_to_hash(hex: String) -> Result<[u8; 32], Error> {
}

/// [`cuprate_types::blockchain::BlockchainResponse::ChainHeight`] minus 1.
pub(super) async fn top_height(state: &mut CupratedRpcHandler) -> Result<(u64, [u8; 32]), Error> {
let (chain_height, hash) = blockchain::chain_height(&mut state.blockchain_read).await?;
let height = chain_height.checked_sub(1).unwrap();
Ok((height, hash))
pub(super) fn top_height(state: &mut CupratedRpcHandler) -> (u64, [u8; 32]) {
let context = state.blockchain_context.blockchain_context();
let height = context.chain_height.checked_sub(1).unwrap();
(usize_to_u64(height), context.top_hash)
}

/// TODO: impl bootstrap
Expand Down
23 changes: 10 additions & 13 deletions binaries/cuprated/src/rpc/handlers/json_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,9 +258,7 @@ async fn get_block_count(
Ok(GetBlockCountResponse {
base: helper::response_base(false),
// Block count starts at 1
count: blockchain::chain_height(&mut state.blockchain_read)
.await?
.0,
count: usize_to_u64(state.blockchain_context.blockchain_context().chain_height),
})
}

Expand Down Expand Up @@ -345,7 +343,7 @@ async fn get_last_block_header(
mut state: CupratedRpcHandler,
request: GetLastBlockHeaderRequest,
) -> Result<GetLastBlockHeaderResponse, Error> {
let (height, _) = helper::top_height(&mut state).await?;
let (height, _) = helper::top_height(&mut state);
let block_header = helper::block_header(&mut state, height, request.fill_pow_hash).await?;

Ok(GetLastBlockHeaderResponse {
Expand Down Expand Up @@ -387,7 +385,8 @@ async fn get_block_header_by_height(
mut state: CupratedRpcHandler,
request: GetBlockHeaderByHeightRequest,
) -> Result<GetBlockHeaderByHeightResponse, Error> {
helper::check_height(&mut state, request.height).await?;
helper::check_height(&mut state, request.height)?;

let block_header =
helper::block_header(&mut state, request.height, request.fill_pow_hash).await?;

Expand All @@ -402,7 +401,7 @@ async fn get_block_headers_range(
mut state: CupratedRpcHandler,
request: GetBlockHeadersRangeRequest,
) -> Result<GetBlockHeadersRangeResponse, Error> {
let (top_height, _) = helper::top_height(&mut state).await?;
let (top_height, _) = helper::top_height(&mut state);

if request.start_height >= top_height
|| request.end_height >= top_height
Expand Down Expand Up @@ -457,7 +456,8 @@ async fn get_block(
request: GetBlockRequest,
) -> Result<GetBlockResponse, Error> {
let (block, block_header) = if request.hash.is_empty() {
helper::check_height(&mut state, request.height).await?;
helper::check_height(&mut state, request.height)?;

let block = blockchain::block(&mut state.blockchain_read, request.height).await?;
let block_header =
helper::block_header(&mut state, request.height, request.fill_pow_hash).await?;
Expand Down Expand Up @@ -871,9 +871,8 @@ async fn get_coinbase_tx_sum(
mut state: CupratedRpcHandler,
request: GetCoinbaseTxSumRequest,
) -> Result<GetCoinbaseTxSumResponse, Error> {
let chain_height = blockchain::chain_height(&mut state.blockchain_read)
.await?
.0;
let chain_height = usize_to_u64(state.blockchain_context.blockchain_context().chain_height);

if request.height >= chain_height || request.count > chain_height - request.height {
return Err(anyhow!("requested range exceeds blockchain height"));
}
Expand Down Expand Up @@ -906,9 +905,7 @@ async fn get_version(
mut state: CupratedRpcHandler,
_: GetVersionRequest,
) -> Result<GetVersionResponse, Error> {
let current_height = blockchain::chain_height(&mut state.blockchain_read)
.await?
.0;
let current_height = usize_to_u64(state.blockchain_context.blockchain_context().chain_height);
let target_height = state.syncer_handle.target_height();

let mut hard_forks: Vec<HardForkEntry> =
Expand Down
5 changes: 3 additions & 2 deletions binaries/cuprated/src/rpc/handlers/other_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,9 @@ async fn get_height(
mut state: CupratedRpcHandler,
_: GetHeightRequest,
) -> Result<GetHeightResponse, Error> {
let (height, hash) = blockchain::chain_height(&mut state.blockchain_read).await?;
let hash = Hex(hash);
let context = state.blockchain_context.blockchain_context();
let height = usize_to_u64(context.chain_height);
let hash = Hex(context.top_hash);

Ok(GetHeightResponse {
base: helper::response_base(false),
Expand Down
Loading
Loading