Procházet zdrojové kódy

validator/consensus: cleaned up slots logic

skoupidi před 2 roky
rodič
revize
3e15d146a3

+ 0 - 88
Cargo.lock

@@ -1880,7 +1880,6 @@ dependencies = [
  "darkfi-derive",
  "darkfi-sdk",
  "darkfi-serial",
- "dashu",
  "easy-parallel",
  "ed25519-compact",
  "futures",
@@ -2267,78 +2266,6 @@ dependencies = [
  "parking_lot_core 0.9.9",
 ]
 
-[[package]]
-name = "dashu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b669b1473cc6b33aba72ab3ddfe1055ff8fc28accd85130c412c2cd922a7c4e"
-dependencies = [
- "dashu-base",
- "dashu-float",
- "dashu-int",
- "dashu-macros",
- "dashu-ratio",
-]
-
-[[package]]
-name = "dashu-base"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e183fc153511989674ede304b5592c74683393ca09cf20391898c28d6ba04264"
-
-[[package]]
-name = "dashu-float"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a672ddc5e64033c8279692d973a89831eb3c3f0ebb1def47435aee0401b6269d"
-dependencies = [
- "dashu-base",
- "dashu-int",
- "num-modular",
- "num-order",
- "static_assertions",
-]
-
-[[package]]
-name = "dashu-int"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc257a884b3e8c9a1a577ff7226dcb4d6bda0ff96dfa76975e2c9d7205e3b8ea"
-dependencies = [
- "cfg-if 1.0.0",
- "dashu-base",
- "num-modular",
- "num-order",
- "static_assertions",
-]
-
-[[package]]
-name = "dashu-macros"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496c319e615b86b21d6b0ea9e2f96a4f5fb2eb4178293b04a51ffc30a6c3f54"
-dependencies = [
- "dashu-base",
- "dashu-float",
- "dashu-int",
- "dashu-ratio",
- "proc-macro2",
- "quote",
-]
-
-[[package]]
-name = "dashu-ratio"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f0f73f0ad6cbc94f52306455603e307b065af83bc61101968d53b6870127a05"
-dependencies = [
- "dashu-base",
- "dashu-float",
- "dashu-int",
- "num-modular",
- "num-order",
-]
-
 [[package]]
 name = "dasp_sample"
 version = "0.11.0"
@@ -4456,21 +4383,6 @@ dependencies = [
  "num-traits",
 ]
 
-[[package]]
-name = "num-modular"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
-
-[[package]]
-name = "num-order"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6"
-dependencies = [
- "num-modular",
-]
-
 [[package]]
 name = "num-rational"
 version = "0.4.1"

+ 1 - 4
Cargo.toml

@@ -87,9 +87,6 @@ semver = {version = "1.0.21", optional = true}
 structopt = {version= "0.3.26", optional = true}
 structopt-toml = {version= "0.5.1", optional = true}
 toml = {version = "0.8.8", optional = true}
-# Big float high precision arithmetics
-dashu = {version = "0.4.0", optional = true}
-num-bigint = {version = "0.4.4", optional = true}
 
 # Utilities
 # TODO: check chrono usage and impl our own
@@ -97,6 +94,7 @@ chrono = {version = "0.4.31", optional = true}
 darkfi-serial = {path = "src/serial", optional = true}
 darkfi-derive = {path = "src/serial/derive", optional = true}
 lazy_static = {version = "1.4.0", optional = true}
+num-bigint = {version = "0.4.4", optional = true}
 url = {version = "2.5.0", features = ["serde"], optional = true}
 
 # Misc
@@ -164,7 +162,6 @@ validator = [
     "async-trait",
     "blake3",
     "crypto_api_chachapoly",
-    "dashu",
     "halo2_proofs",
     "lazy_static",
     "num-bigint",

+ 1 - 1
bin/darkfid/src/proto/protocol_tx.rs

@@ -103,7 +103,7 @@ impl ProtocolTx {
             let tx_copy = (*tx).clone();
 
             // Nodes use unconfirmed_txs vector as seen_txs pool.
-            match self.validator.append_tx(&tx_copy).await {
+            match self.validator.append_tx(&tx_copy, true).await {
                 Ok(()) => {
                     self.p2p.broadcast_with_exclude(&tx_copy, &exclude_list).await;
                     let encoded_tx =

+ 3 - 5
bin/darkfid/src/rpc_tx.rs

@@ -70,8 +70,7 @@ impl Darkfid {
         };
 
         // Simulate state transition
-        let current_slot = self.validator.consensus.time_keeper.current_slot();
-        let result = self.validator.add_transactions(&[tx], current_slot, false).await;
+        let result = self.validator.append_tx(&tx, false).await;
         if result.is_err() {
             error!(
                 target: "darkfid::rpc::tx_simulate", "Failed to validate state transition: {}",
@@ -124,14 +123,13 @@ impl Darkfid {
             // Consensus participants can directly perform
             // the state transition check and append to their
             // pending transactions store.
-            if self.validator.append_tx(&tx).await.is_err() {
+            if self.validator.append_tx(&tx, true).await.is_err() {
                 error!(target: "darkfid::rpc::tx_broadcast", "Failed to append transaction to mempool");
                 return server_error(RpcError::TxSimulationFail, id, None)
             }
         } else {
             // We'll perform the state transition check here.
-            let current_slot = self.validator.consensus.time_keeper.current_slot();
-            let result = self.validator.add_transactions(&[tx.clone()], current_slot, false).await;
+            let result = self.validator.append_tx(&tx, false).await;
             if result.is_err() {
                 error!(
                     target: "darkfid::rpc::tx_broadcast", "Failed to validate state transition: {}",

+ 6 - 8
bin/darkfid/src/task/miner.rs

@@ -95,7 +95,7 @@ async fn miner_loop(node: &Darkfid, recipient: &PublicKey) -> Result<()> {
 
     // Generate a new fork to be able to extend
     info!(target: "darkfid::task::miner_task", "Generating new empty fork...");
-    node.validator.consensus.generate_pow_slot().await?;
+    node.validator.consensus.generate_empty_fork().await?;
 
     // Grab blocks subscriber
     let block_sub = node.subscribers.get("blocks").unwrap();
@@ -156,16 +156,16 @@ async fn generate_next_block(
     let fork = &forks[fork_index];
 
     // Generate new signing key for next block
-    let height = fork.slots.last().unwrap().id;
+    let next_block_height = fork.get_next_block_height()?;
     // We are deriving the next secret key for optimization.
     // Next secret is the poseidon hash of:
     //  [prefix, current(previous) secret, signing(block) height].
     let prefix = pallas::Base::from_raw([4, 0, 0, 0]);
-    let next_secret = poseidon_hash([prefix, secret.inner(), height.into()]);
+    let next_secret = poseidon_hash([prefix, secret.inner(), next_block_height.into()]);
     *secret = SecretKey::from(next_secret);
 
     // Generate reward transaction
-    let tx = generate_pow_transaction(fork, secret, recipient, zkbin, pk)?;
+    let tx = generate_transaction(fork, secret, recipient, zkbin, pk, next_block_height)?;
 
     // Generate next block proposal
     let target = fork.module.next_mine_target()?;
@@ -178,16 +178,14 @@ async fn generate_next_block(
 }
 
 /// Auxiliary function to generate a Money::PoWReward transaction
-fn generate_pow_transaction(
+fn generate_transaction(
     fork: &Fork,
     secret: &SecretKey,
     recipient: &PublicKey,
     zkbin: &ZkBinary,
     pk: &ProvingKey,
+    block_height: u64,
 ) -> Result<Transaction> {
-    // Grab next block height
-    let block_height = fork.slots.last().unwrap().id;
-
     // Grab extended proposal info
     let last_proposal = fork.last_proposal()?;
     let last_nonce = last_proposal.block.header.nonce;

+ 3 - 58
bin/darkfid/src/tests/harness.rs

@@ -19,19 +19,14 @@
 use std::{collections::HashMap, sync::Arc};
 
 use darkfi::{
-    blockchain::{BlockInfo, Header},
+    blockchain::BlockInfo,
     net::Settings,
     rpc::jsonrpc::JsonSubscriber,
-    tx::Transaction,
     util::time::TimeKeeper,
-    validator::{pid::slot_pid_output, utils::genesis_txs_total, Validator, ValidatorConfig},
+    validator::{utils::genesis_txs_total, Validator, ValidatorConfig},
     Result,
 };
 use darkfi_contract_test_harness::{vks, Holder, TestHarness};
-use darkfi_sdk::{
-    blockchain::{expected_reward, PidOutput, PreviousSlot, Slot, POS_START},
-    pasta::{group::ff::Field, pallas},
-};
 use num_bigint::BigUint;
 use url::Url;
 
@@ -163,7 +158,7 @@ impl Harness {
         Ok(())
     }
 
-    pub async fn add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
+    pub async fn _add_blocks(&self, blocks: &[BlockInfo]) -> Result<()> {
         // We simply broadcast the block using Alice's sync P2P
         for block in blocks {
             self.alice.sync_p2p.broadcast(&BlockInfoMessage::from(block)).await;
@@ -174,56 +169,6 @@ impl Harness {
 
         Ok(())
     }
-
-    pub async fn generate_next_pos_block(
-        &self,
-        previous: &BlockInfo,
-        slots_count: usize,
-    ) -> Result<BlockInfo> {
-        let previous_hash = previous.hash()?;
-
-        // Generate empty slots
-        let mut slots = Vec::with_capacity(slots_count);
-        let mut previous_slot = previous.slots.last().unwrap().clone();
-        for i in 0..slots_count {
-            let id = if previous_slot.id < POS_START { POS_START } else { previous_slot.id + 1 };
-            // First slot in the sequence has (at least) 1 previous slot producer
-            let producers = if i == 0 { 1 } else { 0 };
-            let previous = PreviousSlot::new(
-                producers,
-                vec![previous_hash],
-                vec![previous.header.previous],
-                previous_slot.pid.error,
-            );
-            let (f, error, sigma1, sigma2) = slot_pid_output(&previous_slot, producers);
-            let pid = PidOutput::new(f, error, sigma1, sigma2);
-            let total_tokens = previous_slot.total_tokens + previous_slot.reward;
-            // Only last slot in the sequence has a reward
-            let reward = if i == slots_count - 1 { expected_reward(id) } else { 0 };
-            let slot = Slot::new(id, previous, pid, pallas::Base::ZERO, total_tokens, reward);
-            slots.push(slot.clone());
-            previous_slot = slot;
-        }
-
-        // We increment timestamp so we don't have to use sleep
-        let mut timestamp = previous.header.timestamp;
-        timestamp.add(1);
-
-        // Generate header
-        let height = slots.last().unwrap().id;
-        let header = Header::new(previous_hash, height, timestamp, previous.header.nonce);
-
-        // Generate the block
-        let mut block = BlockInfo::new_empty(header, slots);
-
-        // Add transactions to the block
-        block.append_txs(vec![Transaction::default()])?;
-
-        // Attach signature
-        block.signature = previous.signature;
-
-        Ok(block)
-    }
 }
 
 // Note: This function should mirror darkfid::main

+ 5 - 5
bin/darkfid/src/tests/mod.rs

@@ -44,19 +44,19 @@ async fn sync_pos_blocks_real(ex: Arc<Executor<'static>>) -> Result<()> {
     let th = Harness::new(config, false, &ex).await?;
 
     // Retrieve genesis block
-    let previous = th.alice.validator.blockchain.last_block()?;
+    let _previous = th.alice.validator.blockchain.last_block()?;
 
     // Generate next block
-    let block1 = th.generate_next_pos_block(&previous, 1).await?;
+    //let block1 = th.generate_next_block(&previous).await?;
 
     // Generate next block, with 4 empty slots inbetween
-    let block2 = th.generate_next_pos_block(&block1, 5).await?;
+    //let block2 = th.generate_next_block(&block1).await?;
 
     // Add it to nodes
-    th.add_blocks(&vec![block1, block2]).await?;
+    //th.add_blocks(&vec![block1, block2]).await?;
 
     // Validate chains
-    th.validate_chains(3, 7).await?;
+    th.validate_chains(1, 1).await?;
 
     // We are going to create a third node and try to sync from the previous two
     let mut sync_settings =

+ 4 - 0
src/contract/dao/tests/integration.rs

@@ -221,6 +221,7 @@ fn integration_test() -> Result<()> {
             user_data,
             &dao,
             &dao_mint_params.dao_bulla,
+            current_block_height,
         )?;
 
         for holder in &HOLDERS {
@@ -245,6 +246,7 @@ fn integration_test() -> Result<()> {
             &dao_keypair,
             &propose_info,
             &propose_params.proposal_bulla,
+            current_block_height,
         )?;
 
         info!("[Bob] Building vote tx (no)");
@@ -255,6 +257,7 @@ fn integration_test() -> Result<()> {
             &dao_keypair,
             &propose_info,
             &propose_params.proposal_bulla,
+            current_block_height,
         )?;
 
         info!("[Charlie] Building vote tx (yes)");
@@ -265,6 +268,7 @@ fn integration_test() -> Result<()> {
             &dao_keypair,
             &propose_info,
             &propose_params.proposal_bulla,
+            current_block_height,
         )?;
 
         for holder in &HOLDERS {

+ 2 - 2
src/contract/test-harness/src/dao_propose.rs

@@ -47,6 +47,7 @@ impl TestHarness {
         user_data: pallas::Base,
         dao: &Dao,
         dao_bulla: &DaoBulla,
+        block_height: u64,
     ) -> Result<(Transaction, DaoProposeParams, DaoProposal)> {
         let wallet = self.holders.get(proposer).unwrap();
 
@@ -98,8 +99,7 @@ impl TestHarness {
             },
         ];
 
-        let creation_day =
-            blockheight_to_day(wallet.validator.consensus.time_keeper.verifying_block_height);
+        let creation_day = blockheight_to_day(block_height);
         let proposal = DaoProposal {
             auth_calls,
             creation_day,

+ 3 - 2
src/contract/test-harness/src/dao_vote.rs

@@ -39,6 +39,7 @@ use rand::rngs::OsRng;
 use super::{Holder, TestHarness, TxAction};
 
 impl TestHarness {
+    #[allow(clippy::too_many_arguments)]
     pub fn dao_vote(
         &mut self,
         voter: &Holder,
@@ -47,6 +48,7 @@ impl TestHarness {
         dao_keypair: &Keypair,
         proposal: &DaoProposal,
         proposal_bulla: &DaoProposalBulla,
+        block_height: u64,
     ) -> Result<(Transaction, DaoVoteParams)> {
         let wallet = self.holders.get(voter).unwrap();
 
@@ -78,8 +80,7 @@ impl TestHarness {
             signature_secret,
         };
 
-        let current_day =
-            blockheight_to_day(wallet.validator.consensus.time_keeper.verifying_block_height);
+        let current_day = blockheight_to_day(block_height);
         let call = DaoVoteCall {
             inputs: vec![input],
             vote_option,

+ 40 - 225
src/validator/consensus.rs

@@ -16,11 +16,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use darkfi_sdk::{
-    blockchain::{expected_reward, PidOutput, PreviousSlot, Slot, POS_START},
-    crypto::SecretKey,
-    pasta::{group::ff::PrimeField, pallas},
-};
+use darkfi_sdk::{crypto::SecretKey, pasta::pallas};
 use darkfi_serial::{async_trait, serialize, SerialDecodable, SerialEncodable};
 use log::{debug, error, info};
 use num_bigint::BigUint;
@@ -29,11 +25,10 @@ use smol::lock::RwLock;
 use crate::{
     blockchain::{BlockInfo, Blockchain, BlockchainOverlay, BlockchainOverlayPtr, Header},
     tx::Transaction,
-    util::time::{TimeKeeper, Timestamp},
+    util::time::Timestamp,
     validator::{
-        pid::slot_pid_output,
         pow::PoWModule,
-        utils::{best_forks_indexes, block_rank, find_extended_fork_index, previous_slot_info},
+        utils::{best_forks_indexes, block_rank, find_extended_fork_index},
         verify_block, verify_proposal, verify_transactions, TxVerifyFailed,
     },
     Error, Result,
@@ -47,131 +42,62 @@ pub const TXS_CAP: usize = 50;
 pub struct Consensus {
     /// Canonical (finalized) blockchain
     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
-    pub checked_finalization: RwLock<u64>,
     /// Fork chains containing block proposals
     pub forks: RwLock<Vec<Fork>>,
     /// Canonical blockchain PoW module state
     pub module: RwLock<PoWModule>,
-    /// Flag to enable PoS testing mode
-    pub pos_testing_mode: bool,
 }
 
 impl Consensus {
     /// Generate a new Consensus state.
     pub fn new(
         blockchain: Blockchain,
-        time_keeper: TimeKeeper,
         finalization_threshold: usize,
         pow_target: usize,
         pow_fixed_difficulty: Option<BigUint>,
-        pos_testing_mode: bool,
     ) -> Result<Self> {
         let module =
             RwLock::new(PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty)?);
         Ok(Self {
             blockchain,
-            time_keeper,
             finalization_threshold,
             participating: false,
-            checked_finalization: RwLock::new(0),
             forks: RwLock::new(vec![]),
             module,
-            pos_testing_mode,
         })
     }
 
-    /// Generate next hot/live PoW slot for all current forks.
-    pub async fn generate_pow_slot(&self) -> Result<()> {
-        // Grab a lock over current forks
-        let mut forks = self.forks.write().await;
-
-        // If no forks exist, create a new one as a basis to extend
-        if forks.is_empty() {
-            forks.push(Fork::new(&self.blockchain, self.module.read().await.clone()).await?);
-        }
-
-        for fork in forks.iter_mut() {
-            fork.generate_pow_slot()?;
-        }
-
-        // Drop forks lock
-        drop(forks);
-
-        Ok(())
-    }
-
-    /// Generate current hot/live PoS slot for all current forks.
-    pub async fn generate_pos_slot(&self) -> Result<()> {
-        // Grab a lock over current forks
-        let mut forks = self.forks.write().await;
-
-        // Grab current slot id
-        let id = self.time_keeper.current_slot();
-
-        // If no forks exist, create a new one as a basis to extend
-        if forks.is_empty() {
-            forks.push(Fork::new(&self.blockchain, self.module.read().await.clone()).await?);
-        }
-
-        // Grab previous slot information
-        let (producers, last_hashes, second_to_last_hashes) = previous_slot_info(&forks, id - 1)?;
-
-        for fork in forks.iter_mut() {
-            fork.generate_pos_slot(id, producers, &last_hashes, &second_to_last_hashes)?;
-        }
-
-        // Drop forks lock
-        drop(forks);
-
-        Ok(())
-    }
-
     /// Generate an unsigned block for provided fork, containing all
-    /// pending transactions. This should only be called after generating
-    /// next/current slot.
+    /// pending transactions.
     pub async fn generate_unsigned_block(
         &self,
         fork: &Fork,
         producer_tx: Transaction,
     ) -> Result<BlockInfo> {
-        // Grab fork's last slot
-        let slot = fork.slots.last().unwrap();
-
-        // Generate a time keeper for next/current slot
-        let time_keeper = if slot.id < POS_START {
-            let mut t = self.time_keeper.current();
-            t.verifying_block_height = slot.id;
-            t
-        } else {
-            self.time_keeper.current()
-        };
+        // Grab forks' next block height
+        let next_block_height = fork.get_next_block_height()?;
 
         // Grab forks' unproposed transactions
-        let mut unproposed_txs =
-            fork.unproposed_txs(&self.blockchain, time_keeper.verifying_block_height).await?;
+        let mut unproposed_txs = fork.unproposed_txs(&self.blockchain, next_block_height).await?;
         unproposed_txs.push(producer_tx);
 
         // Grab forks' last block proposal(previous)
         let previous = fork.last_proposal()?;
 
         // Generate the new header
-        // TODO: verify if header timestamp should be blockchain or system timestamp
         let header = Header::new(
             previous.block.hash()?,
-            slot.id,
+            next_block_height,
             Timestamp::current_time(),
-            slot.last_nonce,
+            pallas::Base::zero(),
         );
 
         // Generate the block
-        let mut block = BlockInfo::new_empty(header, fork.slots.clone());
+        let mut block = BlockInfo::new_empty(header, vec![]);
 
         // Add transactions to the block
         block.append_txs(unproposed_txs)?;
@@ -180,8 +106,7 @@ impl Consensus {
     }
 
     /// Generate a block proposal for provided fork, containing all
-    /// pending transactions. This should only be called after generating
-    /// next/current slot. Proposal is signed using provided secret key,
+    /// pending transactions. Proposal is signed using provided secret key,
     /// which must also have signed the provided proposal transaction.
     pub async fn generate_signed_proposal(
         &self,
@@ -200,6 +125,17 @@ impl Consensus {
         Ok(proposal)
     }
 
+    /// Generate a new empty fork.
+    pub async fn generate_empty_fork(&self) -> Result<()> {
+        debug!(target: "validator::consensus::generate_empty_fork", "Generating new empty fork...");
+        let mut lock = self.forks.write().await;
+        let fork = Fork::new(&self.blockchain, self.module.read().await.clone()).await?;
+        lock.push(fork);
+        drop(lock);
+        debug!(target: "validator::consensus::generate_empty_fork", "Fork generated!");
+        Ok(())
+    }
+
     /// Given a proposal, the node verifys it and finds which fork it extends.
     /// If the proposal extends the canonical blockchain, a new fork chain is created.
     pub async fn append_proposal(&self, proposal: &Proposal) -> Result<()> {
@@ -209,22 +145,10 @@ impl Consensus {
         let (mut fork, index) = verify_proposal(self, proposal).await?;
 
         // Append proposal to the fork
-        fork.append_proposal(proposal.hash, self.pos_testing_mode).await?;
-
-        // Update fork slots based on proposal version
-        match proposal.block.header.version {
-            // PoW proposal
-            1 => {
-                // Update PoW module
-                fork.module
-                    .append(proposal.block.header.timestamp.0, &fork.module.next_difficulty()?);
-                // and generate next PoW slot for this specific fork
-                fork.generate_pow_slot()?;
-            }
-            // PoS proposal
-            2 => fork.slots = vec![],
-            _ => return Err(Error::BlockVersionIsInvalid(proposal.block.header.version)),
-        }
+        fork.append_proposal(proposal.hash).await?;
+
+        // Update PoW module
+        fork.module.append(proposal.block.header.timestamp.0, &fork.module.next_difficulty()?);
 
         // If a fork index was found, replace forks with the mutated one,
         // otherwise push the new fork.
@@ -261,9 +185,9 @@ impl Consensus {
             }
 
             // Check if proposal extends canonical
-            let (last_slot, last_block) = self.blockchain.last()?;
+            let (last_height, last_block) = self.blockchain.last()?;
             if proposal.block.header.previous != last_block ||
-                proposal.block.header.height <= last_slot
+                proposal.block.header.height <= last_height
             {
                 return Err(Error::ExtendedChainIndexNotFound)
             }
@@ -276,16 +200,7 @@ impl Consensus {
             }
 
             // Generate a new fork extending canonical
-            let mut fork = Fork::new(&self.blockchain, self.module.read().await.clone()).await?;
-            if proposal.block.header.height < POS_START {
-                fork.generate_pow_slot()?;
-            } else {
-                let id = self.time_keeper.current_slot();
-                let (producers, last_hashes, second_to_last_hashes) =
-                    previous_slot_info(&forks, id - 1)?;
-                fork.generate_pos_slot(id, producers, &last_hashes, &second_to_last_hashes)?;
-            }
-
+            let fork = Fork::new(&self.blockchain, self.module.read().await.clone()).await?;
             return Ok((fork, None))
         }
 
@@ -316,17 +231,12 @@ impl Consensus {
             };
 
             // Update PoW module
-            if block.header.version == 1 {
-                fork.module.append(block.header.timestamp.0, &fork.module.next_difficulty()?);
-            }
+            fork.module.append(block.header.timestamp.0, &fork.module.next_difficulty()?);
 
             // Use last inserted block as next iteration previous
             previous = block;
         }
 
-        // Rebuilt fork hot/live slots
-        fork.generate_pow_slot()?;
-
         // Drop forks lock
         drop(forks);
 
@@ -340,10 +250,7 @@ impl Consensus {
     /// When best fork can be finalized, blocks(proposals) should be appended to canonical, excluding the
     /// last one, and fork should be rebuilt.
     pub async fn finalization(&self) -> Result<Vec<BlockInfo>> {
-        // Set last slot finalization check occured to current slot
-        let slot = self.time_keeper.current_slot();
-        debug!(target: "validator::consensus::finalization", "Started finalization check for slot: {}", slot);
-        *self.checked_finalization.write().await = slot;
+        debug!(target: "validator::consensus::finalization", "Started finalization check");
 
         // Grab best forks
         let forks = self.forks.read().await;
@@ -408,8 +315,6 @@ pub struct Fork {
     pub module: PoWModule,
     /// Fork proposal hashes sequence
     pub proposals: Vec<blake3::Hash>,
-    /// Hot/live slots
-    pub slots: Vec<Slot>,
     /// Valid pending transaction hashes
     pub mempool: Vec<blake3::Hash>,
     /// Current fork rank, cached for better performance
@@ -421,17 +326,13 @@ impl Fork {
         let mempool =
             blockchain.get_pending_txs()?.iter().map(|tx| blake3::hash(&serialize(tx))).collect();
         let overlay = BlockchainOverlay::new(blockchain)?;
-        Ok(Self { overlay, module, proposals: vec![], slots: vec![], mempool, rank: 0 })
+        Ok(Self { overlay, module, proposals: vec![], mempool, rank: 0 })
     }
 
     /// Auxiliary function to append a proposal and recalculate current fork rank
-    pub async fn append_proposal(
-        &mut self,
-        proposal: blake3::Hash,
-        pos_testing_mode: bool,
-    ) -> Result<()> {
+    pub async fn append_proposal(&mut self, proposal: blake3::Hash) -> Result<()> {
         self.proposals.push(proposal);
-        self.rank = self.rank(pos_testing_mode).await?;
+        self.rank = self.rank().await?;
 
         Ok(())
     }
@@ -448,24 +349,10 @@ impl Fork {
         Proposal::new(block)
     }
 
-    /// Utility function to extract leader selection lottery randomness(nonce/eta),
-    /// defined as the hash of the last block, converted to pallas base.
-    fn get_last_nonce(&self) -> Result<pallas::Base> {
-        // Retrieve last block(or proposal)
+    /// Auxiliary function to compute forks' next block height.
+    pub fn get_next_block_height(&self) -> Result<u64> {
         let proposal = self.last_proposal()?;
-
-        match proposal.block.header.version {
-            1 => Ok(pallas::Base::from(proposal.block.header.nonce)),
-            2 => {
-                // Read first 240 bits of proposal hash
-                let mut bytes: [u8; 32] = *proposal.hash.as_bytes();
-                bytes[30] = 0;
-                bytes[31] = 0;
-
-                Ok(pallas::Base::from_repr(bytes).unwrap())
-            }
-            _ => Err(Error::BlockVersionIsInvalid(proposal.block.header.version)),
-        }
+        Ok(proposal.block.header.height + 1)
     }
 
     /// Auxiliary function to retrieve unproposed valid transactions.
@@ -514,79 +401,8 @@ impl Fork {
         Ok(unproposed_txs)
     }
 
-    /// Generate next hot/live PoW slot
-    pub fn generate_pow_slot(&mut self) -> Result<()> {
-        // Grab last proposal
-        let last = self.last_proposal()?;
-
-        // Generate the slot
-        let last_slot = last.block.slots.last().unwrap().clone();
-        let id = last_slot.id + 1;
-        let producers = 1;
-        let previous = PreviousSlot::new(
-            producers,
-            vec![last.hash],
-            vec![last.block.header.previous],
-            last_slot.pid.error,
-        );
-        let pid = PidOutput::default();
-        let total_tokens = last_slot.total_tokens + last_slot.reward;
-        let reward = expected_reward(id);
-        let slot = Slot::new(
-            id,
-            previous,
-            pid,
-            pallas::Base::from(last.block.header.nonce),
-            total_tokens,
-            reward,
-        );
-
-        // Update fork hot/live slots vector
-        self.slots = vec![slot];
-
-        Ok(())
-    }
-
-    /// Generate current hot/live PoS slot
-    pub fn generate_pos_slot(
-        &mut self,
-        id: u64,
-        producers: u64,
-        last_hashes: &[blake3::Hash],
-        second_to_last_hashes: &[blake3::Hash],
-    ) -> Result<()> {
-        // Grab last known fork slot
-        let previous_slot = if self.slots.is_empty() {
-            self.overlay.lock().unwrap().slots.get_last()?
-        } else {
-            self.slots.last().unwrap().clone()
-        };
-
-        // Generate previous slot information
-        let previous = PreviousSlot::new(
-            producers,
-            last_hashes.to_vec(),
-            second_to_last_hashes.to_vec(),
-            previous_slot.pid.error,
-        );
-
-        // Generate PID controller output
-        let (f, error, sigma1, sigma2) = slot_pid_output(&previous_slot, producers);
-        let pid = PidOutput::new(f, error, sigma1, sigma2);
-
-        // Each slot starts as an empty slot(not reward) when generated, carrying
-        // last nonce(eta)
-        let last_nonce = self.get_last_nonce()?;
-        let total_tokens = previous_slot.total_tokens + previous_slot.reward;
-        let reward = 0;
-        let slot = Slot::new(id, previous, pid, last_nonce, total_tokens, reward);
-        self.slots.push(slot);
-
-        Ok(())
-    }
-
     /// Auxiliarry function to compute fork's rank, assuming all proposals are valid.
-    pub async fn rank(&self, pos_testing_mode: bool) -> Result<u64> {
+    pub async fn rank(&self) -> Result<u64> {
         // If the fork is empty its rank is 0
         if self.proposals.is_empty() {
             return Ok(0)
@@ -608,7 +424,7 @@ impl Fork {
             } else {
                 proposal.clone()
             };
-            sum += block_rank(proposal, &previous_previous, pos_testing_mode).await?;
+            sum += block_rank(proposal, &previous_previous).await?;
         }
 
         // Use fork(proposals) length as a multiplier to compute the actual fork rank
@@ -624,10 +440,9 @@ impl Fork {
         let overlay = self.overlay.lock().unwrap().full_clone()?;
         let module = self.module.clone();
         let proposals = self.proposals.clone();
-        let slots = self.slots.clone();
         let mempool = self.mempool.clone();
         let rank = self.rank;
 
-        Ok(Self { overlay, module, proposals, slots, mempool, rank })
+        Ok(Self { overlay, module, proposals, mempool, rank })
     }
 }

+ 0 - 232
src/validator/float_10.rs

@@ -1,232 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use std::ops::{Add, AddAssign, Div, Mul, Sub};
-
-use darkfi_sdk::pasta::{group::ff::PrimeField, pallas};
-use dashu::{
-    base::Abs,
-    float::{round::mode::Zero, FBig, Repr},
-    integer::{IBig, Sign, UBig},
-};
-use lazy_static::lazy_static;
-
-const RADIX_BITS: usize = 76;
-const B: u64 = 10;
-
-/// Wrapper structure over a Base 10 [`dashu::float::FBig`]
-/// and Zero rounding mode.
-#[derive(Clone, PartialEq, PartialOrd, Debug)]
-pub struct Float10(FBig<Zero, B>);
-
-impl Float10 {
-    pub fn repr(&self) -> &Repr<B> {
-        self.0.repr()
-    }
-
-    pub fn abs(&self) -> Self {
-        Self(self.0.clone().abs())
-    }
-
-    pub fn powf(&self, exp: Self) -> Self {
-        Self(self.0.powf(&exp.0))
-    }
-
-    pub fn ln(&self) -> Self {
-        Self(self.0.ln())
-    }
-
-    pub fn to_f64(&self) -> f64 {
-        self.0.to_f64().value()
-    }
-}
-
-impl Add for Float10 {
-    type Output = Self;
-
-    fn add(self, other: Self) -> Self {
-        Self(self.0 + other.0)
-    }
-}
-
-impl AddAssign for Float10 {
-    fn add_assign(&mut self, other: Self) {
-        *self = Self(self.0.clone() + other.0);
-    }
-}
-
-impl Sub for Float10 {
-    type Output = Self;
-
-    fn sub(self, other: Self) -> Self {
-        Self(self.0 - other.0)
-    }
-}
-
-impl Mul for Float10 {
-    type Output = Self;
-
-    fn mul(self, other: Self) -> Self {
-        Self(self.0 * other.0)
-    }
-}
-
-impl Div for Float10 {
-    type Output = Self;
-
-    fn div(self, other: Self) -> Self {
-        Self(self.0 / other.0)
-    }
-}
-
-impl std::fmt::Display for Float10 {
-    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
-        write!(f, "{}", self.0)
-    }
-}
-
-impl TryFrom<&str> for Float10 {
-    type Error = crate::Error;
-
-    fn try_from(value: &str) -> Result<Self, Self::Error> {
-        Ok(Self(FBig::from_str_native(value)?.with_precision(RADIX_BITS).value()))
-    }
-}
-
-impl TryFrom<u64> for Float10 {
-    type Error = crate::Error;
-
-    fn try_from(value: u64) -> Result<Self, Self::Error> {
-        Ok(Self(FBig::from(value)))
-    }
-}
-
-impl TryFrom<i64> for Float10 {
-    type Error = crate::Error;
-
-    fn try_from(value: i64) -> Result<Self, Self::Error> {
-        Ok(Self(FBig::from(value)))
-    }
-}
-
-impl TryFrom<f64> for Float10 {
-    type Error = crate::Error;
-
-    fn try_from(value: f64) -> Result<Self, Self::Error> {
-        Ok(Self(FBig::try_from(value)?.with_precision(RADIX_BITS).value().with_base().value()))
-    }
-}
-
-// Commonly used Float10
-lazy_static! {
-    pub static ref FLOAT10_NEG_TWO: Float10 = Float10::try_from("-2").unwrap();
-    pub static ref FLOAT10_NEG_ONE: Float10 = Float10::try_from("-1").unwrap();
-    pub static ref FLOAT10_ZERO: Float10 = Float10::try_from("0").unwrap();
-    pub static ref FLOAT10_ONE: Float10 = Float10::try_from("1").unwrap();
-    pub static ref FLOAT10_TWO: Float10 = Float10::try_from("2").unwrap();
-    pub static ref FLOAT10_THREE: Float10 = Float10::try_from("3").unwrap();
-    pub static ref FLOAT10_FIVE: Float10 = Float10::try_from("5").unwrap();
-    pub static ref FLOAT10_NINE: Float10 = Float10::try_from("9").unwrap();
-    pub static ref FLOAT10_TEN: Float10 = Float10::try_from("10").unwrap();
-}
-
-// Utility functions
-/// Convert a Float10 to [`dashu::integer::IBig`].
-pub fn fbig2ibig(f: Float10) -> IBig {
-    let rad = IBig::from(10);
-    let sig = f.repr().significand();
-    let exp = f.repr().exponent();
-
-    let val: IBig = if exp >= 0 {
-        sig.clone() * rad.pow(exp.unsigned_abs())
-    } else {
-        sig.clone() / rad.pow(exp.unsigned_abs())
-    };
-
-    val
-}
-
-/// Convert a Float10 to [`pallas::Base`].
-/// Note: negative values in pallas field don't wrap,
-/// and can't be converted back to original value.
-pub fn fbig2base(f: Float10) -> pallas::Base {
-    let val: IBig = fbig2ibig(f);
-    let (sign, word) = val.as_sign_words();
-    let mut words: [u64; 4] = [0, 0, 0, 0];
-    words[..word.len()].copy_from_slice(word);
-    match sign {
-        Sign::Positive => pallas::Base::from_raw(words),
-        Sign::Negative => pallas::Base::from_raw(words).neg(),
-    }
-}
-
-/// Convert a [`pallas::Base`] to [`dashu::integer::IBig`].
-/// Note: only zero and positive numbers conversion is supported.
-/// Used for testing purposes on non-negative values at the moment.
-pub fn base2ibig(base: pallas::Base) -> IBig {
-    let byts: [u8; 32] = base.to_repr();
-    let words: [u64; 4] = [
-        u64::from_le_bytes(byts[0..8].try_into().expect("")),
-        u64::from_le_bytes(byts[8..16].try_into().expect("")),
-        u64::from_le_bytes(byts[16..24].try_into().expect("")),
-        u64::from_le_bytes(byts[24..32].try_into().expect("")),
-    ];
-    let uparts = UBig::from_words(&words);
-    IBig::from_parts(Sign::Positive, uparts)
-}
-
-#[cfg(test)]
-mod tests {
-    use darkfi_sdk::pasta::pallas;
-    use dashu::integer::IBig;
-
-    use super::{base2ibig, fbig2base, fbig2ibig, Float10};
-
-    #[test]
-    fn dashu_fbig2ibig() {
-        let f = Float10::try_from("234234223.000").unwrap();
-        let i: IBig = fbig2ibig(f);
-        let sig = IBig::from(234234223);
-        assert_eq!(i, sig);
-    }
-
-    #[test]
-    fn dashu_test_base2ibig() {
-        let fbig: Float10 = Float10::try_from(
-            "289480223093290488558927462521719769633630564819415607159546767643499676303",
-        )
-        .unwrap();
-        let ibig = fbig2ibig(fbig.clone());
-        let res_base: pallas::Base = fbig2base(fbig.clone());
-        let res_ibig: IBig = base2ibig(res_base);
-        assert_eq!(res_ibig, ibig);
-    }
-
-    #[test]
-    fn dashu_test2_base2ibig() {
-        // Verify that field wrapping for negative values won't hold during conversions.
-        let fbig: Float10 = Float10::try_from(
-            "-20065240046497827215558476051577517633529246907153511707181011345840062564.87",
-        )
-        .unwrap();
-        let ibig = fbig2ibig(fbig.clone());
-        let res_base: pallas::Base = fbig2base(fbig.clone());
-        let res_ibig: IBig = base2ibig(res_base);
-        assert_ne!(res_ibig, ibig);
-    }
-}

+ 21 - 40
src/validator/mod.rs

@@ -43,9 +43,6 @@ use consensus::{Consensus, Proposal};
 pub mod pow;
 use pow::PoWModule;
 
-/// DarkFi consensus PID controller
-pub mod pid;
-
 /// Verification functions
 pub mod verification;
 use verification::{
@@ -60,9 +57,6 @@ pub mod fees;
 pub mod utils;
 use utils::deploy_native_contracts;
 
-/// Base 10 big float implementation for high precision arithmetics
-pub mod float_10;
-
 /// Configuration for initializing [`Validator`]
 #[derive(Clone)]
 pub struct ValidatorConfig {
@@ -161,11 +155,9 @@ impl Validator {
         info!(target: "validator::new", "Initializing Consensus");
         let consensus = Consensus::new(
             blockchain.clone(),
-            config.time_keeper,
             config.finalization_threshold,
             config.pow_target,
             config.pow_fixed_difficulty,
-            pos_testing_mode,
         )?;
 
         // Create the actual state
@@ -183,7 +175,7 @@ impl Validator {
 
     /// The node retrieves a transaction, validates its state transition,
     /// and appends it to the pending txs store.
-    pub async fn append_tx(&self, tx: &Transaction) -> Result<()> {
+    pub async fn append_tx(&self, tx: &Transaction, write: bool) -> Result<()> {
         let tx_hash = blake3::hash(&serialize_async(tx).await);
 
         // Check if we have already seen this tx
@@ -203,19 +195,17 @@ impl Validator {
         // Grab a lock over current consensus forks state
         let mut forks = self.consensus.forks.write().await;
 
-        // Generate a time keeper for current slot
-        let time_keeper = self.consensus.time_keeper.current();
-
         // If node participates in consensus and holds any forks, iterate over them
         // to verify transaction validity in their overlays
         for fork in forks.iter_mut() {
             // Clone forks' overlay
             let overlay = fork.overlay.lock().unwrap().full_clone()?;
 
+            // Grab forks' next block height
+            let next_block_height = fork.get_next_block_height()?;
+
             // Verify transaction
-            match verify_transactions(&overlay, time_keeper.verifying_block_height, &tx_vec, false)
-                .await
-            {
+            match verify_transactions(&overlay, next_block_height, &tx_vec, false).await {
                 Ok(_) => {}
                 Err(crate::Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => continue,
                 Err(e) => return Err(e),
@@ -224,15 +214,16 @@ impl Validator {
             valid = true;
 
             // Store transaction hash in forks' mempool
-            fork.mempool.push(tx_hash);
+            if write {
+                fork.mempool.push(tx_hash);
+            }
         }
 
         // Verify transaction against canonical state
         let overlay = BlockchainOverlay::new(&self.blockchain)?;
+        let next_block_height = self.blockchain.last_block()?.header.height + 1;
         let mut erroneous_txs = vec![];
-        match verify_transactions(&overlay, time_keeper.verifying_block_height, &tx_vec, false)
-            .await
-        {
+        match verify_transactions(&overlay, next_block_height, &tx_vec, false).await {
             Ok(_) => valid = true,
             Err(crate::Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(etx))) => {
                 erroneous_txs = etx
@@ -249,8 +240,10 @@ impl Validator {
         }
 
         // Add transaction to pending txs store
-        self.blockchain.add_pending_txs(&tx_vec)?;
-        info!(target: "validator::append_tx", "Appended tx to pending txs store");
+        if write {
+            self.blockchain.add_pending_txs(&tx_vec)?;
+            info!(target: "validator::append_tx", "Appended tx to pending txs store");
+        }
 
         Ok(())
     }
@@ -269,9 +262,6 @@ impl Validator {
         // Grab a lock over current consensus forks state
         let mut forks = self.consensus.forks.write().await;
 
-        // Generate a time keeper for current slot
-        let time_keeper = self.consensus.time_keeper.current();
-
         let mut removed_txs = vec![];
         for tx in pending_txs {
             let tx_hash = &blake3::hash(&serialize_async(&tx).await);
@@ -284,15 +274,11 @@ impl Validator {
                 // Clone forks' overlay
                 let overlay = fork.overlay.lock().unwrap().full_clone()?;
 
+                // Grab forks' next block height
+                let next_block_height = fork.get_next_block_height()?;
+
                 // Verify transaction
-                match verify_transactions(
-                    &overlay,
-                    time_keeper.verifying_block_height,
-                    &tx_vec,
-                    false,
-                )
-                .await
-                {
+                match verify_transactions(&overlay, next_block_height, &tx_vec, false).await {
                     Ok(_) => {
                         valid = true;
                         continue
@@ -307,10 +293,8 @@ impl Validator {
 
             // Verify transaction against canonical state
             let overlay = BlockchainOverlay::new(&self.blockchain)?;
-
-            match verify_transactions(&overlay, time_keeper.verifying_block_height, &tx_vec, false)
-                .await
-            {
+            let next_block_height = self.blockchain.last_block()?.header.height + 1;
+            match verify_transactions(&overlay, next_block_height, &tx_vec, false).await {
                 Ok(_) => valid = true,
                 Err(crate::Error::TxVerifyFailed(TxVerifyFailed::ErroneousTxs(_))) => {}
                 Err(e) => return Err(e),
@@ -376,7 +360,6 @@ impl Validator {
 
         // Rebuild best fork using last proposal
         *self.consensus.forks.write().await = vec![];
-        self.consensus.generate_pow_slot().await?;
         self.consensus.append_proposal(&Proposal::new(last)?).await?;
         info!(target: "validator::finalization", "Finalization completed!");
 
@@ -559,12 +542,10 @@ impl Validator {
         let mut previous = &blocks[0];
 
         // Create a time keeper and a PoW module to validate each block
-        let time_keeper = self.consensus.time_keeper.clone();
         let mut module = PoWModule::new(blockchain.clone(), pow_target, pow_fixed_difficulty)?;
 
         // Deploy native wasm contracts
-        deploy_native_contracts(&overlay, time_keeper.verifying_block_height, &faucet_pubkeys)
-            .await?;
+        deploy_native_contracts(&overlay, 0, &faucet_pubkeys).await?;
 
         // Validate genesis block
         verify_genesis_block(&overlay, previous).await?;

+ 0 - 142
src/validator/pid.rs

@@ -1,142 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi_sdk::{blockchain::Slot, pasta::pallas};
-use lazy_static::lazy_static;
-use log::debug;
-
-use super::float_10::{
-    fbig2base, Float10, FLOAT10_NEG_ONE, FLOAT10_NEG_TWO, FLOAT10_ONE, FLOAT10_TWO, FLOAT10_ZERO,
-};
-
-/// PID controller configuration
-const P: &str = "28948022309329048855892746252171976963363056481941560715954676764349967630337";
-lazy_static! {
-    static ref FIELD_P: Float10 = Float10::try_from(P).unwrap();
-    static ref KP: Float10 = Float10::try_from("0.18").unwrap();
-    static ref KI: Float10 = Float10::try_from("0.02").unwrap();
-    static ref KD: Float10 = Float10::try_from("-0.1").unwrap();
-    static ref MAX_F: Float10 = Float10::try_from("0.99").unwrap();
-    static ref MIN_F: Float10 = Float10::try_from("0.01").unwrap();
-    static ref EPSILON: Float10 = Float10::try_from("1").unwrap();
-    // PID controller K values based on constants
-    static ref K1: Float10 = KP.clone() + KI.clone() + KD.clone();
-    static ref K2: Float10 = FLOAT10_NEG_ONE.clone() * KP.clone() + FLOAT10_NEG_TWO.clone() * KD.clone();
-    static ref K3: Float10 = KD.clone();
-}
-
-/// Return 2-term target approximation sigma coefficients,
-/// alogn with the inverse probability `f` of becoming a
-/// block producer and the feedback error, corresponding
-/// to provided slot consensus state,
-pub fn slot_pid_output(
-    previous_slot: &Slot,
-    previous_producers: u64,
-) -> (f64, f64, pallas::Base, pallas::Base) {
-    let (f, error) = calculate_f(previous_slot, previous_producers);
-    let total_tokens =
-        Float10::try_from(previous_slot.total_tokens + previous_slot.reward).unwrap();
-    let (sigma1, sigma2) = calculate_sigmas(f.clone(), total_tokens);
-
-    (f.to_f64(), error.to_f64(), sigma1, sigma2)
-}
-
-/// Calculate the inverse probability `f` of becoming a block producer (winning the lottery)
-/// having all the tokens, and the feedback error, represented as Float10.
-fn calculate_f(previous_slot: &Slot, previous_producers: u64) -> (Float10, Float10) {
-    // Convert slot values to Float10
-    let previous_slot_f = Float10::try_from(previous_slot.pid.f).unwrap();
-    debug!(target: "validator::consensus::pid::calculate_f", "Previous slot f: {previous_slot_f}");
-    let previous_slot_error = Float10::try_from(previous_slot.pid.error).unwrap();
-    debug!(target: "validator::consensus::pid::calculate_f", "Previous slot error: {previous_slot_error}");
-    let previous_slot_previous_slot_error =
-        Float10::try_from(previous_slot.previous.error).unwrap();
-    debug!(target: "validator::consensus::pid::calculate_f", "Previous slot previous slot error: {previous_slot_previous_slot_error}");
-
-    // Calculate feedback error based on previous block producers.
-    let feedback = Float10::try_from(previous_producers).unwrap();
-    debug!(target: "validator::consensus::pid::calculate_f", "Feedback: {feedback}");
-    let error = FLOAT10_ONE.clone() - feedback;
-    debug!(target: "validator::consensus::pid::calculate_f", "Error: {error}");
-
-    // Calculate f
-    let mut f = previous_slot_f +
-        K1.clone() * error.clone() +
-        K2.clone() * previous_slot_error +
-        K3.clone() * previous_slot_previous_slot_error;
-    debug!(target: "validator::consensus::pid::calculate_f", "Unbounded f: {f}");
-
-    // Boundaries control
-    if f <= *FLOAT10_ZERO {
-        f = MIN_F.clone()
-    } else if f >= *FLOAT10_ONE {
-        f = MAX_F.clone()
-    }
-    debug!(target: "validator::consensus::pid::calculate_f", "Bounded f: {f}");
-
-    (f, error)
-}
-
-/// Return 2-term target approximation sigma coefficients,
-/// corresponding to provided `f` and `total_tokens` values.
-fn calculate_sigmas(f: Float10, total_tokens: Float10) -> (pallas::Base, pallas::Base) {
-    // Calculate `neg_c` value
-    let x = FLOAT10_ONE.clone() - f;
-    let c = x.ln();
-    let neg_c = FLOAT10_NEG_ONE.clone() * c;
-    debug!(target: "validator::consensus::pid::calculate_sigmas", "neg_c: {neg_c}");
-
-    // Calculate sigma 1
-    let sigma1_fbig = neg_c.clone() / (total_tokens.clone() + EPSILON.clone()) * FIELD_P.clone();
-    let sigma1 = fbig2base(sigma1_fbig);
-    debug!(target: "validator::consensus::pid::calculate_sigmas", "Sigma 1: {sigma1:?}");
-
-    // Calculate sigma 2
-    let sigma2_fbig = (neg_c / (total_tokens + EPSILON.clone())).powf(FLOAT10_TWO.clone()) *
-        (FIELD_P.clone() / FLOAT10_TWO.clone());
-    let sigma2 = fbig2base(sigma2_fbig);
-    debug!(target: "validator::consensus::pid::calculate_sigmas", "Sigma 2: {sigma2:?}");
-
-    (sigma1, sigma2)
-}
-
-#[cfg(test)]
-mod tests {
-    use super::{calculate_f, Slot};
-    // use super::Float10;
-    use super::{MAX_F, MIN_F};
-
-    #[test]
-    fn f_is_bounded() {
-        // Method: calculate_f takes a slot previous_slot as an argument.
-        // This slot's f value is summed with other low numbers to produce f.
-        // By setting the previous_slot's f to a very large value, we can check
-        // that calculate_f is properly bounding the result of the sum.
-        let mut slot = Slot::default();
-        slot.pid.f = -1_000_000.0;
-        let (f, _) = calculate_f(&slot, 0);
-        assert!(f >= *MIN_F);
-        assert!(f <= *MAX_F);
-
-        let mut slot = Slot::default();
-        slot.pid.f = 1_000_000.0;
-        let (f, _) = calculate_f(&slot, 0);
-        assert!(f >= *MIN_F);
-        assert!(f <= *MAX_F);
-    }
-}

+ 5 - 37
src/validator/utils.rs

@@ -103,11 +103,7 @@ pub async fn deploy_native_contracts(
 /// Genesis block has rank 0.
 /// First 2 blocks rank is equal to their nonce, since their previous
 /// previous block producer doesn't exist or have a VRF.
-pub async fn block_rank(
-    block: &BlockInfo,
-    previous_previous: &BlockInfo,
-    pos_testing_mode: bool,
-) -> Result<u64> {
+pub async fn block_rank(block: &BlockInfo, previous_previous: &BlockInfo) -> Result<u64> {
     // Genesis block has rank 0
     if block.header.height == 0 {
         return Ok(0)
@@ -118,23 +114,17 @@ pub async fn block_rank(
     nonce.copy_from_slice(&block.header.nonce.to_repr()[..8]);
     let nonce = u64::from_be_bytes(nonce);
 
-    // First 2 blocks or testing ones have rank equal to their nonce
-    if block.header.height < 3 || pos_testing_mode {
+    // First 2 blocks have rank equal to their nonce
+    if block.header.height < 3 {
         return Ok(nonce)
     }
 
     // Extract VRF proof from the previous previous producer transaction
     let tx = previous_previous.txs.last().unwrap();
     let data = &tx.calls[0].data.data;
-    let position = match previous_previous.header.version {
-        // PoW uses MoneyPoWRewardParamsV1
-        1 => 563,
-        // PoS uses ConsensusProposalParamsV1
-        2 => 490,
-        _ => return Err(Error::BlockVersionIsInvalid(previous_previous.header.version)),
-    };
     let mut decoder = Cursor::new(&data);
-    decoder.set_position(position);
+    // PoW uses MoneyPoWRewardParamsV1
+    decoder.set_position(563);
     let vrf_proof: VrfProof = AsyncDecodable::decode_async(&mut decoder).await?;
 
     // Compute VRF u64
@@ -217,28 +207,6 @@ pub async fn genesis_txs_total(txs: &[Transaction]) -> Result<u64> {
     Ok(total)
 }
 
-/// Retrieve previous slot producers, last proposal hashes,
-/// and their second to last hashes, from all provided forks.
-pub fn previous_slot_info(
-    forks: &Vec<Fork>,
-    slot: u64,
-) -> Result<(u64, Vec<blake3::Hash>, Vec<blake3::Hash>)> {
-    let mut producers = 0;
-    let mut last_hashes = vec![];
-    let mut second_to_last_hashes = vec![];
-
-    for fork in forks {
-        let last_proposal = fork.last_proposal()?;
-        if last_proposal.block.header.height == slot {
-            producers += 1;
-        }
-        last_hashes.push(last_proposal.hash);
-        second_to_last_hashes.push(last_proposal.block.header.previous);
-    }
-
-    Ok((producers, last_hashes, second_to_last_hashes))
-}
-
 /// Given a proposal, find the index of the fork chain it extends, along with the specific
 /// extended proposal index. Additionally, check that proposal doesn't already exists in any
 /// fork chain.

+ 0 - 193
tests/blockchain.rs

@@ -1,193 +0,0 @@
-/* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2024 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-use darkfi::{
-    blockchain::{BlockInfo, Blockchain, BlockchainOverlay, Header},
-    validator::{
-        pid::slot_pid_output,
-        pow::PoWModule,
-        verification::{validate_block, validate_blockchain},
-    },
-    Error, Result,
-};
-use darkfi_sdk::{
-    blockchain::{expected_reward, PidOutput, PreviousSlot, Slot, POS_START},
-    pasta::{group::ff::Field, pallas},
-};
-
-const POW_TARGET: usize = 10;
-
-struct Node {
-    blockchain: Blockchain,
-    module: PoWModule,
-}
-
-impl Node {
-    fn new() -> Result<Self> {
-        let blockchain = Blockchain::new(&sled::Config::new().temporary(true).open()?)?;
-        let module = PoWModule::new(blockchain.clone(), POW_TARGET, None)?;
-        Ok(Self { blockchain, module })
-    }
-}
-
-struct Harness {
-    pub alice: Node,
-    pub bob: Node,
-}
-
-impl Harness {
-    fn new() -> Result<Self> {
-        let alice = Node::new()?;
-        let bob = Node::new()?;
-        Ok(Self { alice, bob })
-    }
-
-    fn is_empty(&self) {
-        assert!(self.alice.blockchain.is_empty());
-        assert!(self.bob.blockchain.is_empty());
-    }
-
-    fn validate_chains(&self) -> Result<()> {
-        validate_blockchain(&self.alice.blockchain, POW_TARGET, None)?;
-        validate_blockchain(&self.bob.blockchain, POW_TARGET, None)?;
-
-        assert_eq!(self.alice.blockchain.len(), self.bob.blockchain.len());
-
-        Ok(())
-    }
-
-    fn generate_next_pos_block(&self, previous: &BlockInfo) -> Result<BlockInfo> {
-        let previous_hash = previous.hash()?;
-
-        // Generate slot
-        let previous_slot = previous.slots.last().unwrap();
-        let id = if previous_slot.id < POS_START { POS_START } else { previous_slot.id + 1 };
-        let producers = 1;
-        let previous_slot_info = PreviousSlot::new(
-            producers,
-            vec![previous_hash],
-            vec![previous.header.previous],
-            previous_slot.pid.error,
-        );
-        let (f, error, sigma1, sigma2) = slot_pid_output(previous_slot, producers);
-        let pid = PidOutput::new(f, error, sigma1, sigma2);
-        let total_tokens = previous_slot.total_tokens + previous_slot.reward;
-        let reward = expected_reward(id);
-        let slot = Slot::new(id, previous_slot_info, pid, pallas::Base::ZERO, total_tokens, reward);
-
-        // We increment timestamp so we don't have to use sleep
-        let mut timestamp = previous.header.timestamp;
-        timestamp.add(1);
-
-        // Generate header
-        let header = Header::new(previous_hash, id, timestamp, previous.header.nonce);
-
-        // Generate the block
-        let mut block = BlockInfo::new_empty(header, vec![slot]);
-
-        // Add transactions to the block
-        block.append_txs(previous.txs.clone())?;
-
-        // Attach signature
-        block.signature = previous.signature;
-
-        Ok(block)
-    }
-
-    fn add_pos_blocks(&mut self, blocks: &[BlockInfo]) -> Result<()> {
-        Self::add_pos_blocks_to_chain(&mut self.alice, blocks)?;
-        Self::add_pos_blocks_to_chain(&mut self.bob, blocks)?;
-
-        Ok(())
-    }
-
-    // This is what the validator will execute when it receives a block.
-    fn add_pos_blocks_to_chain(node: &mut Node, blocks: &[BlockInfo]) -> Result<()> {
-        // Create overlay
-        let blockchain_overlay = BlockchainOverlay::new(&node.blockchain)?;
-        let lock = blockchain_overlay.lock().unwrap();
-
-        // When we insert genesis, chain is empty
-        let mut previous = if !lock.is_empty()? { Some(lock.last_block()?) } else { None };
-
-        // Validate and insert each block
-        for block in blocks {
-            // Check if block already exists
-            if lock.has_block(block)? {
-                return Err(Error::BlockAlreadyExists(block.hash()?.to_string()))
-            }
-
-            // This will be true for every insert, apart from genesis
-            if let Some(p) = previous {
-                // Validate block
-                validate_block(block, &p, &node.module)?;
-
-                // Update PoW module
-                if block.header.version == 1 {
-                    node.module.append(block.header.timestamp.0, &node.module.next_difficulty()?);
-                }
-            }
-
-            // Insert block
-            lock.add_block(block)?;
-
-            // Use last inserted block as next iteration previous
-            previous = Some(block.clone());
-        }
-
-        // Write overlay
-        lock.overlay.lock().unwrap().apply()?;
-
-        Ok(())
-    }
-}
-
-#[ignore]
-#[test]
-fn blockchain_add_pos_blocks() -> Result<()> {
-    smol::block_on(async {
-        // Initialize harness
-        let mut th = Harness::new()?;
-
-        // Check that nothing exists
-        th.is_empty();
-
-        // We generate some pos blocks
-        let mut blocks = vec![];
-
-        let genesis_block = BlockInfo::default();
-        blocks.push(genesis_block.clone());
-
-        let block = th.generate_next_pos_block(&genesis_block)?;
-        blocks.push(block.clone());
-
-        let block = th.generate_next_pos_block(&block)?;
-        blocks.push(block.clone());
-
-        let block = th.generate_next_pos_block(&block)?;
-        blocks.push(block.clone());
-
-        th.add_pos_blocks(&blocks)?;
-
-        // Validate chains
-        th.validate_chains()?;
-
-        // Thanks for reading
-        Ok(())
-    })
-}