use chia_consensus::consensus_constants::ConsensusConstants;
use chia_protocol::Bytes32;
use hex_literal::hex;
#[derive(Debug, Clone)]
pub struct NetworkConstants {
inner: ConsensusConstants,
}
impl NetworkConstants {
pub fn consensus(&self) -> &ConsensusConstants {
&self.inner
}
pub fn genesis_challenge(&self) -> Bytes32 {
self.inner.genesis_challenge
}
pub fn agg_sig_me_additional_data(&self) -> Bytes32 {
self.inner.agg_sig_me_additional_data
}
pub fn max_block_cost_clvm(&self) -> u64 {
self.inner.max_block_cost_clvm
}
pub fn cost_per_byte(&self) -> u64 {
self.inner.cost_per_byte
}
pub fn max_coin_amount(&self) -> u64 {
self.inner.max_coin_amount
}
}
const DIG_MAINNET_GENESIS_CHALLENGE: [u8; 32] =
hex!("0af981862a4df51f51ec59c312315d959931d917c375730b89b9e2b0854d1abf");
pub const DIG_MAINNET: NetworkConstants = NetworkConstants {
inner: ConsensusConstants {
genesis_challenge: Bytes32::new(DIG_MAINNET_GENESIS_CHALLENGE),
agg_sig_me_additional_data: Bytes32::new(DIG_MAINNET_GENESIS_CHALLENGE),
agg_sig_parent_additional_data: Bytes32::new(hex!(
"196d63b6dfbd4440656f9c1eadc686cacfaae771c565762a8cd6e51c892a0077"
)),
agg_sig_puzzle_additional_data: Bytes32::new(hex!(
"9ca719659b5e2355a91ff330c8612cb58c74f1063eaff99e507602d450b1f71f"
)),
agg_sig_amount_additional_data: Bytes32::new(hex!(
"d13767da4a8bd9520dbd9e039e68b3eb4b16fdcbb7e7755b5064840eaeb553ce"
)),
agg_sig_puzzle_amount_additional_data: Bytes32::new(hex!(
"73eea3473bd0daa28793d4bcd218ade462b634b53af97f9a01a91f3059ac75df"
)),
agg_sig_parent_amount_additional_data: Bytes32::new(hex!(
"eb7302224e77c0f269d0c8b105d4cc786775ae012ed2db49751c33c244c3f647"
)),
agg_sig_parent_puzzle_additional_data: Bytes32::new(hex!(
"ccac5983685257d50ee7b439bbb502128ddb262813dde4e4a11ac6cdfc66fa8e"
)),
max_block_cost_clvm: 11_000_000_000, cost_per_byte: 12_000,
max_coin_amount: u64::MAX,
max_generator_size: 1_000_000,
max_generator_ref_list_size: 512,
hard_fork_height: 0,
hard_fork2_height: 0,
genesis_pre_farm_pool_puzzle_hash: Bytes32::new([0u8; 32]),
genesis_pre_farm_farmer_puzzle_hash: Bytes32::new([0u8; 32]),
slot_blocks_target: 32,
min_blocks_per_challenge_block: 16,
max_sub_slot_blocks: 128,
num_sps_sub_slot: 64,
sub_slot_iters_starting: 1 << 27,
difficulty_constant_factor: 1 << 67,
difficulty_starting: 7,
difficulty_change_max_factor: 3,
sub_epoch_blocks: 384,
epoch_blocks: 4608,
significant_bits: 8,
discriminant_size_bits: 1024,
number_zero_bits_plot_filter_v1: 9,
number_zero_bits_plot_filter_v2: 9,
min_plot_size_v1: 32,
max_plot_size_v1: 50,
min_plot_size_v2: 28,
max_plot_size_v2: 32,
sub_slot_time_target: 600,
num_sp_intervals_extra: 3,
max_future_time2: 120,
number_of_timestamps: 11,
max_vdf_witness_size: 64,
mempool_block_buffer: 10,
weight_proof_threshold: 2,
blocks_cache_size: 4608 + (128 * 4),
weight_proof_recent_blocks: 1000,
max_block_count_per_requests: 32,
pool_sub_slot_iters: 37_600_000_000,
plot_filter_128_height: 0xffff_ffff,
plot_filter_64_height: 0xffff_ffff,
plot_filter_32_height: 0xffff_ffff,
plot_difficulty_initial: 2,
plot_difficulty_4_height: 0xffff_ffff,
plot_difficulty_5_height: 0xffff_ffff,
plot_difficulty_6_height: 0xffff_ffff,
plot_difficulty_7_height: 0xffff_ffff,
plot_difficulty_8_height: 0xffff_ffff,
},
};
pub const DIG_RELAY_URL: &str = "wss://relay.dig.net:443";
pub const DIG_NODE_PORT: u16 = 9778;
pub const DIG_ASSET_ID: Bytes32 = Bytes32::new(hex!(
"a406d3a9de984d03c9591c10d917593b434d5263cabe2b42f6b367df16832f81"
));
pub const DIG_TREASURY_INNER_PUZZLE_HASH: Bytes32 = Bytes32::new(hex!(
"ec7c304708c7d59c078d5ae098d0dea004decf47fa1cafebb266c10ad6466ce8"
));
pub const DIG_TREASURY_ADDRESS: &str =
"xch1a37rq3cgcl2ecpudttsf35x75qzdan68lgw2l6ajvmqs44jxdn5qv6pk3y";
pub const CHIA_L1_MAINNET_AGG_SIG_ME: [u8; 32] =
hex!("ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb");
pub const CHIA_L1_TESTNET11_AGG_SIG_ME: [u8; 32] =
hex!("37a90eb5185a9c4439a91ddc98bbadce7b4feba060d50116a067de66bf236615");
const DIG_TESTNET_GENESIS_CHALLENGE: [u8; 32] =
hex!("088c18d6b7859d885dc2f03166e862c958f74b63b6353c3df71d103b9b806c3b");
pub const DIG_TESTNET: NetworkConstants = NetworkConstants {
inner: ConsensusConstants {
genesis_challenge: Bytes32::new(DIG_TESTNET_GENESIS_CHALLENGE),
agg_sig_me_additional_data: Bytes32::new(DIG_TESTNET_GENESIS_CHALLENGE),
agg_sig_parent_additional_data: Bytes32::new(hex!(
"85b3963bdeb9848af970a9bbd1d36809ae41491ffd67aee7f27e8883936d495c"
)),
agg_sig_puzzle_additional_data: Bytes32::new(hex!(
"66aba1939e128e1465d58fde414325630e891747c1428d76ebce193cbe966301"
)),
agg_sig_amount_additional_data: Bytes32::new(hex!(
"eccab86920a6d982a68898b2dcb7c150383529fcd532fe84c693fb4592c38ae3"
)),
agg_sig_puzzle_amount_additional_data: Bytes32::new(hex!(
"eb088fad0d4caba66e29130fb07407e60a7545d035d19a188fef0855c874084e"
)),
agg_sig_parent_amount_additional_data: Bytes32::new(hex!(
"232aec0a351ba4936b04920e074aebcc621a458f6b1461c4b28c658552f2f35d"
)),
agg_sig_parent_puzzle_additional_data: Bytes32::new(hex!(
"96263ac395703ab9b3b0f0587e79185f4a9898574a28b4491015ddcf9d321873"
)),
max_block_cost_clvm: 11_000_000_000,
cost_per_byte: 12_000,
max_coin_amount: u64::MAX,
max_generator_size: 1_000_000,
max_generator_ref_list_size: 512,
hard_fork_height: 0,
hard_fork2_height: 0,
genesis_pre_farm_pool_puzzle_hash: Bytes32::new([0u8; 32]),
genesis_pre_farm_farmer_puzzle_hash: Bytes32::new([0u8; 32]),
slot_blocks_target: 32,
min_blocks_per_challenge_block: 16,
max_sub_slot_blocks: 128,
num_sps_sub_slot: 64,
sub_slot_iters_starting: 1 << 27,
difficulty_constant_factor: 1 << 67,
difficulty_starting: 7,
difficulty_change_max_factor: 3,
sub_epoch_blocks: 384,
epoch_blocks: 4608,
significant_bits: 8,
discriminant_size_bits: 1024,
number_zero_bits_plot_filter_v1: 9,
number_zero_bits_plot_filter_v2: 9,
min_plot_size_v1: 32,
max_plot_size_v1: 50,
min_plot_size_v2: 28,
max_plot_size_v2: 32,
sub_slot_time_target: 600,
num_sp_intervals_extra: 3,
max_future_time2: 120,
number_of_timestamps: 11,
max_vdf_witness_size: 64,
mempool_block_buffer: 10,
weight_proof_threshold: 2,
blocks_cache_size: 4608 + (128 * 4),
weight_proof_recent_blocks: 1000,
max_block_count_per_requests: 32,
pool_sub_slot_iters: 37_600_000_000,
plot_filter_128_height: 0xffff_ffff,
plot_filter_64_height: 0xffff_ffff,
plot_filter_32_height: 0xffff_ffff,
plot_difficulty_initial: 2,
plot_difficulty_4_height: 0xffff_ffff,
plot_difficulty_5_height: 0xffff_ffff,
plot_difficulty_6_height: 0xffff_ffff,
plot_difficulty_7_height: 0xffff_ffff,
plot_difficulty_8_height: 0xffff_ffff,
},
};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dig_relay_url_is_canonical_endpoint() {
assert_eq!(DIG_RELAY_URL, "wss://relay.dig.net:443");
}
#[test]
fn dig_relay_url_is_well_formed() {
assert!(
DIG_RELAY_URL.starts_with("wss://"),
"relay must use secure WebSocket"
);
assert!(
DIG_RELAY_URL.contains("relay.dig.net"),
"relay must point at the canonical host"
);
assert!(
DIG_RELAY_URL.ends_with(":443"),
"relay must use the live NLB public TLS port 443"
);
}
#[test]
fn dig_node_port_is_canonical() {
assert_eq!(DIG_NODE_PORT, 9778);
}
use sha2::{Digest, Sha256};
const AGG_SIG_OPCODES: [u8; 6] = [43, 44, 45, 46, 47, 48];
fn sha256(bytes: &[u8]) -> [u8; 32] {
let mut hasher = Sha256::new();
hasher.update(bytes);
hasher.finalize().into()
}
#[test]
fn genesis_challenges_are_non_zero() {
assert_ne!(DIG_MAINNET.genesis_challenge(), Bytes32::new([0u8; 32]));
assert_ne!(DIG_TESTNET.genesis_challenge(), Bytes32::new([0u8; 32]));
}
#[test]
fn genesis_challenges_are_the_pinned_values() {
assert_eq!(
DIG_MAINNET_GENESIS_CHALLENGE,
hex_literal::hex!("0af981862a4df51f51ec59c312315d959931d917c375730b89b9e2b0854d1abf"),
);
assert_eq!(
DIG_TESTNET_GENESIS_CHALLENGE,
sha256(b"DIG_TESTNET:genesis:v1"),
);
}
#[test]
fn mainnet_and_testnet_genesis_differ() {
assert_ne!(
DIG_MAINNET.genesis_challenge(),
DIG_TESTNET.genesis_challenge(),
);
}
#[test]
fn dig_asset_id_is_canonical() {
assert_eq!(
DIG_ASSET_ID,
Bytes32::new(hex_literal::hex!(
"a406d3a9de984d03c9591c10d917593b434d5263cabe2b42f6b367df16832f81"
)),
);
}
#[test]
fn chia_l1_agg_sig_me_constants_are_the_pinned_values() {
assert_eq!(
CHIA_L1_MAINNET_AGG_SIG_ME,
hex_literal::hex!("ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb"),
);
assert_eq!(
CHIA_L1_TESTNET11_AGG_SIG_ME,
hex_literal::hex!("37a90eb5185a9c4439a91ddc98bbadce7b4feba060d50116a067de66bf236615"),
);
}
#[test]
fn chia_l1_agg_sig_me_matches_chia_sdk_types() {
use chia_sdk_types::{MAINNET_CONSTANTS, TESTNET11_CONSTANTS};
assert_eq!(
CHIA_L1_MAINNET_AGG_SIG_ME.as_slice(),
MAINNET_CONSTANTS.agg_sig_me_additional_data.as_ref(),
);
assert_eq!(
CHIA_L1_TESTNET11_AGG_SIG_ME.as_slice(),
TESTNET11_CONSTANTS.agg_sig_me_additional_data.as_ref(),
);
}
#[test]
fn chia_l1_agg_sig_me_differs_from_dig_l2_genesis() {
assert_ne!(
Bytes32::new(CHIA_L1_MAINNET_AGG_SIG_ME),
DIG_MAINNET.genesis_challenge(),
);
assert_ne!(
Bytes32::new(CHIA_L1_TESTNET11_AGG_SIG_ME),
DIG_TESTNET.genesis_challenge(),
);
}
#[test]
fn dig_treasury_inner_puzzle_hash_is_canonical() {
assert_eq!(
DIG_TREASURY_INNER_PUZZLE_HASH,
Bytes32::new(hex_literal::hex!(
"ec7c304708c7d59c078d5ae098d0dea004decf47fa1cafebb266c10ad6466ce8"
)),
);
}
#[test]
fn dig_treasury_address_is_canonical() {
assert_eq!(
DIG_TREASURY_ADDRESS,
"xch1a37rq3cgcl2ecpudttsf35x75qzdan68lgw2l6ajvmqs44jxdn5qv6pk3y",
);
}
#[test]
fn dig_treasury_address_decodes_to_inner_puzzle_hash() {
use bech32::Hrp;
let (hrp, data) = bech32::decode(DIG_TREASURY_ADDRESS).expect("valid bech32m");
assert_eq!(hrp, Hrp::parse("xch").unwrap(), "HRP must be xch");
assert_eq!(
data.as_slice(),
DIG_TREASURY_INNER_PUZZLE_HASH.to_bytes(),
"address must decode to the pinned inner puzzle hash",
);
}
#[test]
fn agg_sig_additional_data_matches_derivation_rule() {
for net in [&DIG_MAINNET, &DIG_TESTNET] {
let genesis = net.genesis_challenge();
assert_eq!(net.agg_sig_me_additional_data(), genesis);
let c = net.consensus();
let derived: Vec<Bytes32> = AGG_SIG_OPCODES
.iter()
.map(|&op| {
let mut preimage = genesis.as_ref().to_vec();
preimage.push(op);
Bytes32::new(sha256(&preimage))
})
.collect();
assert_eq!(c.agg_sig_parent_additional_data, derived[0]);
assert_eq!(c.agg_sig_puzzle_additional_data, derived[1]);
assert_eq!(c.agg_sig_amount_additional_data, derived[2]);
assert_eq!(c.agg_sig_puzzle_amount_additional_data, derived[3]);
assert_eq!(c.agg_sig_parent_amount_additional_data, derived[4]);
assert_eq!(c.agg_sig_parent_puzzle_additional_data, derived[5]);
}
}
}