Skip to main content

blvm_protocol/
genesis.rs

1//! Genesis Blocks
2//!
3//! Provides actual Bitcoin genesis blocks for mainnet, testnet, and regtest networks.
4
5use blvm_consensus::types::*;
6
7/// Create Bitcoin mainnet genesis block
8pub fn mainnet_genesis() -> Block {
9    // Bitcoin mainnet genesis block
10    // Hash: 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
11    // Merkle root must be in Bitcoin internal byte order (reversed from display)
12    Block {
13        header: BlockHeader {
14            version: 1,
15            prev_block_hash: [0u8; 32], // All zeros for genesis
16            merkle_root: [
17                0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76,
18                0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa,
19                0x4b, 0x1e, 0x5e, 0x4a,
20            ],
21            timestamp: 1231006505, // Jan 3, 2009
22            bits: 0x1d00ffff,
23            nonce: 2083236893,
24        },
25        transactions: vec![Transaction {
26            version: 1,
27            inputs: crate::tx_inputs![TransactionInput {
28                prevout: OutPoint {
29                    hash: [0u8; 32],
30                    index: 0xffffffff,
31                },
32                script_sig: vec![
33                    0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54,
34                    0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, 0x2f, 0x32,
35                    0x30, 0x30, 0x39, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f,
36                    0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66,
37                    0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, 0x6f,
38                    0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73,
39                ], // "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
40                sequence: 0xffffffff,
41            }],
42            outputs: crate::tx_outputs![TransactionOutput {
43                value: 50_0000_0000, // 50 BTC in satoshis
44                script_pubkey: vec![
45                    0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1,
46                    0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6,
47                    0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c,
48                    0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, 0x5c, 0x38,
49                    0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
50                    0x5f, 0xac,
51                ],
52            }],
53            lock_time: 0,
54        }]
55        .into_boxed_slice(),
56    }
57}
58
59/// Create Bitcoin testnet genesis block
60pub fn testnet_genesis() -> Block {
61    // Bitcoin testnet genesis block
62    // Hash: 0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943
63    // Same coinbase as mainnet → same merkle root (internal byte order)
64    Block {
65        header: BlockHeader {
66            version: 1,
67            prev_block_hash: [0u8; 32],
68            merkle_root: [
69                0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76,
70                0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa,
71                0x4b, 0x1e, 0x5e, 0x4a,
72            ],
73            timestamp: 1296688602, // Testnet genesis timestamp
74            bits: 0x1d00ffff,
75            nonce: 414098458,
76        },
77        transactions: vec![Transaction {
78            version: 1,
79            inputs: crate::tx_inputs![TransactionInput {
80                prevout: OutPoint {
81                    hash: [0u8; 32],
82                    index: 0xffffffff,
83                },
84                script_sig: vec![
85                    0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54,
86                    0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, 0x2f, 0x32,
87                    0x30, 0x30, 0x39, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f,
88                    0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66,
89                    0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, 0x6f,
90                    0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73,
91                ],
92                sequence: 0xffffffff,
93            }],
94            outputs: crate::tx_outputs![TransactionOutput {
95                value: 50_0000_0000,
96                script_pubkey: vec![
97                    0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1,
98                    0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6,
99                    0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c,
100                    0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, 0x5c, 0x38,
101                    0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
102                    0x5f, 0xac,
103                ],
104            }],
105            lock_time: 0,
106        }]
107        .into_boxed_slice(),
108    }
109}
110
111/// Create Bitcoin regtest genesis block
112pub fn regtest_genesis() -> Block {
113    // Bitcoin regtest genesis block
114    // Hash: 0x0f9188f13cb7b2c28f4514ac48c96e0d99c5cb2f5e33a1748f0baf3323f6e5c0
115    // Same coinbase as mainnet → same merkle root (internal byte order)
116    Block {
117        header: BlockHeader {
118            version: 1,
119            prev_block_hash: [0u8; 32],
120            merkle_root: [
121                0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76,
122                0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa,
123                0x4b, 0x1e, 0x5e, 0x4a,
124            ],
125            timestamp: 1296688602, // Same as testnet for regtest
126            bits: 0x207fffff,      // Easier difficulty
127            nonce: 2,
128        },
129        transactions: vec![Transaction {
130            version: 1,
131            inputs: crate::tx_inputs![TransactionInput {
132                prevout: OutPoint {
133                    hash: [0u8; 32],
134                    index: 0xffffffff,
135                },
136                script_sig: vec![
137                    0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54,
138                    0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, 0x2f, 0x32,
139                    0x30, 0x30, 0x39, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f,
140                    0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66,
141                    0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, 0x6f,
142                    0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73,
143                ],
144                sequence: 0xffffffff,
145            }],
146            outputs: crate::tx_outputs![TransactionOutput {
147                value: 50_0000_0000,
148                script_pubkey: vec![
149                    0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1,
150                    0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6,
151                    0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c,
152                    0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, 0x5c, 0x38,
153                    0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
154                    0x5f, 0xac,
155                ],
156            }],
157            lock_time: 0,
158        }]
159        .into_boxed_slice(),
160    }
161}
162
163/// Create Bitcoin testnet4 genesis block (BIP94).
164///
165/// Hash: `00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043`
166pub fn testnet4_genesis() -> Block {
167    let msg = b"03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e";
168    let mut script_sig = vec![
169        0x04,
170        0xff,
171        0xff,
172        0x00,
173        0x1d,
174        0x01,
175        0x04,
176        0x4c,
177        msg.len() as u8,
178    ];
179    script_sig.extend_from_slice(msg);
180    let mut script_pubkey = vec![0x21];
181    script_pubkey.extend_from_slice(&[0u8; 33]);
182    script_pubkey.push(0xac);
183    let coinbase = Transaction {
184        version: 1,
185        inputs: crate::tx_inputs![TransactionInput {
186            prevout: OutPoint {
187                hash: [0u8; 32],
188                index: 0xffffffff,
189            },
190            script_sig,
191            sequence: 0xffffffff,
192        }],
193        outputs: crate::tx_outputs![TransactionOutput {
194            value: 50_0000_0000,
195            script_pubkey,
196        }],
197        lock_time: 0,
198    };
199    let merkle_root =
200        blvm_consensus::mining::calculate_merkle_root(std::slice::from_ref(&coinbase))
201            .expect("testnet4 genesis merkle root");
202    Block {
203        header: BlockHeader {
204            version: 1,
205            prev_block_hash: [0u8; 32],
206            merkle_root,
207            timestamp: 1_714_777_860,
208            bits: 0x1d00ffff,
209            nonce: 393_743_547,
210        },
211        transactions: vec![coinbase].into_boxed_slice(),
212    }
213}
214
215/// Create Bitcoin signet genesis block (default public signet, BIP325)
216pub fn signet_genesis() -> Block {
217    // Hash: 0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6
218    Block {
219        header: BlockHeader {
220            version: 1,
221            prev_block_hash: [0u8; 32],
222            merkle_root: [
223                0x3b, 0xa3, 0xed, 0xfd, 0x7a, 0x7b, 0x12, 0xb2, 0x7a, 0xc7, 0x2c, 0x3e, 0x67, 0x76,
224                0x8f, 0x61, 0x7f, 0xc8, 0x1b, 0xc3, 0x88, 0x8a, 0x51, 0x32, 0x3a, 0x9f, 0xb8, 0xaa,
225                0x4b, 0x1e, 0x5e, 0x4a,
226            ],
227            timestamp: 1_598_918_400,
228            bits: 0x1e0377ae,
229            nonce: 52_613_770,
230        },
231        transactions: vec![Transaction {
232            version: 1,
233            inputs: crate::tx_inputs![TransactionInput {
234                prevout: OutPoint {
235                    hash: [0u8; 32],
236                    index: 0xffffffff,
237                },
238                script_sig: vec![
239                    0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04, 0x45, 0x54, 0x68, 0x65, 0x20, 0x54,
240                    0x69, 0x6d, 0x65, 0x73, 0x20, 0x30, 0x33, 0x2f, 0x4a, 0x61, 0x6e, 0x2f, 0x32,
241                    0x30, 0x30, 0x39, 0x20, 0x43, 0x68, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x6f,
242                    0x72, 0x20, 0x6f, 0x6e, 0x20, 0x62, 0x72, 0x69, 0x6e, 0x6b, 0x20, 0x6f, 0x66,
243                    0x20, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x20, 0x62, 0x61, 0x69, 0x6c, 0x6f,
244                    0x75, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x62, 0x61, 0x6e, 0x6b, 0x73,
245                ],
246                sequence: 0xffffffff,
247            }],
248            outputs: crate::tx_outputs![TransactionOutput {
249                value: 50_0000_0000,
250                script_pubkey: vec![
251                    0x41, 0x04, 0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27, 0x19, 0x67, 0xf1,
252                    0xa6, 0x71, 0x30, 0xb7, 0x10, 0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6,
253                    0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6, 0x49, 0xf6, 0xbc, 0x3f, 0x4c,
254                    0xef, 0x38, 0xc4, 0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde, 0x5c, 0x38,
255                    0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57, 0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d,
256                    0x5f, 0xac,
257                ],
258            }],
259            lock_time: 0,
260        }]
261        .into_boxed_slice(),
262    }
263}
264
265#[cfg(test)]
266mod tests {
267    use super::*;
268
269    #[test]
270    fn testnet4_genesis_matches_core() {
271        let block = testnet4_genesis();
272        let hash = blvm_consensus::block::block_header_hash(&block.header);
273        let mut display = hash;
274        display.reverse();
275        assert_eq!(
276            hex_encode(&display),
277            "00000000da84f2bafbbc53dee25a72ae507ff4914b867c565be350b0da8bf043"
278        );
279        let mut merkle = block.header.merkle_root;
280        merkle.reverse();
281        assert_eq!(
282            hex_encode(&merkle),
283            "7aa0a7ae1e223414cb807e40cd57e667b718e42aaf9306db9102fe28912b7b4e"
284        );
285    }
286
287    fn hex_encode(bytes: &[u8]) -> String {
288        const HEX: &[u8; 16] = b"0123456789abcdef";
289        let mut out = String::with_capacity(bytes.len() * 2);
290        for b in bytes {
291            out.push(HEX[(b >> 4) as usize] as char);
292            out.push(HEX[(b & 0xf) as usize] as char);
293        }
294        out
295    }
296}