//! Genesis block and chain configuration for Synor. //! //! This module defines the genesis block for different networks //! and provides chain configuration parameters. use synor_types::{ block::BlockBody, transaction::{Outpoint, ScriptPubKey, ScriptType, SubnetworkId}, Amount, Block, BlockHeader, BlueScore, Hash256, Network, Timestamp, Transaction, TxInput, TxOutput, }; /// Chain configuration parameters. #[derive(Clone, Debug)] pub struct ChainConfig { /// Network identifier. pub network: Network, /// Genesis block. pub genesis: Block, /// Genesis hash. pub genesis_hash: Hash256, /// Target block time in milliseconds. pub target_block_time_ms: u64, /// GHOSTDAG K parameter. pub ghostdag_k: u64, /// Maximum block parents. pub max_block_parents: u64, /// Maximum block mass. pub max_block_mass: u64, /// Coinbase maturity. pub coinbase_maturity: u64, /// Finality depth. pub finality_depth: u64, /// Pruning depth. pub pruning_depth: u64, /// Initial difficulty bits. pub initial_difficulty: u32, /// Halving interval in blocks. pub halving_interval: u64, /// Initial block reward in sompi. pub initial_reward: u64, /// DNS seeds. pub dns_seeds: Vec, /// Bootstrap nodes. pub bootstrap_nodes: Vec, /// BIP32 coin type. pub bip32_coin_type: u32, /// Address prefix (for bech32). pub address_prefix: String, } impl ChainConfig { /// Creates mainnet configuration. pub fn mainnet() -> Self { let genesis = create_mainnet_genesis(); let genesis_hash = genesis.header.block_id(); ChainConfig { network: Network::Mainnet, genesis, genesis_hash, target_block_time_ms: 100, // 10 bps ghostdag_k: 18, max_block_parents: 64, max_block_mass: 500_000, coinbase_maturity: 100, finality_depth: 86_400, // ~24 hours pruning_depth: 288_000, // ~8 hours of data initial_difficulty: 0x1d00ffff, // Bitcoin-style initial difficulty halving_interval: 315_360_000, // ~1 year at 10 bps initial_reward: 500 * 100_000_000, // 500 SYNOR dns_seeds: vec![ "seed1.synor.cc".to_string(), "seed2.synor.cc".to_string(), "seed3.synor.cc".to_string(), ], bootstrap_nodes: vec![], bip32_coin_type: 0x5359, // "SY" in hex address_prefix: "synor".to_string(), } } /// Creates testnet configuration. pub fn testnet() -> Self { let genesis = create_testnet_genesis(); let genesis_hash = genesis.header.block_id(); ChainConfig { network: Network::Testnet, genesis, genesis_hash, target_block_time_ms: 100, ghostdag_k: 18, max_block_parents: 64, max_block_mass: 500_000, coinbase_maturity: 10, // Lower for testing finality_depth: 1000, // Lower for testing pruning_depth: 5000, initial_difficulty: 0x1f00ffff, // Lower difficulty halving_interval: 10_000, // Quick halvings for testing initial_reward: 500 * 100_000_000, dns_seeds: vec![ "testnet-seed1.synor.cc".to_string(), "testnet-seed2.synor.cc".to_string(), ], bootstrap_nodes: vec![], bip32_coin_type: 0x5359, address_prefix: "tsynor".to_string(), } } /// Creates devnet configuration. pub fn devnet() -> Self { let genesis = create_devnet_genesis(); let genesis_hash = genesis.header.block_id(); ChainConfig { network: Network::Devnet, genesis, genesis_hash, target_block_time_ms: 1000, // 1 second blocks for dev ghostdag_k: 3, // Smaller K for dev max_block_parents: 10, max_block_mass: 100_000, coinbase_maturity: 1, finality_depth: 10, pruning_depth: 100, initial_difficulty: 0x207fffff, // Minimum difficulty halving_interval: 100, initial_reward: 1000 * 100_000_000, // Higher reward for dev dns_seeds: vec![], bootstrap_nodes: vec!["/ip4/127.0.0.1/tcp/16511".to_string()], bip32_coin_type: 0x5359, address_prefix: "dsynor".to_string(), } } /// Returns the configuration for a network. pub fn for_network(network: Network) -> Self { match network { Network::Mainnet => Self::mainnet(), Network::Testnet => Self::testnet(), Network::Devnet => Self::devnet(), } } /// Validates a block against chain rules. pub fn validate_block_header( &self, header: &BlockHeader, _parent_blue_score: u64, ) -> Result<(), GenesisError> { // Check timestamp is reasonable let now_ms = Timestamp::now().as_millis(); let max_future = 2 * 60 * 60 * 1000; // 2 hours if header.timestamp.as_millis() > now_ms + max_future { return Err(GenesisError::TimestampTooFar); } // Check version if header.version == 0 { return Err(GenesisError::InvalidVersion); } // Check number of parents if header.parents.len() > self.max_block_parents as usize { return Err(GenesisError::TooManyParents); } Ok(()) } } /// Genesis-related errors. #[derive(Debug, thiserror::Error)] pub enum GenesisError { #[error("Invalid genesis block")] InvalidGenesis, #[error("Genesis hash mismatch")] HashMismatch, #[error("Invalid block version")] InvalidVersion, #[error("Block timestamp too far in future")] TimestampTooFar, #[error("Too many parent blocks")] TooManyParents, } /// Creates the mainnet genesis block. fn create_mainnet_genesis() -> Block { // Genesis timestamp: 2025-01-01 00:00:00 UTC let genesis_timestamp = Timestamp::from_millis(1735689600000); // Genesis message embedded in coinbase let genesis_message = b"Synor Genesis - The Dawn of Quantum-Secure Decentralized Computing - 2025"; // Create coinbase transaction let coinbase_tx = create_coinbase_transaction( genesis_message, Amount::from_synor(500), &genesis_allocation_mainnet(), ); let txid = coinbase_tx.txid(); // Create genesis header let header = BlockHeader { version: 1, parents: vec![], // Genesis has no parents merkle_root: txid, accepted_id_merkle_root: Hash256::ZERO, utxo_commitment: Hash256::ZERO, timestamp: genesis_timestamp, bits: 0x1d00ffff, nonce: 0, daa_score: 0, blue_work: Hash256::ZERO, blue_score: BlueScore::new(0), pruning_point: Hash256::ZERO, }; let body = BlockBody::new(vec![coinbase_tx]); Block::new(header, body) } /// Creates the testnet genesis block. fn create_testnet_genesis() -> Block { let genesis_timestamp = Timestamp::from_millis(1735689600000); let genesis_message = b"Synor Testnet Genesis - Testing the Future"; let coinbase_tx = create_coinbase_transaction( genesis_message, Amount::from_synor(500), &genesis_allocation_testnet(), ); let txid = coinbase_tx.txid(); let header = BlockHeader { version: 1, parents: vec![], merkle_root: txid, accepted_id_merkle_root: Hash256::ZERO, utxo_commitment: Hash256::ZERO, timestamp: genesis_timestamp, bits: 0x1f00ffff, nonce: 0, daa_score: 0, blue_work: Hash256::ZERO, blue_score: BlueScore::new(0), pruning_point: Hash256::ZERO, }; let body = BlockBody::new(vec![coinbase_tx]); Block::new(header, body) } /// Creates the devnet genesis block. fn create_devnet_genesis() -> Block { let genesis_timestamp = Timestamp::now(); let genesis_message = b"Synor Devnet - Local Development"; let coinbase_tx = create_coinbase_transaction( genesis_message, Amount::from_synor(1000), &genesis_allocation_devnet(), ); let txid = coinbase_tx.txid(); let header = BlockHeader { version: 1, parents: vec![], merkle_root: txid, accepted_id_merkle_root: Hash256::ZERO, utxo_commitment: Hash256::ZERO, timestamp: genesis_timestamp, bits: 0x207fffff, nonce: 0, daa_score: 0, blue_work: Hash256::ZERO, blue_score: BlueScore::new(0), pruning_point: Hash256::ZERO, }; let body = BlockBody::new(vec![coinbase_tx]); Block::new(header, body) } /// Genesis allocation entry. #[derive(Clone, Debug)] pub struct GenesisAllocation { /// Recipient address (as string for genesis, actual address derived later). pub address_hash: Hash256, /// Amount to allocate. pub amount: Amount, /// Description/purpose. pub description: String, } /// Returns mainnet genesis allocations. fn genesis_allocation_mainnet() -> Vec { vec![ // Development fund (15%) GenesisAllocation { address_hash: Hash256::from([0x01; 32]), amount: Amount::from_synor(10_500_000), description: "Development Fund".to_string(), }, // Ecosystem grants (10%) GenesisAllocation { address_hash: Hash256::from([0x02; 32]), amount: Amount::from_synor(7_000_000), description: "Ecosystem Grants".to_string(), }, // Team (10%, vested) GenesisAllocation { address_hash: Hash256::from([0x03; 32]), amount: Amount::from_synor(7_000_000), description: "Team (4yr vest, 1yr cliff)".to_string(), }, // Reserve (5%) GenesisAllocation { address_hash: Hash256::from([0x04; 32]), amount: Amount::from_synor(3_500_000), description: "Reserve".to_string(), }, // Initial staking rewards pool (10%) GenesisAllocation { address_hash: Hash256::from([0x05; 32]), amount: Amount::from_synor(7_000_000), description: "Staking Rewards Pool".to_string(), }, // Note: Remaining 50% (35M) is for community/public distribution via mining ] } /// Returns testnet genesis allocations. fn genesis_allocation_testnet() -> Vec { vec![GenesisAllocation { address_hash: Hash256::from([0x10; 32]), amount: Amount::from_synor(1_000_000), description: "Testnet Faucet".to_string(), }] } /// Returns devnet genesis allocations. fn genesis_allocation_devnet() -> Vec { vec![GenesisAllocation { address_hash: Hash256::from([0x20; 32]), amount: Amount::from_synor(100_000_000), description: "Dev Account".to_string(), }] } /// Creates a coinbase transaction for genesis. fn create_coinbase_transaction( message: &[u8], block_reward: Amount, allocations: &[GenesisAllocation], ) -> Transaction { // Coinbase input with genesis message let input = TxInput { previous_output: Outpoint::null(), signature_script: message.to_vec(), sequence: u64::MAX, }; // Outputs for allocations let mut outputs: Vec = allocations .iter() .map(|alloc| TxOutput { amount: alloc.amount, script_pubkey: ScriptPubKey { script_type: ScriptType::P2PKH, data: alloc.address_hash.as_bytes().to_vec(), }, }) .collect(); // Add block reward output (to miner - for genesis, burned or to fund) outputs.push(TxOutput { amount: block_reward, script_pubkey: ScriptPubKey::op_return(&[0x00; 32]), // OP_RETURN style burn for genesis }); Transaction { version: 1, inputs: vec![input], outputs, lock_time: 0, subnetwork_id: SubnetworkId::COINBASE, gas: 0, payload: vec![], } } /// Checkpoint for chain validation. #[derive(Clone, Debug)] pub struct Checkpoint { /// Blue score at checkpoint. pub blue_score: u64, /// Block hash at checkpoint. pub hash: Hash256, /// Timestamp for reference. pub timestamp: u64, } /// Returns hardcoded checkpoints for mainnet. pub fn mainnet_checkpoints() -> Vec { vec![ // Genesis Checkpoint { blue_score: 0, hash: ChainConfig::mainnet().genesis_hash, timestamp: 1735689600000, }, // Add more checkpoints as network grows ] } /// Returns hardcoded checkpoints for testnet. pub fn testnet_checkpoints() -> Vec { vec![Checkpoint { blue_score: 0, hash: ChainConfig::testnet().genesis_hash, timestamp: 1735689600000, }] } /// Network magic bytes for message framing. pub fn network_magic(network: Network) -> [u8; 4] { match network { Network::Mainnet => [0x53, 0x59, 0x4E, 0x4F], // "SYNO" Network::Testnet => [0x54, 0x53, 0x59, 0x4E], // "TSYN" Network::Devnet => [0x44, 0x53, 0x59, 0x4E], // "DSYN" } } #[cfg(test)] mod tests { use super::*; #[test] fn test_mainnet_genesis() { let config = ChainConfig::mainnet(); assert_eq!(config.network, Network::Mainnet); assert_eq!(config.genesis.body.transactions.len(), 1); assert_eq!(config.genesis.header.parents.len(), 0); assert_eq!(config.genesis.header.blue_score.value(), 0); } #[test] fn test_testnet_genesis() { let config = ChainConfig::testnet(); assert_eq!(config.network, Network::Testnet); // Higher bits value = lower difficulty (easier), so testnet < devnet means testnet is harder assert!(config.initial_difficulty < ChainConfig::devnet().initial_difficulty); } #[test] fn test_devnet_genesis() { let config = ChainConfig::devnet(); assert_eq!(config.network, Network::Devnet); assert_eq!(config.coinbase_maturity, 1); } #[test] fn test_genesis_hash_consistency() { let config1 = ChainConfig::mainnet(); let config2 = ChainConfig::mainnet(); // Genesis hash should be deterministic assert_eq!(config1.genesis_hash, config2.genesis_hash); } #[test] fn test_network_magic() { assert_eq!(network_magic(Network::Mainnet), [0x53, 0x59, 0x4E, 0x4F]); assert_eq!(network_magic(Network::Testnet), [0x54, 0x53, 0x59, 0x4E]); } #[test] fn test_genesis_allocations() { let allocations = genesis_allocation_mainnet(); // Should have 5 allocations assert_eq!(allocations.len(), 5); // Total should be 35M (50% of 70M supply, rest is mined) let total: u64 = allocations.iter().map(|a| a.amount.as_sompi()).sum(); assert_eq!(total, 35_000_000 * 100_000_000); } #[test] fn test_config_for_network() { let mainnet = ChainConfig::for_network(Network::Mainnet); assert_eq!(mainnet.network, Network::Mainnet); let testnet = ChainConfig::for_network(Network::Testnet); assert_eq!(testnet.network, Network::Testnet); } }