mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-22 11:39:30 +00:00
Compare commits
5 commits
ed8de29504
...
b2b7e93e4c
Author | SHA1 | Date | |
---|---|---|---|
|
b2b7e93e4c | ||
|
114a5db52e | ||
|
d47f8ec7dc | ||
|
dff77e8bed | ||
|
cb6fdb76e4 |
17 changed files with 909 additions and 538 deletions
860
Cargo.lock
generated
860
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -23,7 +23,7 @@ use cuprate_helper::{
|
|||
fmt::HexPrefix,
|
||||
map::split_u128_into_low_high_bits,
|
||||
};
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_hex::{Hex, HexVec};
|
||||
use cuprate_p2p_core::{client::handshaker::builder::DummyAddressBook, ClearNet, Network};
|
||||
use cuprate_rpc_interface::RpcHandler;
|
||||
use cuprate_rpc_types::{
|
||||
|
@ -54,7 +54,7 @@ use cuprate_rpc_types::{
|
|||
};
|
||||
use cuprate_types::{
|
||||
rpc::{AuxPow, CoinbaseTxSum, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry},
|
||||
BlockTemplate, HardFork,
|
||||
BlockTemplate, Chain, HardFork,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
@ -162,7 +162,7 @@ async fn get_block_template(
|
|||
}
|
||||
|
||||
let blob_reserve = hex::decode(request.extra_nonce)?;
|
||||
let prev_block = helper::hex_to_hash(request.prev_block)?;
|
||||
let prev_block: [u8; 32] = request.prev_block.try_into()?;
|
||||
let extra_nonce = hex::decode(request.extra_nonce)?;
|
||||
|
||||
let BlockTemplate {
|
||||
|
@ -182,11 +182,11 @@ async fn get_block_template(
|
|||
)
|
||||
.await?;
|
||||
|
||||
let blockhashing_blob = hex::encode(block.serialize_pow_hash());
|
||||
let blocktemplate_blob = hex::encode(block.serialize());
|
||||
let blockhashing_blob = HexVec(block.serialize_pow_hash());
|
||||
let blocktemplate_blob = HexVec(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 next_seed_hash = HexVec::empty_if_zeroed(next_seed_hash);
|
||||
let prev_hash = Hex(block.header.previous);
|
||||
let seed_hash = Hex(seed_hash);
|
||||
let wide_difficulty = (difficulty, difficulty_top64).hex_prefix();
|
||||
|
@ -215,7 +215,10 @@ async fn get_block_count(
|
|||
) -> Result<GetBlockCountResponse, Error> {
|
||||
Ok(GetBlockCountResponse {
|
||||
base: helper::response_base(false),
|
||||
count: helper::top_height(&mut state).await?.0,
|
||||
// Block count starts at 1
|
||||
count: blockchain::chain_height(&mut state.blockchain_read)
|
||||
.await?
|
||||
.0,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -225,12 +228,7 @@ async fn on_get_block_hash(
|
|||
request: OnGetBlockHashRequest,
|
||||
) -> Result<OnGetBlockHashResponse, Error> {
|
||||
let [height] = request.block_height;
|
||||
let hash = blockchain::block_hash(
|
||||
&mut state.blockchain_read,
|
||||
height,
|
||||
todo!("access to `cuprated`'s Chain"),
|
||||
)
|
||||
.await?;
|
||||
let hash = blockchain::block_hash(&mut state.blockchain_read, height, Chain::Main).await?;
|
||||
|
||||
Ok(OnGetBlockHashResponse {
|
||||
block_hash: Hex(hash),
|
||||
|
@ -244,8 +242,7 @@ async fn submit_block(
|
|||
) -> Result<SubmitBlockResponse, Error> {
|
||||
// Parse hex into block.
|
||||
let [blob] = request.block_blob;
|
||||
let bytes = hex::decode(blob)?;
|
||||
let block = Block::read(&mut bytes.as_slice())?;
|
||||
let block = Block::read(&mut blob.0.as_slice())?;
|
||||
let block_id = Hex(block.hash());
|
||||
|
||||
// Attempt to relay the block.
|
||||
|
@ -272,7 +269,7 @@ async fn generate_blocks(
|
|||
let prev_block = if request.prev_block.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(helper::hex_to_hash(request.prev_block)?)
|
||||
Some(request.prev_block.try_into()?)
|
||||
};
|
||||
|
||||
let (blocks, height) = blockchain_manager::generate_blocks(
|
||||
|
@ -318,21 +315,13 @@ async fn get_block_header_by_hash(
|
|||
));
|
||||
}
|
||||
|
||||
async fn get(
|
||||
state: &mut CupratedRpcHandler,
|
||||
hash: [u8; 32],
|
||||
fill_pow_hash: bool,
|
||||
) -> Result<BlockHeader, Error> {
|
||||
let block_header = helper::block_header_by_hash(state, hash, fill_pow_hash).await?;
|
||||
Ok(block_header)
|
||||
}
|
||||
|
||||
let block_header = get(&mut state, request.hash.0, request.fill_pow_hash).await?;
|
||||
let block_header =
|
||||
helper::block_header_by_hash(&mut state, request.hash.0, request.fill_pow_hash).await?;
|
||||
|
||||
// FIXME PERF: could make a `Vec` on await on all tasks at the same time.
|
||||
let mut block_headers = Vec::with_capacity(request.hashes.len());
|
||||
for hash in request.hashes {
|
||||
let hash = get(&mut state, hash.0, request.fill_pow_hash).await?;
|
||||
let hash = helper::block_header_by_hash(&mut state, hash.0, request.fill_pow_hash).await?;
|
||||
block_headers.push(hash);
|
||||
}
|
||||
|
||||
|
@ -425,16 +414,16 @@ async fn get_block(
|
|||
helper::block_header(&mut state, request.height, request.fill_pow_hash).await?;
|
||||
(block, block_header)
|
||||
} else {
|
||||
let hash = helper::hex_to_hash(request.hash)?;
|
||||
let hash: [u8; 32] = request.hash.try_into()?;
|
||||
let block = blockchain::block_by_hash(&mut state.blockchain_read, hash).await?;
|
||||
let block_header =
|
||||
helper::block_header_by_hash(&mut state, hash, request.fill_pow_hash).await?;
|
||||
(block, block_header)
|
||||
};
|
||||
|
||||
let blob = hex::encode(block.serialize());
|
||||
let blob = HexVec(block.serialize());
|
||||
let miner_tx_hash = Hex(block.miner_transaction.hash());
|
||||
let tx_hashes = block.transactions.iter().map(|a| Hex(*a)).collect();
|
||||
let tx_hashes = block.transactions.iter().copied().map(Hex).collect();
|
||||
let json = {
|
||||
let block = cuprate_types::json::block::Block::from(block);
|
||||
serde_json::to_string_pretty(&block)?
|
||||
|
@ -473,8 +462,7 @@ async fn get_info(
|
|||
|
||||
let c = context.unchecked_blockchain_context();
|
||||
let cumulative_difficulty = c.cumulative_difficulty;
|
||||
let adjusted_time = c.current_adjusted_timestamp_for_time_lock(); // TODO: is this correct?
|
||||
|
||||
let adjusted_time = c.current_adjusted_timestamp_for_time_lock();
|
||||
let c = &c.context_to_verify_block;
|
||||
|
||||
let alt_blocks_count = if restricted {
|
||||
|
@ -482,76 +470,98 @@ async fn get_info(
|
|||
} else {
|
||||
blockchain::alt_chain_count(&mut state.blockchain_read).await?
|
||||
};
|
||||
let block_weight_limit = usize_to_u64(c.effective_median_weight); // TODO: is this correct?
|
||||
let block_weight_median = usize_to_u64(c.median_weight_for_block_reward); // TODO: is this correct?
|
||||
|
||||
let block_weight_limit = usize_to_u64(c.effective_median_weight);
|
||||
let block_weight_median = usize_to_u64(c.median_weight_for_block_reward);
|
||||
let block_size_limit = block_weight_limit;
|
||||
let block_size_median = block_weight_median;
|
||||
|
||||
#[expect(clippy::if_same_then_else, reason = "TODO: support bootstrap")]
|
||||
let (bootstrap_daemon_address, was_bootstrap_ever_used) = if restricted {
|
||||
(String::new(), false)
|
||||
} else {
|
||||
todo!("support bootstrap daemon")
|
||||
(String::new(), false)
|
||||
};
|
||||
|
||||
let busy_syncing = blockchain_manager::syncing(&mut state.blockchain_manager).await?;
|
||||
|
||||
let (cumulative_difficulty, cumulative_difficulty_top64) =
|
||||
split_u128_into_low_high_bits(cumulative_difficulty);
|
||||
|
||||
let (database_size, free_space) = blockchain::database_size(&mut state.blockchain_read).await?;
|
||||
let (database_size, free_space) = if restricted {
|
||||
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L131-L134>
|
||||
const fn round_up(value: u64, quantum: u64) -> u64 {
|
||||
value.div_ceil(quantum)
|
||||
}
|
||||
|
||||
let database_size = round_up(database_size, 5 * 1024 * 1024 * 1024);
|
||||
(database_size, u64::MAX)
|
||||
} else {
|
||||
(database_size, free_space)
|
||||
};
|
||||
|
||||
let (difficulty, difficulty_top64) = split_u128_into_low_high_bits(c.next_difficulty);
|
||||
|
||||
let height = usize_to_u64(c.chain_height);
|
||||
let height_without_bootstrap = if restricted { 0 } else { height };
|
||||
|
||||
let (incoming_connections_count, outgoing_connections_count) = if restricted {
|
||||
(0, 0)
|
||||
} else {
|
||||
address_book::connection_count::<ClearNet>(&mut DummyAddressBook).await?
|
||||
};
|
||||
let (mainnet, testnet, stagenet) = match todo!("access to `cuprated`'s `Network`") {
|
||||
|
||||
// TODO: This should be `cuprated`'s active network.
|
||||
let network = Network::Mainnet;
|
||||
|
||||
let (mainnet, testnet, stagenet) = match network {
|
||||
Network::Mainnet => (true, false, false),
|
||||
Network::Testnet => (false, true, false),
|
||||
Network::Stagenet => (false, false, true),
|
||||
};
|
||||
// TODO: make sure this is:
|
||||
// - the same case as `monerod`
|
||||
// - untagged (no `Network::`)
|
||||
let nettype = todo!("access to `cuprated`'s `Network`").to_string();
|
||||
let offline = todo!("access to CLI/config's `--offline`");
|
||||
let rpc_connections_count = if restricted {
|
||||
0
|
||||
} else {
|
||||
todo!("implement a connection counter in axum/RPC")
|
||||
};
|
||||
|
||||
let nettype = network.to_string();
|
||||
// TODO: access to CLI/config's `--offline`
|
||||
let offline = false;
|
||||
|
||||
#[expect(
|
||||
clippy::if_same_then_else,
|
||||
reason = "TODO: implement a connection counter in axum/RPC"
|
||||
)]
|
||||
let rpc_connections_count = if restricted { 0 } else { 0 };
|
||||
|
||||
let start_time = if restricted { 0 } else { *START_INSTANT_UNIX };
|
||||
let synchronized = blockchain_manager::synced(&mut state.blockchain_manager).await?;
|
||||
|
||||
let target_height = blockchain_manager::target_height(&mut state.blockchain_manager).await?;
|
||||
let target = blockchain_manager::target(&mut state.blockchain_manager)
|
||||
.await?
|
||||
.as_secs();
|
||||
let top_block_hash = Hex(c.top_hash);
|
||||
|
||||
let tx_count = blockchain::total_tx_count(&mut state.blockchain_read).await?;
|
||||
let tx_pool_size = txpool::size(&mut state.txpool_read, !restricted).await?;
|
||||
let update_available = if restricted {
|
||||
false
|
||||
} else {
|
||||
todo!("implement an update checker for `cuprated`")
|
||||
};
|
||||
|
||||
#[expect(
|
||||
clippy::if_same_then_else,
|
||||
clippy::needless_bool,
|
||||
reason = "TODO: implement an update checker for `cuprated`?"
|
||||
)]
|
||||
let update_available = if restricted { false } else { false };
|
||||
|
||||
let version = if restricted {
|
||||
String::new()
|
||||
} else {
|
||||
VERSION_BUILD.to_string()
|
||||
};
|
||||
|
||||
let (white_peerlist_size, grey_peerlist_size) = if restricted {
|
||||
(0, 0)
|
||||
} else {
|
||||
address_book::peerlist_size::<ClearNet>(&mut DummyAddressBook).await?
|
||||
};
|
||||
|
||||
let wide_cumulative_difficulty = format!("{cumulative_difficulty:#x}");
|
||||
let wide_difficulty = format!("{:#x}", c.next_difficulty);
|
||||
|
||||
|
@ -613,18 +623,12 @@ async fn hard_fork_info(
|
|||
.current_hf
|
||||
};
|
||||
|
||||
let info = blockchain_context::hard_fork_info(&mut state.blockchain_context, hard_fork).await?;
|
||||
let hard_fork_info =
|
||||
blockchain_context::hard_fork_info(&mut state.blockchain_context, hard_fork).await?;
|
||||
|
||||
Ok(HardForkInfoResponse {
|
||||
base: helper::access_response_base(false),
|
||||
earliest_height: info.earliest_height,
|
||||
enabled: info.enabled,
|
||||
state: info.state,
|
||||
threshold: info.threshold,
|
||||
version: info.version,
|
||||
votes: info.votes,
|
||||
voting: info.voting,
|
||||
window: info.window,
|
||||
hard_fork_info,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1024,8 +1028,7 @@ async fn calc_pow(
|
|||
request: CalcPowRequest,
|
||||
) -> Result<CalcPowResponse, Error> {
|
||||
let hardfork = HardFork::from_version(request.major_version)?;
|
||||
let block_blob: Vec<u8> = hex::decode(request.block_blob)?;
|
||||
let block = Block::read(&mut block_blob.as_slice())?;
|
||||
let block = Block::read(&mut request.block_blob.0.as_slice())?;
|
||||
let seed_hash = request.seed_hash.0;
|
||||
|
||||
// let block_weight = todo!();
|
||||
|
@ -1043,6 +1046,7 @@ async fn calc_pow(
|
|||
// }
|
||||
|
||||
// TODO: will `CalculatePow` do the above checks?
|
||||
|
||||
let pow_hash = blockchain_context::calculate_pow(
|
||||
&mut state.blockchain_context,
|
||||
hardfork,
|
||||
|
@ -1056,23 +1060,16 @@ async fn calc_pow(
|
|||
})
|
||||
}
|
||||
|
||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3542-L3551>
|
||||
async fn flush_cache(
|
||||
state: CupratedRpcHandler,
|
||||
request: FlushCacheRequest,
|
||||
) -> Result<FlushCacheResponse, Error> {
|
||||
// TODO: cuprated doesn't need this call; decide behavior.
|
||||
|
||||
Ok(FlushCacheResponse {
|
||||
base: helper::response_base(false),
|
||||
})
|
||||
}
|
||||
|
||||
/// An async-friendly wrapper for [`add_aux_pow_inner`].
|
||||
async fn add_aux_pow(
|
||||
state: CupratedRpcHandler,
|
||||
request: AddAuxPowRequest,
|
||||
) -> Result<AddAuxPowResponse, Error> {
|
||||
// This method can be a bit heavy, so rate-limit restricted use.
|
||||
if state.is_restricted() {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
}
|
||||
|
||||
tokio::task::spawn_blocking(|| add_aux_pow_inner(state, request)).await?
|
||||
}
|
||||
|
||||
|
@ -1222,10 +1219,7 @@ fn add_aux_pow_inner(
|
|||
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())?
|
||||
};
|
||||
let block_template = Block::read(&mut request.blocktemplate_blob.0.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")
|
||||
|
@ -1256,8 +1250,8 @@ fn add_aux_pow_inner(
|
|||
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 blocktemplate_blob = HexVec(blocktemplate_blob);
|
||||
let blockhashing_blob = HexVec(blockhashing_blob);
|
||||
let merkle_root = Hex(merkle_root);
|
||||
let aux_pow = aux_pow.into_vec();
|
||||
|
||||
|
@ -1271,16 +1265,25 @@ fn add_aux_pow_inner(
|
|||
})
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Unsupported RPC calls (for now)
|
||||
|
||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3553-L3627>
|
||||
async fn get_tx_ids_loose(
|
||||
state: CupratedRpcHandler,
|
||||
request: GetTxIdsLooseRequest,
|
||||
) -> Result<GetTxIdsLooseResponse, Error> {
|
||||
// TODO: this RPC call is not yet in the v0.18 branch.
|
||||
return Err(anyhow!("Not implemented"));
|
||||
|
||||
Ok(GetTxIdsLooseResponse {
|
||||
base: helper::response_base(false),
|
||||
txids: todo!(),
|
||||
txids: todo!("this RPC call is not yet in the v0.18 branch."),
|
||||
})
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Unsupported RPC calls (forever)
|
||||
|
||||
/// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L3542-L3551>
|
||||
async fn flush_cache(
|
||||
state: CupratedRpcHandler,
|
||||
request: FlushCacheRequest,
|
||||
) -> Result<FlushCacheResponse, Error> {
|
||||
unreachable!()
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ use cuprate_constants::rpc::{
|
|||
RESTRICTED_TRANSACTIONS_COUNT,
|
||||
};
|
||||
use cuprate_helper::cast::usize_to_u64;
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_hex::{Hex, HexVec};
|
||||
use cuprate_p2p_core::{client::handshaker::builder::DummyAddressBook, ClearNet};
|
||||
use cuprate_rpc_interface::RpcHandler;
|
||||
use cuprate_rpc_types::{
|
||||
|
@ -157,23 +157,23 @@ async fn get_transactions(
|
|||
let prunable_hash = Hex(tx.prunable_hash);
|
||||
|
||||
let (pruned_as_hex, prunable_as_hex) = if tx.pruned_blob.is_empty() {
|
||||
(String::new(), String::new())
|
||||
(HexVec::new(), HexVec::new())
|
||||
} else {
|
||||
(hex::encode(tx.pruned_blob), hex::encode(tx.prunable_blob))
|
||||
(HexVec(tx.pruned_blob), HexVec(tx.prunable_blob))
|
||||
};
|
||||
|
||||
let as_hex = if pruned_as_hex.is_empty() {
|
||||
// `monerod` will insert a `""` into the `txs_as_hex` array for pruned transactions.
|
||||
// curl http://127.0.0.1:18081/get_transactions -d '{"txs_hashes":["4c8b98753d1577d225a497a50f453827cff3aa023a4add60ec4ce4f923f75de8"]}' -H 'Content-Type: application/json'
|
||||
String::new()
|
||||
HexVec::new()
|
||||
} else {
|
||||
hex::encode(&tx.tx_blob)
|
||||
HexVec(tx.tx_blob)
|
||||
};
|
||||
|
||||
txs_as_hex.push(as_hex.clone());
|
||||
|
||||
let as_json = if request.decode_as_json {
|
||||
let tx = Transaction::read(&mut tx.tx_blob.as_slice())?;
|
||||
let tx = Transaction::read(&mut as_hex.0.as_slice())?;
|
||||
let json_type = cuprate_types::json::tx::Transaction::from(tx);
|
||||
let json = serde_json::to_string(&json_type).unwrap();
|
||||
txs_as_json.push(json.clone());
|
||||
|
@ -217,11 +217,11 @@ async fn get_transactions(
|
|||
let tx_hash = Hex(tx_hash);
|
||||
let tx = Transaction::read(&mut tx_blob.as_slice())?;
|
||||
|
||||
let pruned_as_hex = String::new();
|
||||
let prunable_as_hex = String::new();
|
||||
let pruned_as_hex = HexVec::new();
|
||||
let prunable_as_hex = HexVec::new();
|
||||
let prunable_hash = Hex([0; 32]);
|
||||
|
||||
let as_hex = hex::encode(tx_blob);
|
||||
let as_hex = HexVec(tx_blob);
|
||||
txs_as_hex.push(as_hex.clone());
|
||||
|
||||
let as_json = if request.decode_as_json {
|
||||
|
@ -351,10 +351,7 @@ async fn send_raw_transaction(
|
|||
tx_extra_too_big: false,
|
||||
};
|
||||
|
||||
let tx = {
|
||||
let blob = hex::decode(request.tx_as_hex)?;
|
||||
Transaction::read(&mut blob.as_slice())?
|
||||
};
|
||||
let tx = Transaction::read(&mut request.tx_as_hex.0.as_slice())?;
|
||||
|
||||
if request.do_sanity_checks {
|
||||
/// FIXME: these checks could be defined elsewhere.
|
||||
|
|
|
@ -59,7 +59,7 @@ pub async fn size(
|
|||
Ok(usize_to_u64(size))
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// [`TxpoolReadRequest::PoolInfo`]
|
||||
pub async fn pool_info(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
include_sensitive_txs: bool,
|
||||
|
@ -84,7 +84,7 @@ pub async fn pool_info(
|
|||
Ok(pool_info)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// [`TxpoolReadRequest::TxsByHash`]
|
||||
pub async fn txs_by_hash(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
tx_hashes: Vec<[u8; 32]>,
|
||||
|
@ -107,7 +107,7 @@ pub async fn txs_by_hash(
|
|||
Ok(txs_in_pool)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// [`TxpoolReadRequest::KeyImagesSpent`]
|
||||
pub async fn key_images_spent(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
key_images: Vec<[u8; 32]>,
|
||||
|
@ -130,7 +130,7 @@ pub async fn key_images_spent(
|
|||
Ok(status)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// [`TxpoolReadRequest::Pool`]
|
||||
pub async fn pool(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
include_sensitive_txs: bool,
|
||||
|
@ -157,7 +157,7 @@ pub async fn pool(
|
|||
Ok((txs, spent_key_images))
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// [`TxpoolReadRequest::PoolStats`]
|
||||
pub async fn pool_stats(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
include_sensitive_txs: bool,
|
||||
|
@ -178,7 +178,7 @@ pub async fn pool_stats(
|
|||
Ok(txpool_stats)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// [`TxpoolReadRequest::AllHashes`]
|
||||
pub async fn all_hashes(
|
||||
txpool_read: &mut TxpoolReadHandle,
|
||||
include_sensitive_txs: bool,
|
||||
|
@ -199,19 +199,19 @@ pub async fn all_hashes(
|
|||
Ok(hashes)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// TODO: impl txpool manager.
|
||||
pub async fn flush(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> {
|
||||
todo!();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// TODO: impl txpool manager.
|
||||
pub async fn relay(txpool_manager: &mut Infallible, tx_hashes: Vec<[u8; 32]>) -> Result<(), Error> {
|
||||
todo!();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// TODO
|
||||
/// TODO: impl txpool manager.
|
||||
pub async fn check_maybe_relay_local(
|
||||
txpool_manager: &mut Infallible,
|
||||
tx: Transaction,
|
||||
|
|
|
@ -8,7 +8,7 @@ use bytes::{Buf, BufMut, Bytes, BytesMut};
|
|||
|
||||
use cuprate_fixed_bytes::{ByteArray, ByteArrayVec};
|
||||
use cuprate_helper::cast::u64_to_usize;
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_hex::{Hex, HexVec};
|
||||
|
||||
use crate::{
|
||||
io::{checked_read_primitive, checked_write_primitive},
|
||||
|
@ -437,6 +437,18 @@ impl<const N: usize> EpeeValue for Vec<Hex<N>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl EpeeValue for HexVec {
|
||||
const MARKER: Marker = <Vec<u8> as EpeeValue>::MARKER;
|
||||
|
||||
fn read<B: Buf>(r: &mut B, marker: &Marker) -> Result<Self> {
|
||||
Ok(Self(<Vec<u8> as EpeeValue>::read(r, marker)?))
|
||||
}
|
||||
|
||||
fn write<B: BufMut>(self, w: &mut B) -> Result<()> {
|
||||
<Vec<u8> as EpeeValue>::write(self.0, w)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! epee_seq {
|
||||
($val:ty) => {
|
||||
impl EpeeValue for Vec<$val> {
|
||||
|
@ -503,6 +515,7 @@ epee_seq!(u16);
|
|||
epee_seq!(f64);
|
||||
epee_seq!(bool);
|
||||
epee_seq!(Vec<u8>);
|
||||
epee_seq!(HexVec);
|
||||
epee_seq!(String);
|
||||
epee_seq!(Bytes);
|
||||
epee_seq!(BytesMut);
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
};
|
||||
|
||||
use cuprate_helper::{fmt::HexPrefix, map::ipv4_from_u32};
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_hex::{Hex, HexVec};
|
||||
use cuprate_p2p_core::{
|
||||
types::{ConnectionId, ConnectionInfo, SetBan, Span},
|
||||
NetZoneAddress,
|
||||
|
@ -34,7 +34,7 @@ impl From<BlockHeader> for crate::misc::BlockHeader {
|
|||
nonce: x.nonce,
|
||||
num_txes: x.num_txes,
|
||||
orphan_status: x.orphan_status,
|
||||
pow_hash: x.pow_hash.map_or_else(String::new, hex::encode),
|
||||
pow_hash: x.pow_hash.map_or_else(HexVec::new, |a| HexVec(a.into())),
|
||||
prev_hash: Hex(x.prev_hash),
|
||||
reward: x.reward,
|
||||
timestamp: x.timestamp,
|
||||
|
@ -178,7 +178,7 @@ impl From<TxInfo> for crate::misc::TxInfo {
|
|||
max_used_block_id_hash: Hex(x.max_used_block_id_hash),
|
||||
receive_time: x.receive_time,
|
||||
relayed: x.relayed,
|
||||
tx_blob: hex::encode(x.tx_blob),
|
||||
tx_blob: HexVec(x.tx_blob),
|
||||
tx_json: x.tx_json,
|
||||
weight: x.weight,
|
||||
}
|
||||
|
@ -201,7 +201,11 @@ impl From<crate::misc::OutKeyBin> for crate::misc::OutKey {
|
|||
mask: Hex(x.mask),
|
||||
unlocked: x.unlocked,
|
||||
height: x.height,
|
||||
txid: hex::encode(x.txid),
|
||||
txid: if x.txid == [0; 32] {
|
||||
HexVec::new()
|
||||
} else {
|
||||
HexVec::from(x.txid)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_types::rpc::{AuxPow, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry};
|
||||
use cuprate_hex::{Hex, HexVec};
|
||||
use cuprate_types::rpc::{
|
||||
AuxPow, GetMinerDataTxBacklogEntry, HardForkEntry, HardForkInfo, TxBacklogEntry,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
base::{AccessResponseBase, ResponseBase},
|
||||
|
@ -79,7 +81,7 @@ define_request_and_response! {
|
|||
// This is a HACK since `serde`'s default attribute only takes in
|
||||
// string literals and macros (stringify) within attributes do not work.
|
||||
extra_nonce: String = default::<String>(), "default",
|
||||
prev_block: String = default::<String>(), "default",
|
||||
prev_block: HexVec = default::<HexVec>(), "default",
|
||||
|
||||
// Another optional expression:
|
||||
// This indicates to the macro to (de)serialize
|
||||
|
@ -116,13 +118,14 @@ define_request_and_response! {
|
|||
// status: crate::Status,
|
||||
// untrusted: bool,
|
||||
// ```
|
||||
blockhashing_blob: String,
|
||||
blocktemplate_blob: String,
|
||||
blockhashing_blob: HexVec,
|
||||
blocktemplate_blob: HexVec,
|
||||
difficulty_top64: u64,
|
||||
difficulty: u64,
|
||||
expected_reward: u64,
|
||||
height: u64,
|
||||
next_seed_hash: String,
|
||||
/// This is a [`Hex<32>`] that is sometimes empty.
|
||||
next_seed_hash: HexVec,
|
||||
prev_hash: Hex<32>,
|
||||
reserved_offset: u64,
|
||||
seed_hash: Hex<32>,
|
||||
|
@ -179,7 +182,7 @@ define_request_and_response! {
|
|||
Request {
|
||||
// This is `std::vector<std::string>` in `monerod` but
|
||||
// it must be a 1 length array or else it will error.
|
||||
block_blob: [String; 1],
|
||||
block_blob: [HexVec; 1],
|
||||
},
|
||||
|
||||
// FIXME: `cuprate_test_utils` only has an `error` response for this.
|
||||
|
@ -197,7 +200,7 @@ define_request_and_response! {
|
|||
|
||||
Request {
|
||||
amount_of_blocks: u64,
|
||||
prev_block: String = default::<String>(), "default",
|
||||
prev_block: HexVec = default::<HexVec>(), "default",
|
||||
starting_nonce: u32,
|
||||
wallet_address: String,
|
||||
},
|
||||
|
@ -290,13 +293,15 @@ define_request_and_response! {
|
|||
// `monerod` has both `hash` and `height` fields.
|
||||
// In the RPC handler, if `hash.is_empty()`, it will use it, else, it uses `height`.
|
||||
// <https://github.com/monero-project/monero/blob/cc73fe71162d564ffda8e549b79a350bca53c454/src/rpc/core_rpc_server.cpp#L2674>
|
||||
hash: String = default::<String>(), "default",
|
||||
|
||||
/// This is a [`Hex<32>`] that is sometimes empty.
|
||||
hash: HexVec = default::<HexVec>(), "default",
|
||||
height: u64 = default::<u64>(), "default",
|
||||
fill_pow_hash: bool = default::<bool>(), "default",
|
||||
},
|
||||
|
||||
AccessResponseBase {
|
||||
blob: String,
|
||||
blob: HexVec,
|
||||
block_header: BlockHeader,
|
||||
/// `cuprate_types::json::block::Block` should be used
|
||||
/// to create this JSON string in a type-safe manner.
|
||||
|
@ -382,14 +387,9 @@ define_request_and_response! {
|
|||
},
|
||||
|
||||
AccessResponseBase {
|
||||
earliest_height: u64,
|
||||
enabled: bool,
|
||||
state: u32,
|
||||
threshold: u32,
|
||||
version: u8,
|
||||
votes: u32,
|
||||
voting: u8,
|
||||
window: u32,
|
||||
/// This field is [flattened](https://serde.rs/field-attrs.html#flatten).
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
hard_fork_info: HardForkInfo,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -662,7 +662,7 @@ define_request_and_response! {
|
|||
Request {
|
||||
major_version: u8,
|
||||
height: u64,
|
||||
block_blob: String,
|
||||
block_blob: HexVec,
|
||||
seed_hash: Hex<32>,
|
||||
},
|
||||
|
||||
|
@ -697,13 +697,13 @@ define_request_and_response! {
|
|||
AddAuxPow,
|
||||
|
||||
Request {
|
||||
blocktemplate_blob: String,
|
||||
blocktemplate_blob: HexVec,
|
||||
aux_pow: Vec<AuxPow>,
|
||||
},
|
||||
|
||||
ResponseBase {
|
||||
blocktemplate_blob: String,
|
||||
blockhashing_blob: String,
|
||||
blocktemplate_blob: HexVec,
|
||||
blockhashing_blob: HexVec,
|
||||
merkle_root: Hex<32>,
|
||||
merkle_tree_depth: u64,
|
||||
aux_pow: Vec<AuxPow>,
|
||||
|
@ -722,7 +722,7 @@ define_request_and_response! {
|
|||
num_matching_bits: u32,
|
||||
},
|
||||
ResponseBase {
|
||||
txids: Vec<String>,
|
||||
txids: Vec<Hex<32>>,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -959,7 +959,7 @@ mod test {
|
|||
test_json_request(json::GET_BLOCK_TEMPLATE_REQUEST, GetBlockTemplateRequest {
|
||||
reserve_size: 60,
|
||||
extra_nonce: String::default(),
|
||||
prev_block: String::default(),
|
||||
prev_block: HexVec::default(),
|
||||
wallet_address: "44GBHzv6ZyQdJkjqZje6KLZ3xSyN1hBSFAnLP6EAqJtCRVzMzZmeXTC2AHKDS9aEDTRKmo6a6o9r9j86pYfhCWDkKjbtcns".into(),
|
||||
});
|
||||
}
|
||||
|
@ -968,13 +968,13 @@ mod test {
|
|||
fn get_block_template_response() {
|
||||
test_json_response(json::GET_BLOCK_TEMPLATE_RESPONSE, GetBlockTemplateResponse {
|
||||
base: ResponseBase::OK,
|
||||
blockhashing_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a00000000e0c20372be23d356347091025c5b5e8f2abf83ab618378565cce2b703491523401".into(),
|
||||
blocktemplate_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(),
|
||||
blockhashing_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a00000000e0c20372be23d356347091025c5b5e8f2abf83ab618378565cce2b703491523401").into()),
|
||||
blocktemplate_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()),
|
||||
difficulty_top64: 0,
|
||||
difficulty: 283305047039,
|
||||
expected_reward: 600000000000,
|
||||
height: 3195018,
|
||||
next_seed_hash: String::new(),
|
||||
next_seed_hash: HexVec::new(),
|
||||
prev_hash: Hex(hex!("9d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a")),
|
||||
reserved_offset: 131,
|
||||
seed_hash: Hex(hex!("e2aa0b7b55042cd48b02e395d78fa66a29815ccc1584e38db2d1f0e8485cd44f")),
|
||||
|
@ -1019,7 +1019,7 @@ mod test {
|
|||
#[test]
|
||||
fn submit_block_request() {
|
||||
test_json_request(json::SUBMIT_BLOCK_REQUEST, SubmitBlockRequest {
|
||||
block_blob: ["0707e6bdfedc053771512f1bc27c62731ae9e8f2443db64ce742f4e57f5cf8d393de28551e441a0000000002fb830a01ffbf830a018cfe88bee283060274c0aae2ef5730e680308d9c00b6da59187ad0352efe3c71d36eeeb28782f29f2501bd56b952c3ddc3e350c2631d3a5086cac172c56893831228b17de296ff4669de020200000000".into()],
|
||||
block_blob: [HexVec(hex!("0707e6bdfedc053771512f1bc27c62731ae9e8f2443db64ce742f4e57f5cf8d393de28551e441a0000000002fb830a01ffbf830a018cfe88bee283060274c0aae2ef5730e680308d9c00b6da59187ad0352efe3c71d36eeeb28782f29f2501bd56b952c3ddc3e350c2631d3a5086cac172c56893831228b17de296ff4669de020200000000").into())],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1027,7 +1027,7 @@ mod test {
|
|||
fn generate_blocks_request() {
|
||||
test_json_request(json::GENERATE_BLOCKS_REQUEST, GenerateBlocksRequest {
|
||||
amount_of_blocks: 1,
|
||||
prev_block: String::default(),
|
||||
prev_block: HexVec::default(),
|
||||
wallet_address: "44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A".into(),
|
||||
starting_nonce: 0
|
||||
});
|
||||
|
@ -1074,7 +1074,7 @@ mod test {
|
|||
nonce: 1885649739,
|
||||
num_txes: 37,
|
||||
orphan_status: false,
|
||||
pow_hash: String::new(),
|
||||
pow_hash: HexVec::new(),
|
||||
prev_hash: Hex(hex!(
|
||||
"22c72248ae9c5a2863c94735d710a3525c499f70707d1c2f395169bc5c8a0da3"
|
||||
)),
|
||||
|
@ -1129,7 +1129,7 @@ mod test {
|
|||
nonce: 1646,
|
||||
num_txes: 0,
|
||||
orphan_status: false,
|
||||
pow_hash: String::new(),
|
||||
pow_hash: HexVec::new(),
|
||||
prev_hash: Hex(hex!(
|
||||
"b61c58b2e0be53fad5ef9d9731a55e8a81d972b8d90ed07c04fd37ca6403ff78"
|
||||
)),
|
||||
|
@ -1180,7 +1180,7 @@ mod test {
|
|||
nonce: 1646,
|
||||
num_txes: 0,
|
||||
orphan_status: false,
|
||||
pow_hash: String::new(),
|
||||
pow_hash: HexVec::new(),
|
||||
prev_hash: Hex(hex!(
|
||||
"b61c58b2e0be53fad5ef9d9731a55e8a81d972b8d90ed07c04fd37ca6403ff78"
|
||||
)),
|
||||
|
@ -1233,7 +1233,7 @@ mod test {
|
|||
nonce: 3246403956,
|
||||
num_txes: 20,
|
||||
orphan_status: false,
|
||||
pow_hash: String::new(),
|
||||
pow_hash: HexVec::new(),
|
||||
prev_hash: Hex(hex!(
|
||||
"0ef6e948f77b8f8806621003f5de24b1bcbea150bc0e376835aea099674a5db5"
|
||||
)),
|
||||
|
@ -1263,7 +1263,7 @@ mod test {
|
|||
nonce: 3737164176,
|
||||
num_txes: 1,
|
||||
orphan_status: false,
|
||||
pow_hash: String::new(),
|
||||
pow_hash: HexVec::new(),
|
||||
prev_hash: Hex(hex!(
|
||||
"86d1d20a40cefcf3dd410ff6967e0491613b77bf73ea8f1bf2e335cf9cf7d57a"
|
||||
)),
|
||||
|
@ -1283,7 +1283,7 @@ mod test {
|
|||
json::GET_BLOCK_REQUEST,
|
||||
GetBlockRequest {
|
||||
height: 2751506,
|
||||
hash: String::new(),
|
||||
hash: HexVec::new(),
|
||||
fill_pow_hash: false,
|
||||
},
|
||||
);
|
||||
|
@ -1293,7 +1293,7 @@ mod test {
|
|||
fn get_block_response() {
|
||||
test_json_response(json::GET_BLOCK_RESPONSE, GetBlockResponse {
|
||||
base: AccessResponseBase::OK,
|
||||
blob: "1010c58bab9b06b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7807e07f502cef8a70101ff92f8a7010180e0a596bb1103d7cbf826b665d7a532c316982dc8dbc24f285cbc18bbcc27c7164cd9b3277a85d034019f629d8b36bd16a2bfce3ea80c31dc4d8762c67165aec21845494e32b7582fe00211000000297a787a000000000000000000000000".into(),
|
||||
blob: HexVec(hex!("1010c58bab9b06b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7807e07f502cef8a70101ff92f8a7010180e0a596bb1103d7cbf826b665d7a532c316982dc8dbc24f285cbc18bbcc27c7164cd9b3277a85d034019f629d8b36bd16a2bfce3ea80c31dc4d8762c67165aec21845494e32b7582fe00211000000297a787a000000000000000000000000").into()),
|
||||
block_header: BlockHeader {
|
||||
block_size: 106,
|
||||
block_weight: 106,
|
||||
|
@ -1311,7 +1311,7 @@ mod test {
|
|||
nonce: 4110909056,
|
||||
num_txes: 0,
|
||||
orphan_status: false,
|
||||
pow_hash: String::new(),
|
||||
pow_hash: HexVec::new(),
|
||||
prev_hash: Hex(hex!("b27bdecfc6cd0a46172d136c08831cf67660377ba992332363228b1b722781e7")),
|
||||
reward: 600000000000,
|
||||
timestamp: 1667941829,
|
||||
|
@ -1461,6 +1461,7 @@ mod test {
|
|||
json::HARD_FORK_INFO_RESPONSE,
|
||||
HardForkInfoResponse {
|
||||
base: AccessResponseBase::OK,
|
||||
hard_fork_info: HardForkInfo {
|
||||
earliest_height: 2689608,
|
||||
enabled: true,
|
||||
state: 0,
|
||||
|
@ -1470,6 +1471,7 @@ mod test {
|
|||
voting: 16,
|
||||
window: 10080,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1904,7 +1906,7 @@ mod test {
|
|||
test_json_request(json::CALC_POW_REQUEST, CalcPowRequest {
|
||||
major_version: 14,
|
||||
height: 2286447,
|
||||
block_blob: "0e0ed286da8006ecdc1aab3033cf1716c52f13f9d8ae0051615a2453643de94643b550d543becd0000000002abc78b0101ffefc68b0101fcfcf0d4b422025014bb4a1eade6622fd781cb1063381cad396efa69719b41aa28b4fce8c7ad4b5f019ce1dc670456b24a5e03c2d9058a2df10fec779e2579753b1847b74ee644f16b023c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051399a1bc46a846474f5b33db24eae173a26393b976054ee14f9feefe99925233802867097564c9db7a36af5bb5ed33ab46e63092bd8d32cef121608c3258edd55562812e21cc7e3ac73045745a72f7d74581d9a0849d6f30e8b2923171253e864f4e9ddea3acb5bc755f1c4a878130a70c26297540bc0b7a57affb6b35c1f03d8dbd54ece8457531f8cba15bb74516779c01193e212050423020e45aa2c15dcb".into(),
|
||||
block_blob: HexVec(hex!("0e0ed286da8006ecdc1aab3033cf1716c52f13f9d8ae0051615a2453643de94643b550d543becd0000000002abc78b0101ffefc68b0101fcfcf0d4b422025014bb4a1eade6622fd781cb1063381cad396efa69719b41aa28b4fce8c7ad4b5f019ce1dc670456b24a5e03c2d9058a2df10fec779e2579753b1847b74ee644f16b023c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000051399a1bc46a846474f5b33db24eae173a26393b976054ee14f9feefe99925233802867097564c9db7a36af5bb5ed33ab46e63092bd8d32cef121608c3258edd55562812e21cc7e3ac73045745a72f7d74581d9a0849d6f30e8b2923171253e864f4e9ddea3acb5bc755f1c4a878130a70c26297540bc0b7a57affb6b35c1f03d8dbd54ece8457531f8cba15bb74516779c01193e212050423020e45aa2c15dcb").into()),
|
||||
seed_hash: Hex(hex!("d432f499205150873b2572b5f033c9c6e4b7c6f3394bd2dd93822cd7085e7307")),
|
||||
});
|
||||
}
|
||||
|
@ -1945,7 +1947,7 @@ mod test {
|
|||
#[test]
|
||||
fn add_aux_pow_request() {
|
||||
test_json_request(json::ADD_AUX_POW_REQUEST, AddAuxPowRequest {
|
||||
blocktemplate_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(),
|
||||
blocktemplate_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()),
|
||||
aux_pow: vec![AuxPow {
|
||||
id: Hex(hex!("3200b4ea97c3b2081cd4190b58e49572b2319fed00d030ad51809dff06b5d8c8")),
|
||||
hash: Hex(hex!("7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a"))
|
||||
|
@ -1961,8 +1963,8 @@ mod test {
|
|||
hash: Hex(hex!("7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a")),
|
||||
id: Hex(hex!("3200b4ea97c3b2081cd4190b58e49572b2319fed00d030ad51809dff06b5d8c8")),
|
||||
}],
|
||||
blockhashing_blob: "1010ee97e2a106e9f8ebe8887e5b609949ac8ea6143e560ed13552b110cb009b21f0cfca1eaccf00000000b2685c1283a646bc9020c758daa443be145b7370ce5a6efacb3e614117032e2c22".into(),
|
||||
blocktemplate_blob: "1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".into(),
|
||||
blockhashing_blob: HexVec(hex!("1010ee97e2a106e9f8ebe8887e5b609949ac8ea6143e560ed13552b110cb009b21f0cfca1eaccf00000000b2685c1283a646bc9020c758daa443be145b7370ce5a6efacb3e614117032e2c22").into()),
|
||||
blocktemplate_blob: HexVec(hex!("1010f4bae0b4069d648e741d85ca0e7acb4501f051b27e9b107d3cd7a3f03aa7f776089117c81a0000000002c681c30101ff8a81c3010180e0a596bb11033b7eedf47baf878f3490cb20b696079c34bd017fe59b0d070e74d73ffabc4bb0e05f011decb630f3148d0163b3bd39690dde4078e4cfb69fecf020d6278a27bad10c58023c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").into()),
|
||||
merkle_root: Hex(hex!("7b35762de164b20885e15dbe656b1138db06bb402fa1796f5765a23933d8859a")),
|
||||
merkle_tree_depth: 0,
|
||||
});
|
||||
|
|
|
@ -33,9 +33,9 @@ use crate::constants::{
|
|||
/// use cuprate_rpc_types::{
|
||||
/// misc::Status,
|
||||
/// CORE_RPC_STATUS_BUSY, CORE_RPC_STATUS_NOT_MINING, CORE_RPC_STATUS_OK,
|
||||
/// CORE_RPC_STATUS_PAYMENT_REQUIRED
|
||||
/// CORE_RPC_STATUS_PAYMENT_REQUIRED, CORE_RPC_STATUS_FAILED
|
||||
/// };
|
||||
/// use serde_json::to_string;
|
||||
/// use serde_json::{to_string, from_str};
|
||||
///
|
||||
/// let other = Status::Other("OTHER".into());
|
||||
///
|
||||
|
@ -46,6 +46,16 @@ use crate::constants::{
|
|||
/// assert_eq!(to_string(&Status::PaymentRequired).unwrap(), r#""PAYMENT REQUIRED""#);
|
||||
/// assert_eq!(to_string(&other).unwrap(), r#""OTHER""#);
|
||||
///
|
||||
/// assert_eq!(from_str::<Status>(r#""Ok""#).unwrap(), Status::Ok);
|
||||
/// assert_eq!(from_str::<Status>(r#""OK""#).unwrap(), Status::Ok);
|
||||
/// assert_eq!(from_str::<Status>(r#""Failed""#).unwrap(), Status::Failed);
|
||||
/// assert_eq!(from_str::<Status>(r#""FAILED""#).unwrap(), Status::Failed);
|
||||
/// assert_eq!(from_str::<Status>(r#""Busy""#).unwrap(), Status::Busy);
|
||||
/// assert_eq!(from_str::<Status>(r#""BUSY""#).unwrap(), Status::Busy);
|
||||
/// assert_eq!(from_str::<Status>(r#""NOT MINING""#).unwrap(), Status::NotMining);
|
||||
/// assert_eq!(from_str::<Status>(r#""PAYMENT REQUIRED""#).unwrap(), Status::PaymentRequired);
|
||||
/// assert_eq!(from_str::<Status>(r#""OTHER""#).unwrap(), other);
|
||||
///
|
||||
/// assert_eq!(Status::Ok.as_ref(), CORE_RPC_STATUS_OK);
|
||||
/// assert_eq!(Status::Failed.as_ref(), CORE_RPC_STATUS_FAILED);
|
||||
/// assert_eq!(Status::Busy.as_ref(), CORE_RPC_STATUS_BUSY);
|
||||
|
@ -74,16 +84,16 @@ pub enum Status {
|
|||
// `#[serde(rename = "")]` only takes raw string literals?
|
||||
// We have to re-type the constants here...
|
||||
/// Successful RPC response, everything is OK; [`CORE_RPC_STATUS_OK`].
|
||||
#[cfg_attr(feature = "serde", serde(rename = "OK"))]
|
||||
#[cfg_attr(feature = "serde", serde(rename = "OK", alias = "Ok"))]
|
||||
#[default]
|
||||
Ok,
|
||||
|
||||
/// Generic request failure.
|
||||
#[cfg_attr(feature = "serde", serde(rename = "Failed"))]
|
||||
#[cfg_attr(feature = "serde", serde(alias = "FAILED"))]
|
||||
Failed,
|
||||
|
||||
/// The daemon is busy, try later; [`CORE_RPC_STATUS_BUSY`].
|
||||
#[cfg_attr(feature = "serde", serde(rename = "BUSY"))]
|
||||
#[cfg_attr(feature = "serde", serde(rename = "BUSY", alias = "Busy"))]
|
||||
Busy,
|
||||
|
||||
/// The daemon is not mining; [`CORE_RPC_STATUS_NOT_MINING`].
|
||||
|
|
|
@ -11,7 +11,7 @@ use cuprate_epee_encoding::{
|
|||
EpeeObject, EpeeObjectBuilder,
|
||||
};
|
||||
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_hex::{Hex, HexVec};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use crate::serde::{serde_false, serde_true};
|
||||
|
@ -37,12 +37,12 @@ pub struct TxEntry {
|
|||
/// to create this JSON string in a type-safe manner.
|
||||
pub as_json: String,
|
||||
|
||||
pub as_hex: String,
|
||||
pub as_hex: HexVec,
|
||||
pub double_spend_seen: bool,
|
||||
pub tx_hash: Hex<32>,
|
||||
pub prunable_as_hex: String,
|
||||
pub prunable_as_hex: HexVec,
|
||||
pub prunable_hash: Hex<32>,
|
||||
pub pruned_as_hex: String,
|
||||
pub pruned_as_hex: HexVec,
|
||||
|
||||
#[cfg_attr(feature = "serde", serde(flatten))]
|
||||
pub tx_entry_type: TxEntryType,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! the [`crate::misc::ConnectionInfo`] struct defined here.
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use cuprate_hex::Hex;
|
||||
use cuprate_hex::{Hex, HexVec};
|
||||
use cuprate_types::HardFork;
|
||||
|
||||
#[cfg(any(feature = "epee", feature = "serde"))]
|
||||
|
@ -92,8 +92,8 @@ define_struct_and_impl_epee! {
|
|||
nonce: u32,
|
||||
num_txes: u64,
|
||||
orphan_status: bool,
|
||||
/// This is an empty string if the `fill_pow_hash` param is `false`.
|
||||
pow_hash: String,
|
||||
/// This is a [`Hex<32>`] that is sometimes empty.
|
||||
pow_hash: HexVec,
|
||||
prev_hash: Hex<32>,
|
||||
reward: u64,
|
||||
timestamp: u64,
|
||||
|
@ -264,8 +264,8 @@ define_struct_and_impl_epee! {
|
|||
mask: Hex<32>,
|
||||
unlocked: bool,
|
||||
height: u64,
|
||||
/// Optionally empty with `/get_outs`'s `"get_txid": false`.
|
||||
txid: String,
|
||||
/// This is a [`Hex<32>`] that is sometimes empty.
|
||||
txid: HexVec,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ define_struct_and_impl_epee! {
|
|||
max_used_block_id_hash: Hex<32>,
|
||||
receive_time: u64,
|
||||
relayed: bool,
|
||||
tx_blob: String,
|
||||
tx_blob: HexVec,
|
||||
tx_json: cuprate_types::json::tx::Transaction,
|
||||
weight: u64 = default::<u64>(),
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2,7 +2,7 @@
|
|||
|
||||
//---------------------------------------------------------------------------------------------------- Import
|
||||
use curve25519_dalek::edwards::CompressedEdwardsY;
|
||||
use monero_serai::transaction::Timelock;
|
||||
use monero_serai::transaction::{Timelock, Transaction};
|
||||
|
||||
use cuprate_database::{
|
||||
DbResult, RuntimeError, {DatabaseRo, DatabaseRw},
|
||||
|
@ -13,7 +13,9 @@ use cuprate_types::OutputOnChain;
|
|||
|
||||
use crate::{
|
||||
ops::macros::{doc_add_block_inner_invariant, doc_error},
|
||||
tables::{BlockTxsHashes, Outputs, RctOutputs, Tables, TablesMut, TxUnlockTime},
|
||||
tables::{
|
||||
BlockInfos, BlockTxsHashes, Outputs, RctOutputs, Tables, TablesMut, TxBlobs, TxUnlockTime,
|
||||
},
|
||||
types::{Amount, AmountIndex, Output, OutputFlags, PreRctOutputId, RctOutput},
|
||||
};
|
||||
|
||||
|
@ -154,6 +156,8 @@ pub fn output_to_output_on_chain(
|
|||
amount: Amount,
|
||||
table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>,
|
||||
table_block_txs_hashes: &impl DatabaseRo<BlockTxsHashes>,
|
||||
table_block_infos: &impl DatabaseRo<BlockInfos>,
|
||||
table_tx_blobs: &impl DatabaseRo<TxBlobs>,
|
||||
) -> DbResult<OutputOnChain> {
|
||||
let commitment = compute_zero_commitment(amount);
|
||||
|
||||
|
@ -173,7 +177,13 @@ pub fn output_to_output_on_chain(
|
|||
let txid = {
|
||||
let height = u32_to_usize(output.height);
|
||||
let tx_idx = u64_to_usize(output.tx_idx);
|
||||
table_block_txs_hashes.get(&height)?[tx_idx]
|
||||
if let Some(hash) = table_block_txs_hashes.get(&height)?.get(tx_idx) {
|
||||
*hash
|
||||
} else {
|
||||
let miner_tx_id = table_block_infos.get(&height)?.mining_tx_index;
|
||||
let tx_blob = table_tx_blobs.get(&miner_tx_id)?;
|
||||
Transaction::read(&mut tx_blob.0.as_slice())?.hash()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(OutputOnChain {
|
||||
|
@ -198,6 +208,8 @@ pub fn rct_output_to_output_on_chain(
|
|||
rct_output: &RctOutput,
|
||||
table_tx_unlock_time: &impl DatabaseRo<TxUnlockTime>,
|
||||
table_block_txs_hashes: &impl DatabaseRo<BlockTxsHashes>,
|
||||
table_block_infos: &impl DatabaseRo<BlockInfos>,
|
||||
table_tx_blobs: &impl DatabaseRo<TxBlobs>,
|
||||
) -> DbResult<OutputOnChain> {
|
||||
// INVARIANT: Commitments stored are valid when stored by the database.
|
||||
let commitment = CompressedEdwardsY::from_slice(&rct_output.commitment)
|
||||
|
@ -221,7 +233,13 @@ pub fn rct_output_to_output_on_chain(
|
|||
let txid = {
|
||||
let height = u32_to_usize(rct_output.height);
|
||||
let tx_idx = u64_to_usize(rct_output.tx_idx);
|
||||
table_block_txs_hashes.get(&height)?[tx_idx]
|
||||
if let Some(hash) = table_block_txs_hashes.get(&height)?.get(tx_idx) {
|
||||
*hash
|
||||
} else {
|
||||
let miner_tx_id = table_block_infos.get(&height)?.mining_tx_index;
|
||||
let tx_blob = table_tx_blobs.get(&miner_tx_id)?;
|
||||
Transaction::read(&mut tx_blob.0.as_slice())?.hash()
|
||||
}
|
||||
};
|
||||
|
||||
Ok(OutputOnChain {
|
||||
|
@ -245,6 +263,8 @@ pub fn id_to_output_on_chain(id: &PreRctOutputId, tables: &impl Tables) -> DbRes
|
|||
&rct_output,
|
||||
tables.tx_unlock_time(),
|
||||
tables.block_txs_hashes(),
|
||||
tables.block_infos(),
|
||||
tables.tx_blobs(),
|
||||
)?;
|
||||
|
||||
Ok(output_on_chain)
|
||||
|
@ -256,6 +276,8 @@ pub fn id_to_output_on_chain(id: &PreRctOutputId, tables: &impl Tables) -> DbRes
|
|||
id.amount,
|
||||
tables.tx_unlock_time(),
|
||||
tables.block_txs_hashes(),
|
||||
tables.block_infos(),
|
||||
tables.tx_blobs(),
|
||||
)?;
|
||||
|
||||
Ok(output_on_chain)
|
||||
|
|
|
@ -1,7 +1,2 @@
|
|||
# `cuprate-hex`
|
||||
Cuprate's hexadecimal data types.
|
||||
|
||||
# Features flags
|
||||
| Feature flag | Does what |
|
||||
|--------------|-----------|
|
||||
| `serde` | Enables `serde` on types where applicable
|
|
@ -2,6 +2,8 @@
|
|||
// Allow some lints when running in debug mode.
|
||||
#![cfg_attr(debug_assertions, allow(clippy::todo, clippy::multiple_crate_versions))]
|
||||
|
||||
mod hex;
|
||||
mod array;
|
||||
mod vec;
|
||||
|
||||
pub use hex::Hex;
|
||||
pub use array::Hex;
|
||||
pub use vec::HexVec;
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
|
131
types/hex/src/vec.rs
Normal file
131
types/hex/src/vec.rs
Normal file
|
@ -0,0 +1,131 @@
|
|||
//! Hexadecimal serde wrappers for [`Vec<u8>`].
|
||||
//!
|
||||
//! This module provides transparent wrapper types for
|
||||
//! arrays that (de)serialize from hexadecimal input/output.
|
||||
|
||||
use hex::FromHexError;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
|
||||
/// Wrapper type for a byte [`Vec`] that (de)serializes from/to hexadecimal strings.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cuprate_hex::HexVec;
|
||||
/// let hash = [1; 32];
|
||||
/// let hex_vec = HexVec::from(hash);
|
||||
/// let expected_json = r#""0101010101010101010101010101010101010101010101010101010101010101""#;
|
||||
///
|
||||
/// let to_string = serde_json::to_string(&hex_vec).unwrap();
|
||||
/// assert_eq!(to_string, expected_json);
|
||||
///
|
||||
/// let from_str = serde_json::from_str::<HexVec>(expected_json).unwrap();
|
||||
/// assert_eq!(hex_vec, from_str);
|
||||
///
|
||||
/// //------
|
||||
///
|
||||
/// let vec = vec![hex_vec; 2];
|
||||
/// let expected_json = r#"["0101010101010101010101010101010101010101010101010101010101010101","0101010101010101010101010101010101010101010101010101010101010101"]"#;
|
||||
///
|
||||
/// let to_string = serde_json::to_string(&vec).unwrap();
|
||||
/// assert_eq!(to_string, expected_json);
|
||||
///
|
||||
/// let from_str = serde_json::from_str::<Vec<HexVec>>(expected_json).unwrap();
|
||||
/// assert_eq!(vec, from_str);
|
||||
/// ```
|
||||
#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
|
||||
#[serde(transparent)]
|
||||
#[repr(transparent)]
|
||||
pub struct HexVec(#[serde(with = "hex::serde")] pub Vec<u8>);
|
||||
|
||||
impl HexVec {
|
||||
/// [`Vec::new`].
|
||||
pub const fn new() -> Self {
|
||||
Self(Vec::new())
|
||||
}
|
||||
|
||||
/// [`Vec::is_empty`].
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.0.is_empty()
|
||||
}
|
||||
|
||||
/// Returns an empty [`Self`] if `array` is all `0`s.
|
||||
///
|
||||
/// ```rust
|
||||
/// # use cuprate_hex::HexVec;
|
||||
/// assert_eq!(HexVec::empty_if_zeroed([1; 32]).0, [1; 32]);
|
||||
/// assert_eq!(HexVec::empty_if_zeroed([0; 32]), HexVec(vec![]));
|
||||
/// assert!(HexVec::empty_if_zeroed([0; 32]).is_empty());
|
||||
/// ```
|
||||
pub fn empty_if_zeroed<const N: usize>(array: [u8; N]) -> Self {
|
||||
if array == [0; N] {
|
||||
Self(Vec::new())
|
||||
} else {
|
||||
Self(array.to_vec())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for HexVec {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(Self(hex::serde::deserialize(deserializer)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HexVec> for Vec<u8> {
|
||||
fn from(hex: HexVec) -> Self {
|
||||
hex.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for HexVec {
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> From<[u8; N]> for HexVec {
|
||||
fn from(value: [u8; N]) -> Self {
|
||||
Self(value.to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for HexVec {
|
||||
type Error = FromHexError;
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
hex::decode(value).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for HexVec {
|
||||
type Error = FromHexError;
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
hex::decode(value).map(Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const N: usize> TryFrom<HexVec> for [u8; N] {
|
||||
type Error = FromHexError;
|
||||
fn try_from(value: HexVec) -> Result<Self, Self::Error> {
|
||||
Self::try_from(value.0).map_err(|_| FromHexError::InvalidStringLength)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn asdf() {
|
||||
let hash = vec![0; 32];
|
||||
let hex_vec = HexVec(hash);
|
||||
let expected_json = r#""0000000000000000000000000000000000000000000000000000000000000000""#;
|
||||
|
||||
let to_string = serde_json::to_string(&hex_vec).unwrap();
|
||||
assert_eq!(to_string, expected_json);
|
||||
|
||||
let from_str = serde_json::from_str::<HexVec>(expected_json).unwrap();
|
||||
assert_eq!(hex_vec, from_str);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue