1#![allow(
4 const_item_mutation, clippy::missing_panics_doc, )]
7
8use std::sync::LazyLock;
10
11use hex_literal::hex;
12use monero_serai::{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_blob = tx_blob.as_ref().to_vec();
103 let tx = Transaction::read(&mut tx_blob.as_slice()).unwrap();
104 VerifiedTransactionInformation {
105 tx_weight: tx.weight(),
106 fee: tx_fee(&tx),
107 tx_hash: tx.hash(),
108 tx_blob,
109 tx,
110 }
111}
112
113macro_rules! verified_block_information {
126 (
127 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, ) => {
139 #[doc = concat!(
140 "Return [`",
141 stringify!($block_blob),
142 "`] as a [`VerifiedBlockInformation`].",
143 )]
144 $(
147 #[doc = concat!("- [`", stringify!($tx_blob), "`]")]
148 )*
149 #[doc = "# use cuprate_test_utils::data::*;"]
152 #[doc = "# use hex_literal::hex;"]
153 #[doc = "use cuprate_helper::map::combine_low_high_bits_to_u128;"]
154 #[doc = ""]
155 #[doc = concat!("let block = &*", stringify!($name), ";")]
156 #[doc = concat!("assert_eq!(&block.block.serialize(), ", stringify!($block_blob), ");")]
157 #[doc = concat!("assert_eq!(block.pow_hash, hex!(\"", $pow_hash, "\"));")]
158 #[doc = concat!("assert_eq!(block.height, ", $height, ");")]
159 #[doc = concat!("assert_eq!(block.generated_coins, ", $generated_coins, ");")]
160 #[doc = concat!("assert_eq!(block.weight, ", $weight, ");")]
161 #[doc = concat!("assert_eq!(block.long_term_weight, ", $long_term_weight, ");")]
162 #[doc = concat!("assert_eq!(block.txs.len(), ", $tx_len, ");")]
163 #[doc = ""]
164 #[doc = concat!(
165 "assert_eq!(block.cumulative_difficulty, ",
166 "combine_low_high_bits_to_u128(",
167 stringify!($cumulative_difficulty_low),
168 ", ",
169 stringify!($cumulative_difficulty_high),
170 "));"
171 )]
172 pub static $name: LazyLock<VerifiedBlockInformation> = LazyLock::new(|| {
174 VerifiedBlockMap {
175 block_blob: $block_blob,
176 pow_hash: hex!($pow_hash),
177 height: $height,
178 generated_coins: $generated_coins,
179 weight: $weight,
180 long_term_weight: $long_term_weight,
181 cumulative_difficulty_low: $cumulative_difficulty_low,
182 cumulative_difficulty_high: $cumulative_difficulty_high,
183 txs: &[$($tx_blob),*],
184 }
185 .into_verified()
186 });
187 };
188}
189
190verified_block_information! {
191 name: BLOCK_V1_TX2,
192 block_blob: BLOCK_5ECB7E,
193 tx_blobs: [TX_2180A8, TX_D7FEBD],
194 pow_hash: "c960d540000459480560b7816de968c7470083e5874e10040bdd4cc501000000",
195 height: 202_609,
196 generated_coins: 14_535_350_982_449,
197 weight: 21_905,
198 long_term_weight: 21_905,
199 cumulative_difficulty_low: 126_650_740_038_710,
200 cumulative_difficulty_high: 0,
201 tx_len: 2,
202}
203
204verified_block_information! {
205 name: BLOCK_V9_TX3,
206 block_blob: BLOCK_F91043,
207 tx_blobs: [TX_E2D393, TX_E57440, TX_B6B439],
208 pow_hash: "7c78b5b67a112a66ea69ea51477492057dba9cfeaa2942ee7372c61800000000",
209 height: 1_731_606,
210 generated_coins: 3_403_774_022_163,
211 weight: 6_597,
212 long_term_weight: 6_597,
213 cumulative_difficulty_low: 23_558_910_234_058_343,
214 cumulative_difficulty_high: 0,
215 tx_len: 3,
216}
217
218verified_block_information! {
219 name: BLOCK_V16_TX0,
220 block_blob: BLOCK_43BD1F,
221 tx_blobs: [],
222 pow_hash: "10b473b5d097d6bfa0656616951840724dfe38c6fb9c4adf8158800300000000",
223 height: 2_751_506,
224 generated_coins: 600_000_000_000,
225 weight: 106,
226 long_term_weight: 176_470,
227 cumulative_difficulty_low: 236_046_001_376_524_168,
228 cumulative_difficulty_high: 0,
229 tx_len: 0,
230}
231
232macro_rules! transaction_verification_data {
237 (
238 name: $name:ident, tx_blobs: $tx_blob:ident, weight: $weight:literal, hash: $hash:literal, ) => {
243 #[doc = concat!("Return [`", stringify!($tx_blob), "`] as a [`VerifiedTransactionInformation`].")]
244 #[doc = "# use cuprate_test_utils::data::*;"]
247 #[doc = "# use hex_literal::hex;"]
248 #[doc = concat!("let tx = &*", stringify!($name), ";")]
249 #[doc = concat!("assert_eq!(&tx.tx.serialize(), ", stringify!($tx_blob), ");")]
250 #[doc = concat!("assert_eq!(tx.tx_blob, ", stringify!($tx_blob), ");")]
251 #[doc = concat!("assert_eq!(tx.tx_weight, ", $weight, ");")]
252 #[doc = concat!("assert_eq!(tx.tx_hash, hex!(\"", $hash, "\"));")]
253 pub static $name: LazyLock<VerifiedTransactionInformation> = LazyLock::new(|| {
255 to_tx_verification_data($tx_blob)
256 });
257 };
258}
259
260transaction_verification_data! {
261 name: TX_V1_SIG0,
262 tx_blobs: TX_3BC7FF,
263 weight: 248,
264 hash: "3bc7ff015b227e7313cc2e8668bfbb3f3acbee274a9c201d6211cf681b5f6bb1",
265}
266
267transaction_verification_data! {
268 name: TX_V1_SIG2,
269 tx_blobs: TX_9E3F73,
270 weight: 448,
271 hash: "9e3f73e66d7c7293af59c59c1ff5d6aae047289f49e5884c66caaf4aea49fb34",
272}
273
274transaction_verification_data! {
275 name: TX_V2_RCT3,
276 tx_blobs: TX_84D48D,
277 weight: 2743,
278 hash: "84d48dc11ec91950f8b70a85af9db91fe0c8abef71ef5db08304f7344b99ea66",
279}
280
281#[cfg(test)]
283mod tests {
284 use pretty_assertions::assert_eq;
285
286 use crate::rpc::client::HttpRpcClient;
287
288 use super::*;
289
290 #[ignore] #[tokio::test]
293 async fn block_same_as_rpc() {
294 let rpc = HttpRpcClient::new(None).await;
295 for block in [&*BLOCK_V1_TX2, &*BLOCK_V9_TX3, &*BLOCK_V16_TX0] {
296 println!("block_height: {}", block.height);
297 let block_rpc = rpc.get_verified_block_information(block.height).await;
298 assert_eq!(block, &block_rpc);
299 }
300 }
301
302 #[ignore] #[tokio::test]
306 async fn tx_same_as_rpc() {
307 let rpc = HttpRpcClient::new(None).await;
308
309 let mut txs = [&*BLOCK_V1_TX2, &*BLOCK_V9_TX3, &*BLOCK_V16_TX0]
310 .into_iter()
311 .flat_map(|block| block.txs.iter().cloned())
312 .collect::<Vec<VerifiedTransactionInformation>>();
313
314 txs.extend([TX_V1_SIG0.clone(), TX_V1_SIG2.clone(), TX_V2_RCT3.clone()]);
315
316 for tx in txs {
317 println!("tx_hash: {:?}", tx.tx_hash);
318 let tx_rpc = rpc
319 .get_transaction_verification_data(&[tx.tx_hash])
320 .await
321 .collect::<Vec<VerifiedTransactionInformation>>()
322 .pop()
323 .unwrap();
324 assert_eq!(tx, tx_rpc);
325 }
326 }
327}