use hashes::{sha256d, Hash};
use internals::impl_array_newtype;
use crate::blockdata::block::{self, Block};
use crate::blockdata::locktime::absolute;
use crate::blockdata::opcodes::all::*;
use crate::blockdata::script;
use crate::blockdata::transaction::{self, OutPoint, Sequence, Transaction, TxIn, TxOut};
use crate::blockdata::witness::Witness;
use crate::consensus::Params;
use crate::internal_macros::impl_bytes_newtype;
use crate::network::Network;
use crate::pow::CompactTarget;
use crate::Amount;
pub const TARGET_BLOCK_SPACING: u32 = 600;
pub const DIFFCHANGE_INTERVAL: u32 = 2016;
pub const DIFFCHANGE_TIMESPAN: u32 = 14 * 24 * 3600;
pub const WITNESS_SCALE_FACTOR: usize = units::weight::WITNESS_SCALE_FACTOR;
pub const MAX_BLOCK_SIGOPS_COST: i64 = 80_000;
pub const PUBKEY_ADDRESS_PREFIX_MAIN: u8 = 0; pub const SCRIPT_ADDRESS_PREFIX_MAIN: u8 = 5; pub const PUBKEY_ADDRESS_PREFIX_TEST: u8 = 111; pub const SCRIPT_ADDRESS_PREFIX_TEST: u8 = 196; pub const MAX_SCRIPT_ELEMENT_SIZE: usize = 520;
pub const SUBSIDY_HALVING_INTERVAL: u32 = 210_000;
pub const MAX_SCRIPTNUM_VALUE: u32 = 0x80000000; pub const COINBASE_MATURITY: u32 = 100;
#[rustfmt::skip]
const GENESIS_OUTPUT_PK: [u8; 65] = [
0x04,
0x67, 0x8a, 0xfd, 0xb0, 0xfe, 0x55, 0x48, 0x27,
0x19, 0x67, 0xf1, 0xa6, 0x71, 0x30, 0xb7, 0x10,
0x5c, 0xd6, 0xa8, 0x28, 0xe0, 0x39, 0x09, 0xa6,
0x79, 0x62, 0xe0, 0xea, 0x1f, 0x61, 0xde, 0xb6,
0x49, 0xf6, 0xbc, 0x3f, 0x4c, 0xef, 0x38, 0xc4,
0xf3, 0x55, 0x04, 0xe5, 0x1e, 0xc1, 0x12, 0xde,
0x5c, 0x38, 0x4d, 0xf7, 0xba, 0x0b, 0x8d, 0x57,
0x8a, 0x4c, 0x70, 0x2b, 0x6b, 0xf1, 0x1d, 0x5f
];
#[rustfmt::skip]
const TESTNET4_GENESIS_OUTPUT_PK: [u8; 33] = [0x00; 33];
fn bitcoin_genesis_tx(params: &Params) -> Transaction {
let mut ret = Transaction {
version: transaction::Version::ONE,
lock_time: absolute::LockTime::ZERO,
input: vec![],
output: vec![],
};
let (in_script, out_script) = {
match params.network {
Network::Testnet4 => (
script::Builder::new()
.push_int(486604799)
.push_int_non_minimal(4)
.push_slice(b"03/May/2024 000000000000000000001ebd58c244970b3aa9d783bb001011fbe8ea8e98e00e")
.into_script(),
script::Builder::new().push_slice(TESTNET4_GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script(),
),
_ => (
script::Builder::new()
.push_int(486604799)
.push_int_non_minimal(4)
.push_slice(b"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks")
.into_script(),
script::Builder::new().push_slice(GENESIS_OUTPUT_PK).push_opcode(OP_CHECKSIG).into_script(),
),
}
};
ret.input.push(TxIn {
previous_output: OutPoint::null(),
script_sig: in_script,
sequence: Sequence::MAX,
witness: Witness::default(),
});
ret.output.push(TxOut { value: Amount::from_sat(50 * 100_000_000), script_pubkey: out_script });
ret
}
pub fn genesis_block(params: impl AsRef<Params>) -> Block {
let params = params.as_ref();
let txdata = vec![bitcoin_genesis_tx(params)];
let hash: sha256d::Hash = txdata[0].compute_txid().into();
let merkle_root: crate::TxMerkleNode = hash.into();
match params.network {
Network::Bitcoin => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
merkle_root,
time: 1231006505,
bits: CompactTarget::from_consensus(0x1d00ffff),
nonce: 2083236893,
},
txdata,
},
Network::Testnet => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
merkle_root,
time: 1296688602,
bits: CompactTarget::from_consensus(0x1d00ffff),
nonce: 414098458,
},
txdata,
},
Network::Testnet4 => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
merkle_root,
time: 1714777860,
bits: CompactTarget::from_consensus(0x1d00ffff),
nonce: 393743547,
},
txdata,
},
Network::Signet => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
merkle_root,
time: 1598918400,
bits: CompactTarget::from_consensus(0x1e0377ae),
nonce: 52613770,
},
txdata,
},
Network::Regtest => Block {
header: block::Header {
version: block::Version::ONE,
prev_blockhash: Hash::all_zeros(),
merkle_root,
time: 1296688602,
bits: CompactTarget::from_consensus(0x207fffff),
nonce: 2,
},
txdata,
},
}
}
#[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 {
pub const BITCOIN: Self = Self([
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,
]);
#[deprecated(since = "0.32.4", note = "Use TESTNET3 instead")]
pub const TESTNET: Self = Self([
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,
]);
pub const TESTNET3: Self = Self([
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,
]);
pub const TESTNET4: Self = Self([
67, 240, 139, 218, 176, 80, 227, 91, 86, 124, 134, 75, 145, 244, 127, 80, 174, 114, 90,
226, 222, 83, 188, 251, 186, 242, 132, 218, 0, 0, 0, 0,
]);
pub const SIGNET: Self = Self([
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,
]);
pub const REGTEST: Self = Self([
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,
]);
pub fn using_genesis_block(params: impl AsRef<Params>) -> Self {
match params.as_ref().network {
Network::Bitcoin => Self::BITCOIN,
Network::Testnet => Self::TESTNET3,
Network::Testnet4 => Self::TESTNET4,
Network::Signet => Self::SIGNET,
Network::Regtest => Self::REGTEST,
}
}
pub const fn using_genesis_block_const(network: Network) -> Self {
match network {
Network::Bitcoin => Self::BITCOIN,
Network::Testnet => Self::TESTNET3,
Network::Testnet4 => Self::TESTNET4,
Network::Signet => Self::SIGNET,
Network::Regtest => Self::REGTEST,
}
}
pub fn from_genesis_block_hash(block_hash: crate::BlockHash) -> Self {
ChainHash(block_hash.to_byte_array())
}
}
#[cfg(test)]
mod test {
use core::str::FromStr;
use hex::test_hex_unwrap as hex;
use super::*;
use crate::consensus::params;
use crate::consensus::encode::serialize;
#[test]
fn bitcoin_genesis_first_transaction() {
let gen = bitcoin_genesis_tx(&Params::MAINNET);
assert_eq!(gen.version, transaction::Version::ONE);
assert_eq!(gen.input.len(), 1);
assert_eq!(gen.input[0].previous_output.txid, Hash::all_zeros());
assert_eq!(gen.input[0].previous_output.vout, 0xFFFFFFFF);
assert_eq!(serialize(&gen.input[0].script_sig),
hex!("4d04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"));
assert_eq!(gen.input[0].sequence, Sequence::MAX);
assert_eq!(gen.output.len(), 1);
assert_eq!(serialize(&gen.output[0].script_pubkey),
hex!("434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac"));
assert_eq!(gen.output[0].value, Amount::from_str("50 BTC").unwrap());
assert_eq!(gen.lock_time, absolute::LockTime::ZERO);
assert_eq!(
gen.compute_wtxid().to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
}
#[test]
fn bitcoin_genesis_block_calling_convention() {
let _ = genesis_block(¶ms::MAINNET);
let _ = genesis_block(&Network::Bitcoin);
let _ = genesis_block(Network::Bitcoin);
let _ = genesis_block(Params::MAINNET);
let _ = genesis_block(&Params::MAINNET);
}
#[test]
fn bitcoin_genesis_full_block() {
let gen = genesis_block(¶ms::MAINNET);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
assert_eq!(gen.header.time, 1231006505);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
assert_eq!(gen.header.nonce, 2083236893);
assert_eq!(
gen.header.block_hash().to_string(),
"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
);
}
#[test]
fn testnet_genesis_full_block() {
let gen = genesis_block(¶ms::TESTNET3);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
assert_eq!(gen.header.time, 1296688602);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1d00ffff));
assert_eq!(gen.header.nonce, 414098458);
assert_eq!(
gen.header.block_hash().to_string(),
"000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
);
}
#[test]
fn signet_genesis_full_block() {
let gen = genesis_block(¶ms::SIGNET);
assert_eq!(gen.header.version, block::Version::ONE);
assert_eq!(gen.header.prev_blockhash, Hash::all_zeros());
assert_eq!(
gen.header.merkle_root.to_string(),
"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"
);
assert_eq!(gen.header.time, 1598918400);
assert_eq!(gen.header.bits, CompactTarget::from_consensus(0x1e0377ae));
assert_eq!(gen.header.nonce, 52613770);
assert_eq!(
gen.header.block_hash().to_string(),
"00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"
);
}
fn chain_hash_and_genesis_block(network: Network) {
use hashes::sha256;
let genesis_hash = genesis_block(network).block_hash();
let hash = sha256::Hash::from_slice(genesis_hash.as_byte_array()).unwrap();
let want = format!("{:02x}", hash);
let chain_hash = ChainHash::using_genesis_block_const(network);
let got = format!("{:02x}", chain_hash);
assert_eq!(got, want);
#[allow(unreachable_patterns)] match network {
Network::Bitcoin => {},
Network::Testnet => {},
Network::Testnet4 => {},
Network::Signet => {},
Network::Regtest => {},
_ => panic!("Update ChainHash::using_genesis_block and chain_hash_genesis_block with new variants"),
}
}
macro_rules! chain_hash_genesis_block {
($($test_name:ident, $network:expr);* $(;)*) => {
$(
#[test]
fn $test_name() {
chain_hash_and_genesis_block($network);
}
)*
}
}
chain_hash_genesis_block! {
mainnet_chain_hash_genesis_block, Network::Bitcoin;
testnet_chain_hash_genesis_block, Network::Testnet;
testnet4_chain_hash_genesis_block, Network::Testnet4;
signet_chain_hash_genesis_block, Network::Signet;
regtest_chain_hash_genesis_block, Network::Regtest;
}
#[test]
fn mainnet_chain_hash_test_vector() {
let got = ChainHash::using_genesis_block_const(Network::Bitcoin).to_string();
let want = "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000";
assert_eq!(got, want);
}
}