1#![allow(
4 const_item_mutation, clippy::missing_panics_doc, )]
7
8use std::sync::LazyLock;
10
11use hex_literal::hex;
12use monero_oxide::{block::Block, transaction::Transaction};
13
14use cuprate_helper::{map::combine_low_high_bits_to_u128, tx::tx_fee};
15use cuprate_types::{VerifiedBlockInformation, VerifiedTransactionInformation};
16
17use crate::data::constants::{
18 BLOCK_43BD1F, BLOCK_5ECB7E, BLOCK_F91043, TX_2180A8, TX_3BC7FF, TX_84D48D, TX_9E3F73,
19 TX_B6B439, TX_D7FEBD, TX_E2D393, TX_E57440,
20};
21
22struct VerifiedBlockMap {
32 block_blob: &'static [u8],
33 pow_hash: [u8; 32],
34 height: usize,
35 generated_coins: u64,
36 weight: usize,
37 long_term_weight: usize,
38 cumulative_difficulty_low: u64,
39 cumulative_difficulty_high: u64,
40 txs: &'static [&'static [u8]],
43}
44
45impl VerifiedBlockMap {
46 fn into_verified(self) -> VerifiedBlockInformation {
52 let Self {
53 block_blob,
54 pow_hash,
55 height,
56 generated_coins,
57 weight,
58 long_term_weight,
59 cumulative_difficulty_low,
60 cumulative_difficulty_high,
61 txs,
62 } = self;
63
64 let block_blob = block_blob.to_vec();
65 let block = Block::read(&mut block_blob.as_slice()).unwrap();
66
67 let txs = txs.iter().map(to_tx_verification_data).collect::<Vec<_>>();
68
69 assert_eq!(
70 txs.len(),
71 block.transactions.len(),
72 "(deserialized txs).len() != (txs hashes in block).len()"
73 );
74
75 for (tx, tx_hash_in_block) in txs.iter().zip(&block.transactions) {
76 assert_eq!(
77 &tx.tx_hash, tx_hash_in_block,
78 "deserialized tx hash is not the same as the one in the parent block"
79 );
80 }
81
82 VerifiedBlockInformation {
83 block_hash: block.hash(),
84 block_blob,
85 block,
86 txs,
87 pow_hash,
88 height,
89 generated_coins,
90 weight,
91 long_term_weight,
92 cumulative_difficulty: combine_low_high_bits_to_u128(
93 cumulative_difficulty_low,
94 cumulative_difficulty_high,
95 ),
96 }
97 }
98}
99
100fn to_tx_verification_data(tx_blob: impl AsRef<[u8]>) -> VerifiedTransactionInformation {
102 let tx = Transaction::read(&mut tx_blob.as_ref()).unwrap();
103 let tx_weight = tx.weight();
104 let fee = tx_fee(&tx);
105 let tx_hash = tx.hash();
106
107 let (tx, tx_prunable_blob) = tx.pruned_with_prunable();
108 VerifiedTransactionInformation {
109 tx_weight,
110 fee,
111 tx_hash,
112 tx_prunable_blob,
113 tx_pruned: tx.serialize(),
114 tx,
115 }
116}
117
118macro_rules! verified_block_information {
131 (
132 name: $name:ident, block_blob: $block_blob:ident, tx_blobs: [$($tx_blob:ident),*], pow_hash: $pow_hash:literal, height: $height:literal, generated_coins: $generated_coins:literal, weight: $weight:literal, long_term_weight: $long_term_weight:literal, cumulative_difficulty_low: $cumulative_difficulty_low:literal, cumulative_difficulty_high: $cumulative_difficulty_high:literal, tx_len: $tx_len:literal, ) => {
144 #[doc = concat!(
145 "Return [`",
146 stringify!($block_blob),
147 "`] as a [`VerifiedBlockInformation`].",
148 )]
149 $(
152 #[doc = concat!("- [`", stringify!($tx_blob), "`]")]
153 )*
154 #[doc = "# use cuprate_test_utils::data::*;"]
157 #[doc = "# use hex_literal::hex;"]
158 #[doc = "use cuprate_helper::map::combine_low_high_bits_to_u128;"]
159 #[doc = ""]
160 #[doc = concat!("let block = &*", stringify!($name), ";")]
161 #[doc = concat!("assert_eq!(&block.block.serialize(), ", stringify!($block_blob), ");")]
162 #[doc = concat!("assert_eq!(block.pow_hash, hex!(\"", $pow_hash, "\"));")]
163 #[doc = concat!("assert_eq!(block.height, ", $height, ");")]
164 #[doc = concat!("assert_eq!(block.generated_coins, ", $generated_coins, ");")]
165 #[doc = concat!("assert_eq!(block.weight, ", $weight, ");")]
166 #[doc = concat!("assert_eq!(block.long_term_weight, ", $long_term_weight, ");")]
167 #[doc = concat!("assert_eq!(block.txs.len(), ", $tx_len, ");")]
168 #[doc = ""]
169 #[doc = concat!(
170 "assert_eq!(block.cumulative_difficulty, ",
171 "combine_low_high_bits_to_u128(",
172 stringify!($cumulative_difficulty_low),
173 ", ",
174 stringify!($cumulative_difficulty_high),
175 "));"
176 )]
177 pub static $name: LazyLock<VerifiedBlockInformation> = LazyLock::new(|| {
179 VerifiedBlockMap {
180 block_blob: $block_blob,
181 pow_hash: hex!($pow_hash),
182 height: $height,
183 generated_coins: $generated_coins,
184 weight: $weight,
185 long_term_weight: $long_term_weight,
186 cumulative_difficulty_low: $cumulative_difficulty_low,
187 cumulative_difficulty_high: $cumulative_difficulty_high,
188 txs: &[$($tx_blob),*],
189 }
190 .into_verified()
191 });
192 };
193}
194
195verified_block_information! {
196 name: BLOCK_V1_TX2,
197 block_blob: BLOCK_5ECB7E,
198 tx_blobs: [TX_2180A8, TX_D7FEBD],
199 pow_hash: "c960d540000459480560b7816de968c7470083e5874e10040bdd4cc501000000",
200 height: 202_609,
201 generated_coins: 14_535_350_982_449,
202 weight: 21_905,
203 long_term_weight: 21_905,
204 cumulative_difficulty_low: 126_650_740_038_710,
205 cumulative_difficulty_high: 0,
206 tx_len: 2,
207}
208
209verified_block_information! {
210 name: BLOCK_V9_TX3,
211 block_blob: BLOCK_F91043,
212 tx_blobs: [TX_E2D393, TX_E57440, TX_B6B439],
213 pow_hash: "7c78b5b67a112a66ea69ea51477492057dba9cfeaa2942ee7372c61800000000",
214 height: 1_731_606,
215 generated_coins: 3_403_774_022_163,
216 weight: 6_597,
217 long_term_weight: 6_597,
218 cumulative_difficulty_low: 23_558_910_234_058_343,
219 cumulative_difficulty_high: 0,
220 tx_len: 3,
221}
222
223verified_block_information! {
224 name: BLOCK_V16_TX0,
225 block_blob: BLOCK_43BD1F,
226 tx_blobs: [],
227 pow_hash: "10b473b5d097d6bfa0656616951840724dfe38c6fb9c4adf8158800300000000",
228 height: 2_751_506,
229 generated_coins: 600_000_000_000,
230 weight: 106,
231 long_term_weight: 176_470,
232 cumulative_difficulty_low: 236_046_001_376_524_168,
233 cumulative_difficulty_high: 0,
234 tx_len: 0,
235}
236
237macro_rules! transaction_verification_data {
242 (
243 name: $name:ident, tx_blobs: $tx_blob:ident, weight: $weight:literal, hash: $hash:literal, ) => {
248 #[doc = concat!("Return [`", stringify!($tx_blob), "`] as a [`VerifiedTransactionInformation`].")]
249 #[doc = "# use cuprate_test_utils::data::*;"]
252 #[doc = "# use hex_literal::hex;"]
253 #[doc = concat!("let tx = &*", stringify!($name), ";")]
254 #[doc = concat!("assert_eq!([tx.tx_pruned.as_slice(), tx.tx_prunable_blob.as_slice()].concat(), ", stringify!($tx_blob), ");")]
255 #[doc = concat!("assert_eq!(tx.tx_weight, ", $weight, ");")]
256 #[doc = concat!("assert_eq!(tx.tx_hash, hex!(\"", $hash, "\"));")]
257 pub static $name: LazyLock<VerifiedTransactionInformation> = LazyLock::new(|| {
259 to_tx_verification_data($tx_blob)
260 });
261 };
262}
263
264transaction_verification_data! {
265 name: TX_V1_SIG0,
266 tx_blobs: TX_3BC7FF,
267 weight: 248,
268 hash: "3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1",
269}
270
271transaction_verification_data! {
272 name: TX_V1_SIG2,
273 tx_blobs: TX_9E3F73,
274 weight: 448,
275 hash: "9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34",
276}
277
278transaction_verification_data! {
279 name: TX_V2_RCT3,
280 tx_blobs: TX_84D48D,
281 weight: 2743,
282 hash: "84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66",
283}
284
285#[cfg(test)]
287mod tests {
288 use pretty_assertions::assert_eq;
289
290 use crate::rpc::client::HttpRpcClient;
291
292 use super::*;
293
294 #[ignore] #[tokio::test]
297 async fn block_same_as_rpc() {
298 let rpc = HttpRpcClient::new(None).await;
299 for block in [&*BLOCK_V1_TX2, &*BLOCK_V9_TX3, &*BLOCK_V16_TX0] {
300 println!("block_height: {}", block.height);
301 let block_rpc = rpc.get_verified_block_information(block.height).await;
302 assert_eq!(block, &block_rpc);
303 }
304 }
305
306 #[ignore] #[tokio::test]
310 async fn tx_same_as_rpc() {
311 let rpc = HttpRpcClient::new(None).await;
312
313 let mut txs = [&*BLOCK_V1_TX2, &*BLOCK_V9_TX3, &*BLOCK_V16_TX0]
314 .into_iter()
315 .flat_map(|block| block.txs.iter().cloned())
316 .collect::<Vec<VerifiedTransactionInformation>>();
317
318 txs.extend([TX_V1_SIG0.clone(), TX_V1_SIG2.clone(), TX_V2_RCT3.clone()]);
319
320 for tx in txs {
321 println!("tx_hash: {:?}", tx.tx_hash);
322 let tx_rpc = rpc
323 .get_transaction_verification_data(&[tx.tx_hash])
324 .await
325 .collect::<Vec<VerifiedTransactionInformation>>()
326 .pop()
327 .unwrap();
328 assert_eq!(tx, tx_rpc);
329 }
330 }
331}