Skip to content

Commit

Permalink
Add ChainHash type
Browse files Browse the repository at this point in the history
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.
It is calculated by hashing the genesis block for the respective
network. Chain hash is now being used by the DLC folks, as such it is
useful to have it implemented in rust-bitcoin.

Add a `ChainHash` type that can be used to get the unique identifier of
each of the 4 Bitcoin networks we support.
  • Loading branch information
tcharding committed Mar 18, 2022
1 parent 1ffcd45 commit 182fe2e
Showing 1 changed file with 70 additions and 2 deletions.
72 changes: 70 additions & 2 deletions src/blockdata/constants.rs
Expand Up @@ -23,8 +23,8 @@ use prelude::*;

use core::default::Default;

use hashes::hex::{HexIterator, Error as HexError};
use hashes::sha256d;
use hashes::hex::{HexIterator, Error as HexError, FromHex};
use hashes::{Hash, sha256d};
use blockdata::opcodes;
use blockdata::script;
use blockdata::transaction::{OutPoint, Transaction, TxOut, TxIn};
Expand Down Expand Up @@ -176,6 +176,38 @@ pub fn genesis_block(network: Network) -> Block {
}
}

// Mainnet value can be verified at https://github.com/lightning/bolts/blob/master/00-introduction.md
const CHAIN_HASH_BITCOIN: &str = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000";
const CHAIN_HASH_TESTNET: &str = "43497fd7f826957108f4a30fd9cec3aeba79972084e90ead01ea330900000000";
const CHAIN_HASH_SIGNET: &str = "f61eee3b63a380a477a063af32b2bbc97c9ff9f01f2c4225e973988108000000";
const CHAIN_HASH_REGTEST: &str = "06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f";


/// The uniquely identifying hash of the target blockchain.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChainHash([u8; 32]);
impl_array_newtype!(ChainHash, u8, 32);
impl_bytes_newtype!(ChainHash, 32);

impl ChainHash {
/// Returns the hash of the `network` genesis block for use as a chain hash.
///
/// See [BOLT 0](https://github.com/lightning/bolts/blob/ffeece3dab1c52efdb9b53ae476539320fa44938/00-introduction.md#chain_hash)
/// for specification.
pub fn for_network(network: Network) -> Self {
let s = match network {
Network::Bitcoin => CHAIN_HASH_BITCOIN,
Network::Testnet => CHAIN_HASH_TESTNET,
Network::Signet => CHAIN_HASH_SIGNET,
Network::Regtest => CHAIN_HASH_REGTEST,
};

// Chain hash is the block hash of the genesis block and `BlockHash` is a sha256d.
let hash = sha256d::Hash::from_hex(s).expect("valid static hex string");
ChainHash(hash.into_inner())
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down Expand Up @@ -250,5 +282,41 @@ mod test {
assert_eq!(format!("{:x}", gen.header.block_hash()),
"00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6".to_string());
}

// The *_chain_hash tests are sanity/regression tests, they verify that the const hex string
// representing the genesis block is the same as the string created by hashing the genesis block.
fn chain_hash_and_genesis_block(network: Network) -> (String, String) {
let chain_hash = ChainHash::for_network(network);
let genesis = genesis_block(network).block_hash();

let got = format!("{:x}", chain_hash);
let want = format!("{:x}", genesis);

(got, want)
}

#[test]
fn mainnet_chain_hash() {
let (got, want) = chain_hash_and_genesis_block(Network::Bitcoin);
assert_eq!(got, want);
}

#[test]
fn testnet_chain_hash() {
let (got, want) = chain_hash_and_genesis_block(Network::Testnet);
assert_eq!(got, want);
}

#[test]
fn signet_chain_hash() {
let (got, want) = chain_hash_and_genesis_block(Network::Signet);
assert_eq!(got, want);
}

#[test]
fn regtest_chain_hash() {
let (got, want) = chain_hash_and_genesis_block(Network::Regtest);
assert_eq!(got, want);
}
}

0 comments on commit 182fe2e

Please sign in to comment.