diff --git a/bin/darkfid/darkfid_config.toml b/bin/darkfid/darkfid_config.toml index 36aed3f5b..e43c49788 100644 --- a/bin/darkfid/darkfid_config.toml +++ b/bin/darkfid/darkfid_config.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8340" # Participate in the consensus protocol consensus = false +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol #consensus_p2p_accept = ["tls://127.0.0.1:8341"] diff --git a/bin/darkfid/src/main.rs b/bin/darkfid/src/main.rs index d9b85d9e4..085a71fec 100644 --- a/bin/darkfid/src/main.rs +++ b/bin/darkfid/src/main.rs @@ -75,6 +75,10 @@ struct Args { /// Participate in consensus consensus: bool, + #[structopt(long)] + /// Enable single-node mode for local testing + single_node: bool, + #[structopt(long, default_value = "~/.config/darkfi/darkfid_wallet.db")] /// Path to wallet database wallet_path: String, @@ -327,6 +331,10 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { faucet_pubkeys.push(pk); } + if args.single_node { + info!("Node is configured to tun in single-node mode!"); + } + // Initialize validator state let state = ValidatorState::new( &sled_db, @@ -337,6 +345,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { wallet.clone(), faucet_pubkeys, args.consensus, + args.single_node, ) .await?; diff --git a/bin/faucetd/src/main.rs b/bin/faucetd/src/main.rs index 22ab72fa4..51f2d22da 100644 --- a/bin/faucetd/src/main.rs +++ b/bin/faucetd/src/main.rs @@ -574,6 +574,7 @@ async fn realmain(args: Args, ex: Arc>) -> Result<()> { wallet.clone(), faucet_pubkeys, false, + false, ) .await?; diff --git a/contrib/localnet/darkfid-five-nodes/darkfid0.toml b/contrib/localnet/darkfid-five-nodes/darkfid0.toml index f23df3384..6ad483b60 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid0.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid0.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8340" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8341"] diff --git a/contrib/localnet/darkfid-five-nodes/darkfid1.toml b/contrib/localnet/darkfid-five-nodes/darkfid1.toml index 77ec1751f..6c3ad1db7 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid1.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid1.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8440" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8441"] diff --git a/contrib/localnet/darkfid-five-nodes/darkfid2.toml b/contrib/localnet/darkfid-five-nodes/darkfid2.toml index 1dc344fa3..f440b47be 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid2.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid2.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8540" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8541"] diff --git a/contrib/localnet/darkfid-five-nodes/darkfid3.toml b/contrib/localnet/darkfid-five-nodes/darkfid3.toml index b34cbcb72..6cb6056f9 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid3.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid3.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8640" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8641"] diff --git a/contrib/localnet/darkfid-five-nodes/darkfid4.toml b/contrib/localnet/darkfid-five-nodes/darkfid4.toml index a0883e4d9..0860032ec 100644 --- a/contrib/localnet/darkfid-five-nodes/darkfid4.toml +++ b/contrib/localnet/darkfid-five-nodes/darkfid4.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8740" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8741"] diff --git a/contrib/localnet/darkfid-single-node/darkfid0.toml b/contrib/localnet/darkfid-single-node/darkfid0.toml index 166ecdd15..8f35bd52e 100644 --- a/contrib/localnet/darkfid-single-node/darkfid0.toml +++ b/contrib/localnet/darkfid-single-node/darkfid0.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8340" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = true + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8341"] diff --git a/contrib/localnet/darkfid-small/darkfid0.toml b/contrib/localnet/darkfid-small/darkfid0.toml index f23df3384..6ad483b60 100644 --- a/contrib/localnet/darkfid-small/darkfid0.toml +++ b/contrib/localnet/darkfid-small/darkfid0.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8340" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8341"] diff --git a/contrib/localnet/darkfid-small/darkfid1.toml b/contrib/localnet/darkfid-small/darkfid1.toml index 77ec1751f..6c3ad1db7 100644 --- a/contrib/localnet/darkfid-small/darkfid1.toml +++ b/contrib/localnet/darkfid-small/darkfid1.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8440" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8441"] diff --git a/contrib/localnet/darkfid-small/darkfid2.toml b/contrib/localnet/darkfid-small/darkfid2.toml index 6cc77fa57..95b841dc7 100644 --- a/contrib/localnet/darkfid-small/darkfid2.toml +++ b/contrib/localnet/darkfid-small/darkfid2.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8540" # Participate in the consensus protocol consensus = false +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol #consensus_p2p_accept = ["tcp://127.0.0.1:8541"] diff --git a/contrib/localnet/darkfid/darkfid0.toml b/contrib/localnet/darkfid/darkfid0.toml index 2f5fd17c4..e528f0190 100644 --- a/contrib/localnet/darkfid/darkfid0.toml +++ b/contrib/localnet/darkfid/darkfid0.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8340" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8341"] diff --git a/contrib/localnet/darkfid/darkfid1.toml b/contrib/localnet/darkfid/darkfid1.toml index 98a85d144..96cdbdb83 100644 --- a/contrib/localnet/darkfid/darkfid1.toml +++ b/contrib/localnet/darkfid/darkfid1.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8440" # Participate in the consensus protocol consensus = true +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol consensus_p2p_accept = ["tcp://127.0.0.1:8441"] diff --git a/contrib/localnet/darkfid/darkfid2.toml b/contrib/localnet/darkfid/darkfid2.toml index 7492aea55..daa589477 100644 --- a/contrib/localnet/darkfid/darkfid2.toml +++ b/contrib/localnet/darkfid/darkfid2.toml @@ -24,6 +24,9 @@ rpc_listen = "tcp://127.0.0.1:8540" # Participate in the consensus protocol consensus = false +# Enable single-node mode for local testing +single_node = false + # P2P accept addresses for the consensus protocol #consensus_p2p_accept = ["tcp://127.0.0.1:8541"] diff --git a/script/research/nodes-tool/src/main.rs b/script/research/nodes-tool/src/main.rs index 0b6260b53..3964e3697 100644 --- a/script/research/nodes-tool/src/main.rs +++ b/script/research/nodes-tool/src/main.rs @@ -328,6 +328,7 @@ async fn generate(localnet: &str, name: &str) -> Result<()> { wallet, vec![], false, + false, ) .await?; let info = StateInfo::new(&*state.read().await); diff --git a/src/consensus/state.rs b/src/consensus/state.rs index 0a0d8d2b1..20e925de9 100644 --- a/src/consensus/state.rs +++ b/src/consensus/state.rs @@ -53,6 +53,8 @@ pub struct ConsensusState { pub genesis_block: blake3::Hash, /// Total sum of initial staking coins pub initial_distribution: u64, + /// Flag to enable single-node mode + pub single_node: bool, /// Slot the network was bootstrapped pub bootstrap_slot: u64, /// Participating start slot @@ -91,6 +93,7 @@ impl ConsensusState { genesis_ts: Timestamp, genesis_data: blake3::Hash, initial_distribution: u64, + single_node: bool, ) -> Result { let genesis_block = Block::genesis_block(genesis_ts, genesis_data).blockhash(); Ok(Self { @@ -99,6 +102,7 @@ impl ConsensusState { genesis_ts, genesis_block, initial_distribution, + single_node, bootstrap_slot: 0, participating: None, proposing: false, @@ -303,9 +307,10 @@ impl ConsensusState { // Temporarily, we compete with fixed stake. // This stake should be based on how many nodes we want to run, and they all // must sum to initial distribution total coins. - //let stake = self.initial_distribution; + let stake = self.initial_distribution; + //let stake = 200; let coin = LeadCoin::new( - 200, + stake, slot, epoch_secrets.secret_keys[0].inner(), epoch_secrets.merkle_roots[0], @@ -453,6 +458,12 @@ impl ConsensusState { self.forks[fork_index as usize].sequence.last().unwrap().coins.clone() }; + // If on single-node mode, node always proposes by extending the + // single fork it holds. + if self.single_node { + return (true, fork_index, 0) + } + let mut won = false; let mut highest_stake = 0; let mut highest_stake_idx = 0; diff --git a/src/consensus/validator.rs b/src/consensus/validator.rs index 44bd0a606..f86f180f0 100644 --- a/src/consensus/validator.rs +++ b/src/consensus/validator.rs @@ -86,6 +86,8 @@ pub struct ValidatorState { pub verifying_keys: VerifyingKeyMap, /// Wallet interface pub wallet: WalletPtr, + /// Flag to enable single-node mode + pub single_node: bool, } impl ValidatorState { @@ -98,6 +100,7 @@ impl ValidatorState { wallet: WalletPtr, faucet_pubkeys: Vec, enable_participation: bool, + single_node: bool, ) -> Result { debug!(target: "consensus::validator", "Initializing ValidatorState"); @@ -130,6 +133,7 @@ impl ValidatorState { genesis_ts, genesis_data, initial_distribution, + single_node, )?; let unconfirmed_txs = vec![]; @@ -222,6 +226,7 @@ impl ValidatorState { subscribers, verifying_keys: Arc::new(RwLock::new(verifying_keys)), wallet, + single_node, })); Ok(state) @@ -458,59 +463,64 @@ impl ValidatorState { return Err(Error::ProposalHeadersMissmatchError) } - // Verify proposal leader proof - if let Err(e) = lf.proof.verify(&self.lead_verifying_key, &lf.public_inputs) { - error!(target: "consensus::validator", "receive_proposal(): Error during leader proof verification: {}", e); - return Err(Error::LeaderProofVerification) - }; - info!(target: "consensus::validator", "receive_proposal(): Leader proof verified successfully!"); + // Ignore node coin validations if we oporate in single-node mode + if !self.single_node { + // Verify proposal leader proof + if let Err(e) = lf.proof.verify(&self.lead_verifying_key, &lf.public_inputs) { + error!(target: "consensus::validator", "receive_proposal(): Error during leader proof verification: {}", e); + return Err(Error::LeaderProofVerification) + }; + info!(target: "consensus::validator", "receive_proposal(): Leader proof verified successfully!"); - // Validate proposal public value against coin creation slot checkpoint - let (mu_y, mu_rho) = - LeadCoin::election_seeds_u64(self.consensus.get_eta(), self.consensus.current_slot()); - // y - let prop_mu_y = lf.public_inputs[constants::PI_MU_Y_INDEX]; - - if mu_y != prop_mu_y { - error!( - target: "consensus::validator", - "receive_proposal(): Failed to verify mu_y: {:?}, proposed: {:?}", - mu_y, prop_mu_y + // Validate proposal public value against coin creation slot checkpoint + let (mu_y, mu_rho) = LeadCoin::election_seeds_u64( + self.consensus.get_eta(), + self.consensus.current_slot(), ); - return Err(Error::ProposalPublicValuesMismatched) - } + // y + let prop_mu_y = lf.public_inputs[constants::PI_MU_Y_INDEX]; - // rho - let prop_mu_rho = lf.public_inputs[constants::PI_MU_RHO_INDEX]; + if mu_y != prop_mu_y { + error!( + target: "consensus::validator", + "receive_proposal(): Failed to verify mu_y: {:?}, proposed: {:?}", + mu_y, prop_mu_y + ); + return Err(Error::ProposalPublicValuesMismatched) + } - if mu_rho != prop_mu_rho { - error!( - target: "consensus::validator", - "receive_proposal(): Failed to verify mu_rho: {:?}, proposed: {:?}", - mu_rho, prop_mu_rho - ); - return Err(Error::ProposalPublicValuesMismatched) - } + // rho + let prop_mu_rho = lf.public_inputs[constants::PI_MU_RHO_INDEX]; - // Validate proposal coin sigmas against current slot checkpoint - let checkpoint = self.consensus.get_slot_checkpoint(current)?; - // sigma1 - let prop_sigma1 = lf.public_inputs[constants::PI_SIGMA1_INDEX]; - if checkpoint.sigma1 != prop_sigma1 { - error!( - target: "consensus::validator", - "receive_proposal(): Failed to verify public value sigma1: {:?}, to proposed: {:?}", - checkpoint.sigma1, prop_sigma1 - ); - } - // sigma2 - let prop_sigma2 = lf.public_inputs[constants::PI_SIGMA2_INDEX]; - if checkpoint.sigma2 != prop_sigma2 { - error!( - target: "consensus::validator", - "receive_proposal(): Failed to verify public value sigma2: {:?}, to proposed: {:?}", - checkpoint.sigma2, prop_sigma2 - ); + if mu_rho != prop_mu_rho { + error!( + target: "consensus::validator", + "receive_proposal(): Failed to verify mu_rho: {:?}, proposed: {:?}", + mu_rho, prop_mu_rho + ); + return Err(Error::ProposalPublicValuesMismatched) + } + + // Validate proposal coin sigmas against current slot checkpoint + let checkpoint = self.consensus.get_slot_checkpoint(current)?; + // sigma1 + let prop_sigma1 = lf.public_inputs[constants::PI_SIGMA1_INDEX]; + if checkpoint.sigma1 != prop_sigma1 { + error!( + target: "consensus::validator", + "receive_proposal(): Failed to verify public value sigma1: {:?}, to proposed: {:?}", + checkpoint.sigma1, prop_sigma1 + ); + } + // sigma2 + let prop_sigma2 = lf.public_inputs[constants::PI_SIGMA2_INDEX]; + if checkpoint.sigma2 != prop_sigma2 { + error!( + target: "consensus::validator", + "receive_proposal(): Failed to verify public value sigma2: {:?}, to proposed: {:?}", + checkpoint.sigma2, prop_sigma2 + ); + } } // Create corresponding state checkpoint for validations