1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
//! Network methods for fetching blockchain vectors.
//!

use std::collections::BTreeMap;

use crate::{block::Block, parameters::Network, serialization::ZcashDeserializeInto};

use zebra_test::vectors::{
    BLOCK_MAINNET_1046400_BYTES, BLOCK_MAINNET_653599_BYTES, BLOCK_MAINNET_982681_BYTES,
    BLOCK_TESTNET_1116000_BYTES, BLOCK_TESTNET_583999_BYTES, BLOCK_TESTNET_925483_BYTES,
    CONTINUOUS_MAINNET_BLOCKS, CONTINUOUS_TESTNET_BLOCKS, MAINNET_BLOCKS,
    MAINNET_FINAL_SAPLING_ROOTS, MAINNET_FINAL_SPROUT_ROOTS,
    SAPLING_FINAL_ROOT_MAINNET_1046400_BYTES, SAPLING_FINAL_ROOT_TESTNET_1116000_BYTES,
    TESTNET_BLOCKS, TESTNET_FINAL_SAPLING_ROOTS, TESTNET_FINAL_SPROUT_ROOTS,
};

/// Network methods for fetching blockchain vectors.
impl Network {
    /// Returns true if network is of type Mainnet.
    pub fn is_mainnet(&self) -> bool {
        matches!(self, Network::Mainnet)
    }

    /// Returns iterator over blocks.
    pub fn block_iter(&self) -> std::collections::btree_map::Iter<'static, u32, &'static [u8]> {
        if self.is_mainnet() {
            MAINNET_BLOCKS.iter()
        } else {
            TESTNET_BLOCKS.iter()
        }
    }

    /// Returns blocks indexed by height in a [`BTreeMap`].
    ///
    /// Returns Mainnet blocks if `self` is set to Mainnet, and Testnet blocks otherwise.
    pub fn block_map(&self) -> BTreeMap<u32, &'static [u8]> {
        if self.is_mainnet() {
            zebra_test::vectors::MAINNET_BLOCKS.clone()
        } else {
            zebra_test::vectors::TESTNET_BLOCKS.clone()
        }
    }

    /// Returns genesis block for chain.
    pub fn gen_block(&self) -> std::option::Option<&&[u8]> {
        if self.is_mainnet() {
            MAINNET_BLOCKS.get(&0)
        } else {
            TESTNET_BLOCKS.get(&0)
        }
    }

    /// Returns block bytes
    pub fn test_block(&self, main_height: u32, test_height: u32) -> Option<Block> {
        match (self.is_mainnet(), main_height, test_height) {
            (true, 653_599, _) => BLOCK_MAINNET_653599_BYTES.zcash_deserialize_into().ok(),
            (true, 982_681, _) => BLOCK_MAINNET_982681_BYTES.zcash_deserialize_into().ok(),
            (false, _, 583_999) => BLOCK_TESTNET_583999_BYTES.zcash_deserialize_into().ok(),
            (false, _, 925_483) => BLOCK_TESTNET_925483_BYTES.zcash_deserialize_into().ok(),
            _ => None,
        }
    }

    /// Returns iterator over blockchain.
    pub fn blockchain_iter(&self) -> std::collections::btree_map::Iter<'_, u32, &[u8]> {
        if self.is_mainnet() {
            CONTINUOUS_MAINNET_BLOCKS.iter()
        } else {
            CONTINUOUS_TESTNET_BLOCKS.iter()
        }
    }

    /// Returns BTreemap of blockchain.
    pub fn blockchain_map(&self) -> &BTreeMap<u32, &'static [u8]> {
        if self.is_mainnet() {
            &CONTINUOUS_MAINNET_BLOCKS
        } else {
            &CONTINUOUS_TESTNET_BLOCKS
        }
    }

    /// Returns iterator over blocks and sapling roots.
    pub fn block_sapling_roots_iter(
        &self,
    ) -> (
        std::collections::btree_map::Iter<'_, u32, &[u8]>,
        std::collections::BTreeMap<u32, &[u8; 32]>,
    ) {
        if self.is_mainnet() {
            (MAINNET_BLOCKS.iter(), MAINNET_FINAL_SAPLING_ROOTS.clone())
        } else {
            (TESTNET_BLOCKS.iter(), TESTNET_FINAL_SAPLING_ROOTS.clone())
        }
    }

    /// Returns BTreemap of blocks and sapling roots.
    pub fn block_sapling_roots_map(
        &self,
    ) -> (
        &std::collections::BTreeMap<u32, &'static [u8]>,
        &std::collections::BTreeMap<u32, &'static [u8; 32]>,
    ) {
        if self.is_mainnet() {
            (&*MAINNET_BLOCKS, &*MAINNET_FINAL_SAPLING_ROOTS)
        } else {
            (&*TESTNET_BLOCKS, &*TESTNET_FINAL_SAPLING_ROOTS)
        }
    }

    /// Returns block and sapling root bytes
    pub fn test_block_sapling_roots(
        &self,
        main_height: u32,
        test_height: u32,
    ) -> Option<(&[u8], [u8; 32])> {
        match (self.is_mainnet(), main_height, test_height) {
            (true, 1_046_400, _) => Some((
                &BLOCK_MAINNET_1046400_BYTES[..],
                *SAPLING_FINAL_ROOT_MAINNET_1046400_BYTES,
            )),
            (false, _, 1_116_000) => Some((
                &BLOCK_TESTNET_1116000_BYTES[..],
                *SAPLING_FINAL_ROOT_TESTNET_1116000_BYTES,
            )),
            _ => None,
        }
    }

    /// Returns BTreemap of blocks and sprout roots, and last split height.
    pub fn block_sprout_roots_height(
        &self,
    ) -> (
        &std::collections::BTreeMap<u32, &'static [u8]>,
        &std::collections::BTreeMap<u32, &'static [u8; 32]>,
        u32,
    ) {
        // The mainnet block height at which the first JoinSplit occurred.
        const MAINNET_FIRST_JOINSPLIT_HEIGHT: u32 = 396;

        // The testnet block height at which the first JoinSplit occurred.
        const TESTNET_FIRST_JOINSPLIT_HEIGHT: u32 = 2259;
        if self.is_mainnet() {
            (
                &*MAINNET_BLOCKS,
                &*MAINNET_FINAL_SPROUT_ROOTS,
                MAINNET_FIRST_JOINSPLIT_HEIGHT,
            )
        } else {
            (
                &*TESTNET_BLOCKS,
                &*TESTNET_FINAL_SPROUT_ROOTS,
                TESTNET_FIRST_JOINSPLIT_HEIGHT,
            )
        }
    }
}