Skip to content

Commit 4e08c43

Browse files
author
ChallengeDev210
committed
Merge rust-bitcoin/rust-bitcoin#878: Add chain hash type using consts
8e29f2b Add ChainHash type (Tobin Harding) cd8f511 blockdata: constants: Use wildcard import in unit tests (Tobin Harding) 71bf196 Use fully qualified path in macro (Tobin Harding) Pull request description: The Lightning network defines a type called 'chain hash' that is used to uniquely represent the various Bitcoin networks as a 32 byte hash value. Chain hash is now being used by the DLC folks, as such it is useful to have it implemented in rust-bitcoin. One method of calculating a chain hash is by hashing the genesis block for the respective network. Add a `ChainHash` type that can be used to get the unique identifier of each of the 4 Bitcoin networks we support. Add a method that calculates the chain hash for a network using the double sha256 of the genesis block. Do so using hard coded consts and add unit tests (regression/sanity) that show these hard coded byte arrays match the hash of the data we return for the genesis block for the respective network. The chain hash for the main Bitcoin network can be verified from LN docs (BOLT 0), add a link to this document. Closes: #481 ACKs for top commit: Kixunil: ACK 8e29f2b sanket1729: ACK 8e29f2b. Tree-SHA512: 8156bb55838b73694ddf77a606cbe403f53a31d363aa0dee11b97dc31aa9b62609d7d84b8f0f92c08e90372a3e8c7b416fb07989d6da9633763373b41339b1f5
2 parents d1c9264 + 79967a3 commit 4e08c43

File tree

2 files changed

+76
-7
lines changed

2 files changed

+76
-7
lines changed

src/blockdata/constants.rs

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,40 @@ pub fn genesis_block(network: Network) -> Block {
176176
}
177177
}
178178

