Compare commits

...

3 commits

Author SHA1 Message Date
hinto.janai
e975c420d9
add_aux_pow 2024-11-14 19:58:24 -05:00
hinto.janai
1f3b5ed127
fix calculate_pow 2024-11-14 17:44:08 -05:00
hinto.janai
46bf19861a
initial add_aux_pow impl 2024-11-14 17:03:15 -05:00
3 changed files with 198 additions and 31 deletions

View file

@ -8,11 +8,15 @@
use anyhow::{anyhow, Error}; use anyhow::{anyhow, Error};
use monero_serai::block::Block; 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::usize_to_u64, map::split_u128_into_low_high_bits};
use cuprate_rpc_types::misc::{BlockHeader, KeyImageSpentStatus}; use cuprate_rpc_types::misc::{BlockHeader, KeyImageSpentStatus};
use cuprate_types::ExtendedBlockHeader; use cuprate_types::ExtendedBlockHeader;
use crate::{rpc::request::blockchain, rpc::CupratedRpcHandler}; use crate::{
rpc::request::{blockchain, blockchain_context},
rpc::CupratedRpcHandler,
};
pub(super) fn into_block_header( pub(super) fn into_block_header(
height: u64, height: u64,

View file

@ -13,7 +13,7 @@ use cuprate_constants::{
rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE}, rpc::{RESTRICTED_BLOCK_COUNT, RESTRICTED_BLOCK_HEADER_RANGE},
}; };
use cuprate_helper::{ use cuprate_helper::{
cast::{u64_to_usize, usize_to_u64}, cast::{u32_to_usize, u64_to_usize, usize_to_u64},
map::split_u128_into_low_high_bits, map::split_u128_into_low_high_bits,
}; };
use cuprate_p2p_core::{client::handshaker::builder::DummyAddressBook, ClearNet, Network}; use cuprate_p2p_core::{client::handshaker::builder::DummyAddressBook, ClearNet, Network};
@ -403,7 +403,7 @@ async fn get_info(
let (database_size, free_space) = blockchain::database_size(&mut state.blockchain_read).await?; let (database_size, free_space) = blockchain::database_size(&mut state.blockchain_read).await?;
let (database_size, free_space) = if restricted { let (database_size, free_space) = if restricted {
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L131-L134> // <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L131-L134>
fn round_up(value: u64, quantum: u64) -> u64 { const fn round_up(value: u64, quantum: u64) -> u64 {
(value + quantum - 1) / quantum * quantum (value + quantum - 1) / quantum * quantum
} }
let database_size = round_up(database_size, 5 * 1024 * 1024 * 1024); let database_size = round_up(database_size, 5 * 1024 * 1024 * 1024);
@ -931,20 +931,31 @@ async fn calc_pow(
let block = Block::read(&mut block_blob.as_slice())?; let block = Block::read(&mut block_blob.as_slice())?;
let seed_hash = helper::hex_to_hash(request.seed_hash)?; let seed_hash = helper::hex_to_hash(request.seed_hash)?;
// let pow_hash = blockchain_manager::calculate_pow( let block_weight = todo!("calculate block weight");
// &mut state.blockchain_manager,
// hardfork,
// request.height,
// block,
// seed_hash,
// )
// .await?;
// let hex = hex::encode(pow_hash); let median_for_block_reward = blockchain_context::context(&mut state.blockchain_context)
.await?
.unchecked_blockchain_context()
.context_to_verify_block
.median_weight_for_block_reward;
let hex = todo!(); if cuprate_consensus_rules::blocks::check_block_weight(block_weight, median_for_block_reward)
.is_err()
{
return Err(anyhow!("Block blob size is too big, rejecting block"));
}
Ok(CalcPowResponse { pow_hash: hex }) let pow_hash = blockchain_context::calculate_pow(
&mut state.blockchain_context,
hardfork,
block,
seed_hash,
)
.await?;
let pow_hash = hex::encode(pow_hash);
Ok(CalcPowResponse { pow_hash })
} }
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3542-L3551> /// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3542-L3551>
@ -964,8 +975,9 @@ async fn add_aux_pow(
mut state: CupratedRpcHandler, mut state: CupratedRpcHandler,
request: AddAuxPowRequest, request: AddAuxPowRequest,
) -> Result<AddAuxPowResponse, Error> { ) -> Result<AddAuxPowResponse, Error> {
let hex = hex::decode(request.blocktemplate_blob)?; if request.aux_pow.is_empty() {
let block_template = Block::read(&mut hex.as_slice())?; return Err(anyhow!("Empty `aux_pow` vector"));
}
let aux_pow = request let aux_pow = request
.aux_pow .aux_pow
@ -975,31 +987,177 @@ async fn add_aux_pow(
let hash = helper::hex_to_hash(aux.hash)?; let hash = helper::hex_to_hash(aux.hash)?;
Ok(cuprate_types::AuxPow { id, hash }) Ok(cuprate_types::AuxPow { id, hash })
}) })
.collect::<Result<Vec<_>, Error>>()?; .collect::<Result<Box<[_]>, Error>>()?;
// Some of the code below requires that the
// `.len()` of certain containers are the same.
// Boxed slices are used over `Vec` to slightly
// safe-guard against accidently pushing to it.
let resp = todo!(); // --- BEGIN AUX POW IMPL ---
// let resp =
// blockchain_manager::add_aux_pow(&mut state.blockchain_manager, block_template, aux_pow)
// .await?;
let blocktemplate_blob = hex::encode(resp.blocktemplate_blob); // Original impl:
let blockhashing_blob = hex::encode(resp.blockhashing_blob); // <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2110-L2206>
let merkle_root = hex::encode(resp.merkle_root);
let aux_pow = resp let len = aux_pow.len();
.aux_pow
.into_iter() let mut path_domain = 1_usize;
while 1 << path_domain < len {
path_domain += 1;
}
let mut nonce = 0_u32;
let mut collision = true;
let mut slots: Box<[u32]> = vec![0; len].into_boxed_slice(); // INVARIANT: this must be the same `.len()` as `aux_pow`
for n in 0..u32::MAX {
nonce = n;
let slot_seen: Vec<bool> = vec![false; len];
collision = false;
slots.iter_mut().for_each(|i| *i = u32::MAX);
for i in &mut slots {
let slot_u32: u32 = todo!("const uint32_t slot = cryptonote::get_aux_slot(aux_pow[idx].first, nonce, aux_pow.size());");
let slot = u32_to_usize(slot_u32);
if slot >= len {
return Err(anyhow!("Computed slot is out of range"));
}
if slot_seen[slot] {
collision = true;
break;
}
slot_seen[slot] = true;
*i = slot_u32;
}
if !collision {
break;
}
}
let nonce = nonce;
let slots = slots;
if collision {
return Err(anyhow!("Failed to find a suitable nonce"));
}
// FIXME: use iterator version.
let (aux_pow_id_raw, aux_pow_raw) = {
let mut aux_pow_id_raw = Vec::<[u8; 32]>::with_capacity(len);
let mut aux_pow_raw = Vec::<[u8; 32]>::with_capacity(len);
assert_eq!(
aux_pow.len(),
slots.len(),
"these need to be the same or else the below .zip() doesn't make sense"
);
for (aux_pow, slot) in aux_pow.iter().zip(&slots) {
if u32_to_usize(*slot) >= len {
return Err(anyhow!("Slot value out of range"));
}
aux_pow_id_raw.push(aux_pow.id);
aux_pow_raw.push(aux_pow.hash);
}
assert_eq!(
slots.len(),
aux_pow_raw.len(),
"these need to be the same or else the below .zip() doesn't make sense"
);
assert_eq!(
aux_pow_raw.len(),
aux_pow_id_raw.len(),
"these need to be the same or else the below .zip() doesn't make sense"
);
for (slot, aux_pow) in slots.iter().zip(&aux_pow) {
let slot = u32_to_usize(*slot);
if slot >= len {
return Err(anyhow!("Slot value out of range"));
}
aux_pow_raw[slot] = aux_pow.hash;
aux_pow_id_raw[slot] = aux_pow.id;
}
(
aux_pow_id_raw.into_boxed_slice(),
aux_pow_raw.into_boxed_slice(),
)
};
fn tree_hash(aux_pow_raw: &[[u8; 32]]) -> [u8; 32] {
todo!("https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2163")
}
fn encode_mm_depth(aux_pow_len: usize, nonce: u32) -> u64 {
todo!("https://github.com/monero-project/monero/blob/893916ad091a92e765ce3241b94e706ad012b62a/src/cryptonote_basic/merge_mining.cpp#L74")
}
let merkle_root = tree_hash(aux_pow_raw.as_ref());
let merkle_tree_depth = encode_mm_depth(len, nonce);
let block_template = {
let hex = hex::decode(request.blocktemplate_blob)?;
Block::read(&mut hex.as_slice())?
};
fn remove_field_from_tx_extra() -> Result<(), ()> {
todo!("https://github.com/monero-project/monero/blob/master/src/cryptonote_basic/cryptonote_format_utils.cpp#L767")
}
if remove_field_from_tx_extra().is_err() {
return Err(anyhow!("Error removing existing merkle root"));
}
fn add_mm_merkle_root_to_tx_extra() -> Result<(), ()> {
todo!("https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2189
")
}
if add_mm_merkle_root_to_tx_extra().is_err() {
return Err(anyhow!("Error adding merkle root"));
}
fn invalidate_hashes() {
// block_template.invalidate_hashes();
// block_template.miner_tx.invalidate_hashes();
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2195-L2196>
todo!();
}
invalidate_hashes();
let blocktemplate_blob = block_template.serialize();
let blockhashing_blob = block_template.serialize_pow_hash();
let blocktemplate_blob = hex::encode(blocktemplate_blob);
let blockhashing_blob = hex::encode(blockhashing_blob);
let merkle_root = hex::encode(merkle_root);
let aux_pow = IntoIterator::into_iter(aux_pow) // must be explicit due to `boxed_slice_into_iter`
.map(|aux| AuxPow { .map(|aux| AuxPow {
id: hex::encode(aux.id), id: hex::encode(aux.id),
hash: hex::encode(aux.hash), hash: hex::encode(aux.hash),
}) })
.collect::<Vec<AuxPow>>(); .collect::<Vec<AuxPow>>();
// --- END AUX POW IMPL ---
Ok(AddAuxPowResponse { Ok(AddAuxPowResponse {
base: ResponseBase::OK, base: ResponseBase::OK,
blocktemplate_blob, blocktemplate_blob,
blockhashing_blob, blockhashing_blob,
merkle_root, merkle_root,
merkle_tree_depth: resp.merkle_tree_depth, merkle_tree_depth,
aux_pow, aux_pow,
}) })
} }

View file

@ -73,17 +73,22 @@ pub(crate) async fn fee_estimate(
pub(crate) async fn calculate_pow( pub(crate) async fn calculate_pow(
blockchain_context: &mut BlockChainContextService, blockchain_context: &mut BlockChainContextService,
hardfork: HardFork, hardfork: HardFork,
height: u64, block: Block,
block: Box<Block>,
seed_hash: [u8; 32], seed_hash: [u8; 32],
) -> Result<[u8; 32], Error> { ) -> Result<[u8; 32], Error> {
let Some(height) = block.number() else {
return Err(anyhow!("block is missing height"));
};
let block = Box::new(block);
let BlockChainContextResponse::CalculatePow(hash) = blockchain_context let BlockChainContextResponse::CalculatePow(hash) = blockchain_context
.ready() .ready()
.await .await
.map_err(|e| anyhow!(e))? .map_err(|e| anyhow!(e))?
.call(BlockChainContextRequest::CalculatePow { .call(BlockChainContextRequest::CalculatePow {
hardfork, hardfork,
height: u64_to_usize(height), height,
block, block,
seed_hash, seed_hash,
}) })