1use std::{collections::BTreeMap, ops::RangeBounds};
5
6use crate::{
7 amount::Amount,
8 block::Block,
9 parameters::Network,
10 serialization::ZcashDeserializeInto,
11 transaction::{UnminedTx, VerifiedUnminedTx},
12};
13
14use zebra_test::vectors::{
15 BLOCK_MAINNET_1046400_BYTES, BLOCK_MAINNET_653599_BYTES, BLOCK_MAINNET_982681_BYTES,
16 BLOCK_TESTNET_1116000_BYTES, BLOCK_TESTNET_583999_BYTES, BLOCK_TESTNET_925483_BYTES,
17 CONTINUOUS_MAINNET_BLOCKS, CONTINUOUS_TESTNET_BLOCKS, MAINNET_BLOCKS,
18 MAINNET_FINAL_ORCHARD_ROOTS, MAINNET_FINAL_SAPLING_ROOTS, MAINNET_FINAL_SPROUT_ROOTS,
19 SAPLING_FINAL_ROOT_MAINNET_1046400_BYTES, SAPLING_FINAL_ROOT_TESTNET_1116000_BYTES,
20 TESTNET_BLOCKS, TESTNET_FINAL_ORCHARD_ROOTS, TESTNET_FINAL_SAPLING_ROOTS,
21 TESTNET_FINAL_SPROUT_ROOTS,
22};
23
24impl Network {
26 pub fn is_mainnet(&self) -> bool {
28 matches!(self, Network::Mainnet)
29 }
30
31 pub fn block_iter(&self) -> std::collections::btree_map::Iter<'static, u32, &'static [u8]> {
33 if self.is_mainnet() {
34 MAINNET_BLOCKS.iter()
35 } else {
36 TESTNET_BLOCKS.iter()
37 }
38 }
39
40 pub fn block_parsed_iter(&self) -> impl Iterator<Item = Block> {
42 self.block_iter().map(|(_, block_bytes)| {
43 block_bytes
44 .zcash_deserialize_into::<Block>()
45 .expect("block is structurally valid")
46 })
47 }
48
49 pub fn unmined_transactions_in_blocks(
51 &self,
52 block_height_range: impl RangeBounds<u32>,
53 ) -> impl DoubleEndedIterator<Item = VerifiedUnminedTx> {
54 let blocks = self.block_iter();
55
56 let selected_blocks = blocks
58 .filter(move |(&height, _)| block_height_range.contains(&height))
59 .map(|(_, block)| {
60 block
61 .zcash_deserialize_into::<Block>()
62 .expect("block test vector is structurally valid")
63 });
64
65 selected_blocks
69 .flat_map(|block| block.transactions)
70 .map(UnminedTx::from)
71 .filter_map(|transaction| {
73 VerifiedUnminedTx::new(
74 transaction,
75 Amount::try_from(1_000_000).expect("valid amount"),
76 0,
77 0,
78 std::sync::Arc::new(vec![]),
79 )
80 .ok()
81 })
82 }
83
84 pub fn block_map(&self) -> BTreeMap<u32, &'static [u8]> {
88 if self.is_mainnet() {
89 zebra_test::vectors::MAINNET_BLOCKS.clone()
90 } else {
91 zebra_test::vectors::TESTNET_BLOCKS.clone()
92 }
93 }
94
95 pub fn gen_block(&self) -> std::option::Option<&&[u8]> {
97 if self.is_mainnet() {
98 MAINNET_BLOCKS.get(&0)
99 } else {
100 TESTNET_BLOCKS.get(&0)
101 }
102 }
103
104 pub fn test_block(&self, main_height: u32, test_height: u32) -> Option<Block> {
106 match (self.is_mainnet(), main_height, test_height) {
107 (true, 653_599, _) => BLOCK_MAINNET_653599_BYTES.zcash_deserialize_into().ok(),
108 (true, 982_681, _) => BLOCK_MAINNET_982681_BYTES.zcash_deserialize_into().ok(),
109 (false, _, 583_999) => BLOCK_TESTNET_583999_BYTES.zcash_deserialize_into().ok(),
110 (false, _, 925_483) => BLOCK_TESTNET_925483_BYTES.zcash_deserialize_into().ok(),
111 _ => None,
112 }
113 }
114
115 pub fn blockchain_iter(&self) -> std::collections::btree_map::Iter<'_, u32, &[u8]> {
117 if self.is_mainnet() {
118 CONTINUOUS_MAINNET_BLOCKS.iter()
119 } else {
120 CONTINUOUS_TESTNET_BLOCKS.iter()
121 }
122 }
123
124 pub fn blockchain_map(&self) -> &BTreeMap<u32, &'static [u8]> {
126 if self.is_mainnet() {
127 &CONTINUOUS_MAINNET_BLOCKS
128 } else {
129 &CONTINUOUS_TESTNET_BLOCKS
130 }
131 }
132
133 pub fn sapling_anchors(&self) -> std::collections::BTreeMap<u32, &[u8; 32]> {
135 if self.is_mainnet() {
136 MAINNET_FINAL_SAPLING_ROOTS.clone()
137 } else {
138 TESTNET_FINAL_SAPLING_ROOTS.clone()
139 }
140 }
141
142 pub fn orchard_anchors(&self) -> std::collections::BTreeMap<u32, &[u8; 32]> {
144 if self.is_mainnet() {
145 MAINNET_FINAL_ORCHARD_ROOTS.clone()
146 } else {
147 TESTNET_FINAL_ORCHARD_ROOTS.clone()
148 }
149 }
150
151 pub fn block_sapling_roots_map(
153 &self,
154 ) -> (
155 &std::collections::BTreeMap<u32, &'static [u8]>,
156 &std::collections::BTreeMap<u32, &'static [u8; 32]>,
157 ) {
158 if self.is_mainnet() {
159 (&*MAINNET_BLOCKS, &*MAINNET_FINAL_SAPLING_ROOTS)
160 } else {
161 (&*TESTNET_BLOCKS, &*TESTNET_FINAL_SAPLING_ROOTS)
162 }
163 }
164
165 pub fn test_block_sapling_roots(
167 &self,
168 main_height: u32,
169 test_height: u32,
170 ) -> Option<(&[u8], [u8; 32])> {
171 match (self.is_mainnet(), main_height, test_height) {
172 (true, 1_046_400, _) => Some((
173 &BLOCK_MAINNET_1046400_BYTES[..],
174 *SAPLING_FINAL_ROOT_MAINNET_1046400_BYTES,
175 )),
176 (false, _, 1_116_000) => Some((
177 &BLOCK_TESTNET_1116000_BYTES[..],
178 *SAPLING_FINAL_ROOT_TESTNET_1116000_BYTES,
179 )),
180 _ => None,
181 }
182 }
183
184 pub fn block_sprout_roots_height(
186 &self,
187 ) -> (
188 &std::collections::BTreeMap<u32, &'static [u8]>,
189 &std::collections::BTreeMap<u32, &'static [u8; 32]>,
190 u32,
191 ) {
192 const MAINNET_FIRST_JOINSPLIT_HEIGHT: u32 = 396;
194
195 const TESTNET_FIRST_JOINSPLIT_HEIGHT: u32 = 2259;
197 if self.is_mainnet() {
198 (
199 &*MAINNET_BLOCKS,
200 &*MAINNET_FINAL_SPROUT_ROOTS,
201 MAINNET_FIRST_JOINSPLIT_HEIGHT,
202 )
203 } else {
204 (
205 &*TESTNET_BLOCKS,
206 &*TESTNET_FINAL_SPROUT_ROOTS,
207 TESTNET_FIRST_JOINSPLIT_HEIGHT,
208 )
209 }
210 }
211}