179+
// Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md
180+
const GENESIS_BLOCK_HASH_BITCOIN: [u8; 32] = [111, 226, 140, 10, 182, 241, 179, 114, 193, 166, 162, 70, 174, 99, 247, 79, 147, 30, 131, 101, 225, 90, 8, 156, 104, 214, 25, 0, 0, 0, 0, 0];
181+
const GENESIS_BLOCK_HASH_TESTNET: [u8; 32] = [67, 73, 127, 215, 248, 38, 149, 113, 8, 244, 163, 15, 217, 206, 195, 174, 186, 121, 151, 32, 132, 233, 14, 173, 1, 234, 51, 9, 0, 0, 0, 0];
182+
const GENESIS_BLOCK_HASH_SIGNET: [u8; 32] = [246, 30, 238, 59, 99, 163, 128, 164, 119, 160, 99, 175, 50, 178, 187, 201, 124, 159, 249, 240, 31, 44, 66, 37, 233, 115, 152, 129, 8, 0, 0, 0];
183+
const GENESIS_BLOCK_HASH_REGTEST: [u8; 32] = [6, 34, 110, 70, 17, 26, 11, 89, 202, 175, 18, 96, 67, 235, 91, 191, 40, 195, 79, 58, 94, 51, 42, 31, 199, 178, 183, 60, 241, 136, 145, 15];
184+
185+
/// The uniquely identifying hash of the target blockchain.
186+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
187+
pub struct ChainHash([u8; 32]);
188+
impl_array_newtype!(ChainHash, u8, 32);
189+
impl_bytes_newtype!(ChainHash, 32);
190+
191+
impl ChainHash {
192+
/// Returns the hash of the `network` genesis block for use as a chain hash.
193+
///
194+
/// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash)
195+
/// for specification.
196+
pub fn using_genesis_block(network: Network) -> Self {
197+
match network {
198+
Network::Bitcoin => ChainHash(GENESIS_BLOCK_HASH_BITCOIN),
199+
Network::Testnet => ChainHash(GENESIS_BLOCK_HASH_TESTNET),
200+
Network::Signet => ChainHash(GENESIS_BLOCK_HASH_SIGNET),
201+
Network::Regtest => ChainHash(GENESIS_BLOCK_HASH_REGTEST),
202+
}
203+
}
204+
}
205+
179206
#[cfg(test)]
180207
mod test {
181208
use core::default::Default;
209+
use super::*;
182210
use crate::hashes::hex::FromHex;
183-
184211
use crate::network::constants::Network;
185212
use crate::consensus::encode::serialize;
186-
use crate::blockdata::constants::{genesis_block, bitcoin_genesis_tx};
187-
use crate::blockdata::constants::{MAX_SEQUENCE, COIN_VALUE};
188213

189214
#[test]
190215
fn bitcoin_genesis_first_transaction() {
@@ -250,5 +275,49 @@ mod test {
250275
assert_eq!(format!("{:x}", gen.header.block_hash()),
251276
"00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6".to_string());
252277
}
278+
279+
// The *_chain_hash tests are sanity/regression tests, they verify that the const byte array
280+
// representing the genesis block is the same as that created by hashing the genesis block.
281+
fn chain_hash_and_genesis_block(network: Network) {
282+
use hashes::{sha256, Hash};
283+
284+
// The genesis block hash is a double-sha256 and it is displayed backwards.
285+
let genesis_hash = genesis_block(network).block_hash();
286+
// We abuse the sha256 hash here so we get a LowerHex impl that does not print the hex backwards.
287+
let hash = sha256::Hash::from_slice(&genesis_hash.into_inner()).unwrap();
288+
let want = format!("{:02x}", hash);
289+
290+
let chain_hash = ChainHash::using_genesis_block(network);
291+
let got = format!("{:02x}", chain_hash);
292+
293+
// Compare strings because the spec specifically states how the chain hash must encode to hex.
294+
assert_eq!(got, want);
295+
}
296+
297+
macro_rules! chain_hash_genesis_block {
298+
($($test_name:ident, $network:expr);* $(;)*) => {
299+
$(
300+
#[test]
301+
fn $test_name() {
302+
chain_hash_and_genesis_block($network);
303+
}
304+
)*
305+
}
306+
}
307+
308+
chain_hash_genesis_block! {
309+
mainnet_chain_hash_genesis_block, Network::Bitcoin;
310+
testnet_chain_hash_genesis_block, Network::Testnet;
311+
signet_chain_hash_genesis_block, Network::Signet;
312+
regtest_chain_hash_genesis_block, Network::Regtest;
313+
}
314+
315+
// Test vector taken from: https://github.com/lightning/bolts/blob/master/00-introduction.md
316+
#[test]
317+
fn mainnet_chain_hash_test_vector() {
318+
let got = format!("{:x}", ChainHash::using_genesis_block(Network::Bitcoin));
319+
let want = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000";
320+
assert_eq!(got, want);
321+
}
253322
}
254323

src/internal_macros.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ macro_rules! impl_array_newtype {
9494
pub fn into_bytes(self) -> [$ty; $len] { self.0 }
9595
}
9696

97-
impl<'a> ::core::convert::From<&'a [$ty]> for $thing {
97+
impl<'a> core::convert::From<&'a [$ty]> for $thing {
9898
fn from(data: &'a [$ty]) -> $thing {
9999
assert_eq!(data.len(), $len);
100100
let mut ret = [0; $len];
@@ -119,7 +119,7 @@ macro_rules! impl_array_newtype {
119119

120120
macro_rules! display_from_debug {
121121
($thing:ident) => {
122-
impl ::core::fmt::Display for $thing {
122+
impl core::fmt::Display for $thing {
123123
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> Result<(), ::core::fmt::Error> {
124124
::core::fmt::Debug::fmt(self, f)
125125
}
@@ -375,13 +375,13 @@ macro_rules! impl_bytes_newtype {
375375

376376
impl ::core::fmt::Display for $t {
377377
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
378-
fmt::LowerHex::fmt(self, f)
378+
::core::fmt::LowerHex::fmt(self, f)
379379
}
380380
}
381381

382382
impl ::core::fmt::Debug for $t {
383383
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
384-
fmt::LowerHex::fmt(self, f)
384+
::core::fmt::LowerHex::fmt(self, f)
385385
}
386386
}
387387

0 commit comments

Comments
 (0)