1use crate::{block::Block, header::Header, subnets::SUBNETWORK_ID_COINBASE, tx::Transaction};
2use kaspa_hashes::{Hash, ZERO_HASH};
3use kaspa_muhash::EMPTY_MUHASH;
4
5#[derive(Clone, Debug)]
7pub struct GenesisBlock {
8 pub hash: Hash,
9 pub version: u16,
10 pub hash_merkle_root: Hash,
11 pub utxo_commitment: Hash,
12 pub timestamp: u64,
13 pub bits: u32,
14 pub nonce: u64,
15 pub daa_score: u64,
16 pub coinbase_payload: &'static [u8],
17}
18
19impl GenesisBlock {
20 pub fn build_genesis_transactions(&self) -> Vec<Transaction> {
21 vec![Transaction::new(0, Vec::new(), Vec::new(), 0, SUBNETWORK_ID_COINBASE, 0, self.coinbase_payload.to_vec())]
22 }
23}
24
25impl From<&GenesisBlock> for Header {
26 fn from(genesis: &GenesisBlock) -> Self {
27 Header::new_finalized(
28 genesis.version,
29 Vec::new(),
30 genesis.hash_merkle_root,
31 ZERO_HASH,
32 genesis.utxo_commitment,
33 genesis.timestamp,
34 genesis.bits,
35 genesis.nonce,
36 genesis.daa_score,
37 0.into(),
38 0,
39 ZERO_HASH,
40 )
41 }
42}
43
44impl From<&GenesisBlock> for Block {
45 fn from(genesis: &GenesisBlock) -> Self {
46 Block::new(genesis.into(), genesis.build_genesis_transactions())
47 }
48}
49
50impl From<(&Header, &'static [u8])> for GenesisBlock {
51 fn from((header, payload): (&Header, &'static [u8])) -> Self {
52 Self {
53 hash: header.hash,
54 version: header.version,
55 hash_merkle_root: header.hash_merkle_root,
56 utxo_commitment: header.utxo_commitment,
57 timestamp: header.timestamp,
58 bits: header.bits,
59 nonce: header.nonce,
60 daa_score: header.daa_score,
61 coinbase_payload: payload,
62 }
63 }
64}
65
66pub const GENESIS: GenesisBlock = GenesisBlock {
68 hash: Hash::from_bytes([
69 0x58, 0xc2, 0xd4, 0x19, 0x9e, 0x21, 0xf9, 0x10, 0xd1, 0x57, 0x1d, 0x11, 0x49, 0x69, 0xce, 0xce, 0xf4, 0x8f, 0x9, 0xf9, 0x34,
70 0xd4, 0x2c, 0xcb, 0x6a, 0x28, 0x1a, 0x15, 0x86, 0x8f, 0x29, 0x99,
71 ]),
72 version: 0,
73 hash_merkle_root: Hash::from_bytes([
74 0x8e, 0xc8, 0x98, 0x56, 0x8c, 0x68, 0x1, 0xd1, 0x3d, 0xf4, 0xee, 0x6e, 0x2a, 0x1b, 0x54, 0xb7, 0xe6, 0x23, 0x6f, 0x67, 0x1f,
75 0x20, 0x95, 0x4f, 0x5, 0x30, 0x64, 0x10, 0x51, 0x8e, 0xeb, 0x32,
76 ]),
77 utxo_commitment: Hash::from_bytes([
78 0x71, 0x0f, 0x27, 0xdf, 0x42, 0x3e, 0x63, 0xaa, 0x6c, 0xdb, 0x72, 0xb8, 0x9e, 0xa5, 0xa0, 0x6c, 0xff, 0xa3, 0x99, 0xd6, 0x6f,
79 0x16, 0x77, 0x04, 0x45, 0x5b, 0x5a, 0xf5, 0x9d, 0xef, 0x8e, 0x20,
80 ]),
81 timestamp: 1637609671037,
82 bits: 486722099,
83 nonce: 0x3392c,
84 daa_score: 1312860, #[rustfmt::skip]
86 coinbase_payload: &[
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xd7, 0x95, 0xd7, 0x9e, 0xd7, 0x94, 0x20, 0xd7, 0x93, 0xd7, 0x99, 0x20, 0xd7, 0xa2, 0xd7, 0x9c,
94 0xd7, 0x99, 0xd7, 0x9a, 0x20, 0xd7, 0x95, 0xd7,
95 0xa2, 0xd7, 0x9c, 0x20, 0xd7, 0x90, 0xd7, 0x97,
96 0xd7, 0x99, 0xd7, 0x9a, 0x20, 0xd7, 0x99, 0xd7,
97 0x99, 0xd7, 0x98, 0xd7, 0x91, 0x20, 0xd7, 0x91,
98 0xd7, 0xa9, 0xd7, 0x90, 0xd7, 0xa8, 0x20, 0xd7,
99 0x9b, 0xd7, 0xa1, 0xd7, 0xa4, 0xd7, 0x90, 0x20,
100 0xd7, 0x95, 0xd7, 0x93, 0xd7, 0x94, 0xd7, 0x91,
101 0xd7, 0x94, 0x20, 0xd7, 0x9c, 0xd7, 0x9e, 0xd7,
102 0xa2, 0xd7, 0x91, 0xd7, 0x93, 0x20, 0xd7, 0x9b,
103 0xd7, 0xa8, 0xd7, 0xa2, 0xd7, 0x95, 0xd7, 0xaa,
104 0x20, 0xd7, 0x90, 0xd7, 0x9c, 0xd7, 0x94, 0xd7,
105 0x9b, 0xd7, 0x9d, 0x20, 0xd7, 0xaa, 0xd7, 0xa2,
106 0xd7, 0x91, 0xd7, 0x93, 0xd7, 0x95, 0xd7, 0x9f,
107 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x1f, 0x8e, 0x1c, 0x17, 0xb0, 0x13,
109 0x3d, 0x43, 0x91, 0x74, 0xe5, 0x2e, 0xfb, 0xb0,
110 0xc4, 0x1c, 0x35, 0x83, 0xa8, 0xaa, 0x66, 0xb0,
111 0x0f, 0xca, 0x37, 0xca, 0x66, 0x7c, 0x2d, 0x55, 0x0a, 0x6c, 0x44, 0x16, 0xda, 0xd9, 0x71, 0x7e,
113 0x50, 0x92, 0x71, 0x28, 0xc4, 0x24, 0xfa, 0x4e,
114 0xdb, 0xeb, 0xc4, 0x36, 0xab, 0x13, 0xae, 0xef,
115 ],
116};
117
118pub const TESTNET_GENESIS: GenesisBlock = GenesisBlock {
119 hash: Hash::from_bytes([
120 0xf8, 0x96, 0xa3, 0x03, 0x48, 0x73, 0xbe, 0x17, 0x39, 0xfc, 0x43, 0x59, 0x23, 0x68, 0x99, 0xfd, 0x3d, 0x65, 0xd2, 0xbc, 0x94,
121 0xf9, 0x78, 0x0d, 0xf0, 0xd0, 0xda, 0x3e, 0xb1, 0xcc, 0x43, 0x70,
122 ]),
123 version: 0,
124 hash_merkle_root: Hash::from_bytes([
125 0x17, 0x34, 0x14, 0x08, 0xa5, 0x72, 0x45, 0x56, 0x50, 0x4d, 0xf4, 0xd6, 0xcf, 0x51, 0x5c, 0xbf, 0xbb, 0x22, 0x04, 0x30, 0xdc,
126 0x45, 0x1c, 0x74, 0x3c, 0x22, 0xd5, 0xe9, 0x11, 0x72, 0x0c, 0x2a,
127 ]),
128 utxo_commitment: EMPTY_MUHASH,
129 timestamp: 0x17c5f62fbb6,
130 bits: 0x1e7fffff,
131 nonce: 0x14582,
132 daa_score: 0,
133 #[rustfmt::skip]
134 coinbase_payload: &[
135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x6e, 0x65, 0x74, ],
142};
143
144pub const TESTNET11_GENESIS: GenesisBlock = GenesisBlock {
145 hash: Hash::from_bytes([
146 0xcf, 0xa2, 0xa7, 0xeb, 0xfb, 0x8b, 0x4e, 0xa3, 0x45, 0x30, 0x7b, 0xc2, 0x5e, 0xf9, 0x42, 0x1b, 0x23, 0x91, 0xf0, 0x9c, 0x8b,
147 0x2c, 0xf2, 0x15, 0xf0, 0x75, 0x60, 0xaf, 0x0d, 0x4d, 0x71, 0x64,
148 ]),
149 hash_merkle_root: Hash::from_bytes([
150 0x3c, 0x35, 0xdb, 0x98, 0x02, 0x7e, 0x84, 0x6e, 0x02, 0xcc, 0x60, 0xb7, 0xa7, 0xfa, 0xb1, 0x6d, 0x6c, 0xf2, 0xa5, 0x42, 0xd8,
151 0xe1, 0x60, 0xad, 0x9c, 0xd9, 0x08, 0x5f, 0x51, 0x0c, 0x47, 0xbb,
152 ]),
153 bits: 504155340, #[rustfmt::skip]
155 coinbase_payload: &[
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x6e, 0x65, 0x74, 11, 4 ],
164 ..TESTNET_GENESIS
165};
166
167pub const SIMNET_GENESIS: GenesisBlock = GenesisBlock {
168 hash: Hash::from_bytes([
169 0x41, 0x1f, 0x8c, 0xd2, 0x6f, 0x3d, 0x41, 0xae, 0xa3, 0x9e, 0x78, 0x57, 0x39, 0x27, 0xda, 0x24, 0xd2, 0x39, 0x95, 0x70, 0x5b,
170 0x57, 0x9f, 0x30, 0x95, 0x9b, 0x91, 0x27, 0xe9, 0x6b, 0x79, 0xe3,
171 ]),
172 version: 0,
173 hash_merkle_root: Hash::from_bytes([
174 0x19, 0x46, 0xd6, 0x29, 0xf7, 0xe9, 0x22, 0xa7, 0xbc, 0xed, 0x59, 0x19, 0x05, 0x21, 0xc3, 0x77, 0x1f, 0x73, 0xd3, 0x52, 0xdd,
175 0xbb, 0xb6, 0x86, 0x56, 0x4a, 0xd7, 0xfd, 0x56, 0x85, 0x7c, 0x1b,
176 ]),
177 utxo_commitment: EMPTY_MUHASH,
178 timestamp: 0x17c5f62fbb6,
179 bits: 0x207fffff,
180 nonce: 0x2,
181 daa_score: 0,
182 #[rustfmt::skip]
183 coinbase_payload: &[
184 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x2d, 0x73, 0x69, 0x6d, 0x6e, 0x65, 0x74, ],
191};
192
193pub const DEVNET_GENESIS: GenesisBlock = GenesisBlock {
194 hash: Hash::from_bytes([
195 0x4c, 0xb4, 0x8d, 0x0b, 0x20, 0x73, 0xb8, 0x02, 0x36, 0x01, 0x45, 0xa1, 0x5a, 0xd1, 0xab, 0xdc, 0x01, 0xd8, 0x9b, 0x5c, 0x2f,
201 0xe4, 0x72, 0x26, 0x30, 0xab, 0x9b, 0x5f, 0xe9, 0xdf, 0xc4, 0xf2,
202 ]),
203 version: 0,
204 hash_merkle_root: Hash::from_bytes([
205 0x58, 0xab, 0xf2, 0x03, 0x21, 0xd7, 0x07, 0x16, 0x16, 0x2b, 0x6b, 0xf8, 0xd9, 0xf5, 0x89, 0xca, 0x33, 0xae, 0x6e, 0x32, 0xb3,
206 0xb1, 0x9a, 0xbb, 0x7f, 0xa6, 0x5d, 0x11, 0x41, 0xa3, 0xf9, 0x4d,
207 ]),
208 utxo_commitment: EMPTY_MUHASH,
209 timestamp: 0x11e9db49828,
210 bits: 0x1e21bc1c, nonce: 0x48e5e,
213 daa_score: 0,
214 #[rustfmt::skip]
215 coinbase_payload: &[
216 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF5, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x6b, 0x61, 0x73, 0x70, 0x61, 0x2d, 0x64, 0x65, 0x76, 0x6e, 0x65, 0x74, ],
223};
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228 use crate::{config::bps::Testnet11Bps, merkle::calc_hash_merkle_root};
229
230 #[test]
231 fn test_genesis_hashes() {
232 [GENESIS, TESTNET_GENESIS, TESTNET11_GENESIS, SIMNET_GENESIS, DEVNET_GENESIS].into_iter().for_each(|genesis| {
233 let block: Block = (&genesis).into();
234 assert_hashes_eq(calc_hash_merkle_root(block.transactions.iter(), false), block.header.hash_merkle_root);
235 assert_hashes_eq(block.hash(), genesis.hash);
236 });
237 }
238
239 #[test]
240 fn gen_testnet11_genesis() {
241 let bps = Testnet11Bps::bps();
242 let mut genesis = TESTNET_GENESIS;
243 let target = kaspa_math::Uint256::from_compact_target_bits(genesis.bits);
244 let scaled_target = target * bps / 100;
245 let scaled_bits = scaled_target.compact_target_bits();
246 genesis.bits = scaled_bits;
247 if genesis.bits != TESTNET11_GENESIS.bits {
248 panic!("Testnet 11: new bits: {}\nnew hash: {:#04x?}", scaled_bits, Block::from(&genesis).hash().as_bytes());
249 }
250 }
251
252 fn assert_hashes_eq(got: Hash, expected: Hash) {
253 if got != expected {
254 panic!("Got hash {:#04x?} while expecting {:#04x?}", got.as_bytes(), expected.as_bytes());
256 }
257 }
258}