Răsfoiți Sursa

scr/consensus: BlockOrderStore created, validatord: retrieve last block info from sled (removed redudant ConsensusState attributes), added subnets configs, simulation script modified, nodes-tool: removed redudant info

aggstam 4 ani în urmă
părinte
comite
71cd403ceb

+ 43 - 7
script/research/nodes-tool/src/main.rs

@@ -2,7 +2,7 @@ use std::{fs::File, io::Write};
 
 use darkfi::{
     consensus::{
-        block::{Block, BlockProposal, BlockStore},
+        block::{Block, BlockOrderStore, BlockProposal, BlockStore},
         blockchain::{Blockchain, ProposalsChain},
         metadata::{Metadata, OuroborosMetadata, StreamletMetadata, StreamletMetadataStore},
         participant::Participant,
@@ -141,21 +141,17 @@ impl ProposalsInfoChain {
 #[derive(Debug)]
 struct ConsensusInfo {
     _genesis: Timestamp,
-    _last_block: blake3::Hash,
-    _last_sl: u64,
     _proposals: Vec<ProposalsInfoChain>,
 }
 
 impl ConsensusInfo {
     pub fn new(consensus: &ConsensusState) -> ConsensusInfo {
         let _genesis = consensus.genesis.clone();
-        let _last_block = consensus.last_block.clone();
-        let _last_sl = consensus.last_sl.clone();
         let mut _proposals = Vec::new();
         for proposal in &consensus.proposals {
             _proposals.push(ProposalsInfoChain::new(&proposal));
         }
-        ConsensusInfo { _genesis, _last_block, _last_sl, _proposals }
+        ConsensusInfo { _genesis, _proposals }
     }
 }
 
@@ -200,6 +196,44 @@ impl BlockInfoChain {
     }
 }
 
+#[derive(Debug)]
+struct OrderInfo {
+    _sl: u64,
+    _hash: blake3::Hash,
+}
+
+impl OrderInfo {
+    pub fn new(_sl: u64, _hash: blake3::Hash) -> OrderInfo {
+        OrderInfo { _sl, _hash }
+    }
+}
+
+#[derive(Debug)]
+struct BlockOrderStoreInfo {
+    _order: Vec<OrderInfo>,
+}
+
+impl BlockOrderStoreInfo {
+    pub fn new(orderstore: &BlockOrderStore) -> BlockOrderStoreInfo {
+        let mut _order = Vec::new();
+        let result = orderstore.get_all();
+        match result {
+            Ok(iter) => {
+                for item in iter.iter() {
+                    match item {
+                        Some((slot, hash)) => {
+                            _order.push(OrderInfo::new(slot.clone(), hash.clone()))
+                        }
+                        None => (),
+                    };
+                }
+            }
+            Err(e) => println!("Error: {:?}", e),
+        }
+        BlockOrderStoreInfo { _order }
+    }
+}
+
 #[derive(Debug)]
 struct TxInfo {
     _hash: blake3::Hash,
@@ -279,6 +313,7 @@ impl MetadataStoreInfo {
 #[derive(Debug)]
 struct BlockchainInfo {
     _blocks: BlockInfoChain,
+    _order: BlockOrderStoreInfo,
     _transactions: TxStoreInfo,
     _metadata: MetadataStoreInfo,
 }
@@ -286,9 +321,10 @@ struct BlockchainInfo {
 impl BlockchainInfo {
     pub fn new(blockchain: &Blockchain) -> BlockchainInfo {
         let _blocks = BlockInfoChain::new(&blockchain.blocks);
+        let _order = BlockOrderStoreInfo::new(&blockchain.order);
         let _transactions = TxStoreInfo::new(&blockchain.transactions);
         let _metadata = MetadataStoreInfo::new(&blockchain.streamlet_metadata);
-        BlockchainInfo { _blocks, _transactions, _metadata }
+        BlockchainInfo { _blocks, _order, _transactions, _metadata }
     }
 }
 

+ 18 - 2
script/research/validatord/simulation.sh

@@ -25,7 +25,15 @@ sleep 2
 bound=$(($nodes-2))
 for i in $(eval echo "{1..$bound}")
 do
-  cargo run -- --accept 0.0.0.0:1100$i --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$i --external 127.0.0.1:1100$i --id $i --database ~/.config/darkfi/validatord_db_$i &
+  cargo run -- \
+    --accept 0.0.0.0:1100$i \
+    --caccept 0.0.0.0:1200$i \
+    --cseeds 127.0.0.1:12000 \
+    --rpc 127.0.0.1:666$i \
+    --external 127.0.0.1:1100$i \
+    --cexternal 127.0.0.1:1200$i \
+    --id $i \
+    --database ~/.config/darkfi/validatord_db_$i &
   pids[${#pids[@]}]=$!
   # waiting for node to setup
   sleep 2
@@ -44,7 +52,15 @@ function ctrl_c() {
 
 bound=$(($nodes-1))
 # Starting last node
-cargo run -- --accept 0.0.0.0:1100$bound --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$bound --external 127.0.0.1:1100$bound --id $bound --database ~/.config/darkfi/validatord_db_$bound
+cargo run -- \
+    --accept 0.0.0.0:1100$bound \
+    --caccept 0.0.0.0:1200$bound \
+    --cseeds 127.0.0.1:12000 \
+    --rpc 127.0.0.1:666$bound \
+    --external 127.0.0.1:1100$bound \
+    --cexternal 127.0.0.1:1200$bound \
+    --id $bound \
+    --database ~/.config/darkfi/validatord_db_$bound
 
 # Node states are flushed on each node state file at epoch end (every 2 minutes).
 # To sugmit a TX, telnet to a node and push the json as per following example:

+ 28 - 4
script/research/validatord/src/main.rs

@@ -51,10 +51,16 @@ struct Opt {
     #[structopt(long, default_value = "0.0.0.0:11000")]
     /// Accept address
     accept: SocketAddr,
+    #[structopt(long, default_value = "0.0.0.0:12000")]
+    /// Consensus accept address
+    caccept: SocketAddr,
     #[structopt(long)]
     /// Seed nodes
     seeds: Vec<SocketAddr>,
     #[structopt(long)]
+    /// Consensus seed nodes
+    cseeds: Vec<SocketAddr>,
+    #[structopt(long)]
     /// Manual connections
     connect: Vec<SocketAddr>,
     #[structopt(long, default_value = "5")]
@@ -63,6 +69,9 @@ struct Opt {
     #[structopt(long, default_value = "127.0.0.1:11000")]
     /// External address
     external: SocketAddr,
+    #[structopt(long, default_value = "127.0.0.1:12000")]
+    /// Consensus accept address
+    cexternal: SocketAddr,
     #[structopt(long, default_value = "/tmp/darkfid.log")]
     /// Logfile path
     log: String,
@@ -188,7 +197,8 @@ async fn start(executor: Arc<Executor<'_>>, opts: &Opt) -> Result<()> {
         identity_pass: opts.password.clone(),
     };
 
-    let network_settings = net::Settings {
+    // Main subnet settings
+    let subnet_settings = net::Settings {
         inbound: Some(opts.accept),
         outbound_connections: opts.slots,
         external_addr: Some(opts.external),
@@ -197,14 +207,28 @@ async fn start(executor: Arc<Executor<'_>>, opts: &Opt) -> Result<()> {
         ..Default::default()
     };
 
+    // Consensus subnet settings
+    let consensus_subnet_settings = net::Settings {
+        inbound: Some(opts.caccept),
+        outbound_connections: opts.slots,
+        external_addr: Some(opts.cexternal),
+        peers: opts.connect.clone(),
+        seeds: opts.cseeds.clone(),
+        ..Default::default()
+    };
+
     // State setup
     let genesis = opts.genesis;
     let database_path = expand_path(&opts.database).unwrap();
     let id = opts.id.clone();
     let state = ValidatorState::new(database_path, id, genesis).unwrap();
 
-    // P2P registry setup
-    let p2p = net::P2p::new(network_settings).await;
+    // Main P2P registry setup
+    let p2p = net::P2p::new(subnet_settings).await;
+    let _registry = p2p.protocol_registry();
+
+    // Consensus P2P registry setup
+    let p2p = net::P2p::new(consensus_subnet_settings).await;
     let registry = p2p.protocol_registry();
 
     // Adding ProtocolTx to the registry
@@ -245,7 +269,7 @@ async fn start(executor: Arc<Executor<'_>>, opts: &Opt) -> Result<()> {
 
     // Performs seed session
     p2p.clone().start(executor.clone()).await?;
-    // Actual main p2p session
+    // Actual consensus p2p session
     let ex2 = executor.clone();
     let p2p2 = p2p.clone();
     executor

+ 9 - 0
script/research/validatord/validatord_config.toml

@@ -9,9 +9,15 @@ config = "~/.config/darkfi/validatord_config.toml"
 # Accept address
 accept = "0.0.0.0:11000"
 
+# Consensus accept address
+caccept = "0.0.0.0:12000"
+
 # Seed nodes
 #seeds = "127.0.0.1:11000"
 
+# Consensus seed nodes
+#cseeds = "127.0.0.1:12000"
+
 # Manual connections
 #connect = "127.0.0.1:11000"
 
@@ -21,6 +27,9 @@ slots = 5
 # External address
 external = "127.0.0.1:11000"
 
+# Consensus external address
+cexternal = "127.0.0.1:12000"
+
 # Logfile path
 #log = "/tmp/darkfid.log"
 

+ 54 - 0
src/consensus/block.rs

@@ -16,6 +16,7 @@ use super::{
 };
 
 const SLED_BLOCK_TREE: &[u8] = b"_blocks";
+const SLED_BLOCK_ORDER_TREE: &[u8] = b"_blocks_order";
 
 /// This struct represents a tuple of the form (st, sl, txs, metadata).
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
@@ -91,6 +92,59 @@ impl BlockStore {
     }
 }
 
+#[derive(Debug)]
+pub struct BlockOrderStore(sled::Tree);
+
+impl BlockOrderStore {
+    /// Opens a new or existing blockorderstore tree given a sled database.
+    pub fn new(db: &sled::Db, genesis: i64) -> Result<Self> {
+        let tree = db.open_tree(SLED_BLOCK_ORDER_TREE)?;
+        let store = Self(tree);
+        if store.0.is_empty() {
+            // Genesis block record is generated.
+            let block = Block::genesis_block(genesis);
+            let blockhash = blake3::hash(&serialize(&block));
+            store.insert(block.sl, blockhash)?;
+        }
+
+        Ok(store)
+    }
+
+    /// Insert a block hash into the blockorderstore.
+    /// The block slot is used as the key, where value is the block hash.
+    pub fn insert(&self, slot: u64, block: blake3::Hash) -> Result<()> {
+        self.0.insert(slot.to_be_bytes(), serialize(&block))?;
+        Ok(())
+    }
+
+    /// Retrieve the last block hash in the tree, based on the Ord implementation for Vec<u8>.
+    pub fn get_last(&self) -> Result<Option<(u64, blake3::Hash)>> {
+        if let Some(found) = self.0.last()? {
+            let slot_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap();
+            let slot = u64::from_be_bytes(slot_bytes);
+            let block_hash = deserialize(&found.1)?;
+            return Ok(Some((slot, block_hash)))
+        }
+
+        Ok(None)
+    }
+
+    /// Retrieve all blocks hashes.
+    /// Be carefull as this will try to load everything in memory.
+    pub fn get_all(&self) -> Result<Vec<Option<(u64, blake3::Hash)>>> {
+        let mut block_hashes = Vec::new();
+        let mut iterator = self.0.into_iter().enumerate();
+        while let Some((_, r)) = iterator.next() {
+            let (k, v) = r.unwrap();
+            let slot_bytes: [u8; 8] = k.as_ref().try_into().unwrap();
+            let slot = u64::from_be_bytes(slot_bytes);
+            let block_hash = deserialize(&v)?;
+            block_hashes.push(Some((slot, block_hash)));
+        }
+        Ok(block_hashes)
+    }
+}
+
 /// This struct represents a Block proposal, used for consensus.
 #[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
 pub struct BlockProposal {

+ 13 - 2
src/consensus/blockchain.rs

@@ -9,7 +9,7 @@ use crate::{
 };
 
 use super::{
-    block::{Block, BlockProposal, BlockStore},
+    block::{Block, BlockOrderStore, BlockProposal, BlockStore},
     metadata::StreamletMetadataStore,
     tx::TxStore,
 };
@@ -19,6 +19,8 @@ use super::{
 pub struct Blockchain {
     /// Blocks sled database
     pub blocks: BlockStore,
+    /// Blocks order sled database
+    pub order: BlockOrderStore,
     /// Transactions sled database
     pub transactions: TxStore,
     /// Streamlet metadata sled database
@@ -28,9 +30,10 @@ pub struct Blockchain {
 impl Blockchain {
     pub fn new(db: &sled::Db, genesis: i64) -> Result<Blockchain> {
         let blocks = BlockStore::new(db, genesis)?;
+        let order = BlockOrderStore::new(db, genesis)?;
         let transactions = TxStore::new(db)?;
         let streamlet_metadata = StreamletMetadataStore::new(db)?;
-        Ok(Blockchain { blocks, transactions, streamlet_metadata })
+        Ok(Blockchain { blocks, order, transactions, streamlet_metadata })
     }
 
     /// Insertion of a block proposal.
@@ -46,11 +49,19 @@ impl Blockchain {
         let block = Block { st: proposal.st, sl: proposal.sl, txs, metadata: proposal.metadata };
         let hash = self.blocks.insert(&block)?;
 
+        // Storing block order
+        self.order.insert(block.sl, hash)?;
+
         // Storing streamlet metadata
         self.streamlet_metadata.insert(hash, &proposal.sm)?;
 
         Ok(hash)
     }
+
+    /// Retrieve the last block slot and hash.
+    pub fn last(&self) -> Result<Option<(u64, blake3::Hash)>> {
+        self.order.get_last()
+    }
 }
 
 /// This struct represents a sequence of block proposals.

+ 7 - 14
src/consensus/state.rs

@@ -32,15 +32,10 @@ const DELTA: u64 = 60;
 const SLED_CONSESUS_STATE_TREE: &[u8] = b"_consensus_state";
 
 /// This struct represents the information required by the consensus algorithm.
-/// Last finalized block hash and slot are used because SLED order follows the Ord implementation for Vec<u8>.
 #[derive(Debug, SerialEncodable, SerialDecodable)]
 pub struct ConsensusState {
     /// Genesis block creation timestamp
     pub genesis: Timestamp,
-    /// Last finalized block hash,
-    pub last_block: blake3::Hash,
-    /// Last finalized block slot,
-    pub last_sl: u64,
     /// Fork chains containing block proposals
     pub proposals: Vec<ProposalsChain>,
     /// Orphan votes pool, in case a vote reaches a node before the corresponding block
@@ -59,8 +54,6 @@ impl ConsensusState {
         } else {
             let consensus = ConsensusState {
                 genesis: Timestamp(genesis),
-                last_block: blake3::hash(&serialize(&Block::genesis_block(genesis))),
-                last_sl: 0,
                 proposals: Vec::new(),
                 orphan_votes: Vec::new(),
                 participants: BTreeMap::new(),
@@ -226,7 +219,7 @@ impl ValidatorState {
             }
             longest_notarized_chain.proposals.last().unwrap().hash()
         } else {
-            self.consensus.last_block
+            self.blockchain.last()?.unwrap().1
         };
         Ok(hash)
     }
@@ -334,7 +327,8 @@ impl ValidatorState {
             }
         }
 
-        if proposal.st != self.consensus.last_block || proposal.sl <= self.consensus.last_sl {
+        let (last_sl, last_block) = self.blockchain.last()?.unwrap();
+        if proposal.st != last_block || proposal.sl <= last_sl {
             debug!("Proposal doesn't extend any known chains.");
             return Ok(-2)
         }
@@ -471,15 +465,14 @@ impl ValidatorState {
                 }
                 chain.proposals.drain(0..(consecutive - 1));
                 for proposal in &finalized {
-                    let hash = self.blockchain.add(proposal.clone())?;
-                    self.consensus.last_block = hash;
-                    self.consensus.last_sl = proposal.sl;
+                    self.blockchain.add(proposal.clone())?;
                 }
 
+                let (last_sl, last_block) = self.blockchain.last()?.unwrap();
                 let mut dropped = Vec::new();
                 for chain in self.consensus.proposals.iter() {
                     let first = chain.proposals.first().unwrap();
-                    if first.st != self.consensus.last_block || first.sl <= self.consensus.last_sl {
+                    if first.st != last_block || first.sl <= last_sl {
                         dropped.push(chain.clone());
                     }
                 }
@@ -490,7 +483,7 @@ impl ValidatorState {
                 // Remove orphan votes
                 let mut orphans = Vec::new();
                 for vote in self.consensus.orphan_votes.iter() {
-                    if vote.sl <= self.consensus.last_sl {
+                    if vote.sl <= last_sl {
                         orphans.push(vote.clone());
                     }
                 }