From 44482105c86073763425466214aa28798e491152 Mon Sep 17 00:00:00 2001 From: aggstam Date: Thu, 26 Oct 2023 21:20:31 +0300 Subject: [PATCH] darkfid2: enchanched args configuration --- bin/darkfid2/Cargo.toml | 2 +- bin/darkfid2/darkfid_config.toml | 390 +++++++++++++++++++++++++-- bin/darkfid2/genesis_block_localnet | 1 + bin/darkfid2/genesis_block_mainnet | 1 + bin/darkfid2/genesis_block_testnet | 1 + bin/darkfid2/src/main.rs | 164 ++++++++--- bin/darkfid2/src/tests/forks.rs | 2 +- bin/darkfid2/src/tests/harness.rs | 22 +- bin/darkfid2/src/tests/mod.rs | 14 +- src/contract/test-harness/src/lib.rs | 4 +- src/net/settings.rs | 4 + src/validator/consensus.rs | 15 +- src/validator/mod.rs | 20 +- src/validator/pow.rs | 27 +- src/validator/validation.rs | 8 +- tests/blockchain.rs | 9 +- 16 files changed, 573 insertions(+), 111 deletions(-) create mode 100644 bin/darkfid2/genesis_block_localnet create mode 100644 bin/darkfid2/genesis_block_mainnet create mode 100644 bin/darkfid2/genesis_block_testnet diff --git a/bin/darkfid2/Cargo.toml b/bin/darkfid2/Cargo.toml index 0cad510c3..8cedad1e7 100644 --- a/bin/darkfid2/Cargo.toml +++ b/bin/darkfid2/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] # Darkfi -darkfi = {path = "../../", features = ["async-daemonize"]} +darkfi = {path = "../../", features = ["async-daemonize", "bs58"]} darkfi-consensus-contract = {path = "../../src/contract/consensus"} darkfi-money-contract = {path = "../../src/contract/money"} darkfi-contract-test-harness = {path = "../../src/contract/test-harness"} diff --git a/bin/darkfid2/darkfid_config.toml b/bin/darkfid2/darkfid_config.toml index b6ddccb9d..87f001cb9 100644 --- a/bin/darkfid2/darkfid_config.toml +++ b/bin/darkfid2/darkfid_config.toml @@ -7,7 +7,174 @@ ## uncommenting, or by using the command-line. # JSON-RPC listen URL -rpc_listen = "tcp://127.0.0.1:18340" +rpc_listen = "tcp://127.0.0.1:8340" + +# Blockchain network to use +network = "testnet" + +# Localnet blockchain network configuration +[localnet] +# Path to the blockchain database directory +database = "~/.local/darkfi/darkfid_blockchain_localnet" + +# Finalization threshold, denominated by number of blocks +threshold = 3 + +# PoW miner number of threads to use +pow_threads = 4 + +# PoW block production target, in seconds +pow_target = 10 + +# Epoch duration, denominated by number of blocks/slots +epoch_length = 10 + +# PoS slot duration, in seconds +slot_time = 10 + +# Whitelisted faucet addresses +faucet_pub = [] + +# Participate in the consensus protocol +consensus = true + +# Wallet address to receive consensus rewards. +# This is a dummy one so the miner can start, +# replace with your own one. +recipient = "5ZHfYpt4mpJcwBNxfEyxLzeFJUEeoePs5NQ5jVEgHrMf" + +# Skip syncing process and start node right away +skip_sync = true + +# Enable testing mode for local testing +testing_mode = true + +## Localnet sync P2P network settings +[localnet.sync_net] +# P2P accept addresses the instance listens on for inbound connections +inbound = ["tcp+tls://0.0.0.0:8242"] + +# P2P external addresses the instance advertises so other peers can +# reach us and connect to us, as long as inbound addrs are configured. +#external_addrs = [] + +# Peer nodes to manually connect to +#peers = [] + +# Seed nodes to connect to for peer discovery and/or adversising our +# own external addresses +#seeds = [] + +# Whitelisted network transports for outbound connections +#allowed_transports = [] + +# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`) +#transport_mixing = true + +# Outbound connection slots number, this many connections will be +# attempted. (This does not include manual connections) +#outbound_connections = 8 + +# Inbound connections slots number, this many active inbound connections +# will be allowed. (This does not include manual or outbound connections) +#inbound_connections = 0 + +# Manual connections retry limit, 0 for forever looping +#manual_attempt_limit = 0 + +# Outbound connection timeout (in seconds) +#outbound_connect_timeout = 10 + +# Exchange versions (handshake) timeout (in seconds) +#channel_handshake_timeout = 4 + +# Ping-pong exchange execution interval (in seconds) +#channel_heartbeat_interval = 10 + +# Allow localnet hosts +localnet = true + +# Delete a peer from hosts if they've been quarantined N times +#hosts_quarantine_limit = 50 + +# Cooling off time for peer discovery when unsuccessful +#outbound_peer_discovery_cooloff_time = 30 + +# Time between peer discovery attempts +#outbound_peer_discovery_attempt_time = 5 + +## Localnet consensus P2P network settings +[localnet.consensus_net] +# P2P accept addresses the instance listens on for inbound connections +#inbound = ["tcp+tls://0.0.0.0:8241"] + +# P2P external addresses the instance advertises so other peers can +# reach us and connect to us, as long as inbound addrs are configured. +#external_addrs = [] + +# Peer nodes to manually connect to +#peers = [] + +# Seed nodes to connect to for peer discovery and/or adversising our +# own external addresses +#seeds = [] + +# Whitelisted network transports for outbound connections +#allowed_transports = [] + +# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`) +#transport_mixing = true + +# Outbound connection slots number, this many connections will be +# attempted. (This does not include manual connections) +#outbound_connections = 8 + +# Manual connections retry limit, 0 for forever looping +#manual_attempt_limit = 0 + +# Outbound connection timeout (in seconds) +#outbound_connect_timeout = 10 + +# Exchange versions (handshake) timeout (in seconds) +#channel_handshake_timeout = 4 + +# Ping-pong exchange execution interval (in seconds) +#channel_heartbeat_interval = 10 + +# Allow localnet hosts +localnet = true + +# Delete a peer from hosts if they've been quarantined N times +#hosts_quarantine_limit = 50 + +# Cooling off time for peer discovery when unsuccessful +#outbound_peer_discovery_cooloff_time = 30 + +# Time between peer discovery attempts +#outbound_peer_discovery_attempt_time = 5 + +# Testnet blockchain network configuration +[testnet] +# Path to the blockchain database directory +database = "~/.local/darkfi/darkfid_blockchain_testnet" + +# Finalization threshold, denominated by number of blocks +threshold = 6 + +# PoW miner number of threads to use +pow_threads = 6 + +# PoW block production target, in seconds +pow_target = 90 + +# Epoch duration, denominated by number of blocks/slots +epoch_length = 10 + +# PoS slot duration, in seconds +slot_time = 90 + +# Whitelisted faucet addresses +faucet_pub = ["3ce5xa3PjuQGFtTaF7AvMJp7fGxqeGRJx7zj3LCwNCkP"] # Participate in the consensus protocol consensus = false @@ -21,34 +188,34 @@ skip_sync = false # Enable testing mode for local testing testing_mode = false -## Sync P2P network settings -[sync_net] +## Testnet sync P2P network settings +[testnet.sync_net] # P2P accept addresses the instance listens on for inbound connections # You can also use an IPv6 address -inbound = ["tcp+tls://0.0.0.0:18342"] +inbound = ["tls://0.0.0.0:8342"] # IPv6 version: -#inbound = ["tcp+tls://[::]:8342"] +#inbound = ["tls://[::]:8342"] # Combined: -#inbound = ["tcp+tls://0.0.0.0:8342", "tcp+tls://[::]:8342"] +#inbound = ["tls://0.0.0.0:8342", "tls://[::]:8342"] # P2P external addresses the instance advertises so other peers can # reach us and connect to us, as long as inbound addrs are configured. # You can also use an IPv6 address -#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8342"] +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8342"] # IPv6 version: -#external_addrs = ["tcp+tls://[ipv6 address here]:8342"] +#external_addrs = ["tls://[ipv6 address here]:8342"] # Combined: -#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8342", "tcp+tls://[ipv6 address here]:8342"] +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8342", "tls://[ipv6 address here]:8342"] # Peer nodes to manually connect to #peers = [] # Seed nodes to connect to for peer discovery and/or adversising our # own external addresses -#seeds = ["tcp+tls://lilith0.dark.fi:8342", "tcp+tls://lilith1.dark.fi:8342"] +seeds = ["tls://lilith0.dark.fi:8342", "tls://lilith1.dark.fi:8342"] # Whitelisted network transports for outbound connections -allowed_transports = ["tcp+tls"] +allowed_transports = ["tls"] # Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`) #transport_mixing = true @@ -74,36 +241,45 @@ outbound_connections = 8 #channel_heartbeat_interval = 10 # Allow localnet hosts -#localnet = false +localnet = false -## Sync P2P network settings -[consensus_net] +# Delete a peer from hosts if they've been quarantined N times +#hosts_quarantine_limit = 50 + +# Cooling off time for peer discovery when unsuccessful +#outbound_peer_discovery_cooloff_time = 30 + +# Time between peer discovery attempts +#outbound_peer_discovery_attempt_time = 5 + +## Testnet consensus P2P network settings +[testnet.consensus_net] # P2P accept addresses the instance listens on for inbound connections # You can also use an IPv6 address -#inbound = ["tcp+tls://0.0.0.0:8341"] +inbound = ["tls://0.0.0.0:8341"] # IPv6 version: -#inbound = ["tcp+tls://[::]:8341"] +#inbound = ["tls://[::]:8341"] # Combined: -#inbound = ["tcp+tls://0.0.0.0:8341", "tcp+tls://[::]:8341"] +#inbound = ["tls://0.0.0.0:8341", "tls://[::]:8341"] # P2P external addresses the instance advertises so other peers can # reach us and connect to us, as long as inbound addrs are configured. # You can also use an IPv6 address -#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8341"] +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8341"] # IPv6 version: -#external_addrs = ["tcp+tls://[ipv6 address here]:8341"] +#external_addrs = ["tls://[ipv6 address here]:8341"] # Combined: -#external_addrs = ["tcp+tls://XXX.XXX.XXX.XXX:8341", "tcp+tls://[ipv6 address here]:8341"] +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8341", "tls://[ipv6 address here]:8341"] # Peer nodes to manually connect to #peers = [] # Seed nodes to connect to for peer discovery and/or adversising our # own external addresses -#seeds = ["tcp+tls://lilith0.dark.fi:8341", "tcp+tls://lilith1.dark.fi:8341"] +seeds = ["tls://lilith0.dark.fi:8341", "tls://lilith1.dark.fi:8341"] # Whitelisted network transports for outbound connections -#allowed_transports = ["tcp+tls"] +allowed_transports = ["tls"] # Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`) #transport_mixing = true @@ -125,4 +301,172 @@ outbound_connections = 8 #channel_heartbeat_interval = 10 # Allow localnet hosts -#localnet = false +localnet = false + +# Delete a peer from hosts if they've been quarantined N times +#hosts_quarantine_limit = 50 + +# Cooling off time for peer discovery when unsuccessful +#outbound_peer_discovery_cooloff_time = 30 + +# Time between peer discovery attempts +#outbound_peer_discovery_attempt_time = 5 + +# Mainnet blockchain network configuration +[mainnet] +# Path to the blockchain database directory +database = "~/.local/darkfi/darkfid_blockchain_mainnet" + +# Finalization threshold, denominated by number of blocks +threshold = 11 + +# PoW miner number of threads to use +pow_threads = 8 + +# PoW block production target, in seconds +pow_target = 90 + +# Epoch duration, denominated by number of blocks/slots +epoch_length = 10 + +# PoS slot duration, in seconds +slot_time = 90 + +# Whitelisted faucet addresses +faucet_pub = [] + +# Participate in the consensus protocol +consensus = false + +# Wallet address to receive consensus rewards +#recipient = "YOUR_WALLET_ADDRESS_HERE" + +# Skip syncing process and start node right away +skip_sync = false + +# Enable testing mode for local testing +testing_mode = false + +## Mainnet sync P2P network settings +[mainnet.sync_net] +# P2P accept addresses the instance listens on for inbound connections +# You can also use an IPv6 address +inbound = ["tls://0.0.0.0:8442"] +# IPv6 version: +#inbound = ["tls://[::]:8442"] +# Combined: +#inbound = ["tls://0.0.0.0:8442", "tls://[::]:8442"] + +# P2P external addresses the instance advertises so other peers can +# reach us and connect to us, as long as inbound addrs are configured. +# You can also use an IPv6 address +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8442"] +# IPv6 version: +#external_addrs = ["tls://[ipv6 address here]:8442"] +# Combined: +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8442", "tls://[ipv6 address here]:8442"] + +# Peer nodes to manually connect to +#peers = [] + +# Seed nodes to connect to for peer discovery and/or adversising our +# own external addresses +seeds = ["tls://lilith0.dark.fi:8442", "tls://lilith1.dark.fi:8442"] + +# Whitelisted network transports for outbound connections +allowed_transports = ["tls"] + +# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`) +#transport_mixing = true + +# Outbound connection slots number, this many connections will be +# attempted. (This does not include manual connections) +outbound_connections = 8 + +# Inbound connections slots number, this many active inbound connections +# will be allowed. (This does not include manual or outbound connections) +#inbound_connections = 0 + +# Manual connections retry limit, 0 for forever looping +#manual_attempt_limit = 0 + +# Outbound connection timeout (in seconds) +#outbound_connect_timeout = 10 + +# Exchange versions (handshake) timeout (in seconds) +#channel_handshake_timeout = 4 + +# Ping-pong exchange execution interval (in seconds) +#channel_heartbeat_interval = 10 + +# Allow localnet hosts +localnet = false + +# Delete a peer from hosts if they've been quarantined N times +#hosts_quarantine_limit = 50 + +# Cooling off time for peer discovery when unsuccessful +#outbound_peer_discovery_cooloff_time = 30 + +# Time between peer discovery attempts +#outbound_peer_discovery_attempt_time = 5 + +## Mainnet consensus P2P network settings +[mainnet.consensus_net] +# P2P accept addresses the instance listens on for inbound connections +# You can also use an IPv6 address +inbound = ["tls://0.0.0.0:8441"] +# IPv6 version: +#inbound = ["tls://[::]:8441"] +# Combined: +#inbound = ["tls://0.0.0.0:8441", "tls://[::]:8441"] + +# P2P external addresses the instance advertises so other peers can +# reach us and connect to us, as long as inbound addrs are configured. +# You can also use an IPv6 address +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8441"] +# IPv6 version: +#external_addrs = ["tls://[ipv6 address here]:8441"] +# Combined: +#external_addrs = ["tls://XXX.XXX.XXX.XXX:8441", "tls://[ipv6 address here]:8441"] + +# Peer nodes to manually connect to +#peers = [] + +# Seed nodes to connect to for peer discovery and/or adversising our +# own external addresses +seeds = ["tls://lilith0.dark.fi:8441", "tls://lilith1.dark.fi:8441"] + +# Whitelisted network transports for outbound connections +allowed_transports = ["tls"] + +# Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`) +#transport_mixing = true + +# Outbound connection slots number, this many connections will be +# attempted. (This does not include manual connections) +#outbound_connections = 8 + +# Manual connections retry limit, 0 for forever looping +#manual_attempt_limit = 0 + +# Outbound connection timeout (in seconds) +#outbound_connect_timeout = 10 + +# Exchange versions (handshake) timeout (in seconds) +#channel_handshake_timeout = 4 + +# Ping-pong exchange execution interval (in seconds) +#channel_heartbeat_interval = 10 + +# Allow localnet hosts +localnet = false + +# Delete a peer from hosts if they've been quarantined N times +#hosts_quarantine_limit = 50 + +# Cooling off time for peer discovery when unsuccessful +#outbound_peer_discovery_cooloff_time = 30 + +# Time between peer discovery attempts +#outbound_peer_discovery_attempt_time = 5 diff --git a/bin/darkfid2/genesis_block_localnet b/bin/darkfid2/genesis_block_localnet new file mode 100644 index 000000000..98a1fa119 --- /dev/null +++ b/bin/darkfid2/genesis_block_localnet @@ -0,0 +1 @@ +3N337zZEeEFfZFBPotybXsdtKNjrAUx56QLqcr4izXLvyTVCY6E4MgUvUpEj57f6RNbkqMtZ4vqxFzWKGEnhvoMuaj1QK1fs7nRA4bY3JNrbvfzvP5UBCL9F7uTT3vpDbUiNEWwwr1UnvrzFkj7jryLLGkFDo7VMYXgovrnxMfQQczSiPVSQWGm8yXXMp9SaWeDW96r6GLbJWVc5roofVyGYYw4Cdd4vrbRMGnP7n78xWRGcmmHRebBHru2TqDSFnxYRKN3vtu1s42TkyxbbWVLrJft8ta1sq6PPPvk4idJsboEaxX9gj1DCMdvkq5gKFp5WohfhfMz7jXJod6do4xdPfutedLK3fUVYvTkRRqoSVogbzr2jdjiRPzf9WuvJyULZY7KT6Knby6aenGLdPPd3TcndiqXyWscU1LcWFX59Z7Nkp63no6rmps diff --git a/bin/darkfid2/genesis_block_mainnet b/bin/darkfid2/genesis_block_mainnet new file mode 100644 index 000000000..98a1fa119 --- /dev/null +++ b/bin/darkfid2/genesis_block_mainnet @@ -0,0 +1 @@ +3N337zZEeEFfZFBPotybXsdtKNjrAUx56QLqcr4izXLvyTVCY6E4MgUvUpEj57f6RNbkqMtZ4vqxFzWKGEnhvoMuaj1QK1fs7nRA4bY3JNrbvfzvP5UBCL9F7uTT3vpDbUiNEWwwr1UnvrzFkj7jryLLGkFDo7VMYXgovrnxMfQQczSiPVSQWGm8yXXMp9SaWeDW96r6GLbJWVc5roofVyGYYw4Cdd4vrbRMGnP7n78xWRGcmmHRebBHru2TqDSFnxYRKN3vtu1s42TkyxbbWVLrJft8ta1sq6PPPvk4idJsboEaxX9gj1DCMdvkq5gKFp5WohfhfMz7jXJod6do4xdPfutedLK3fUVYvTkRRqoSVogbzr2jdjiRPzf9WuvJyULZY7KT6Knby6aenGLdPPd3TcndiqXyWscU1LcWFX59Z7Nkp63no6rmps diff --git a/bin/darkfid2/genesis_block_testnet b/bin/darkfid2/genesis_block_testnet new file mode 100644 index 000000000..98a1fa119 --- /dev/null +++ b/bin/darkfid2/genesis_block_testnet @@ -0,0 +1 @@ +3N337zZEeEFfZFBPotybXsdtKNjrAUx56QLqcr4izXLvyTVCY6E4MgUvUpEj57f6RNbkqMtZ4vqxFzWKGEnhvoMuaj1QK1fs7nRA4bY3JNrbvfzvP5UBCL9F7uTT3vpDbUiNEWwwr1UnvrzFkj7jryLLGkFDo7VMYXgovrnxMfQQczSiPVSQWGm8yXXMp9SaWeDW96r6GLbJWVc5roofVyGYYw4Cdd4vrbRMGnP7n78xWRGcmmHRebBHru2TqDSFnxYRKN3vtu1s42TkyxbbWVLrJft8ta1sq6PPPvk4idJsboEaxX9gj1DCMdvkq5gKFp5WohfhfMz7jXJod6do4xdPfutedLK3fUVYvTkRRqoSVogbzr2jdjiRPzf9WuvJyULZY7KT6Knby6aenGLdPPd3TcndiqXyWscU1LcWFX59Z7Nkp63no6rmps diff --git a/bin/darkfid2/src/main.rs b/bin/darkfid2/src/main.rs index 6d79d3c2d..987a12664 100644 --- a/bin/darkfid2/src/main.rs +++ b/bin/darkfid2/src/main.rs @@ -37,12 +37,12 @@ use darkfi::{ server::{listen_and_serve, RequestHandler}, }, system::{StoppableTask, StoppableTaskPtr}, - util::time::TimeKeeper, + util::{path::expand_path, time::TimeKeeper}, validator::{utils::genesis_txs_total, Validator, ValidatorConfig, ValidatorPtr}, Error, Result, }; -use darkfi_contract_test_harness::vks; use darkfi_sdk::crypto::PublicKey; +use darkfi_serial::deserialize; #[cfg(test)] mod tests; @@ -68,6 +68,12 @@ use utils::{spawn_consensus_p2p, spawn_sync_p2p}; const CONFIG_FILE: &str = "darkfid_config.toml"; const CONFIG_FILE_CONTENTS: &str = include_str!("../darkfid_config.toml"); +/// Note: +/// If you change these don't forget to remove their corresponding database folder, +/// since if it already has a genesis block, provided one is ignored. +const GENESIS_BLOCK_LOCALNET: &str = include_str!("../genesis_block_localnet"); +const GENESIS_BLOCK_TESTNET: &str = include_str!("../genesis_block_testnet"); +const GENESIS_BLOCK_MAINNET: &str = include_str!("../genesis_block_mainnet"); #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)] #[serde(default)] @@ -81,29 +87,21 @@ struct Args { /// JSON-RPC listen URL rpc_listen: Url, - #[structopt(long)] - /// Participate in the consensus protocol - consensus: bool, + #[structopt(long, default_value = "testnet")] + /// Blockchain network to use + network: String, - #[structopt(long)] - /// Wallet address to receive consensus rewards - recipient: Option, - - #[structopt(long)] - /// Skip syncing process and start node right away - skip_sync: bool, - - /// Syncing network settings #[structopt(flatten)] - sync_net: SettingsOpt, + /// Localnet blockchain network configuration + localnet: BlockchainNetwork, - /// Consensus network settings #[structopt(flatten)] - consensus_net: SettingsOpt, + /// Testnet blockchain network configuration + testnet: BlockchainNetwork, - #[structopt(long)] - /// Enable testing mode for local testing - testing_mode: bool, + #[structopt(flatten)] + /// Mainnet blockchain network configuration + mainnet: BlockchainNetwork, #[structopt(short, long)] /// Set log file to ouput into @@ -114,6 +112,64 @@ struct Args { verbose: u8, } +/// Defines a blockchain network configuration. +/// Default values correspond to a local network. +#[derive(Clone, Debug, serde::Deserialize, structopt::StructOpt, structopt_toml::StructOptToml)] +#[structopt()] +pub struct BlockchainNetwork { + #[structopt(long, default_value = "~/.local/darkfi/darkfid_blockchain_localnet")] + /// Path to blockchain database + pub database: String, + + #[structopt(long, default_value = "3")] + /// Finalization threshold, denominated by number of blocks + pub threshold: usize, + + #[structopt(long, default_value = "4")] + /// PoW miner number of threads to use + pub pow_threads: usize, + + #[structopt(long, default_value = "10")] + /// PoW block production target, in seconds + pub pow_target: usize, + + #[structopt(long, default_value = "10")] + /// Epoch duration, denominated by number of blocks/slots + pub epoch_length: u64, + + #[structopt(long, default_value = "10")] + /// PoS slot duration, in seconds + pub slot_time: u64, + + #[structopt(long)] + /// Whitelisted faucet public key (repeatable flag) + pub faucet_pub: Vec, + + #[structopt(long)] + /// Participate in the consensus protocol + pub consensus: bool, + + #[structopt(long)] + /// Wallet address to receive consensus rewards + pub recipient: Option, + + #[structopt(long)] + /// Skip syncing process and start node right away + pub skip_sync: bool, + + #[structopt(long)] + /// Enable testing mode for local testing + pub testing_mode: bool, + + /// Syncing network settings + #[structopt(flatten)] + pub sync_net: SettingsOpt, + + /// Consensus network settings + #[structopt(flatten)] + pub consensus_net: SettingsOpt, +} + /// Daemon structure pub struct Darkfid { /// Syncing P2P network pointer @@ -149,30 +205,46 @@ async_daemonize!(realmain); async fn realmain(args: Args, ex: Arc>) -> Result<()> { info!(target: "darkfid", "Initializing DarkFi node..."); - if args.testing_mode { + // Grab blockchain network configuration + let (blockchain_config, genesis_block) = match args.network.as_str() { + "localnet" => (args.localnet, GENESIS_BLOCK_LOCALNET), + "testnet" => (args.testnet, GENESIS_BLOCK_TESTNET), + "mainnet" => (args.mainnet, GENESIS_BLOCK_MAINNET), + _ => { + error!("Unsupported chain `{}`", args.network); + return Err(Error::UnsupportedChain) + } + }; + + if blockchain_config.testing_mode { info!(target: "darkfid", "Node is configured to run in testing mode!"); } - // NOTE: everything is dummy for now - // FIXME: The VKS should only ever have to be generated on initial run. - // Do not use the precompiles for actual production code. + // Parse the genesis block + let bytes = bs58::decode(&genesis_block.trim()).into_vec()?; + let genesis_block: BlockInfo = deserialize(&bytes)?; + // Initialize or open sled database - let sled_db = sled::Config::new().temporary(true).open()?; - let (_, vks) = vks::read_or_gen_vks_and_pks()?; - vks::inject(&sled_db, &vks)?; + let db_path = expand_path(&blockchain_config.database)?; + let sled_db = sled::open(&db_path)?; // Initialize validator configuration - let genesis_block = BlockInfo::default(); let genesis_txs_total = genesis_txs_total(&genesis_block.txs)?; - let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0); - // TODO: add miner threads arg + let time_keeper = TimeKeeper::new( + genesis_block.header.timestamp, + blockchain_config.epoch_length, + blockchain_config.slot_time, + 0, + ); let config = ValidatorConfig::new( time_keeper, - Some(40), + blockchain_config.threshold, + blockchain_config.pow_threads, + blockchain_config.pow_target, genesis_block, genesis_txs_total, vec![], - args.testing_mode, + blockchain_config.testing_mode, ); // Initialize validator @@ -182,19 +254,25 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { let mut subscribers = HashMap::new(); subscribers.insert("blocks", JsonSubscriber::new("blockchain.subscribe_blocks")); subscribers.insert("txs", JsonSubscriber::new("blockchain.subscribe_txs")); - if args.consensus { + if blockchain_config.consensus { subscribers.insert("proposals", JsonSubscriber::new("blockchain.subscribe_proposals")); } // Initialize syncing P2P network let sync_p2p = - spawn_sync_p2p(&args.sync_net.into(), &validator, &subscribers, ex.clone()).await; + spawn_sync_p2p(&blockchain_config.sync_net.into(), &validator, &subscribers, ex.clone()) + .await; // Initialize consensus P2P network - let consensus_p2p = if args.consensus { + let consensus_p2p = if blockchain_config.consensus { Some( - spawn_consensus_p2p(&args.consensus_net.into(), &validator, &subscribers, ex.clone()) - .await, + spawn_consensus_p2p( + &blockchain_config.consensus_net.into(), + &validator, + &subscribers, + ex.clone(), + ) + .await, ) } else { None @@ -230,7 +308,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { sync_p2p.clone().start().await?; // Consensus protocol - if args.consensus { + if blockchain_config.consensus { info!(target: "darkfid", "Starting consensus P2P network"); let consensus_p2p = consensus_p2p.clone().unwrap(); consensus_p2p.clone().start().await?; @@ -239,7 +317,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { } // Sync blockchain - if !args.skip_sync { + if !blockchain_config.skip_sync { sync_task(&darkfid).await?; } else { darkfid.validator.write().await.synced = true; @@ -249,13 +327,13 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { darkfid.validator.write().await.purge_pending_txs().await?; // Consensus protocol - let (consensus_task, consensus_sender) = if args.consensus { + let (consensus_task, consensus_sender) = if blockchain_config.consensus { info!(target: "darkfid", "Starting consensus protocol task"); // Grab rewards recipient public key(address) - if args.recipient.is_none() { + if blockchain_config.recipient.is_none() { return Err(Error::ParseFailed("Recipient address missing")) } - let recipient = match PublicKey::from_str(&args.recipient.unwrap()) { + let recipient = match PublicKey::from_str(&blockchain_config.recipient.unwrap()) { Ok(address) => address, Err(_) => return Err(Error::InvalidAddress), }; @@ -291,7 +369,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { info!(target: "darkfid", "Stopping syncing P2P network..."); sync_p2p.stop().await; - if args.consensus { + if blockchain_config.consensus { info!(target: "darkfid", "Stopping consensus P2P network..."); consensus_p2p.unwrap().stop().await; diff --git a/bin/darkfid2/src/tests/forks.rs b/bin/darkfid2/src/tests/forks.rs index b2cf28014..6e11eb70e 100644 --- a/bin/darkfid2/src/tests/forks.rs +++ b/bin/darkfid2/src/tests/forks.rs @@ -30,7 +30,7 @@ fn forks() -> Result<()> { // Create a temporary blockchain and a PoW module let blockchain = Blockchain::new(&sled::Config::new().temporary(true).open()?)?; - let module = PoWModule::new(blockchain.clone(), None, Some(90))?; + let module = PoWModule::new(blockchain.clone(), 2, 90)?; // Create a fork let fork = Fork::new(&blockchain, module)?; diff --git a/bin/darkfid2/src/tests/harness.rs b/bin/darkfid2/src/tests/harness.rs index cf2c4a5c2..b1318f261 100644 --- a/bin/darkfid2/src/tests/harness.rs +++ b/bin/darkfid2/src/tests/harness.rs @@ -42,7 +42,8 @@ use crate::{ }; pub struct HarnessConfig { - pub pow_target: Option, + pub pow_threads: usize, + pub pow_target: usize, pub testing_node: bool, pub alice_initial: u64, pub bob_initial: u64, @@ -82,6 +83,8 @@ impl Harness { let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0); let validator_config = ValidatorConfig::new( time_keeper, + 3, + config.pow_threads, config.pow_target, genesis_block, genesis_txs_total, @@ -136,8 +139,21 @@ impl Harness { let alice = &self.alice.validator.read().await; let bob = &self.bob.validator.read().await; - alice.validate_blockchain(genesis_txs_total, vec![], self.config.pow_target).await?; - bob.validate_blockchain(genesis_txs_total, vec![], self.config.pow_target).await?; + alice + .validate_blockchain( + genesis_txs_total, + vec![], + self.config.pow_threads, + self.config.pow_target, + ) + .await?; + bob.validate_blockchain( + genesis_txs_total, + vec![], + self.config.pow_threads, + self.config.pow_target, + ) + .await?; let alice_blockchain_len = alice.blockchain.len(); assert_eq!(alice_blockchain_len, bob.blockchain.len()); diff --git a/bin/darkfid2/src/tests/mod.rs b/bin/darkfid2/src/tests/mod.rs index 26a941b7c..f918dbe0c 100644 --- a/bin/darkfid2/src/tests/mod.rs +++ b/bin/darkfid2/src/tests/mod.rs @@ -32,9 +32,15 @@ async fn sync_pos_blocks_real(ex: Arc>) -> Result<()> { init_logger(); // Initialize harness in testing mode - let pow_target = Some(90); - let config = - HarnessConfig { testing_node: true, pow_target, alice_initial: 1000, bob_initial: 500 }; + let pow_threads = 2; + let pow_target = 90; + let config = HarnessConfig { + pow_threads, + pow_target, + testing_node: true, + alice_initial: 1000, + bob_initial: 500, + }; let th = Harness::new(config, &ex).await?; // Retrieve genesis block @@ -67,7 +73,7 @@ async fn sync_pos_blocks_real(ex: Arc>) -> Result<()> { let genesis_txs_total = th.config.alice_initial + th.config.bob_initial; let alice = &th.alice.validator.read().await; let charlie = &charlie.validator.read().await; - charlie.validate_blockchain(genesis_txs_total, vec![], pow_target).await?; + charlie.validate_blockchain(genesis_txs_total, vec![], pow_threads, pow_target).await?; assert_eq!(alice.blockchain.len(), charlie.blockchain.len()); assert_eq!(alice.blockchain.slots.len(), charlie.blockchain.slots.len()); diff --git a/src/contract/test-harness/src/lib.rs b/src/contract/test-harness/src/lib.rs index 8f421b10e..5cdfd937c 100644 --- a/src/contract/test-harness/src/lib.rs +++ b/src/contract/test-harness/src/lib.rs @@ -157,7 +157,9 @@ impl Wallet { let time_keeper = TimeKeeper::new(genesis_block.header.timestamp, 10, 90, 0); let config = ValidatorConfig::new( time_keeper, - Some(90), + 3, + 1, + 90, genesis_block.clone(), 0, faucet_pubkeys.to_vec(), diff --git a/src/net/settings.rs b/src/net/settings.rs index 75787f3c7..325de2022 100644 --- a/src/net/settings.rs +++ b/src/net/settings.rs @@ -162,6 +162,7 @@ pub struct SettingsOpt { #[structopt(long = "transports")] pub allowed_transports: Vec, + /// Allow transport mixing (e.g. Tor would be allowed to connect to `tcp://`) #[structopt(long)] pub transport_mixing: Option, @@ -170,12 +171,15 @@ pub struct SettingsOpt { #[structopt(long)] pub localnet: bool, + /// Delete a peer from hosts if they've been quarantined N times #[structopt(skip)] pub hosts_quarantine_limit: Option, + /// Cooling off time for peer discovery when unsuccessful #[structopt(skip)] pub outbound_peer_discovery_cooloff_time: Option, + /// Time between peer discovery attempts #[structopt(skip)] pub outbound_peer_discovery_attempt_time: Option, } diff --git a/src/validator/consensus.rs b/src/validator/consensus.rs index b692bc4c3..5a9649cd6 100644 --- a/src/validator/consensus.rs +++ b/src/validator/consensus.rs @@ -38,8 +38,6 @@ use crate::{ // Consensus configuration /// Block/proposal maximum transactions pub const TXS_CAP: usize = 50; -/// Fork size(length) after which it can be finalized -const FINALIZATION_SECURITY_THRESSHOLD: usize = 3; /// This struct represents the information required by the consensus algorithm pub struct Consensus { @@ -47,6 +45,8 @@ pub struct Consensus { pub blockchain: Blockchain, /// Helper structure to calculate time related operations pub time_keeper: TimeKeeper, + /// Fork size(length) after which it can be finalized + pub finalization_threshold: usize, /// Node is participating to consensus pub participating: bool, /// Last slot node check for finalization @@ -64,13 +64,16 @@ impl Consensus { pub fn new( blockchain: Blockchain, time_keeper: TimeKeeper, - pow_target: Option, + finalization_threshold: usize, + pow_threads: usize, + pow_target: usize, testing_mode: bool, ) -> Result { - let module = PoWModule::new(blockchain.clone(), None, pow_target)?; + let module = PoWModule::new(blockchain.clone(), pow_threads, pow_target)?; Ok(Self { blockchain, time_keeper, + finalization_threshold, participating: false, checked_finalization: 0, forks: vec![], @@ -393,7 +396,7 @@ impl Consensus { } /// Consensus finalization logic: - /// - If the current best fork has reached greater length than the security thresshold, and + /// - If the current best fork has reached greater length than the security threshold, and /// no other fork exist with same rank, all proposals excluding the last one in that fork // can be finalized (append to canonical blockchain). /// When best fork can be finalized, blocks(proposals) should be appended to canonical, excluding the @@ -417,7 +420,7 @@ impl Consensus { // Check its length let length = fork.proposals.len(); - if length < FINALIZATION_SECURITY_THRESSHOLD { + if length < self.finalization_threshold { debug!(target: "validator::consensus::finalization", "Nothing to finalize yet, best fork size: {}", length); return Ok(vec![]) } diff --git a/src/validator/mod.rs b/src/validator/mod.rs index e6c8ffac9..d1f4f52af 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -70,8 +70,12 @@ pub mod float_10; pub struct ValidatorConfig { /// Helper structure to calculate time related operations pub time_keeper: TimeKeeper, + /// Currently configured finalization security threshold + pub finalization_threshold: usize, + /// Currently configured PoW miner number of threads to use + pub pow_threads: usize, /// Currently configured PoW target - pub pow_target: Option, + pub pow_target: usize, /// Genesis block pub genesis_block: BlockInfo, /// Total amount of minted tokens in genesis block @@ -83,9 +87,12 @@ pub struct ValidatorConfig { } impl ValidatorConfig { + #[allow(clippy::too_many_arguments)] pub fn new( time_keeper: TimeKeeper, - pow_target: Option, + finalization_threshold: usize, + pow_threads: usize, + pow_target: usize, genesis_block: BlockInfo, genesis_txs_total: u64, faucet_pubkeys: Vec, @@ -93,6 +100,8 @@ impl ValidatorConfig { ) -> Self { Self { time_keeper, + finalization_threshold, + pow_threads, pow_target, genesis_block, genesis_txs_total, @@ -150,6 +159,8 @@ impl Validator { let consensus = Consensus::new( blockchain.clone(), config.time_keeper, + config.finalization_threshold, + config.pow_threads, config.pow_target, testing_mode, )?; @@ -527,7 +538,8 @@ impl Validator { &self, genesis_txs_total: u64, faucet_pubkeys: Vec, - pow_target: Option, + pow_threads: usize, + pow_target: usize, ) -> Result<()> { let blocks = self.blockchain.get_all()?; @@ -546,7 +558,7 @@ impl Validator { // Create a time keeper and a PoW module to validate each block let mut time_keeper = self.consensus.time_keeper.clone(); - let mut module = PoWModule::new(blockchain.clone(), None, pow_target)?; + let mut module = PoWModule::new(blockchain.clone(), pow_threads, pow_target)?; // Deploy native wasm contracts deploy_native_contracts(&overlay, &time_keeper, &faucet_pubkeys)?; diff --git a/src/validator/pow.rs b/src/validator/pow.rs index 64e13e565..155ffa5f1 100644 --- a/src/validator/pow.rs +++ b/src/validator/pow.rs @@ -45,8 +45,6 @@ use crate::{ }; // Note: We have combined some constants for better performance. -/// Default number of threads to use for hashing -const N_THREADS: usize = 4; /// Amount of max items(blocks) to use for next difficulty calculation. /// Must be >= 2 and == BUF_SIZE - DIFFICULTY_LAG. const DIFFICULTY_WINDOW: usize = 720; @@ -71,9 +69,6 @@ const RETAINED: usize = 600; const CUT_BEGIN: usize = 60; /// Already known cutoff end index for this config const CUT_END: usize = 660; -/// Default target block time, in seconds -const DIFFICULTY_TARGET: usize = 20; -// TODO: maybe add more difficulty targets (testnet, mainnet, etc) /// How many most recent blocks to use to verify new blocks' timestamp const BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW: usize = 60; /// Time limit in the future of what blocks can be @@ -82,11 +77,9 @@ const BLOCK_FUTURE_TIME_LIMIT: u64 = 60 * 60 * 2; /// This struct represents the information required by the PoW algorithm #[derive(Clone)] pub struct PoWModule { - /// Number of threads to use for hashing, - /// if None provided will use N_THREADS + /// Number of threads to use for hashing pub threads: usize, - /// Target block time, in seconds, - /// if None provided will use DIFFICULTY_TARGET + /// Target block time, in seconds pub target: usize, /// Latest block timestamps ringbuffer pub timestamps: RingBuffer, @@ -100,14 +93,7 @@ pub struct PoWModule { } impl PoWModule { - pub fn new( - blockchain: Blockchain, - threads: Option, - target: Option, - ) -> Result { - let threads = if let Some(t) = threads { t } else { N_THREADS }; - let target = if let Some(t) = target { t } else { DIFFICULTY_TARGET }; - + pub fn new(blockchain: Blockchain, threads: usize, target: usize) -> Result { // Retrieving last BUF_ZISE difficulties from blockchain to build the buffers let mut timestamps = RingBuffer::::new(); let mut difficulties = RingBuffer::::new(); @@ -390,13 +376,15 @@ mod tests { use super::PoWModule; + const DEFAULT_TEST_THREADS: usize = 2; const DEFAULT_TEST_DIFFICULTY_TARGET: usize = 120; #[test] fn test_wide_difficulty() -> Result<()> { let sled_db = sled::Config::new().temporary(true).open()?; let blockchain = Blockchain::new(&sled_db)?; - let mut module = PoWModule::new(blockchain, None, Some(DEFAULT_TEST_DIFFICULTY_TARGET))?; + let mut module = + PoWModule::new(blockchain, DEFAULT_TEST_THREADS, DEFAULT_TEST_DIFFICULTY_TARGET)?; let output = Command::new("./script/research/pow/gen_wide_data.py").output().unwrap(); let reader = Cursor::new(output.stdout); @@ -429,7 +417,8 @@ mod tests { // Default setup let sled_db = sled::Config::new().temporary(true).open()?; let blockchain = Blockchain::new(&sled_db)?; - let module = PoWModule::new(blockchain, None, Some(DEFAULT_TEST_DIFFICULTY_TARGET))?; + let module = + PoWModule::new(blockchain, DEFAULT_TEST_THREADS, DEFAULT_TEST_DIFFICULTY_TARGET)?; let (_, recvr) = smol::channel::bounded(1); let genesis_block = BlockInfo::default(); diff --git a/src/validator/validation.rs b/src/validator/validation.rs index cc2a69f68..0018366bf 100644 --- a/src/validator/validation.rs +++ b/src/validator/validation.rs @@ -333,9 +333,13 @@ pub fn validate_pos_slot( /// A blockchain is considered valid, when every block is valid, /// based on validate_block checks. /// Be careful as this will try to load everything in memory. -pub fn validate_blockchain(blockchain: &Blockchain, pow_target: Option) -> Result<()> { +pub fn validate_blockchain( + blockchain: &Blockchain, + pow_threads: usize, + pow_target: usize, +) -> Result<()> { // Generate a PoW module - let mut module = PoWModule::new(blockchain.clone(), None, pow_target)?; + let mut module = PoWModule::new(blockchain.clone(), pow_threads, pow_target)?; // We use block order store here so we have all blocks in order let blocks = blockchain.order.get_all()?; for (index, block) in blocks[1..].iter().enumerate() { diff --git a/tests/blockchain.rs b/tests/blockchain.rs index d8b4ed33a..4a3dca357 100644 --- a/tests/blockchain.rs +++ b/tests/blockchain.rs @@ -30,7 +30,8 @@ use darkfi_sdk::{ pasta::{group::ff::Field, pallas}, }; -const POW_TARGET: Option = Some(10); +const POW_THREADS: usize = 1; +const POW_TARGET: usize = 10; struct Node { blockchain: Blockchain, @@ -40,7 +41,7 @@ struct Node { impl Node { fn new() -> Result { let blockchain = Blockchain::new(&sled::Config::new().temporary(true).open()?)?; - let module = PoWModule::new(blockchain.clone(), None, POW_TARGET)?; + let module = PoWModule::new(blockchain.clone(), POW_THREADS, POW_TARGET)?; Ok(Self { blockchain, module }) } } @@ -63,8 +64,8 @@ impl Harness { } fn validate_chains(&self) -> Result<()> { - validate_blockchain(&self.alice.blockchain, POW_TARGET)?; - validate_blockchain(&self.bob.blockchain, POW_TARGET)?; + validate_blockchain(&self.alice.blockchain, POW_THREADS, POW_TARGET)?; + validate_blockchain(&self.bob.blockchain, POW_THREADS, POW_TARGET)?; assert_eq!(self.alice.blockchain.len(), self.bob.blockchain.len());