This commit is contained in:
hinto.janai 2024-12-19 17:22:35 -05:00
parent ed8de29504
commit cb6fdb76e4
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
11 changed files with 245 additions and 103 deletions

View file

@ -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::{
@ -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,
})
}
@ -244,8 +247,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 +274,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 +320,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,14 +419,14 @@ 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 json = {
@ -1024,8 +1018,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!();
@ -1222,10 +1215,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 +1246,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();

View file

@ -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.

View file

@ -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);

View file

@ -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)
},
}
}
}

View file

@ -6,7 +6,7 @@
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use cuprate_hex::Hex;
use cuprate_hex::{Hex, HexVec};
use cuprate_types::rpc::{AuxPow, GetMinerDataTxBacklogEntry, HardForkEntry, TxBacklogEntry};
use crate::{
@ -79,7 +79,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 +116,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 +180,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 +198,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 +291,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.
@ -662,7 +665,7 @@ define_request_and_response! {
Request {
major_version: u8,
height: u64,
block_blob: String,
block_blob: HexVec,
seed_hash: Hex<32>,
},
@ -697,13 +700,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 +725,7 @@ define_request_and_response! {
num_matching_bits: u32,
},
ResponseBase {
txids: Vec<String>,
txids: Vec<Hex<32>>,
}
}
@ -959,7 +962,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 +971,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 +1022,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 +1030,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 +1077,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 +1132,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 +1183,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 +1236,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 +1266,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 +1286,7 @@ mod test {
json::GET_BLOCK_REQUEST,
GetBlockRequest {
height: 2751506,
hash: String::new(),
hash: HexVec::new(),
fill_pow_hash: false,
},
);
@ -1293,7 +1296,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 +1314,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,
@ -1904,7 +1907,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 +1948,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 +1964,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,
});

View file

@ -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,

View file

@ -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

View file

@ -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;

124
types/hex/src/vec.rs Normal file
View file

@ -0,0 +1,124 @@
//! 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_bytes = HexVec(hash);
/// let expected_json = r#""0101010101010101010101010101010101010101010101010101010101010101""#;
///
/// let to_string = serde_json::to_string(&hex_bytes).unwrap();
/// assert_eq!(to_string, expected_json);
///
/// let from_str = serde_json::from_str::<HexVec>(expected_json).unwrap();
/// assert_eq!(hex_bytes, from_str);
///
/// //------
///
/// let vec = vec![hex_bytes; 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()
}
/// TODO
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_bytes = HexVec(hash);
let expected_json = r#""0000000000000000000000000000000000000000000000000000000000000000""#;
let to_string = serde_json::to_string(&hex_bytes).unwrap();
assert_eq!(to_string, expected_json);
let from_str = serde_json::from_str::<HexVec>(expected_json).unwrap();
assert_eq!(hex_bytes, from_str);
}
}