diff --git a/binaries/cuprated/src/rpc/handler.rs b/binaries/cuprated/src/rpc/handler.rs index d95bdab..57863db 100644 --- a/binaries/cuprated/src/rpc/handler.rs +++ b/binaries/cuprated/src/rpc/handler.rs @@ -3,6 +3,7 @@ use std::task::{Context, Poll}; use anyhow::Error; +use cuprate_types::BlockTemplate; use futures::future::BoxFuture; use monero_serai::block::Block; use tower::Service; @@ -84,6 +85,13 @@ pub enum BlockchainManagerRequest { // /// Get the next [`PruningSeed`] needed for a pruned sync. NextNeededPruningSeed, + + /// TODO + CreateBlockTemplate { + prev_block: [u8; 32], + account_public_address: String, + extra_nonce: Vec, + }, } /// TODO: use real type when public. @@ -129,6 +137,9 @@ pub enum BlockchainManagerResponse { // Spans(Vec>), /// Response to [`BlockchainManagerRequest::NextNeededPruningSeed`]. NextNeededPruningSeed(PruningSeed), + + /// Response to [`BlockchainManagerRequest::CreateBlockTemplate`]. + CreateBlockTemplate(Box), } /// TODO: use real type when public. diff --git a/binaries/cuprated/src/rpc/json.rs b/binaries/cuprated/src/rpc/json.rs index 17e24dc..e704ce0 100644 --- a/binaries/cuprated/src/rpc/json.rs +++ b/binaries/cuprated/src/rpc/json.rs @@ -20,6 +20,7 @@ use cuprate_constants::{ }; use cuprate_helper::{ cast::{u32_to_usize, u64_to_usize, usize_to_u64}, + fmt::HexPrefix, map::split_u128_into_low_high_bits, }; use cuprate_hex::Hex; @@ -53,7 +54,7 @@ use cuprate_rpc_types::{ }; use cuprate_types::{ rpc::{AuxPow, CoinbaseTxSum, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry}, - HardFork, + BlockTemplate, HardFork, }; use crate::{ @@ -160,65 +161,50 @@ async fn get_block_template( return Err(anyhow!("Mining to subaddress is not supported yet")); } - // block b; - // cryptonote::blobdata blob_reserve; - // size_t reserved_offset; - // if(!request.extra_nonce.empty()) - // { - // if(!string_tools::parse_hexstr_to_binbuff(request.extra_nonce, blob_reserve)) - // { - // error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; - // error_resp.message = "Parameter extra_nonce should be a hex string"; - // return false; - // } - // } - // else - // blob_reserve.resize(request.reserve_size, 0); - // cryptonote::difficulty_type wdiff; - // crypto::hash prev_block; - // if (!request.prev_block.empty()) - // { - // if (!epee::string_tools::hex_to_pod(request.prev_block, prev_block)) - // { - // error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; - // error_resp.message = "Invalid prev_block"; - // return false; - // } - // } - // crypto::hash seed_hash, next_seed_hash; - // if (!get_block_template(info.address, request.prev_block.empty() ? NULL : &prev_block, blob_reserve, reserved_offset, wdiff, res.height, res.expected_reward, res.cumulative_weight, b, res.seed_height, seed_hash, next_seed_hash, error_resp)) - // return false; - // if (b.major_version >= RX_BLOCK_VERSION) - // { - // res.seed_hash = string_tools::pod_to_hex(seed_hash); - // if (seed_hash != next_seed_hash) - // res.next_seed_hash = string_tools::pod_to_hex(next_seed_hash); - // } + let blob_reserve = hex::decode(request.extra_nonce)?; + let prev_block = helper::hex_to_hash(request.prev_block)?; + let extra_nonce = hex::decode(request.extra_nonce)?; - // res.reserved_offset = reserved_offset; - // store_difficulty(wdiff, res.difficulty, res.wide_difficulty, res.difficulty_top64); - // blobdata block_blob = t_serializable_object_to_blob(b); - // blobdata hashing_blob = get_block_hashing_blob(b); - // res.prev_hash = string_tools::pod_to_hex(b.prev_id); - // res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob); - // res.blockhashing_blob = string_tools::buff_to_hex_nodelimer(hashing_blob); - // res.status = CORE_RPC_STATUS_OK; - // return true; + let BlockTemplate { + block, + reserved_offset, + difficulty, + height, + expected_reward, + seed_height, + seed_hash, + next_seed_hash, + } = *blockchain_manager::create_block_template( + &mut state.blockchain_manager, + prev_block, + request.wallet_address, + extra_nonce, + ) + .await?; + + let blockhashing_blob = hex::encode(block.serialize_pow_hash()); + let blocktemplate_blob = hex::encode(block.serialize()); + let (difficulty, difficulty_top64) = split_u128_into_low_high_bits(difficulty); + // let next_seed_hash = Hex(next_seed_hash); + let next_seed_hash = hex::encode(next_seed_hash); + let prev_hash = Hex(block.header.previous); + let seed_hash = Hex(seed_hash); + let wide_difficulty = (difficulty, difficulty_top64).hex_prefix(); Ok(GetBlockTemplateResponse { base: ResponseBase::OK, - blockhashing_blob: todo!(), - blocktemplate_blob: todo!(), - difficulty_top64: todo!(), - difficulty: todo!(), - expected_reward: todo!(), - height: todo!(), - next_seed_hash: todo!(), - prev_hash: todo!(), - reserved_offset: todo!(), - seed_hash: todo!(), - seed_height: todo!(), - wide_difficulty: todo!(), + blockhashing_blob, + blocktemplate_blob, + difficulty_top64, + difficulty, + expected_reward, + height, + next_seed_hash, + prev_hash, + reserved_offset, + seed_hash, + seed_height, + wide_difficulty, }) } diff --git a/binaries/cuprated/src/rpc/other.rs b/binaries/cuprated/src/rpc/other.rs index ca23190..1e70590 100644 --- a/binaries/cuprated/src/rpc/other.rs +++ b/binaries/cuprated/src/rpc/other.rs @@ -8,6 +8,7 @@ use cuprate_constants::rpc::{ MAX_RESTRICTED_GLOBAL_FAKE_OUTS_COUNT, RESTRICTED_SPENT_KEY_IMAGES_COUNT, }; use cuprate_helper::cast::usize_to_u64; +use cuprate_hex::Hex; use cuprate_rpc_interface::RpcHandler; use cuprate_rpc_types::{ base::{AccessResponseBase, ResponseBase}, @@ -100,7 +101,7 @@ async fn get_height( request: GetHeightRequest, ) -> Result { let (height, hash) = helper::top_height(&mut state).await?; - let hash = hex::encode(hash); + let hash = Hex(hash); Ok(GetHeightResponse { base: ResponseBase::OK, @@ -142,9 +143,8 @@ async fn is_key_image_spent( let mut spent_status = Vec::with_capacity(request.key_images.len()); - for hex in request.key_images { - let key_image = helper::hex_to_hash(hex)?; - let status = helper::key_image_spent(&mut state, key_image).await?; + for key_image in request.key_images { + let status = helper::key_image_spent(&mut state, key_image.0).await?; spent_status.push(status.to_u8()); } diff --git a/binaries/cuprated/src/rpc/request/blockchain_manager.rs b/binaries/cuprated/src/rpc/request/blockchain_manager.rs index 11fedc5..ec0d4d5 100644 --- a/binaries/cuprated/src/rpc/request/blockchain_manager.rs +++ b/binaries/cuprated/src/rpc/request/blockchain_manager.rs @@ -1,6 +1,7 @@ //! Functions to send [`BlockchainManagerRequest`]s. use anyhow::Error; +use cuprate_types::BlockTemplate; use monero_serai::block::Block; use tower::{Service, ServiceExt}; @@ -218,3 +219,26 @@ pub(crate) async fn next_needed_pruning_seed( Ok(seed) } + +/// [`BlockchainManagerRequest::CreateBlockTemplate`] +pub(crate) async fn create_block_template( + blockchain_manager: &mut BlockchainManagerHandle, + prev_block: [u8; 32], + account_public_address: String, + extra_nonce: Vec, +) -> Result, Error> { + let BlockchainManagerResponse::CreateBlockTemplate(block_template) = blockchain_manager + .ready() + .await? + .call(BlockchainManagerRequest::CreateBlockTemplate { + prev_block, + account_public_address, + extra_nonce, + }) + .await? + else { + unreachable!(); + }; + + Ok(block_template) +} diff --git a/helper/src/fmt.rs b/helper/src/fmt.rs index d5c043e..4a13927 100644 --- a/helper/src/fmt.rs +++ b/helper/src/fmt.rs @@ -1,18 +1,41 @@ //! Formatting. -use crate::map::combine_low_high_bits_to_u128; +pub trait HexPrefix { + fn hex_prefix(self) -> String; +} -/// Format two [`u64`]'s as a [`u128`] as a lower-case hexadecimal string prefixed with `0x`. -/// -/// ```rust -/// # use cuprate_helper::fmt::hex_prefix_u128; -/// assert_eq!(hex_prefix_u128(0, 0), "0x0"); -/// assert_eq!(hex_prefix_u128(0, u64::MAX), "0xffffffffffffffff0000000000000000"); -/// assert_eq!(hex_prefix_u128(u64::MAX, 0), "0xffffffffffffffff"); -/// assert_eq!(hex_prefix_u128(u64::MAX, u64::MAX), "0xffffffffffffffffffffffffffffffff"); -/// ``` -pub fn hex_prefix_u128(low_bits: u64, high_bits: u64) -> String { - format!("{:#x}", combine_low_high_bits_to_u128(low_bits, high_bits)) +macro_rules! impl_hex_prefix { + ($( + $t:ty + ),*) => { + $( + impl HexPrefix for $t { + fn hex_prefix(self) -> String { + format!("{:#x}", self) + } + } + )* + }; +} + +impl_hex_prefix!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, usize, isize); + +impl HexPrefix for (u64, u64) { + /// Combine the low and high bits of a [`u128`] as a lower-case hexadecimal string prefixed with `0x`. + /// + /// ```rust + /// # use cuprate_helper::fmt::HexPrefix; + /// assert_eq!((0, 0).hex_prefix(), "0x0"); + /// assert_eq!((0, u64::MAX).hex_prefix(), "0xffffffffffffffff0000000000000000"); + /// assert_eq!((u64::MAX, 0).hex_prefix(), "0xffffffffffffffff"); + /// assert_eq!((u64::MAX, u64::MAX).hex_prefix(), "0xffffffffffffffffffffffffffffffff"); + /// ``` + fn hex_prefix(self) -> String { + format!( + "{:#x}", + crate::map::combine_low_high_bits_to_u128(self.0, self.1) + ) + } } #[cfg(test)] diff --git a/rpc/types/src/from.rs b/rpc/types/src/from.rs index 7f07ca1..1738a69 100644 --- a/rpc/types/src/from.rs +++ b/rpc/types/src/from.rs @@ -7,7 +7,7 @@ use std::{ time::Duration, }; -use cuprate_helper::{fmt::hex_prefix_u128, map::ipv4_from_u32}; +use cuprate_helper::{fmt::HexPrefix, map::ipv4_from_u32}; use cuprate_hex::Hex; use cuprate_p2p_core::{ types::{ConnectionId, ConnectionInfo, SetBan, Span}, @@ -40,11 +40,9 @@ impl From for crate::misc::BlockHeader { timestamp: x.timestamp, // FIXME: if we made a type that automatically did `hex_prefix_u128`, // we wouldn't need `crate::misc::BlockHeader`. - wide_cumulative_difficulty: hex_prefix_u128( - x.cumulative_difficulty, - x.cumulative_difficulty_top64, - ), - wide_difficulty: hex_prefix_u128(x.difficulty, x.difficulty_top64), + wide_cumulative_difficulty: (x.cumulative_difficulty, x.cumulative_difficulty_top64) + .hex_prefix(), + wide_difficulty: (x.difficulty, x.difficulty_top64).hex_prefix(), } } } @@ -132,7 +130,7 @@ impl From for crate::misc::ChainInfo { height: x.height, length: x.length, main_chain_parent_block: Hex(x.main_chain_parent_block), - wide_difficulty: hex_prefix_u128(x.difficulty, x.difficulty_top64), + wide_difficulty: (x.difficulty, x.difficulty_top64).hex_prefix(), } } } diff --git a/types/hex/src/prefix.rs b/types/hex/src/prefix.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/types/hex/src/prefix.rs @@ -0,0 +1 @@ + diff --git a/types/types/src/lib.rs b/types/types/src/lib.rs index 1c48648..6f3df4b 100644 --- a/types/types/src/lib.rs +++ b/types/types/src/lib.rs @@ -24,8 +24,8 @@ pub use transaction_verification_data::{ CachedVerificationState, TransactionVerificationData, TxVersion, }; pub use types::{ - AltBlockInformation, Chain, ChainId, ExtendedBlockHeader, OutputOnChain, TxsInBlock, - VerifiedBlockInformation, VerifiedTransactionInformation, + AltBlockInformation, BlockTemplate, Chain, ChainId, ExtendedBlockHeader, OutputOnChain, + TxsInBlock, VerifiedBlockInformation, VerifiedTransactionInformation, }; //---------------------------------------------------------------------------------------------------- Feature-gated diff --git a/types/types/src/types.rs b/types/types/src/types.rs index 24ce98a..3dc3b91 100644 --- a/types/types/src/types.rs +++ b/types/types/src/types.rs @@ -154,6 +154,19 @@ pub struct TxsInBlock { pub txs: Vec>, } +/// A block template, used in RPC's `get_block_template`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct BlockTemplate { + pub block: Block, + pub reserved_offset: u64, + pub difficulty: u128, + pub height: u64, + pub expected_reward: u64, + pub seed_height: u64, + pub seed_hash: [u8; 32], + pub next_seed_hash: [u8; 32], +} + //---------------------------------------------------------------------------------------------------- Tests #[cfg(test)] mod test {