Просмотр исходного кода

research: Remove obsolete Rust code.

parazyd 4 лет назад
Родитель
Сommit
0beab27e31
43 измененных файлов с 0 добавлено и 4631 удалено
  1. 0 2
      script/research/consensusd/.gitignore
  2. 0 32
      script/research/consensusd/Cargo.toml
  3. 0 25
      script/research/consensusd/consensusd_config.toml
  4. 0 1
      script/research/consensusd/src/lib.rs
  5. 0 144
      script/research/consensusd/src/main.rs
  6. 0 245
      script/research/consensusd/src/service/api_service.rs
  7. 0 57
      script/research/consensusd/src/service/block.rs
  8. 0 56
      script/research/consensusd/src/service/blockchain.rs
  9. 0 61
      script/research/consensusd/src/service/metadata.rs
  10. 0 14
      script/research/consensusd/src/service/mod.rs
  11. 0 359
      script/research/consensusd/src/service/state.rs
  12. 0 40
      script/research/consensusd/src/service/util.rs
  13. 0 21
      script/research/consensusd/src/service/vote.rs
  14. 0 2
      script/research/streamlet_rust/.gitignore
  15. 0 13
      script/research/streamlet_rust/Cargo.toml
  16. 0 179
      script/research/streamlet_rust/src/lib.rs
  17. 0 54
      script/research/streamlet_rust/src/structures/block.rs
  18. 0 54
      script/research/streamlet_rust/src/structures/blockchain.rs
  19. 0 58
      script/research/streamlet_rust/src/structures/metadata.rs
  20. 0 15
      script/research/streamlet_rust/src/structures/mod.rs
  21. 0 343
      script/research/streamlet_rust/src/structures/node.rs
  22. 0 19
      script/research/streamlet_rust/src/structures/vote.rs
  23. 0 2
      script/research/validatord/.gitignore
  24. 0 41
      script/research/validatord/Cargo.toml
  25. 0 70
      script/research/validatord/simulation.sh
  26. 0 340
      script/research/validatord/src/consensus/block.rs
  27. 0 203
      script/research/validatord/src/consensus/blockchain.rs
  28. 0 121
      script/research/validatord/src/consensus/metadata.rs
  29. 0 16
      script/research/validatord/src/consensus/mod.rs
  30. 0 55
      script/research/validatord/src/consensus/participant.rs
  31. 0 725
      script/research/validatord/src/consensus/state.rs
  32. 0 78
      script/research/validatord/src/consensus/tx.rs
  33. 0 28
      script/research/validatord/src/consensus/util.rs
  34. 0 43
      script/research/validatord/src/consensus/vote.rs
  35. 0 530
      script/research/validatord/src/main.rs
  36. 0 13
      script/research/validatord/src/protocols/mod.rs
  37. 0 77
      script/research/validatord/src/protocols/protocol_participant.rs
  38. 0 88
      script/research/validatord/src/protocols/protocol_proposal.rs
  39. 0 119
      script/research/validatord/src/protocols/protocol_sync.rs
  40. 0 72
      script/research/validatord/src/protocols/protocol_sync_consensus.rs
  41. 0 74
      script/research/validatord/src/protocols/protocol_tx.rs
  42. 0 85
      script/research/validatord/src/protocols/protocol_vote.rs
  43. 0 57
      script/research/validatord/validatord_config.toml

+ 0 - 2
script/research/consensusd/.gitignore

@@ -1,2 +0,0 @@
-Cargo.lock
-target/*

+ 0 - 32
script/research/consensusd/Cargo.toml

@@ -1,32 +0,0 @@
-[package]
-name = "consensusd"
-version = "0.3.0"
-edition = "2021"
-
-[dependencies.darkfi]
-path = "../../../"
-features = ["crypto", "rpc"]
-
-[dependencies]
-chrono = "0.4.19"
-rand = "0.8.5"
-
-# Async
-smol = "1.2.5"
-async-std = "1.11.0"
-async-trait = "0.1.53"
-async-channel = "1.6.1"
-async-executor = "1.4.1"
-easy-parallel = "3.2.0"
-
-# Misc
-clap = {version = "3.1.18", features = ["derive"]}
-log = "0.4.17"
-num_cpus = "1.13.1"
-simplelog = "0.12.0"
-
-# Encoding and parsing
-serde = {version = "1.0.137", features = ["derive"]}
-serde_json = "1.0.81"
-
-[workspace]

+ 0 - 25
script/research/consensusd/consensusd_config.toml

@@ -1,25 +0,0 @@
-## chaind configuration file
-##
-## Please make sure you go through all the settings so you can configure
-## your daemon properly.
-
-# The endpoint where chaind will bind its RPC socket
-rpc_listen_address = "127.0.0.1:9000"
-
-# Whether to listen with TLS or plain TCP
-serve_tls = false
-
-# Path to DER-formatted PKCS#12 archive. (Unused if serve_tls=false)
-# This can be created using openssl:
-# openssl pkcs12 -export -out chaind_identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
-tls_identity_path = "~/.config/darkfi/consensusd_identity.pfx"
-
-# Password for the created TLS identity. (Unused if serve_tls=false)
-tls_identity_password = "FOOBAR"
-
-# Path to the state file 
-state_path = "~/.config/darkfi/consensusd_state_0"
-
-# Node ID, used only for testing
-id = 0
-

+ 0 - 1
script/research/consensusd/src/lib.rs

@@ -1 +0,0 @@
-pub mod service;

+ 0 - 144
script/research/consensusd/src/main.rs

@@ -1,144 +0,0 @@
-use std::{net::SocketAddr, thread, time};
-
-use async_executor::Executor;
-use async_std::sync::Arc;
-use clap::{IntoApp, Parser};
-use easy_parallel::Parallel;
-use serde::{Deserialize, Serialize};
-use simplelog::{ColorChoice, TermLogger, TerminalMode};
-
-use darkfi::{
-    rpc::rpcserver::{listen_and_serve, RpcServerConfig},
-    util::{
-        cli::{log_config, spawn_config, Config},
-        expand_path,
-        path::get_config_path,
-    },
-    Result,
-};
-
-use consensusd::service::{APIService, State};
-
-/// This struct represent the configuration parameters used by the Consensus daemon.
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct ConsensusdConfig {
-    /// The endpoint where chaind will bind its RPC socket
-    pub rpc_listen_address: SocketAddr,
-    /// Whether to listen with TLS or plain TCP
-    pub serve_tls: bool,
-    /// Path to DER-formatted PKCS#12 archive. (Unused if serve_tls=false)
-    pub tls_identity_path: String,
-    /// Password for the TLS identity. (Unused if serve_tls=false)
-    pub tls_identity_password: String,
-    /// Path to the state file
-    pub state_path: String,
-    /// Node ID, used only for testing
-    pub id: u64,
-}
-
-/// Chaind cli configuration.
-#[derive(Parser)]
-#[clap(name = "consensusd")]
-pub struct CliConsensusd {
-    /// Sets a custom config file
-    #[clap(short, long)]
-    pub config: Option<String>,
-    /// Increase verbosity
-    #[clap(short, parse(from_occurrences))]
-    pub verbose: u8,
-}
-
-/// RPCAPI service initialization.
-async fn api_service_init(executor: Arc<Executor<'_>>, config: &ConsensusdConfig) -> Result<()> {
-    let server_config = RpcServerConfig {
-        socket_addr: config.rpc_listen_address,
-        use_tls: config.serve_tls,
-        identity_path: expand_path(&config.clone().tls_identity_path)?,
-        identity_pass: config.tls_identity_password.clone(),
-    };
-
-    let state_path = expand_path(&config.state_path)?;
-    let id = config.id;
-
-    let api_service = APIService::new(id, state_path)?;
-
-    listen_and_serve(server_config, api_service, executor).await
-}
-
-/// RPCAPI:
-/// Node checks if its the current slot leader and generates the slot Block (represented as a Vote structure).
-/// Missing: 1. Nodes count not hard coded.
-///          2. Proposed block broadcast.
-fn proposal_task(config: &ConsensusdConfig) {
-    let state_path = expand_path(&config.state_path).unwrap();
-    let id = config.id;
-    let nodes_count = 1;
-
-    println!("Waiting for state initialization...");
-    thread::sleep(time::Duration::from_secs(10));
-
-    // After initialization node should wait for next epoch
-    let state = State::load_current_state(id, &state_path).unwrap();
-    let seconds_until_next_epoch = state.get_seconds_until_next_epoch_start();
-    println!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
-    thread::sleep(seconds_until_next_epoch);
-
-    loop {
-        let state = State::load_current_state(id, &state_path).unwrap();
-        let proposed_block =
-            if state.check_if_epoch_leader(nodes_count) { state.propose_block() } else { None };
-        if proposed_block.is_none() {
-            println!("Node is not the epoch leader. Sleeping till next epoch...");
-        } else {
-            // Missing: Proposed block broadcast.
-            println!("Node is the epoch leader. Proposed block: {:?}", proposed_block);
-        }
-
-        let seconds_until_next_epoch = state.get_seconds_until_next_epoch_start();
-        println!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
-        thread::sleep(seconds_until_next_epoch);
-    }
-}
-
-const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../consensusd_config.toml");
-
-/// Consensus daemon initialization.
-#[async_std::main]
-async fn main() -> Result<()> {
-    let args = CliConsensusd::parse();
-    let matches = CliConsensusd::command().get_matches();
-
-    let verbosity_level = matches.occurrences_of("verbose");
-    let (lvl, conf) = log_config(verbosity_level)?;
-    TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
-
-    let config_path = get_config_path(args.config, "consensusd_config.toml")?;
-    spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
-
-    let config: ConsensusdConfig = Config::<ConsensusdConfig>::load(config_path)?;
-
-    let main_ex = Arc::new(Executor::new());
-    let api_ex = main_ex.clone();
-    let (signal, shutdown) = async_channel::unbounded::<()>();
-    let signal1 = signal.clone();
-    let signal2 = signal.clone();
-    let (result, _) = Parallel::new()
-        // Run the RCP API service future in background.
-        .add(|| {
-            smol::future::block_on(async {
-                api_service_init(api_ex, &config).await?;
-                drop(signal1);
-                Ok::<(), darkfi::Error>(())
-            })
-        })
-        // Run the proposal task in background.
-        .add(|| {
-            proposal_task(&config);
-            drop(signal2);
-            Ok::<(), darkfi::Error>(())
-        })
-        // Run the shutdown signal receive future on the current thread.
-        .finish(|| smol::future::block_on(main_ex.run(shutdown.recv())));
-
-    result.first().unwrap().clone()
-}

+ 0 - 245
script/research/consensusd/src/service/api_service.rs

@@ -1,245 +0,0 @@
-use std::path::PathBuf;
-
-use async_executor::Executor;
-use async_std::sync::Arc;
-use async_trait::async_trait;
-use log::debug;
-use serde::Serialize;
-use serde_json::{json, Value};
-
-use darkfi::{
-    crypto::keypair::PublicKey,
-    rpc::{
-        jsonrpc,
-        jsonrpc::{
-            response as jsonresp,
-            ErrorCode::{InvalidParams, MethodNotFound, ServerError},
-            JsonRequest, JsonResult,
-        },
-        rpcserver::RequestHandler,
-    },
-    Result,
-};
-
-use super::{state::State, vote::Vote};
-
-/// This struct represent the Consensus service RPC daemon.
-#[derive(Serialize)]
-pub struct APIService {
-    id: u64,
-    state_path: PathBuf,
-}
-
-impl APIService {
-    pub fn new(id: u64, state_path: PathBuf) -> Result<Arc<APIService>> {
-        match State::reset(id, &state_path) {
-            Err(e) => return Err(e),
-            _ => (),
-        }
-
-        Ok(Arc::new(APIService { id, state_path }))
-    }
-
-    /// RPCAPI:
-    /// Hello world example.
-    /// --> {"jsonrpc": "2.0", "method": "say_hello", "params": [], "id": 0}
-    /// <-- {"jsonrpc": "2.0", "result": "hello world", "id": 0}
-    async fn say_hello(&self) -> JsonResult {
-        JsonResult::Resp(jsonresp(json!("hello world"), serde_json::to_value(self.id).unwrap()))
-    }
-
-    /// RPCAPI:
-    /// Node receives a transaction and stores it in its current state.
-    /// --> {"jsonrpc": "2.0", "method": "receive_tx", "params": ["tx"], "id": 0}
-    /// <-- {"jsonrpc": "2.0", "result": true, "id": 0}
-    async fn receive_tx(&self, params: Value) -> JsonResult {
-        let args = params.as_array().unwrap();
-
-        if args.len() != 1 {
-            return jsonrpc::error(InvalidParams, None, serde_json::to_value(self.id).unwrap())
-                .into()
-        }
-
-        let mut state = State::load_current_state(self.id, &self.state_path).unwrap();
-        let tx = String::from(args[0].as_str().unwrap());
-
-        let result = || -> Result<()> {
-            state.append_tx(tx);
-            state.save(&self.state_path)?;
-            Ok(())
-        };
-
-        match result() {
-            Ok(()) => {
-                JsonResult::Resp(jsonresp(json!(true), serde_json::to_value(self.id).unwrap()))
-            }
-            Err(e) => jsonrpc::error(
-                ServerError(-32603),
-                Some(e.to_string()),
-                serde_json::to_value(self.id).unwrap(),
-            )
-            .into(),
-        }
-    }
-
-    /// RPCAPI:
-    /// Node checks if its the current slot leader and generates the slot Block (represented as a Vote structure).
-    /// --> {"jsonrpc": "2.0", "method": "consensus_task", "params": [1], "id": 0}
-    /// <-- {"jsonrpc": "2.0", "result": [PublicKey, Vote], "id": 0}
-    /// Missing: 1, This should be a scheduled task.
-    ///          2. Nodes count not from request.
-    ///          3. Proposed block broadcast.
-    async fn consensus_task(&self, params: Value) -> JsonResult {
-        let args = params.as_array().unwrap();
-
-        if args.len() != 1 {
-            return jsonrpc::error(InvalidParams, None, serde_json::to_value(self.id).unwrap())
-                .into()
-        }
-
-        let state = State::load_current_state(self.id, &self.state_path).unwrap();
-        let nodes_count = args[0].as_u64().unwrap();
-
-        let result = || -> Result<_> {
-            let proposed_block =
-                if state.check_if_epoch_leader(nodes_count) { state.propose_block() } else { None };
-            Ok(proposed_block)
-        };
-
-        match result() {
-            Ok(x) => {
-                if x.is_none() {
-                    JsonResult::Resp(jsonresp(
-                        json!("Node is not the epoch leader"),
-                        serde_json::to_value(self.id).unwrap(),
-                    ))
-                } else {
-                    // Missing: Proposed block broadcast.
-                    JsonResult::Resp(jsonresp(
-                        json!((state.public_key, x)),
-                        serde_json::to_value(self.id).unwrap(),
-                    ))
-                }
-            }
-            Err(e) => jsonrpc::error(
-                ServerError(-32603),
-                Some(e.to_string()),
-                serde_json::to_value(self.id).unwrap(),
-            )
-            .into(),
-        }
-    }
-
-    /// RPCAPI:
-    /// Node receives a proposed block, verifies it and stores it in its current state.
-    /// --> {"jsonrpc": "2.0", "method": "receive_proposed_block", "params": [PublicKey, Vote, 1], "id": 0}
-    /// <-- {"jsonrpc": "2.0", "result": [PublicKey, Vote], "id": 0}
-    /// Missing: 1. Nodes count not from request.
-    ///          2. Vote broadcast.
-    async fn receive_proposed_block(&self, params: Value) -> JsonResult {
-        let args = params.as_array().unwrap();
-
-        if args.len() != 3 {
-            return jsonrpc::error(InvalidParams, None, serde_json::to_value(self.id).unwrap())
-                .into()
-        }
-
-        let mut state = State::load_current_state(self.id, &self.state_path).unwrap();
-        let proposer_public_key: PublicKey = serde_json::from_value(args[0].clone()).unwrap();
-        let proposed_block: Vote = serde_json::from_value(args[1].clone()).unwrap();
-        let nodes_count = args[2].as_u64().unwrap();
-
-        let mut result = || -> Result<_> {
-            let vote =
-                state.receive_proposed_block(&proposer_public_key, &proposed_block, nodes_count);
-            if vote.is_some() {
-                state.save(&self.state_path)?;
-            }
-            Ok(vote)
-        };
-
-        match result() {
-            Ok(x) => {
-                if x.is_none() {
-                    JsonResult::Resp(jsonresp(
-                        json!("Node did not vote for the proposed block."),
-                        serde_json::to_value(self.id).unwrap(),
-                    ))
-                } else {
-                    // Missing: Vote broadcast.
-                    JsonResult::Resp(jsonresp(
-                        json!((state.public_key, x)),
-                        serde_json::to_value(self.id).unwrap(),
-                    ))
-                }
-            }
-            Err(e) => jsonrpc::error(
-                ServerError(-32603),
-                Some(e.to_string()),
-                serde_json::to_value(self.id).unwrap(),
-            )
-            .into(),
-        }
-    }
-
-    /// RPCAPI:
-    /// Node receives a block vote and perform the consensus protocol corresponding functions, based on its current state.
-    /// --> {"jsonrpc": "2.0", "method": "receive_vote", "params": [PublicKey, Vote, 1], "id": 0}
-    /// <-- {"jsonrpc": "2.0", "result": true, "id": 0}
-    /// Missing: 1. Nodes count not from request.
-    async fn receive_vote(&self, params: Value) -> JsonResult {
-        let args = params.as_array().unwrap();
-
-        if args.len() != 3 {
-            return jsonrpc::error(InvalidParams, None, serde_json::to_value(self.id).unwrap())
-                .into()
-        }
-
-        let mut state = State::load_current_state(self.id, &self.state_path).unwrap();
-        let voter_public_key: PublicKey = serde_json::from_value(args[0].clone()).unwrap();
-        let vote: Vote = serde_json::from_value(args[1].clone()).unwrap();
-        let nodes_count = args[2].as_u64().unwrap() as usize;
-
-        let mut result = || -> Result<()> {
-            state.receive_vote(&voter_public_key, &vote, nodes_count);
-            state.save(&self.state_path)?;
-            Ok(())
-        };
-
-        match result() {
-            Ok(()) => {
-                JsonResult::Resp(jsonresp(json!(true), serde_json::to_value(self.id).unwrap()))
-            }
-            Err(e) => jsonrpc::error(
-                ServerError(-32603),
-                Some(e.to_string()),
-                serde_json::to_value(self.id).unwrap(),
-            )
-            .into(),
-        }
-    }
-}
-
-#[async_trait]
-impl RequestHandler for APIService {
-    /// RPC methods configuration.
-    async fn handle_request(&self, req: JsonRequest, _executor: Arc<Executor<'_>>) -> JsonResult {
-        if req.id.as_u64().unwrap() != self.id || req.params.as_array().is_none() {
-            return jsonrpc::error(InvalidParams, None, serde_json::to_value(self.id).unwrap())
-                .into()
-        }
-
-        debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
-
-        return match req.method.as_str() {
-            Some("say_hello") => self.say_hello().await,
-            Some("receive_tx") => self.receive_tx(req.params).await,
-            Some("consensus_task") => self.consensus_task(req.params).await,
-            Some("receive_proposed_block") => self.receive_proposed_block(req.params).await,
-            Some("receive_vote") => self.receive_vote(req.params).await,
-            Some(_) | None => {
-                jsonrpc::error(MethodNotFound, None, serde_json::to_value(self.id).unwrap()).into()
-            }
-        }
-    }
-}

+ 0 - 57
script/research/consensusd/src/service/block.rs

@@ -1,57 +0,0 @@
-use serde::{Deserialize, Serialize};
-use std::hash::{Hash, Hasher};
-
-use super::metadata::Metadata;
-
-// use darkfi::{tx::Transaction, util::serial::Encodable};
-use darkfi::util::serial::Encodable; // testing
-
-/// This struct represents a tuple of the form (st, sl, txs, metadata).
-/// Each blocks parent hash h may be computed simply as a hash of the parent block.
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct Block {
-    /// Previous block hash
-    pub st: String,
-    /// Slot uid, generated by the beacon
-    pub sl: u64,
-    /// Transactions payload
-    pub txs: Vec<String>,
-    /// Additional block information
-    pub metadata: Metadata,
-}
-
-impl Block {
-    pub fn new(
-        st: String,
-        sl: u64,
-        txs: Vec<String>,
-        proof: String,
-        r: String,
-        s: String,
-    ) -> Block {
-        Block { st, sl, txs, metadata: Metadata::new(proof, r, s) }
-    }
-
-    pub fn signature_encode(&self) -> Vec<u8> {
-        let mut encoded_block = Vec::new();
-        let mut len = 0;
-        len += self.st.encode(&mut encoded_block).unwrap();
-        len += self.sl.encode(&mut encoded_block).unwrap();
-        // len += self.txs.encode(&mut encoded_block).unwrap();
-        len += String::from_iter(self.txs.clone()).encode(&mut encoded_block).unwrap(); // testing
-        assert_eq!(len, encoded_block.len());
-        encoded_block
-    }
-}
-
-impl PartialEq for Block {
-    fn eq(&self, other: &Self) -> bool {
-        self.st == other.st && self.sl == other.sl && self.txs == other.txs
-    }
-}
-
-impl Hash for Block {
-    fn hash<H: Hasher>(&self, hasher: &mut H) {
-        format!("{:?}{:?}{:?}", self.st, self.sl, self.txs).hash(hasher);
-    }
-}

+ 0 - 56
script/research/consensusd/src/service/blockchain.rs

@@ -1,56 +0,0 @@
-use std::{
-    collections::hash_map::DefaultHasher,
-    hash::{Hash, Hasher},
-};
-
-use serde::{Deserialize, Serialize};
-
-use super::block::Block;
-
-/// This struct represents a sequence of blocks starting with the genesis block.
-#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
-pub struct Blockchain {
-    pub blocks: Vec<Block>,
-}
-
-impl Blockchain {
-    pub fn new(intial_block: Block) -> Blockchain {
-        Blockchain { blocks: vec![intial_block] }
-    }
-
-    /// A block is considered valid when its parent hash is equal to the hash of the
-    /// previous block and their epochs are incremental, exluding genesis.
-    /// Additional validity rules can be applied.
-    pub fn check_block_validity(&self, block: &Block, previous_block: &Block) {
-        assert!(block.st != "⊥", "Genesis block provided.");
-        let mut hasher = DefaultHasher::new();
-        previous_block.hash(&mut hasher);
-        assert!(
-            block.st == hasher.finish().to_string() && block.sl > previous_block.sl,
-            "Provided block is invalid."
-        );
-    }
-
-    /// A blockchain is considered valid, when every block is valid, based on check_block_validity method.
-    pub fn check_chain_validity(&self) {
-        for (index, block) in self.blocks[1..].iter().enumerate() {
-            self.check_block_validity(&block, &self.blocks[index])
-        }
-    }
-
-    /// Insertion of a valid block.
-    pub fn add_block(&mut self, block: &Block) {
-        self.check_block_validity(&block, &self.blocks.last().unwrap());
-        self.blocks.push(block.clone());
-    }
-
-    /// Blockchain notarization check.
-    pub fn is_notarized(&self) -> bool {
-        for block in &self.blocks {
-            if !block.metadata.sm.notarized {
-                return false
-            }
-        }
-        true
-    }
-}

+ 0 - 61
script/research/consensusd/src/service/metadata.rs

@@ -1,61 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-use super::{
-    util::{get_current_time, Timestamp},
-    vote::Vote,
-};
-
-/// This struct represents additional Block information used by the consensus protocol.
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct Metadata {
-    /// Block information used by Ouroboros consensus
-    pub om: OuroborosMetadata,
-    /// Block information used by Streamlet consensus
-    pub sm: StreamletMetadata,
-    /// Block creation timestamp
-    pub timestamp: Timestamp,
-}
-
-impl Metadata {
-    pub fn new(proof: String, r: String, s: String) -> Metadata {
-        Metadata {
-            om: OuroborosMetadata::new(proof, r, s),
-            sm: StreamletMetadata::new(),
-            timestamp: get_current_time(),
-        }
-    }
-}
-
-/// This struct represents Block information used by Ouroboros consensus protocol.
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct OuroborosMetadata {
-    /// Proof the stakeholder is the block owner
-    pub proof: String,
-    /// Random seed for VRF
-    pub r: String,
-    /// Block owner signature
-    pub s: String,
-}
-
-impl OuroborosMetadata {
-    pub fn new(proof: String, r: String, s: String) -> OuroborosMetadata {
-        OuroborosMetadata { proof, r, s }
-    }
-}
-
-/// This struct represents Block information used by Streamlet consensus protocol.
-#[derive(Debug, Clone, Deserialize, Serialize)]
-pub struct StreamletMetadata {
-    /// Epoch votes
-    pub votes: Vec<Vote>,
-    /// Block notarization flag
-    pub notarized: bool,
-    /// Block finalization flag
-    pub finalized: bool,
-}
-
-impl StreamletMetadata {
-    pub fn new() -> StreamletMetadata {
-        StreamletMetadata { votes: Vec::new(), notarized: false, finalized: false }
-    }
-}

+ 0 - 14
script/research/consensusd/src/service/mod.rs

@@ -1,14 +0,0 @@
-pub mod api_service;
-pub mod block;
-pub mod blockchain;
-pub mod metadata;
-pub mod state;
-pub mod util;
-pub mod vote;
-
-pub use api_service::APIService;
-pub use block::Block;
-pub use blockchain::Blockchain;
-pub use metadata::Metadata;
-pub use state::State;
-pub use vote::Vote;

+ 0 - 359
script/research/consensusd/src/service/state.rs

@@ -1,359 +0,0 @@
-use chrono::{NaiveDateTime, Utc};
-use serde::{Deserialize, Serialize};
-use std::{
-    collections::hash_map::DefaultHasher,
-    hash::{Hash, Hasher},
-    path::PathBuf,
-    time::Duration,
-};
-
-use super::{
-    block::Block,
-    blockchain::Blockchain,
-    util::{get_current_time, load, save, Timestamp},
-    vote::Vote,
-};
-
-use darkfi::{
-    crypto::{
-        keypair::{PublicKey, SecretKey},
-        schnorr::{SchnorrPublic, SchnorrSecret},
-    },
-    Result,
-};
-use rand::rngs::OsRng;
-
-/// This struct represents the state of a consensus node.
-/// Each node is numbered and has a secret-public keys pair, to sign messages.
-/// Nodes hold a set of Blockchains(some of which are not notarized)
-/// and a set of unconfirmed pending transactions.
-#[derive(Deserialize, Serialize)]
-pub struct State {
-    pub id: u64,
-    pub genesis_time: Timestamp,
-    pub secret_key: SecretKey,
-    pub public_key: PublicKey,
-    pub canonical_blockchain: Blockchain,
-    pub node_blockchains: Vec<Blockchain>,
-    pub unconfirmed_txs: Vec<String>,
-}
-
-impl State {
-    pub fn new(id: u64, genesis_time: Timestamp, init_block: Block) -> State {
-        // Missing: clock sync
-        let secret = SecretKey::random(&mut OsRng);
-        State {
-            id,
-            genesis_time,
-            secret_key: secret,
-            public_key: PublicKey::from_secret(secret),
-            canonical_blockchain: Blockchain::new(init_block),
-            node_blockchains: Vec::new(),
-            unconfirmed_txs: Vec::new(),
-        }
-    }
-
-    /// Node retreives a transaction and append it to the unconfirmed transactions list.
-    /// Additional validity rules must be defined by the protocol for transactions.
-    pub fn append_tx(&mut self, tx: String) {
-        self.unconfirmed_txs.push(tx);
-    }
-
-    /// Node calculates seconds until next epoch starting time.
-    /// Epochs duration is configured using the delta value.
-    pub fn get_seconds_until_next_epoch_start(&self) -> Duration {
-        let delta = 10;
-        let start_time = NaiveDateTime::from_timestamp(self.genesis_time.0, 0);
-        let current_epoch = self.get_current_epoch() + 1;
-        let next_epoch_start_timestamp =
-            (current_epoch * (2 * delta)) + (start_time.timestamp() as u64);
-        let next_epoch_start =
-            NaiveDateTime::from_timestamp(next_epoch_start_timestamp.try_into().unwrap(), 0);
-        let current_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
-        let diff = next_epoch_start - current_time;
-        Duration::new(diff.num_seconds().try_into().unwrap(), 0)
-    }
-
-    /// Node calculates current epoch, based on elapsed time from the genesis block.
-    /// Epochs duration is configured using the delta value.
-    pub fn get_current_epoch(&self) -> u64 {
-        let delta = 10;
-        self.genesis_time.clone().elapsed() / (2 * delta)
-    }
-
-    /// Node finds epochs leader, using a simple hash method.
-    /// Leader calculation is based on how many nodes are participating in the network.
-    pub fn get_epoch_leader(&self, nodes_count: u64) -> u64 {
-        let epoch = self.get_current_epoch();
-        let mut hasher = DefaultHasher::new();
-        epoch.hash(&mut hasher);
-        hasher.finish() % nodes_count
-    }
-
-    /// Node checks if they are the current epoch leader.
-    pub fn check_if_epoch_leader(&self, nodes_count: u64) -> bool {
-        let leader = self.get_epoch_leader(nodes_count);
-        self.id == leader
-    }
-
-    /// Node generates a block proposal(mapped as Vote) for the current epoch,
-    /// containing all uncorfirmed transactions.
-    /// Block extends the longest notarized blockchain the node holds.
-    pub fn propose_block(&self) -> Option<Vote> {
-        let epoch = self.get_current_epoch();
-        let longest_notarized_chain = self.find_longest_notarized_chain();
-        let mut hasher = DefaultHasher::new();
-        longest_notarized_chain.blocks.last().unwrap().hash(&mut hasher);
-        let unproposed_txs = self.get_unproposed_txs();
-        let proposed_block = Block::new(
-            hasher.finish().to_string(),
-            epoch,
-            unproposed_txs,
-            String::from("proof"),
-            String::from("r"),
-            String::from("s"),
-        );
-        let signed_block = self.secret_key.sign(&proposed_block.signature_encode());
-        Some(Vote::new(signed_block, proposed_block, self.id))
-    }
-
-    /// Node retrieves all unconfiremd transactions not proposed in previous blocks.
-    pub fn get_unproposed_txs(&self) -> Vec<String> {
-        let mut unproposed_txs = self.unconfirmed_txs.clone();
-        for blockchain in &self.node_blockchains {
-            for block in &blockchain.blocks {
-                for tx in &block.txs {
-                    if let Some(pos) = unproposed_txs.iter().position(|txs| *txs == *tx) {
-                        unproposed_txs.remove(pos);
-                    }
-                }
-            }
-        }
-        unproposed_txs
-    }
-
-    /// Finds the longest fully notarized blockchain the node holds.
-    pub fn find_longest_notarized_chain(&self) -> &Blockchain {
-        let mut longest_notarized_chain = &self.canonical_blockchain;
-        let mut length = 0;
-        for blockchain in &self.node_blockchains {
-            if blockchain.is_notarized() && blockchain.blocks.len() > length {
-                length = blockchain.blocks.len();
-                longest_notarized_chain = &blockchain;
-            }
-        }
-        &longest_notarized_chain
-    }
-
-    /// Node receives the proposed block(mapped as Vote), verifies its sender(epoch leader),
-    /// and proceeds with voting on it.
-    pub fn receive_proposed_block(
-        &mut self,
-        leader_public_key: &PublicKey,
-        proposed_block_vote: &Vote,
-        nodes_count: u64,
-    ) -> Option<Vote> {
-        assert!(self.get_epoch_leader(nodes_count) == proposed_block_vote.id);
-        assert!(leader_public_key
-            .verify(&proposed_block_vote.block.signature_encode(), &proposed_block_vote.vote));
-        self.vote_block(&proposed_block_vote.block)
-    }
-
-    /// Given a block, node finds which blockchain it extends.
-    /// If block extends the canonical blockchain, a new fork blockchain is created.
-    /// Node votes on the block, only if it extends the longest notarized chain it has seen.
-    pub fn vote_block(&mut self, block: &Block) -> Option<Vote> {
-        let index = self.find_extended_blockchain_index(block);
-
-        let blockchain = if index == -1 {
-            let blockchain = Blockchain::new(block.clone());
-            self.node_blockchains.push(blockchain);
-            self.node_blockchains.last().unwrap()
-        } else {
-            self.node_blockchains[index as usize].add_block(&block);
-            &self.node_blockchains[index as usize]
-        };
-
-        if self.extends_notarized_blockchain(blockchain) {
-            let block_copy = block.clone();
-            let signed_block = self.secret_key.sign(&block_copy.signature_encode());
-            return Some(Vote::new(signed_block, block_copy, self.id))
-        }
-        None
-    }
-
-    /// Node verifies if provided blockchain is notarized excluding the last block.
-    pub fn extends_notarized_blockchain(&self, blockchain: &Blockchain) -> bool {
-        for block in &blockchain.blocks[..(blockchain.blocks.len() - 1)] {
-            if !block.metadata.sm.notarized {
-                return false
-            }
-        }
-        true
-    }
-
-    /// Given a block, node finds the index of the blockchain it extends.
-    pub fn find_extended_blockchain_index(&self, block: &Block) -> i64 {
-        let mut hasher = DefaultHasher::new();
-        for (index, blockchain) in self.node_blockchains.iter().enumerate() {
-            let last_block = blockchain.blocks.last().unwrap();
-            last_block.hash(&mut hasher);
-            if block.st == hasher.finish().to_string() && block.sl > last_block.sl {
-                return index as i64
-            }
-        }
-
-        let last_block = self.canonical_blockchain.blocks.last().unwrap();
-        last_block.hash(&mut hasher);
-        if block.st != hasher.finish().to_string() || block.sl <= last_block.sl {
-            panic!("Proposed block doesn't extend any known chains.");
-        }
-        -1
-    }
-
-    /// Node receives a vote for a block.
-    /// First, sender is verified using their public key.
-    /// Block is searched in nodes blockchains.
-    /// If the vote wasn't received before, it is appended to block votes list.
-    /// When a node sees 2n/3 votes for a block it notarizes it.
-    /// When a block gets notarized, the transactions it contains are removed from
-    /// nodes unconfirmed transactions list.
-    /// Finally, we check if the notarization of the block can finalize parent blocks
-    ///	in its blockchain.
-    pub fn receive_vote(&mut self, node_public_key: &PublicKey, vote: &Vote, nodes_count: usize) {
-        assert!(node_public_key.verify(&vote.block.signature_encode(), &vote.vote));
-        let vote_block = self.find_block(&vote.block);
-        if vote_block == None {
-            panic!("Received vote for unknown block.");
-        }
-
-        let (unwrapped_vote_block, blockchain_index) = vote_block.unwrap();
-        if !unwrapped_vote_block.metadata.sm.votes.contains(vote) {
-            unwrapped_vote_block.metadata.sm.votes.push(vote.clone());
-        }
-
-        if !unwrapped_vote_block.metadata.sm.notarized &&
-            unwrapped_vote_block.metadata.sm.votes.len() > (2 * nodes_count / 3)
-        {
-            unwrapped_vote_block.metadata.sm.notarized = true;
-            self.check_blockchain_finalization(blockchain_index);
-        }
-    }
-
-    /// Node searches it the blockchains it holds for provided block.
-    pub fn find_block(&mut self, vote_block: &Block) -> Option<(&mut Block, i64)> {
-        for (index, blockchain) in &mut self.node_blockchains.iter_mut().enumerate() {
-            for block in blockchain.blocks.iter_mut().rev() {
-                if vote_block == block {
-                    return Some((block, index as i64))
-                }
-            }
-        }
-
-        for block in &mut self.canonical_blockchain.blocks.iter_mut().rev() {
-            if vote_block == block {
-                return Some((block, -1))
-            }
-        }
-        None
-    }
-
-    /// Node checks if the index blockchain can be finalized.
-    /// Consensus finalization logic: If node has observed the notarization of 3 consecutive
-    /// blocks in a fork chain, it finalizes (appends to canonical blockchain) all blocks up to the middle block.
-    /// When fork chain blocks are finalized, rest fork chains not starting by those blocks are removed.
-    pub fn check_blockchain_finalization(&mut self, blockchain_index: i64) {
-        let blockchain = if blockchain_index == -1 {
-            &mut self.canonical_blockchain
-        } else {
-            &mut self.node_blockchains[blockchain_index as usize]
-        };
-
-        let blockchain_len = blockchain.blocks.len();
-        if blockchain_len > 2 {
-            let mut consecutive_notarized = 0;
-            for block in &blockchain.blocks {
-                if block.metadata.sm.notarized {
-                    consecutive_notarized = consecutive_notarized + 1;
-                } else {
-                    break
-                }
-            }
-
-            if consecutive_notarized > 2 {
-                let mut finalized_blocks = Vec::new();
-                for block in &mut blockchain.blocks[..(consecutive_notarized - 1)] {
-                    block.metadata.sm.finalized = true;
-                    finalized_blocks.push(block.clone());
-                    for tx in block.txs.clone() {
-                        if let Some(pos) = self.unconfirmed_txs.iter().position(|txs| *txs == tx) {
-                            self.unconfirmed_txs.remove(pos);
-                        }
-                    }
-                }
-                blockchain.blocks.drain(0..(consecutive_notarized - 1));
-                for block in &finalized_blocks {
-                    self.canonical_blockchain.blocks.push(block.clone());
-                }
-
-                let mut hasher = DefaultHasher::new();
-                let last_finalized_block = self.canonical_blockchain.blocks.last().unwrap();
-                last_finalized_block.hash(&mut hasher);
-                let last_finalized_block_hash = hasher.finish().to_string();
-                let mut dropped_blockchains = Vec::new();
-                for (index, blockchain) in self.node_blockchains.iter().enumerate() {
-                    let first_block = blockchain.blocks.first().unwrap();
-                    if first_block.st != last_finalized_block_hash ||
-                        first_block.sl <= last_finalized_block.sl
-                    {
-                        dropped_blockchains.push(index);
-                    }
-                }
-                for index in dropped_blockchains {
-                    self.node_blockchains.remove(index);
-                }
-            }
-        }
-    }
-
-    /// Util function to save the current node state to provided file path.
-    pub fn save(&self, path: &PathBuf) -> Result<()> {
-        save::<Self>(path, self)
-    }
-
-    /// Util function to load current node state by the provided file path.
-    //  If file is not found, node state is reset.
-    pub fn load_or_create(id: u64, path: &PathBuf) -> Result<Self> {
-        match load::<Self>(path) {
-            Ok(state) => Ok(state),
-            Err(_) => return Self::reset(id, path),
-        }
-    }
-
-    /// Util function to load the current node state by the provided file path.
-    pub fn load_current_state(id: u64, path: &PathBuf) -> Result<State> {
-        let state = Self::load_or_create(id, path)?;
-        Ok(state)
-    }
-
-    /// Util function to reset node state.
-    pub fn reset(id: u64, path: &PathBuf) -> Result<State> {
-        // Genesis block is generated.
-        let mut genesis_block = Block::new(
-            String::from("⊥"),
-            0,
-            vec![],
-            String::from("proof"),
-            String::from("r"),
-            String::from("s"),
-        );
-        genesis_block.metadata.sm.notarized = true;
-        genesis_block.metadata.sm.finalized = true;
-
-        let genesis_time = get_current_time();
-
-        let state = Self::new(id, genesis_time, genesis_block.clone());
-        state.save(path)?;
-        return Ok(state)
-    }
-}

+ 0 - 40
script/research/consensusd/src/service/util.rs

@@ -1,40 +0,0 @@
-use chrono::{NaiveDateTime, Utc};
-use serde::{de::DeserializeOwned, Deserialize, Serialize};
-use std::{fs::File, io::BufReader, path::PathBuf};
-
-use darkfi::Result;
-
-/// Util function to load a structure saved as a JSON in the provided path file, using serde crate.
-pub fn load<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
-    let file = File::open(path)?;
-    let reader = BufReader::new(file);
-
-    let value: T = serde_json::from_reader(reader)?;
-    Ok(value)
-}
-
-/// Util function to save a structure as a JSON in the provided path file, using serde crate.
-pub fn save<T: Serialize>(path: &PathBuf, value: &T) -> Result<()> {
-    let file = File::create(path)?;
-    serde_json::to_writer_pretty(file, value)?;
-    Ok(())
-}
-
-/// Util structure to represend chrono UTC timestamps.
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct Timestamp(pub i64);
-
-impl Timestamp {
-    /// Calculates elapsed time of a Timestamp.
-    pub fn elapsed(self) -> u64 {
-        let start_time = NaiveDateTime::from_timestamp(self.0, 0);
-        let end_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
-        let diff = end_time - start_time;
-        diff.num_seconds().try_into().unwrap()
-    }
-}
-
-/// Util function to generate a Timestamp of current time.
-pub fn get_current_time() -> Timestamp {
-    Timestamp(Utc::now().timestamp())
-}

+ 0 - 21
script/research/consensusd/src/service/vote.rs

@@ -1,21 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-use super::block::Block;
-use darkfi::crypto::schnorr::Signature;
-
-/// This struct represents a tuple of the form (vote, B, id).
-#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
-pub struct Vote {
-    /// signed block
-    pub vote: Signature,
-    /// block to vote on
-    pub block: Block,
-    /// node id
-    pub id: u64,
-}
-
-impl Vote {
-    pub fn new(vote: Signature, block: Block, id: u64) -> Vote {
-        Vote { vote, block, id }
-    }
-}

+ 0 - 2
script/research/streamlet_rust/.gitignore

@@ -1,2 +0,0 @@
-target/*
-Cargo.lock

+ 0 - 13
script/research/streamlet_rust/Cargo.toml

@@ -1,13 +0,0 @@
-[package]
-name = "streamlet_rust"
-version = "0.3.0"
-edition = "2021"
-
-[dependencies.darkfi]
-path = "../../../"
-features = ["crypto", "node"]
-
-[dependencies]
-rand = "0.8.5"
-
-[workspace]

+ 0 - 179
script/research/streamlet_rust/src/lib.rs

@@ -1,179 +0,0 @@
-pub mod structures;
-
-#[cfg(test)]
-mod tests {
-    use std::{
-        thread,
-        time::{Duration, Instant},
-    };
-
-    use super::structures::{block::Block, node::Node};
-
-    use darkfi::{crypto::token_id::generate_id2, util::NetworkName};
-
-    #[test]
-    fn protocol_execution() {
-        // Genesis block is generated.
-        let mut genesis_block = Block::new(
-            String::from("⊥"),
-            0,
-            vec![],
-            String::from("proof"),
-            String::from("r"),
-            String::from("s"),
-        );
-        genesis_block.metadata.sm.notarized = true;
-        genesis_block.metadata.sm.finalized = true;
-
-        let genesis_time = Instant::now();
-
-        // We create some nodes to participate in the Protocol.
-        let mut node0 = Node::new(0, genesis_time, genesis_block.clone());
-        let mut node1 = Node::new(1, genesis_time, genesis_block.clone());
-        let mut node2 = Node::new(2, genesis_time, genesis_block.clone());
-
-        // We store nodes public keys for voting.
-        let node0_public_key = node0.public_key;
-        let node1_public_key = node1.public_key;
-        let node2_public_key = node2.public_key;
-
-        // We simulate some epochs to test consistency.
-        let token_id = generate_id2("STREAMLET", &NetworkName::Ethereum).unwrap();
-
-        let tx = node0.generate_transaction(token_id, 100, &node1_public_key).unwrap();
-        node0.receive_transaction(tx.clone());
-        node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
-        let tx = node1.generate_transaction(token_id, 200, &node2_public_key).unwrap();
-        node1.receive_transaction(tx.clone());
-        node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
-        let tx = node2.generate_transaction(token_id, 300, &node1_public_key).unwrap();
-        node2.receive_transaction(tx.clone());
-        node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
-
-        // Each node checks if they are the epoch leader. Leader will propose the block.
-        let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {
-            node0.propose_block()
-        } else if node1.check_if_epoch_leader(3) {
-            node1.propose_block()
-        } else {
-            node2.propose_block()
-        };
-
-        // Leader broadcasts the proposed_block to rest nodes and they vote on it.
-        let node0_vote =
-            node0.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-        let node1_vote =
-            node1.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-        let node2_vote =
-            node2.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-
-        // Each node broadcasts its vote to rest nodes.
-        node0.receive_vote(&node0_public_key, &node0_vote, 3);
-        node0.receive_vote(&node1_public_key, &node1_vote, 3);
-        node0.receive_vote(&node2_public_key, &node2_vote, 3);
-        node1.receive_vote(&node0_public_key, &node0_vote, 3);
-        node1.receive_vote(&node1_public_key, &node1_vote, 3);
-        node1.receive_vote(&node2_public_key, &node2_vote, 3);
-        node2.receive_vote(&node0_public_key, &node0_vote, 3);
-        node2.receive_vote(&node1_public_key, &node1_vote, 3);
-        node2.receive_vote(&node2_public_key, &node2_vote, 3);
-
-        // We verify that all nodes have the same blockchain on round end.
-        verify_outputs(&node0, &node1, &node2);
-
-        // We use thread sleep to simulate sinchronization period.
-        thread::sleep(Duration::new(5, 0));
-
-        // Next round.
-        let tx = node0.generate_transaction(token_id, 400, &node1_public_key).unwrap();
-        node0.receive_transaction(tx.clone());
-        node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
-        let tx = node1.generate_transaction(token_id, 500, &node2_public_key).unwrap();
-        node1.receive_transaction(tx.clone());
-        node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
-        //let tx = node2.generate_transaction(token_id, 600, &node1_public_key).unwrap();
-        //node2.receive_transaction(tx.clone());
-        //node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
-
-        // Each node checks if they are the epoch leader. Leader will propose the block.
-        let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {
-            node0.propose_block()
-        } else if node1.check_if_epoch_leader(3) {
-            node1.propose_block()
-        } else {
-            node2.propose_block()
-        };
-
-        // Leader broadcasts the proposed_block to rest nodes and they vote on it.
-        let node0_vote =
-            node0.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-        let node1_vote =
-            node1.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-        let node2_vote =
-            node2.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-
-        // Each node broadcasts its vote to rest nodes.
-        node0.receive_vote(&node0_public_key, &node0_vote, 3);
-        node0.receive_vote(&node1_public_key, &node1_vote, 3);
-        node0.receive_vote(&node2_public_key, &node2_vote, 3);
-        node1.receive_vote(&node0_public_key, &node0_vote, 3);
-        node1.receive_vote(&node1_public_key, &node1_vote, 3);
-        node1.receive_vote(&node2_public_key, &node2_vote, 3);
-        node2.receive_vote(&node0_public_key, &node0_vote, 3);
-        node2.receive_vote(&node1_public_key, &node1_vote, 3);
-        node2.receive_vote(&node2_public_key, &node2_vote, 3);
-
-        // We verify that all nodes have the same blockchain on round end.
-        verify_outputs(&node0, &node1, &node2);
-
-        // We use thread sleep to simulate sinchronization period.
-        thread::sleep(Duration::new(5, 0));
-
-        // Next round.
-        let tx = node0.generate_transaction(token_id, 700, &node1_public_key).unwrap();
-        node0.receive_transaction(tx.clone());
-        node0.broadcast_transaction(vec![&mut node1, &mut node2], tx);
-        //let tx = node1.generate_transaction(token_id, 800, &node2_public_key).unwrap();
-        //node1.receive_transaction(tx.clone());
-        //node1.broadcast_transaction(vec![&mut node0, &mut node2], tx);
-        //let tx = node2.generate_transaction(token_id, 900, &node1_public_key).unwrap();
-        //node2.receive_transaction(tx.clone());
-        //node2.broadcast_transaction(vec![&mut node0, &mut node1], tx);
-
-        // Each node checks if they are the epoch leader. Leader will propose the block.
-        let (leader_public_key, block_proposal) = if node0.check_if_epoch_leader(3) {
-            node0.propose_block()
-        } else if node1.check_if_epoch_leader(3) {
-            node1.propose_block()
-        } else {
-            node2.propose_block()
-        };
-
-        // Leader broadcasts the proposed_block to rest nodes and they vote on it.
-        let node0_vote =
-            node0.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-        let node1_vote =
-            node1.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-        let node2_vote =
-            node2.receive_proposed_block(&leader_public_key, &block_proposal, 3).unwrap();
-
-        // Each node broadcasts its vote to rest nodes.
-        node0.receive_vote(&node0_public_key, &node0_vote, 3);
-        node0.receive_vote(&node1_public_key, &node1_vote, 3);
-        node0.receive_vote(&node2_public_key, &node2_vote, 3);
-        node1.receive_vote(&node0_public_key, &node0_vote, 3);
-        node1.receive_vote(&node1_public_key, &node1_vote, 3);
-        node1.receive_vote(&node2_public_key, &node2_vote, 3);
-        node2.receive_vote(&node0_public_key, &node0_vote, 3);
-        node2.receive_vote(&node1_public_key, &node1_vote, 3);
-        node2.receive_vote(&node2_public_key, &node2_vote, 3);
-
-        // We verify that all nodes have the same blockchain on round end.
-        verify_outputs(&node0, &node1, &node2);
-    }
-
-    fn verify_outputs(node0: &Node, node1: &Node, node2: &Node) {
-        assert!(node0.output() == node1.output());
-        assert!(node1.output() == node2.output());
-    }
-}

+ 0 - 54
script/research/streamlet_rust/src/structures/block.rs

@@ -1,54 +0,0 @@
-use std::hash::{Hash, Hasher};
-
-use super::metadata::Metadata;
-
-use darkfi::{tx::Transaction, util::serial::Encodable};
-
-/// This struct represents a tuple of the form (st, sl, txs, metadata).
-/// Each blocks parent hash h may be computed simply as a hash of the parent block.
-#[derive(Debug, Clone)]
-pub struct Block {
-    /// Previous block hash
-    pub st: String,
-    /// Slot uid, generated by the beacon
-    pub sl: u64,
-    /// Transactions payload
-    pub txs: Vec<Transaction>,
-    /// Additional block information
-    pub metadata: Metadata,
-}
-
-impl Block {
-    pub fn new(
-        st: String,
-        sl: u64,
-        txs: Vec<Transaction>,
-        proof: String,
-        r: String,
-        s: String,
-    ) -> Block {
-        Block { st, sl, txs, metadata: Metadata::new(proof, r, s) }
-    }
-
-    pub fn signature_encode(&self) -> Vec<u8> {
-        let mut encoded_block = Vec::new();
-        let mut len = 0;
-        len += self.st.encode(&mut encoded_block).unwrap();
-        len += self.sl.encode(&mut encoded_block).unwrap();
-        len += self.txs.encode(&mut encoded_block).unwrap();
-        assert_eq!(len, encoded_block.len());
-        encoded_block
-    }
-}
-
-impl PartialEq for Block {
-    fn eq(&self, other: &Self) -> bool {
-        self.st == other.st && self.sl == other.sl && self.txs == other.txs
-    }
-}
-
-impl Hash for Block {
-    fn hash<H: Hasher>(&self, hasher: &mut H) {
-        format!("{:?}{:?}{:?}", self.st, self.sl, self.txs).hash(hasher);
-    }
-}

+ 0 - 54
script/research/streamlet_rust/src/structures/blockchain.rs

@@ -1,54 +0,0 @@
-use std::{
-    collections::hash_map::DefaultHasher,
-    hash::{Hash, Hasher},
-};
-
-use super::block::Block;
-
-/// This struct represents a sequence of blocks starting with the genesis block.
-#[derive(Debug, Clone, PartialEq)]
-pub struct Blockchain {
-    pub blocks: Vec<Block>,
-}
-
-impl Blockchain {
-    pub fn new(intial_block: Block) -> Blockchain {
-        Blockchain { blocks: vec![intial_block] }
-    }
-
-    /// A block is considered valid when its parent hash is equal to the hash of the
-    /// previous block and their epochs are incremental, exluding genesis.
-    /// Additional validity rules can be applied.
-    pub fn check_block_validity(&self, block: &Block, previous_block: &Block) {
-        assert!(block.st != "⊥", "Genesis block provided.");
-        let mut hasher = DefaultHasher::new();
-        previous_block.hash(&mut hasher);
-        assert!(
-            block.st == hasher.finish().to_string() && block.sl > previous_block.sl,
-            "Provided block is invalid."
-        );
-    }
-
-    /// A blockchain is considered valid, when every block is valid, based on check_block_validity method.
-    pub fn check_chain_validity(&self) {
-        for (index, block) in self.blocks[1..].iter().enumerate() {
-            self.check_block_validity(&block, &self.blocks[index])
-        }
-    }
-
-    /// Insertion of a valid block.
-    pub fn add_block(&mut self, block: &Block) {
-        self.check_block_validity(&block, &self.blocks.last().unwrap());
-        self.blocks.push(block.clone());
-    }
-
-    /// Blockchain notarization check.
-    pub fn is_notarized(&self) -> bool {
-        for block in &self.blocks {
-            if !block.metadata.sm.notarized {
-                return false
-            }
-        }
-        true
-    }
-}

+ 0 - 58
script/research/streamlet_rust/src/structures/metadata.rs

@@ -1,58 +0,0 @@
-use std::time::Instant;
-
-use super::vote::Vote;
-
-/// This struct represents additional Block information used by the consensus protocol.
-#[derive(Debug, Clone)]
-pub struct Metadata {
-    /// Block information used by Ouroboros consensus
-    pub om: OuroborosMetadata,
-    /// Block information used by Streamlet consensus
-    pub sm: StreamletMetadata,
-    /// Block creation timestamp
-    pub timestamp: Instant,
-}
-
-impl Metadata {
-    pub fn new(proof: String, r: String, s: String) -> Metadata {
-        Metadata {
-            om: OuroborosMetadata::new(proof, r, s),
-            sm: StreamletMetadata::new(),
-            timestamp: Instant::now(),
-        }
-    }
-}
-
-/// This struct represents Block information used by Ouroboros consensus protocol.
-#[derive(Debug, Clone)]
-pub struct OuroborosMetadata {
-    /// Proof the stakeholder is the block owner
-    pub proof: String,
-    /// Random seed for VRF
-    pub r: String,
-    /// Block owner signature
-    pub s: String,
-}
-
-impl OuroborosMetadata {
-    pub fn new(proof: String, r: String, s: String) -> OuroborosMetadata {
-        OuroborosMetadata { proof, r, s }
-    }
-}
-
-/// This struct represents Block information used by Streamlet consensus protocol.
-#[derive(Debug, Clone)]
-pub struct StreamletMetadata {
-    /// Epoch votes
-    pub votes: Vec<Vote>,
-    /// Block notarization flag
-    pub notarized: bool,
-    /// Block finalization flag
-    pub finalized: bool,
-}
-
-impl StreamletMetadata {
-    pub fn new() -> StreamletMetadata {
-        StreamletMetadata { votes: Vec::new(), notarized: false, finalized: false }
-    }
-}

+ 0 - 15
script/research/streamlet_rust/src/structures/mod.rs

@@ -1,15 +0,0 @@
-//! # Structures
-//!
-//! A library for modeling consensus algorithm structures.
-
-pub mod block;
-pub mod blockchain;
-pub mod metadata;
-pub mod node;
-pub mod vote;
-
-pub use block::Block;
-pub use blockchain::Blockchain;
-pub use metadata::Metadata;
-pub use node::Node;
-pub use vote::Vote;

+ 0 - 343
script/research/streamlet_rust/src/structures/node.rs

@@ -1,343 +0,0 @@
-use std::{
-    collections::hash_map::DefaultHasher,
-    hash::{Hash, Hasher},
-    time::Instant,
-};
-
-use super::{block::Block, blockchain::Blockchain, vote::Vote};
-use darkfi::{
-    crypto::{
-        keypair::{PublicKey, SecretKey},
-        proof::ProvingKey,
-        schnorr::{SchnorrPublic, SchnorrSecret},
-        types::DrkTokenId,
-    },
-    tx::{
-        Transaction, TransactionBuilder, TransactionBuilderClearInputInfo,
-        TransactionBuilderOutputInfo,
-    },
-    zk::circuit::{mint_contract::MintContract, spend_contract::SpendContract},
-    Result,
-};
-use rand::rngs::OsRng;
-
-/// This struct represents a protocol node.
-/// Each node is numbered and has a secret-public keys pair, to sign messages.
-/// Nodes hold a set of Blockchains(some of which are not notarized)
-/// and a set of unconfirmed pending transactions.
-#[derive(Debug)]
-pub struct Node {
-    pub id: u64,
-    pub genesis_time: Instant,
-    pub secret_key: SecretKey,
-    pub public_key: PublicKey,
-    pub canonical_blockchain: Blockchain,
-    pub node_blockchains: Vec<Blockchain>,
-    pub unconfirmed_transactions: Vec<Transaction>,
-    pub mint_proving_key: ProvingKey,
-    pub spent_proving_key: ProvingKey,
-}
-
-impl Node {
-    pub fn new(id: u64, genesis_time: Instant, init_block: Block) -> Node {
-        // Missing: clock sync
-        const K: u32 = 11;
-        let secret = SecretKey::random(&mut OsRng);
-        Node {
-            id,
-            genesis_time,
-            secret_key: secret,
-            public_key: PublicKey::from_secret(secret),
-            canonical_blockchain: Blockchain::new(init_block),
-            node_blockchains: Vec::new(),
-            unconfirmed_transactions: Vec::new(),
-            mint_proving_key: ProvingKey::build(K, &MintContract::default()),
-            spent_proving_key: ProvingKey::build(K, &SpendContract::default()),
-        }
-    }
-
-    /// A nodes output is the finalized (canonical) blockchain they hold.
-    pub fn output(&self) -> &Blockchain {
-        &self.canonical_blockchain
-    }
-
-    /// Node generates a dummy transaction for provided token.
-    /// Additional validity rules must be defined by the protocol for transactions.
-    pub fn generate_transaction(
-        &self,
-        token_id: DrkTokenId,
-        value: u64,
-        public: &PublicKey,
-    ) -> Result<Transaction> {
-        let builder = TransactionBuilder {
-            clear_inputs: vec![TransactionBuilderClearInputInfo {
-                value,
-                token_id,
-                signature_secret: self.secret_key,
-            }],
-            inputs: vec![],
-            outputs: vec![TransactionBuilderOutputInfo { value, token_id, public: *public }],
-        };
-
-        builder.build(&self.mint_proving_key, &self.spent_proving_key)
-    }
-
-    /// Node retreives a transaction and append it to the unconfirmed transactions list.
-    /// Additional validity rules must be defined by the protocol for transactions.
-    pub fn receive_transaction(&mut self, transaction: Transaction) {
-        self.unconfirmed_transactions.push(transaction);
-    }
-
-    /// Node broadcast a transaction to provided nodes list.
-    pub fn broadcast_transaction(&mut self, nodes: Vec<&mut Node>, transaction: Transaction) {
-        for node in nodes {
-            node.receive_transaction(transaction.clone())
-        }
-    }
-
-    /// Node calculates current epoch, based on elapsed time from the genesis block.
-    /// Epochs duration is configured using the delta value.
-    pub fn get_current_epoch(&self) -> u64 {
-        let delta = 5;
-        self.genesis_time.elapsed().as_secs() / (2 * delta)
-    }
-
-    /// Node finds epochs leader, using a simple hash method.
-    /// Leader calculation is based on how many nodes are participating in the network.
-    pub fn get_epoch_leader(&self, nodes_count: u64) -> u64 {
-        let epoch = self.get_current_epoch();
-        let mut hasher = DefaultHasher::new();
-        epoch.hash(&mut hasher);
-        hasher.finish() % nodes_count
-    }
-
-    /// Node checks if they are the current epoch leader.
-    pub fn check_if_epoch_leader(&self, nodes_count: u64) -> bool {
-        let leader = self.get_epoch_leader(nodes_count);
-        self.id == leader
-    }
-
-    /// Node retrieves all unconfiremd transactions not proposed in previous blocks.
-    pub fn get_unproposed_transactions(&self) -> Vec<Transaction> {
-        let mut unproposed_transactions = self.unconfirmed_transactions.clone();
-        for blockchain in &self.node_blockchains {
-            for block in &blockchain.blocks {
-                for transaction in &block.txs {
-                    if let Some(pos) =
-                        unproposed_transactions.iter().position(|txs| *txs == *transaction)
-                    {
-                        unproposed_transactions.remove(pos);
-                    }
-                }
-            }
-        }
-        unproposed_transactions
-    }
-
-    /// Node generates a block proposal(mapped as Vote) for the current epoch,
-    /// containing all uncorfirmed transactions.
-    /// Block extends the longest notarized blockchain the node holds.
-    pub fn propose_block(&self) -> (PublicKey, Vote) {
-        let epoch = self.get_current_epoch();
-        let longest_notarized_chain = self.find_longest_notarized_chain();
-        let mut hasher = DefaultHasher::new();
-        longest_notarized_chain.blocks.last().unwrap().hash(&mut hasher);
-        let unproposed_transactions = self.get_unproposed_transactions();
-        let proposed_block = Block::new(
-            hasher.finish().to_string(),
-            epoch,
-            unproposed_transactions,
-            String::from("proof"),
-            String::from("r"),
-            String::from("s"),
-        );
-        let signed_block = self.secret_key.sign(&proposed_block.signature_encode());
-        (self.public_key, Vote::new(signed_block, proposed_block, self.id))
-    }
-
-    /// Node receives the proposed block(mapped as Vote), verifies its sender(epoch leader),
-    /// and proceeds with voting on it.
-    pub fn receive_proposed_block(
-        &mut self,
-        leader_public_key: &PublicKey,
-        proposed_block_vote: &Vote,
-        nodes_count: u64,
-    ) -> Option<Vote> {
-        assert!(self.get_epoch_leader(nodes_count) == proposed_block_vote.id);
-        assert!(leader_public_key
-            .verify(&proposed_block_vote.block.signature_encode(), &proposed_block_vote.vote));
-        self.vote_block(&proposed_block_vote.block)
-    }
-
-    /// Given a block, node finds which blockchain it extends.
-    /// If block extends the canonical blockchain, a new fork blockchain is created.
-    /// Node votes on the block, only if it extends the longest notarized chain it has seen.
-    pub fn vote_block(&mut self, block: &Block) -> Option<Vote> {
-        let index = self.find_extended_blockchain_index(block);
-
-        let blockchain = if index == -1 {
-            let blockchain = Blockchain::new(block.clone());
-            self.node_blockchains.push(blockchain);
-            self.node_blockchains.last().unwrap()
-        } else {
-            self.node_blockchains[index as usize].add_block(&block);
-            &self.node_blockchains[index as usize]
-        };
-
-        if self.extends_notarized_blockchain(blockchain) {
-            let block_copy = block.clone();
-            let signed_block = self.secret_key.sign(&block_copy.signature_encode());
-            return Some(Vote::new(signed_block, block_copy, self.id))
-        }
-        None
-    }
-
-    /// Node verifies if provided blockchain is notarized excluding the last block.
-    pub fn extends_notarized_blockchain(&self, blockchain: &Blockchain) -> bool {
-        for block in &blockchain.blocks[..(blockchain.blocks.len() - 1)] {
-            if !block.metadata.sm.notarized {
-                return false
-            }
-        }
-        true
-    }
-
-    /// Given a block, node finds the index of the blockchain it extends.
-    pub fn find_extended_blockchain_index(&self, block: &Block) -> i64 {
-        let mut hasher = DefaultHasher::new();
-        for (index, blockchain) in self.node_blockchains.iter().enumerate() {
-            let last_block = blockchain.blocks.last().unwrap();
-            last_block.hash(&mut hasher);
-            if block.st == hasher.finish().to_string() && block.sl > last_block.sl {
-                return index as i64
-            }
-        }
-
-        let last_block = self.canonical_blockchain.blocks.last().unwrap();
-        last_block.hash(&mut hasher);
-        if block.st != hasher.finish().to_string() || block.sl <= last_block.sl {
-            panic!("Proposed block doesn't extend any known chains.");
-        }
-        -1
-    }
-
-    /// Finds the longest fully notarized blockchain the node holds.
-    pub fn find_longest_notarized_chain(&self) -> &Blockchain {
-        let mut longest_notarized_chain = &self.canonical_blockchain;
-        let mut length = 0;
-        for blockchain in &self.node_blockchains {
-            if blockchain.is_notarized() && blockchain.blocks.len() > length {
-                length = blockchain.blocks.len();
-                longest_notarized_chain = &blockchain;
-            }
-        }
-        &longest_notarized_chain
-    }
-
-    /// Node receives a vote for a block.
-    /// First, sender is verified using their public key.
-    /// Block is searched in nodes blockchains.
-    /// If the vote wasn't received before, it is appended to block votes list.
-    /// When a node sees 2n/3 votes for a block it notarizes it.
-    /// When a block gets notarized, the transactions it contains are removed from
-    /// nodes unconfirmed transactions list.
-    /// Finally, we check if the notarization of the block can finalize parent blocks
-    ///	in its blockchain.
-    pub fn receive_vote(&mut self, node_public_key: &PublicKey, vote: &Vote, nodes_count: usize) {
-        assert!(node_public_key.verify(&vote.block.signature_encode(), &vote.vote));
-        let vote_block = self.find_block(&vote.block);
-        if vote_block == None {
-            panic!("Received vote for unknown block.");
-        }
-
-        let (unwrapped_vote_block, blockchain_index) = vote_block.unwrap();
-        if !unwrapped_vote_block.metadata.sm.votes.contains(vote) {
-            unwrapped_vote_block.metadata.sm.votes.push(vote.clone());
-        }
-
-        if !unwrapped_vote_block.metadata.sm.notarized &&
-            unwrapped_vote_block.metadata.sm.votes.len() > (2 * nodes_count / 3)
-        {
-            unwrapped_vote_block.metadata.sm.notarized = true;
-            self.check_blockchain_finalization(blockchain_index);
-        }
-    }
-
-    /// Node searches it the blockchains it holds for provided block.
-    pub fn find_block(&mut self, vote_block: &Block) -> Option<(&mut Block, i64)> {
-        for (index, blockchain) in &mut self.node_blockchains.iter_mut().enumerate() {
-            for block in blockchain.blocks.iter_mut().rev() {
-                if vote_block == block {
-                    return Some((block, index as i64))
-                }
-            }
-        }
-
-        for block in &mut self.canonical_blockchain.blocks.iter_mut().rev() {
-            if vote_block == block {
-                return Some((block, -1))
-            }
-        }
-        None
-    }
-
-    /// Node checks if the index blockchain can be finalized.
-    /// Consensus finalization logic: If node has observed the notarization of 3 consecutive
-    /// blocks in a fork chain, it finalizes (appends to canonical blockchain) all blocks up to the middle block.
-    /// When fork chain blocks are finalized, rest fork chains not starting by those blocks are removed.
-    pub fn check_blockchain_finalization(&mut self, blockchain_index: i64) {
-        let blockchain = if blockchain_index == -1 {
-            &mut self.canonical_blockchain
-        } else {
-            &mut self.node_blockchains[blockchain_index as usize]
-        };
-
-        let blockchain_len = blockchain.blocks.len();
-        if blockchain_len > 2 {
-            let mut consecutive_notarized = 0;
-            for block in &blockchain.blocks {
-                if block.metadata.sm.notarized {
-                    consecutive_notarized = consecutive_notarized + 1;
-                } else {
-                    break
-                }
-            }
-
-            if consecutive_notarized > 2 {
-                let mut finalized_blocks = Vec::new();
-                for block in &mut blockchain.blocks[..(consecutive_notarized - 1)] {
-                    block.metadata.sm.finalized = true;
-                    finalized_blocks.push(block.clone());
-                    for transaction in block.txs.clone() {
-                        if let Some(pos) =
-                            self.unconfirmed_transactions.iter().position(|txs| *txs == transaction)
-                        {
-                            self.unconfirmed_transactions.remove(pos);
-                        }
-                    }
-                }
-                blockchain.blocks.drain(0..(consecutive_notarized - 1));
-                for block in &finalized_blocks {
-                    self.canonical_blockchain.blocks.push(block.clone());
-                }
-
-                let mut hasher = DefaultHasher::new();
-                let last_finalized_block = self.canonical_blockchain.blocks.last().unwrap();
-                last_finalized_block.hash(&mut hasher);
-                let last_finalized_block_hash = hasher.finish().to_string();
-                let mut dropped_blockchains = Vec::new();
-                for (index, blockchain) in self.node_blockchains.iter().enumerate() {
-                    let first_block = blockchain.blocks.first().unwrap();
-                    if first_block.st != last_finalized_block_hash ||
-                        first_block.sl <= last_finalized_block.sl
-                    {
-                        dropped_blockchains.push(index);
-                    }
-                }
-                for index in dropped_blockchains {
-                    self.node_blockchains.remove(index);
-                }
-            }
-        }
-    }
-}

+ 0 - 19
script/research/streamlet_rust/src/structures/vote.rs

@@ -1,19 +0,0 @@
-use super::block::Block;
-use darkfi::crypto::schnorr::Signature;
-
-/// This struct represents a tuple of the form (vote, B, id).
-#[derive(Debug, Clone, PartialEq)]
-pub struct Vote {
-    /// signed block
-    pub vote: Signature,
-    /// block to vote on
-    pub block: Block,
-    /// node id
-    pub id: u64,
-}
-
-impl Vote {
-    pub fn new(vote: Signature, block: Block, id: u64) -> Vote {
-        Vote { vote, block, id }
-    }
-}

+ 0 - 2
script/research/validatord/.gitignore

@@ -1,2 +0,0 @@
-target/*
-Cargo.lock

+ 0 - 41
script/research/validatord/Cargo.toml

@@ -1,41 +0,0 @@
-[package]
-name = "validatord"
-version = "0.3.0"
-edition = "2021"
-
-[dependencies.darkfi]
-path = "../../../"
-features = ["blockchain", "crypto", "net", "rpc"]
-
-[dependencies]
-
-# Async
-smol = "1.2.5"
-async-std = "1.11.0"
-async-trait = "0.1.53"
-async-channel = "1.6.1"
-async-executor = "1.4.1"
-easy-parallel = "3.2.0"
-
-# Crypto
-rand = "0.8.5"
-blake3 = "1.3.1"
-
-# Storage
-sled = "0.34.7"
-
-# Structopt dependencies for arguments parsing
-serde = "1.0.137"
-serde_derive = "1.0.137"
-serde_json = "1.0.81"
-structopt = "0.3.26"
-structopt-toml = "0.5.0"
-toml = "0.5.9"
-
-# Misc
-chrono = "0.4.19"
-log = "0.4.17"
-num_cpus = "1.13.1"
-simplelog = "0.12.0"
-
-[workspace]

+ 0 - 70
script/research/validatord/simulation.sh

@@ -1,70 +0,0 @@
-#!/bin/bash
-
-# Simulation of the consensus network for n validator nodes.
-
-nodes=4
-
-# Copying the node state files with a blockchain containing only the genesis block. Uncomment for fresh runs.
-#bound=$(($nodes - 1))
-#for i in $(eval echo "{0..$bound}")
-#do
-#  rm -rf ~/.config/darkfi/validatord_db_$i
-#done
-
-# PIDs array
-pids=()
-
-# Starting node 0 (seed) in background
-cargo run -- &
-pids[${#pids[@]}]=$!
-
-# Waiting for seed to setup
-sleep 2
-
-# Starting nodes 1 till second to last node in background
-bound=$(($nodes-2))
-for i in $(eval echo "{1..$bound}")
-do
-  cargo run -- \
-    --accept 0.0.0.0:1100$i \
-    --caccept 0.0.0.0:1200$i \
-    --seeds 127.0.0.1:11000 \
-    --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
-done
-
-# Trap kill signal
-trap ctrl_c INT
-
-# On kill signal, terminate background node processes
-function ctrl_c() {
-    for pid in ${pids[@]}
-    do
-      kill $pid
-    done
-}
-
-bound=$(($nodes-1))
-# Starting last node
-cargo run -- \
-    --accept 0.0.0.0:1100$bound \
-    --caccept 0.0.0.0:1200$bound \
-    --seeds 127.0.0.1:11000 \
-    --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:
-# telnet 127.0.0.1 6661
-# {"jsonrpc": "2.0", "method": "receive_tx", "params": ["tx"], "id": 42}

+ 0 - 340
script/research/validatord/src/consensus/block.rs

@@ -1,340 +0,0 @@
-use std::io;
-
-use darkfi::{
-    crypto::{keypair::PublicKey, schnorr::Signature},
-    impl_vec, net,
-    util::serial::{
-        deserialize, serialize, Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt,
-    },
-    Result,
-};
-
-use super::{
-    metadata::{Metadata, StreamletMetadata},
-    tx::Tx,
-    util::{Timestamp, EMPTY_HASH_BYTES},
-};
-
-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)]
-pub struct Block {
-    /// Previous block hash
-    pub st: blake3::Hash,
-    /// Slot uid, generated by the beacon
-    pub sl: u64,
-    /// Transaction hashes
-    /// The actual transactions are in [`TxStore`]
-    pub txs: Vec<blake3::Hash>,
-    /// Additional block information
-    pub metadata: Metadata,
-}
-
-impl Block {
-    pub fn new(st: blake3::Hash, sl: u64, txs: Vec<blake3::Hash>, metadata: Metadata) -> Block {
-        Block { st, sl, txs, metadata }
-    }
-
-    /// Generates the genesis block.
-    pub fn genesis_block(genesis: i64) -> Block {
-        let hash = blake3::Hash::from(EMPTY_HASH_BYTES);
-        let metadata = Metadata::new(
-            Timestamp(genesis),
-            String::from("proof"),
-            String::from("r"),
-            String::from("s"),
-        );
-        Block::new(hash, 0, vec![], metadata)
-    }
-}
-
-#[derive(Debug)]
-pub struct BlockStore(sled::Tree);
-
-impl BlockStore {
-    /// Opens a new or existing blockstore tree given a sled database.
-    pub fn new(db: &sled::Db, genesis: i64) -> Result<Self> {
-        let tree = db.open_tree(SLED_BLOCK_TREE)?;
-        let store = Self(tree);
-        if store.0.is_empty() {
-            // Genesis block is generated.
-            store.insert(&Block::genesis_block(genesis))?;
-        }
-
-        Ok(store)
-    }
-
-    /// Insert a block into the blockstore.
-    /// The block is hashed with blake3 and this blockhash is used as
-    /// the key, where value is the serialized block itself.
-    pub fn insert(&self, block: &Block) -> Result<blake3::Hash> {
-        let serialized = serialize(block);
-        let blockhash = blake3::hash(&serialized);
-        self.0.insert(blockhash.as_bytes(), serialized)?;
-
-        Ok(blockhash)
-    }
-
-    /// Fetch given blocks from the blockstore.
-    /// The resulting vector contains `Option` which is `Some` if the block
-    /// was found in the blockstore, and `None`, if it has not.
-    pub fn get(&self, blockhashes: &[blake3::Hash]) -> Result<Vec<Option<(blake3::Hash, Block)>>> {
-        let mut ret: Vec<Option<(blake3::Hash, Block)>> = Vec::with_capacity(blockhashes.len());
-
-        for i in blockhashes {
-            if let Some(found) = self.0.get(i.as_bytes())? {
-                let block = deserialize(&found)?;
-                ret.push(Some((i.clone(), block)));
-            } else {
-                ret.push(None);
-            }
-        }
-
-        Ok(ret)
-    }
-
-    /// Retrieve all blocks.
-    /// Be carefull as this will try to load everything in memory.
-    pub fn get_all(&self) -> Result<Vec<Option<(blake3::Hash, Block)>>> {
-        let mut blocks = Vec::new();
-        let mut iterator = self.0.into_iter().enumerate();
-        while let Some((_, r)) = iterator.next() {
-            let (k, v) = r.unwrap();
-            let hash_bytes: [u8; 32] = k.as_ref().try_into().unwrap();
-            let block = deserialize(&v)?;
-            blocks.push(Some((hash_bytes.into(), block)));
-        }
-        Ok(blocks)
-    }
-}
-
-/// Auxilary structure used for blockchain syncing.
-#[derive(Debug, SerialEncodable, SerialDecodable)]
-pub struct BlockOrder {
-    /// Slot uid
-    pub sl: u64,
-    /// Block hash of that slot
-    pub block: blake3::Hash,
-}
-
-impl net::Message for BlockOrder {
-    fn name() -> &'static str {
-        "blockorder"
-    }
-}
-
-/// Auxilary structure represending a full block data, used for blockchain syncing.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct BlockInfo {
-    /// Previous block hash
-    pub st: blake3::Hash,
-    /// Slot uid, generated by the beacon
-    pub sl: u64,
-    /// Transactions payload
-    pub txs: Vec<Tx>,
-    /// Additional proposal information
-    pub metadata: Metadata,
-    /// Proposal information used by Streamlet consensus
-    pub sm: StreamletMetadata,
-}
-
-impl BlockInfo {
-    pub fn new(
-        st: blake3::Hash,
-        sl: u64,
-        txs: Vec<Tx>,
-        metadata: Metadata,
-        sm: StreamletMetadata,
-    ) -> BlockInfo {
-        BlockInfo { st, sl, txs, metadata, sm }
-    }
-}
-
-impl net::Message for BlockInfo {
-    fn name() -> &'static str {
-        "blockinfo"
-    }
-}
-
-impl_vec!(BlockInfo);
-
-/// Auxilary structure used for blockchain syncing.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct BlockResponse {
-    /// Response blocks.
-    pub blocks: Vec<BlockInfo>,
-}
-
-impl net::Message for BlockResponse {
-    fn name() -> &'static str {
-        "blockresponse"
-    }
-}
-
-#[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(())
-    }
-
-    /// Fetch given slots block hashes from the blockstore.
-    /// The resulting vector contains `Option` which is `Some` if the block
-    /// was found in the blockstore, and `None`, if it has not.
-    pub fn get(&self, slots: &[u64]) -> Result<Vec<Option<BlockOrder>>> {
-        let mut ret: Vec<Option<BlockOrder>> = Vec::with_capacity(slots.len());
-
-        for sl in slots {
-            if let Some(found) = self.0.get(sl.to_be_bytes())? {
-                let block = deserialize(&found)?;
-                ret.push(Some(BlockOrder { sl: sl.clone(), block }));
-            } else {
-                ret.push(None);
-            }
-        }
-
-        Ok(ret)
-    }
-
-    /// 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 n hashes after key.
-    pub fn get_after(&self, mut key: u64, n: u64) -> Result<Vec<blake3::Hash>> {
-        let mut hashes = Vec::new();
-        let mut counter = 0;
-        while counter <= n {
-            if let Some(found) = self.0.get_gt(key.to_be_bytes())? {
-                let key_bytes: [u8; 8] = found.0.as_ref().try_into().unwrap();
-                key = u64::from_be_bytes(key_bytes);
-                let block_hash = deserialize(&found.1)?;
-                hashes.push(block_hash);
-                counter = counter + 1;
-            } else {
-                break
-            }
-        }
-        Ok(hashes)
-    }
-
-    /// 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 {
-    /// leader public key
-    pub public_key: PublicKey,
-    /// signed block
-    pub signature: Signature,
-    /// leader id
-    pub id: u64,
-    /// Previous block hash
-    pub st: blake3::Hash,
-    /// Slot uid, generated by the beacon
-    pub sl: u64,
-    /// Transactions payload
-    pub txs: Vec<Tx>,
-    /// Additional proposal information
-    pub metadata: Metadata,
-    /// Proposal information used by Streamlet consensus
-    pub sm: StreamletMetadata,
-}
-
-impl BlockProposal {
-    pub fn new(
-        public_key: PublicKey,
-        signature: Signature,
-        id: u64,
-        st: blake3::Hash,
-        sl: u64,
-        txs: Vec<Tx>,
-        metadata: Metadata,
-        sm: StreamletMetadata,
-    ) -> BlockProposal {
-        BlockProposal { public_key, signature, id, st, sl, txs, metadata, sm }
-    }
-
-    /// Produce proposal hash using st, sl, txs and metadata.
-    pub fn hash(&self) -> blake3::Hash {
-        Self::to_proposal_hash(self.st, self.sl, &self.txs, &self.metadata)
-    }
-
-    /// Util function generate a proposal hash using provided st, sl, txs and metadata.
-    pub fn to_proposal_hash(
-        st: blake3::Hash,
-        sl: u64,
-        transactions: &Vec<Tx>,
-        metadata: &Metadata,
-    ) -> blake3::Hash {
-        let mut txs = Vec::new();
-        for tx in transactions {
-            let hash = blake3::hash(&serialize(tx));
-            txs.push(hash);
-        }
-
-        blake3::hash(&serialize(&Block::new(st, sl, txs, metadata.clone())))
-    }
-}
-
-impl PartialEq for BlockProposal {
-    fn eq(&self, other: &Self) -> bool {
-        self.public_key == other.public_key &&
-            self.signature == other.signature &&
-            self.id == other.id &&
-            self.st == other.st &&
-            self.sl == other.sl &&
-            self.txs == other.txs &&
-            self.metadata == other.metadata
-    }
-}
-
-impl net::Message for BlockProposal {
-    fn name() -> &'static str {
-        "proposal"
-    }
-}
-
-impl_vec!(BlockProposal);

+ 0 - 203
script/research/validatord/src/consensus/blockchain.rs

@@ -1,203 +0,0 @@
-use std::io;
-
-use log::debug;
-
-use darkfi::{
-    impl_vec,
-    util::serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt},
-    Result,
-};
-
-use super::{
-    block::{Block, BlockInfo, BlockOrderStore, BlockProposal, BlockStore},
-    metadata::StreamletMetadataStore,
-    tx::TxStore,
-};
-
-/// This struct represents the canonical (finalized) blockchain stored in sled database.
-#[derive(Debug)]
-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
-    pub streamlet_metadata: StreamletMetadataStore,
-}
-
-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, genesis)?;
-        Ok(Blockchain { blocks, order, transactions, streamlet_metadata })
-    }
-
-    /// Insertion of a block proposal.
-    pub fn add_by_proposal(&mut self, proposal: BlockProposal) -> Result<blake3::Hash> {
-        // Storing transactions
-        let mut txs = Vec::new();
-        for tx in proposal.txs {
-            let hash = self.transactions.insert(&tx)?;
-            txs.push(hash);
-        }
-
-        // Storing block
-        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)
-    }
-
-    /// Insertion of a block info.
-    pub fn add_by_info(&mut self, info: BlockInfo) -> Result<blake3::Hash> {
-        if self.has_block(&info)? {
-            let blockhash =
-                BlockProposal::to_proposal_hash(info.st, info.sl, &info.txs, &info.metadata);
-            return Ok(blockhash)
-        }
-
-        // Storing transactions
-        let mut txs = Vec::new();
-        for tx in info.txs {
-            let hash = self.transactions.insert(&tx)?;
-            txs.push(hash);
-        }
-
-        // Storing block
-        let block = Block { st: info.st, sl: info.sl, txs, metadata: info.metadata };
-        let hash = self.blocks.insert(&block)?;
-
-        // Storing block order
-        self.order.insert(block.sl, hash)?;
-
-        // Storing streamlet metadata
-        self.streamlet_metadata.insert(hash, &info.sm)?;
-
-        Ok(hash)
-    }
-
-    /// Retrieve the last block slot and hash.
-    pub fn last(&self) -> Result<Option<(u64, blake3::Hash)>> {
-        self.order.get_last()
-    }
-
-    /// Retrieve the last block slot and hash.
-    pub fn has_block(&self, info: &BlockInfo) -> Result<bool> {
-        let hashes = self.order.get(&vec![info.sl])?;
-        if hashes.is_empty() {
-            return Ok(false)
-        }
-        if let Some(found) = &hashes[0] {
-            // Checking provided info produces same hash
-            let blockhash =
-                BlockProposal::to_proposal_hash(info.st, info.sl, &info.txs, &info.metadata);
-
-            return Ok(blockhash == found.block)
-        }
-        Ok(false)
-    }
-
-    /// Retrieve n blocks with all their info, after start key.
-    pub fn get_with_info(&self, key: u64, n: u64) -> Result<Vec<BlockInfo>> {
-        let mut blocks_info = Vec::new();
-
-        // Retrieve requested hashes from order store
-        let hashes = self.order.get_after(key, n)?;
-
-        // Retrieve blocks for found hashes
-        let blocks = self.blocks.get(&hashes)?;
-
-        // For each found block, retrieve its txs and metadata and convert to BlockProposal
-        for option in blocks {
-            match option {
-                None => continue,
-                Some((hash, block)) => {
-                    let mut txs = Vec::new();
-                    let found = self.transactions.get(&block.txs)?;
-                    for option in found {
-                        match option {
-                            Some(tx) => txs.push(tx),
-                            None => continue,
-                        }
-                    }
-                    let sm = self.streamlet_metadata.get(&vec![hash])?[0].as_ref().unwrap().clone();
-                    blocks_info.push(BlockInfo::new(block.st, block.sl, txs, block.metadata, sm));
-                }
-            }
-        }
-
-        Ok(blocks_info)
-    }
-}
-
-/// This struct represents a sequence of block proposals.
-#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct ProposalsChain {
-    pub proposals: Vec<BlockProposal>,
-}
-
-impl ProposalsChain {
-    pub fn new(initial_proposal: BlockProposal) -> ProposalsChain {
-        ProposalsChain { proposals: vec![initial_proposal] }
-    }
-
-    /// A proposal is considered valid when its parent hash is equal to the hash of the
-    /// previous proposal and their epochs are incremental, exluding genesis block proposal.
-    /// Additional validity rules can be applied.
-    pub fn check_proposal(
-        &self,
-        proposal: &BlockProposal,
-        previous: &BlockProposal,
-        genesis: &blake3::Hash,
-    ) -> bool {
-        if &proposal.st == genesis {
-            debug!("Genesis block proposal provided.");
-            return false
-        }
-        let previous_hash = previous.hash();
-        if proposal.st != previous_hash || proposal.sl <= previous.sl {
-            debug!("Provided proposal is invalid.");
-            return false
-        }
-        true
-    }
-
-    /// A proposals chain is considered valid, when every proposal is valid, based on check_proposal function.
-    pub fn check_chain(&self, genesis: &blake3::Hash) -> bool {
-        for (index, proposal) in self.proposals[1..].iter().enumerate() {
-            if !self.check_proposal(proposal, &self.proposals[index], genesis) {
-                return false
-            }
-        }
-        true
-    }
-
-    /// Insertion of a valid proposal.
-    pub fn add(&mut self, proposal: &BlockProposal, genesis: &blake3::Hash) {
-        if self.check_proposal(proposal, self.proposals.last().unwrap(), genesis) {
-            self.proposals.push(proposal.clone());
-        }
-    }
-
-    /// Proposals chain notarization check.
-    pub fn notarized(&self) -> bool {
-        for proposal in &self.proposals {
-            if !proposal.sm.notarized {
-                return false
-            }
-        }
-        true
-    }
-}
-
-impl_vec!(ProposalsChain);

+ 0 - 121
script/research/validatord/src/consensus/metadata.rs

@@ -1,121 +0,0 @@
-use darkfi::{
-    util::serial::{deserialize, serialize, SerialDecodable, SerialEncodable},
-    Result,
-};
-
-use super::{block::Block, participant::Participant, util::Timestamp, vote::Vote};
-
-const SLED_STREAMLET_METADATA_TREE: &[u8] = b"_streamlet_metadata";
-
-/// This struct represents additional Block information used by the consensus protocol.
-#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct Metadata {
-    /// Block creation timestamp
-    pub timestamp: Timestamp,
-    /// Block information used by Ouroboros consensus
-    pub om: OuroborosMetadata,
-}
-
-impl Metadata {
-    pub fn new(timestamp: Timestamp, proof: String, r: String, s: String) -> Metadata {
-        Metadata { timestamp, om: OuroborosMetadata::new(proof, r, s) }
-    }
-}
-
-/// This struct represents Block information used by Ouroboros consensus protocol.
-#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct OuroborosMetadata {
-    /// Proof the stakeholder is the block owner
-    pub proof: String,
-    /// Random seed for VRF
-    pub r: String,
-    /// Block owner signature
-    pub s: String,
-}
-
-impl OuroborosMetadata {
-    pub fn new(proof: String, r: String, s: String) -> OuroborosMetadata {
-        OuroborosMetadata { proof, r, s }
-    }
-}
-
-/// This struct represents Block information used by Streamlet consensus protocol.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct StreamletMetadata {
-    /// Epoch votes
-    pub votes: Vec<Vote>,
-    /// Block notarization flag
-    pub notarized: bool,
-    /// Block finalization flag
-    pub finalized: bool,
-    /// Nodes participated in the voting process
-    pub participants: Vec<Participant>,
-}
-
-impl StreamletMetadata {
-    pub fn new(participants: Vec<Participant>) -> StreamletMetadata {
-        StreamletMetadata { votes: Vec::new(), notarized: false, finalized: false, participants }
-    }
-}
-
-#[derive(Debug)]
-pub struct StreamletMetadataStore(sled::Tree);
-
-impl StreamletMetadataStore {
-    pub fn new(db: &sled::Db, genesis: i64) -> Result<Self> {
-        let tree = db.open_tree(SLED_STREAMLET_METADATA_TREE)?;
-        let store = Self(tree);
-        if store.0.is_empty() {
-            // Genesis block record is generated.
-            let block = blake3::hash(&serialize(&Block::genesis_block(genesis)));
-            let metadata = StreamletMetadata {
-                votes: vec![],
-                notarized: true,
-                finalized: true,
-                participants: vec![],
-            };
-            store.insert(block, &metadata)?;
-        }
-
-        Ok(store)
-    }
-
-    /// Insert streamlet metadata into the store.
-    /// The block hash for the metadata is used as the key, where value is the serialized metadata.
-    pub fn insert(&self, block: blake3::Hash, metadata: &StreamletMetadata) -> Result<()> {
-        self.0.insert(block.as_bytes(), serialize(metadata))?;
-        Ok(())
-    }
-
-    /// Fetch given streamlet metadata from the store.
-    /// The resulting vector contains `Option` which is `Some` if the metadata
-    /// was found in the store, and `None`, if it has not.
-    pub fn get(&self, hashes: &[blake3::Hash]) -> Result<Vec<Option<StreamletMetadata>>> {
-        let mut ret: Vec<Option<StreamletMetadata>> = Vec::with_capacity(hashes.len());
-
-        for i in hashes {
-            if let Some(found) = self.0.get(i.as_bytes())? {
-                let metadata = deserialize(&found)?;
-                ret.push(Some(metadata));
-            } else {
-                ret.push(None);
-            }
-        }
-
-        Ok(ret)
-    }
-
-    /// Retrieve all streamlet metadata.
-    /// Be carefull as this will try to load everything in memory.
-    pub fn get_all(&self) -> Result<Vec<Option<(blake3::Hash, StreamletMetadata)>>> {
-        let mut metadata = Vec::new();
-        let mut iterator = self.0.into_iter().enumerate();
-        while let Some((_, r)) = iterator.next() {
-            let (k, v) = r.unwrap();
-            let hash_bytes: [u8; 32] = k.as_ref().try_into().unwrap();
-            let m = deserialize(&v)?;
-            metadata.push(Some((hash_bytes.into(), m)));
-        }
-        Ok(metadata)
-    }
-}

+ 0 - 16
script/research/validatord/src/consensus/mod.rs

@@ -1,16 +0,0 @@
-pub mod block;
-pub mod blockchain;
-pub mod metadata;
-pub mod participant;
-pub mod state;
-pub mod tx;
-pub mod util;
-pub mod vote;
-
-pub use block::{Block, BlockProposal};
-pub use blockchain::Blockchain;
-pub use metadata::Metadata;
-pub use participant::Participant;
-pub use state::ValidatorState;
-pub use tx::Tx;
-pub use vote::Vote;

+ 0 - 55
script/research/validatord/src/consensus/participant.rs

@@ -1,55 +0,0 @@
-use std::{collections::BTreeMap, io};
-
-use darkfi::{
-    impl_vec, net,
-    util::serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt},
-    Result,
-};
-
-/// This struct represents a tuple of the form (node_id, epoch_joined, last_epoch_voted).
-#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct Participant {
-    /// Node id
-    pub id: u64,
-    /// Epoch node joined the network
-    pub joined: u64,
-    /// Last epoch node voted
-    pub voted: Option<u64>,
-}
-
-impl Participant {
-    pub fn new(id: u64, joined: u64) -> Participant {
-        Participant { id, joined, voted: None }
-    }
-}
-
-impl net::Message for Participant {
-    fn name() -> &'static str {
-        "participant"
-    }
-}
-
-impl Encodable for BTreeMap<u64, Participant> {
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += VarInt(self.len() as u64).encode(&mut s)?;
-        for c in self.iter() {
-            len += c.1.encode(&mut s)?;
-        }
-        Ok(len)
-    }
-}
-
-impl Decodable for BTreeMap<u64, Participant> {
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        let len = VarInt::decode(&mut d)?.0;
-        let mut ret = BTreeMap::new();
-        for _ in 0..len {
-            let participant: Participant = Decodable::decode(&mut d)?;
-            ret.insert(participant.id, participant);
-        }
-        Ok(ret)
-    }
-}
-
-impl_vec!(Participant);

+ 0 - 725
script/research/validatord/src/consensus/state.rs

@@ -1,725 +0,0 @@
-use chrono::{NaiveDateTime, Utc};
-use log::{debug, error, warn};
-use rand::rngs::OsRng;
-use std::{
-    collections::{hash_map::DefaultHasher, BTreeMap},
-    hash::{Hash, Hasher},
-    path::PathBuf,
-    sync::{Arc, RwLock},
-    time::Duration,
-};
-
-use darkfi::{
-    crypto::{
-        keypair::{PublicKey, SecretKey},
-        schnorr::{SchnorrPublic, SchnorrSecret},
-    },
-    net,
-    util::serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable},
-    Error, Result,
-};
-
-use super::{
-    block::{Block, BlockInfo, BlockProposal},
-    blockchain::{Blockchain, ProposalsChain},
-    metadata::{Metadata, StreamletMetadata},
-    participant::Participant,
-    tx::Tx,
-    util::{get_current_time, Timestamp},
-    vote::Vote,
-};
-
-pub const DELTA: u64 = 10;
-const SLED_CONSESUS_STATE_TREE: &[u8] = b"_consensus_state";
-
-/// This struct represents the information required by the consensus algorithm.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct ConsensusState {
-    /// Genesis block creation timestamp
-    pub genesis: Timestamp,
-    /// Fork chains containing block proposals
-    pub proposals: Vec<ProposalsChain>,
-    /// Orphan votes pool, in case a vote reaches a node before the corresponding block
-    pub orphan_votes: Vec<Vote>,
-    /// Node participation identity
-    pub participant: Option<Participant>,
-    /// Validators currently participating in the consensus
-    pub participants: BTreeMap<u64, Participant>,
-    /// Validators to be added on the next epoch as participants
-    pub pending_participants: Vec<Participant>,
-    /// Last slot participants where refreshed
-    pub refreshed: u64,
-}
-
-impl ConsensusState {
-    pub fn new(db: &sled::Db, id: u64, genesis: i64) -> Result<ConsensusState> {
-        let tree = db.open_tree(SLED_CONSESUS_STATE_TREE)?;
-        let consensus = if let Some(found) = tree.get(id.to_ne_bytes())? {
-            deserialize(&found).unwrap()
-        } else {
-            let consensus = ConsensusState {
-                genesis: Timestamp(genesis),
-                proposals: Vec::new(),
-                orphan_votes: Vec::new(),
-                participant: None,
-                participants: BTreeMap::new(),
-                pending_participants: vec![],
-                refreshed: 0,
-            };
-            let serialized = serialize(&consensus);
-            tree.insert(id.to_ne_bytes(), serialized)?;
-            consensus
-        };
-        Ok(consensus)
-    }
-}
-
-/// Auxilary structure used for consensus syncing.
-#[derive(Debug, SerialEncodable, SerialDecodable)]
-pub struct ConsensusRequest {
-    /// Validator id
-    pub id: u64,
-}
-
-impl net::Message for ConsensusRequest {
-    fn name() -> &'static str {
-        "consensusrequest"
-    }
-}
-
-/// Auxilary structure used for consensus syncing.
-#[derive(Debug, Clone, SerialEncodable, SerialDecodable)]
-pub struct ConsensusResponse {
-    /// Hot/live data used by the consensus algorithm
-    pub consensus: ConsensusState,
-}
-
-impl net::Message for ConsensusResponse {
-    fn name() -> &'static str {
-        "consensusresponse"
-    }
-}
-
-/// Atomic pointer to validator state.
-pub type ValidatorStatePtr = Arc<RwLock<ValidatorState>>;
-
-/// This struct represents the state of a validator node.
-pub struct ValidatorState {
-    /// Validator id
-    pub id: u64,
-    /// Secret key, to sign messages
-    pub secret: SecretKey,
-    /// Validator public key
-    pub public: PublicKey,
-    /// Sled database for storage
-    pub db: sled::Db,
-    /// Hot/live data used by the consensus algorithm
-    pub consensus: ConsensusState,
-    /// Canonical (finalized) blockchain
-    pub blockchain: Blockchain,
-    /// Pending transactions
-    pub unconfirmed_txs: Vec<Tx>,
-    /// Genesis block hash, used for validations
-    pub genesis_block: blake3::Hash,
-    /// Participation flag
-    pub participating: bool,
-}
-
-impl ValidatorState {
-    pub fn new(db_path: PathBuf, id: u64, genesis: i64) -> Result<ValidatorStatePtr> {
-        // Missing: clock sync
-        let secret = SecretKey::random(&mut OsRng);
-        let db = sled::open(db_path)?;
-        let public = PublicKey::from_secret(secret);
-        let consensus = ConsensusState::new(&db, id, genesis)?;
-        let blockchain = Blockchain::new(&db, genesis)?;
-        let unconfirmed_txs = Vec::new();
-        let genesis_block = blake3::hash(&serialize(&Block::genesis_block(genesis)));
-        let participating = false;
-        Ok(Arc::new(RwLock::new(ValidatorState {
-            id,
-            secret,
-            public,
-            db,
-            consensus,
-            blockchain,
-            unconfirmed_txs,
-            genesis_block,
-            participating,
-        })))
-    }
-
-    /// Node retreives a transaction and append it to the unconfirmed transactions list.
-    /// Additional validity rules must be defined by the protocol for transactions.
-    pub fn append_tx(&mut self, tx: Tx) -> bool {
-        if self.unconfirmed_txs.contains(&tx) {
-            return false
-        }
-        self.unconfirmed_txs.push(tx);
-        true
-    }
-
-    /// Node calculates seconds until next epoch starting time.
-    /// Epochs duration is configured using the delta value.
-    pub fn next_epoch_start(&self) -> Duration {
-        let start_time = NaiveDateTime::from_timestamp(self.consensus.genesis.0, 0);
-        let current_epoch = self.current_epoch() + 1;
-        let next_epoch_start_timestamp =
-            (current_epoch * (2 * DELTA)) + (start_time.timestamp() as u64);
-        let next_epoch_start =
-            NaiveDateTime::from_timestamp(next_epoch_start_timestamp.try_into().unwrap(), 0);
-        let current_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
-        let diff = next_epoch_start - current_time;
-        Duration::new(diff.num_seconds().try_into().unwrap(), 0)
-    }
-
-    /// Node calculates current epoch, based on elapsed time from the genesis block.
-    /// Epochs duration is configured using the delta value.
-    pub fn current_epoch(&self) -> u64 {
-        self.consensus.genesis.clone().elapsed() / (2 * DELTA)
-    }
-    
-    /// Finds the last epoch a proposal or block was generated.
-    pub fn last_epoch(&self) -> Result<u64> {
-        let mut epoch = 0;
-        for chain in &self.consensus.proposals {
-            for proposal in &chain.proposals {
-                if proposal.block.sl > epoch {
-                    epoch = proposal.block.sl;
-                }
-            }
-        }
-
-        // We return here in case proposals exist,
-        // so we don't query the sled database.
-        if epoch > 0 {
-            return Ok(epoch)
-        }
-
-        let (last_sl, _) = self.blockchain.last()?.unwrap();
-        Ok(last_sl)
-    }
-
-    /// Node finds epochs leader, using a simple hash method.
-    /// Leader calculation is based on how many nodes are participating in the network.
-    pub fn epoch_leader(&mut self) -> u64 {
-        let epoch = self.current_epoch();
-        // DefaultHasher is used to hash the epoch number
-        // because it produces a number string which then can be modulated by the len.
-        // blake3 produces alphanumeric
-        let mut hasher = DefaultHasher::new();
-        epoch.hash(&mut hasher);
-        let pos = hasher.finish() % (self.consensus.participants.len() as u64);
-        // Since BTreeMap orders by key in asceding order, each node will have
-        // the same key in calculated position.
-        self.consensus.participants.iter().nth(pos as usize).unwrap().1.id
-    }
-
-    /// Node checks if they are the current epoch leader.
-    pub fn is_epoch_leader(&mut self) -> bool {
-        let leader = self.epoch_leader();
-        self.id == leader
-    }
-
-    /// Node generates a block proposal for the current epoch,
-    /// containing all uncorfirmed transactions.
-    /// Proposal extends the longest notarized fork chain the node holds.
-    pub fn propose(&self) -> Result<Option<BlockProposal>> {
-        let epoch = self.current_epoch();
-        let (previous_hash, index) = self.longest_notarized_chain_last_hash().unwrap();
-        let unproposed_txs = self.unproposed_txs(index);
-        let metadata = Metadata::new(
-            get_current_time(),
-            String::from("proof"),
-            String::from("r"),
-            String::from("s"),
-        );
-        let sm = StreamletMetadata::new(self.consensus.participants.values().cloned().collect());
-        let signed_block = self.secret.sign(
-            BlockProposal::to_proposal_hash(previous_hash, epoch, &unproposed_txs, &metadata)
-                .as_bytes(),
-        );
-        Ok(Some(BlockProposal::new(
-            self.public,
-            signed_block,
-            self.id,
-            previous_hash,
-            epoch,
-            unproposed_txs,
-            metadata,
-            sm,
-        )))
-    }
-
-    /// Node retrieves all unconfirmed transactions not proposed
-    /// in previous blocks of provided index chain.
-    pub fn unproposed_txs(&self, index: i64) -> Vec<Tx> {
-        let mut unproposed_txs = self.unconfirmed_txs.clone();
-
-        // If index is -1(canonical blockchain) a new fork chain will be generated,
-        // therefore all unproposed transactions can be included in the proposal.
-        if index == -1 {
-            return unproposed_txs
-        }
-
-        // We iterate the fork chain proposals to find already proposed transactions
-        // and remove them from the local unproposed_txs vector.
-        let chain = &self.consensus.proposals[index as usize];
-        for proposal in &chain.proposals {
-            for tx in &proposal.txs {
-                if let Some(pos) = unproposed_txs.iter().position(|txs| *txs == *tx) {
-                    unproposed_txs.remove(pos);
-                }
-            }
-        }
-
-        unproposed_txs
-    }
-
-    /// Finds the longest fully notarized blockchain the node holds and returns the last block hash
-    /// and the chain index.
-    pub fn longest_notarized_chain_last_hash(&self) -> Result<(blake3::Hash, i64)> {
-        let mut longest_notarized_chain: Option<ProposalsChain> = None;
-        let mut length = 0;
-        let mut index = -1;
-        if !self.consensus.proposals.is_empty() {
-            for (i, chain) in self.consensus.proposals.iter().enumerate() {
-                if chain.notarized() && chain.proposals.len() > length {
-                    longest_notarized_chain = Some(chain.clone());
-                    length = chain.proposals.len();
-                    index = i as i64;
-                }
-            }
-        }
-
-        let hash = match longest_notarized_chain {
-            Some(chain) => chain.proposals.last().unwrap().hash(),
-            None => self.blockchain.last()?.unwrap().1,
-        };
-
-        Ok((hash, index))
-    }
-
-    /// Node receives the proposed block, verifies its sender(epoch leader),
-    /// and proceeds with voting on it.
-    pub fn receive_proposal(&mut self, proposal: &BlockProposal) -> Result<Option<Vote>> {
-        // Node hasn't started participating
-        if !self.participating {
-            return Ok(None)
-        }
-        
-        // Node refreshes participants records
-        self.refresh_participants()?;
-
-        let leader = self.epoch_leader();
-        if leader != proposal.id {
-            debug!(
-                "Received proposal not from epoch leader ({:?}). Proposer: {:?}",
-                leader, proposal.id
-            );
-            return Ok(None)
-        }
-        if !proposal.public_key.verify(
-            BlockProposal::to_proposal_hash(
-                proposal.st,
-                proposal.sl,
-                &proposal.txs,
-                &proposal.metadata,
-            )
-            .as_bytes(),
-            &proposal.signature,
-        ) {
-            debug!("Proposer signature couldn't be verified. Proposer: {:?}", proposal.id);
-            return Ok(None)
-        }
-        self.vote(proposal)
-    }
-
-    /// Given a proposal, node finds which blockchain it extends.
-    /// If proposal extends the canonical blockchain, a new fork chain is created.
-    /// Node votes on the proposal, only if it extends the longest notarized fork chain it has seen.
-    pub fn vote(&mut self, proposal: &BlockProposal) -> Result<Option<Vote>> {
-        let mut proposal = proposal.clone();
-
-        // Generate proposal hash
-        let proposal_hash = proposal.hash();
-
-        // Add orphan votes
-        let mut orphans = Vec::new();
-        for vote in self.consensus.orphan_votes.iter() {
-            if vote.proposal == proposal_hash {
-                proposal.sm.votes.push(vote.clone());
-                orphans.push(vote.clone());
-            }
-        }
-        for vote in orphans {
-            self.consensus.orphan_votes.retain(|v| *v != vote);
-        }
-
-        let index = self.find_extended_chain_index(&proposal).unwrap();
-
-        if index == -2 {
-            return Ok(None)
-        }
-        let chain = match index {
-            -1 => {
-                let proposalschain = ProposalsChain::new(proposal.clone());
-                self.consensus.proposals.push(proposalschain);
-                self.consensus.proposals.last().unwrap()
-            }
-            _ => {
-                self.consensus.proposals[index as usize].add(&proposal, &self.genesis_block);
-                &self.consensus.proposals[index as usize]
-            }
-        };
-
-        if self.extends_notarized_chain(chain) {
-            let signed_hash = self.secret.sign(&serialize(&proposal_hash)[..]);
-            return Ok(Some(Vote::new(
-                self.public,
-                signed_hash,
-                proposal_hash,
-                proposal.sl,
-                self.id,
-            )))
-        }
-        Ok(None)
-    }
-
-    /// Node verifies if provided chain is notarized excluding the last block.
-    pub fn extends_notarized_chain(&self, chain: &ProposalsChain) -> bool {
-        if chain.proposals.len() > 1 {
-            for proposal in &chain.proposals[..(chain.proposals.len() - 1)] {
-                if !proposal.sm.notarized {
-                    return false
-                }
-            }
-        }
-
-        true
-    }
-
-    /// Given a proposal, node finds the index of the chain it extends.
-    pub fn find_extended_chain_index(&mut self, proposal: &BlockProposal) -> Result<i64> {
-        for (index, chain) in self.consensus.proposals.iter().enumerate() {
-            let last = chain.proposals.last().unwrap();
-            let hash = last.hash();
-            if proposal.st == hash && proposal.sl > last.sl {
-                return Ok(index as i64)
-            }
-            if proposal.st == last.st && proposal.sl == last.sl {
-                debug!("Proposal already received.");
-                return Ok(-2)
-            }
-        }
-
-        let (last_sl, last_block) = self.blockchain.last()?.unwrap();
-        if proposal.st != last_block || proposal.sl <= last_sl {
-            error!("Proposal doesn't extend any known chains.");
-            return Ok(-2)
-        }
-
-        Ok(-1)
-    }
-
-    /// Node receives a vote for a proposal.
-    /// First, sender is verified using their public key.
-    /// Proposal is searched in nodes fork chains.
-    /// If the vote wasn't received before, it is appended to proposal votes list.
-    /// When a node sees 2n/3 votes for a proposal it notarizes it.
-    /// When a proposal gets notarized, the transactions it contains are removed from
-    /// nodes unconfirmed transactions list.
-    /// Finally, we check if the notarization of the proposal can finalize parent proposals
-    /// in its chain.
-    pub fn receive_vote(&mut self, vote: &Vote) -> Result<(bool, Option<Vec<BlockInfo>>)> {
-        // Node hasn't started participating
-        if !self.participating {
-            return Ok((false, None))
-        }
-
-        let mut encoded_proposal = vec![];
-        let result = vote.proposal.encode(&mut encoded_proposal);
-        match result {
-            Ok(_) => (),
-            Err(e) => {
-                error!("Proposal encoding failed. Error: {:?}", e);
-                return Ok((false, None))
-            }
-        };
-
-        if !vote.public_key.verify(&encoded_proposal[..], &vote.vote) {
-            debug!("Voter signature couldn't be verified. Voter: {:?}", vote.id);
-            return Ok((false, None))
-        }
-        
-        // Node refreshes participants records
-        self.refresh_participants()?;
-
-        let nodes_count = self.consensus.participants.len();
-        // Checking that the voter can actually vote.
-        match self.consensus.participants.get(&vote.id) {
-            Some(participant) => {
-                if self.current_epoch() <= participant.joined {
-                    debug!("Voter joined after current epoch. Voter: {:?}", vote.id);
-                    return Ok((false, None))
-                }
-            }
-            None => {
-                debug!("Voter is not a participant. Voter: {:?}", vote.id);
-                return Ok((false, None))
-            }
-        }
-
-        let proposal = self.find_proposal(&vote.proposal).unwrap();
-        if proposal == None {
-            debug!("Received vote for unknown proposal.");
-            if !self.consensus.orphan_votes.contains(vote) {
-                self.consensus.orphan_votes.push(vote.clone());
-            }
-            return Ok((false, None))
-        }
-
-        let (unwrapped, chain_index) = proposal.unwrap();
-        if !unwrapped.sm.votes.contains(vote) {
-            unwrapped.sm.votes.push(vote.clone());
-
-            let mut to_broadcast = Vec::new();
-            if !unwrapped.sm.notarized && unwrapped.sm.votes.len() > (2 * nodes_count / 3) {
-                unwrapped.sm.notarized = true;
-                to_broadcast = self.chain_finalization(chain_index)?;
-            }
-
-            // updating participant vote
-            let exists = self.consensus.participants.get(&vote.id);
-            let mut participant = match exists {
-                Some(p) => p.clone(),
-                None => Participant::new(vote.id, vote.sl),
-            };
-
-            match participant.voted {
-                Some(voted) => {
-                    if vote.sl > voted {
-                        participant.voted = Some(vote.sl);
-                    }
-                }
-                None => participant.voted = Some(vote.sl),
-            }
-
-            self.consensus.participants.insert(participant.id, participant);
-
-            return Ok((true, Some(to_broadcast)))
-        }
-        return Ok((false, None))
-    }
-
-    /// Node searches it the chains it holds for provided proposal.
-    pub fn find_proposal(
-        &mut self,
-        vote_proposal: &blake3::Hash,
-    ) -> Result<Option<(&mut BlockProposal, i64)>> {
-        for (index, chain) in &mut self.consensus.proposals.iter_mut().enumerate() {
-            for proposal in chain.proposals.iter_mut().rev() {
-                let proposal_hash = proposal.hash();
-                if vote_proposal == &proposal_hash {
-                    return Ok(Some((proposal, index as i64)))
-                }
-            }
-        }
-        Ok(None)
-    }
-
-    /// Note removes provided transactions vector, from unconfirmed_txs, if they exist.
-    pub fn remove_txs(&mut self, transactions: Vec<Tx>) -> Result<()> {
-        for tx in transactions {
-            if let Some(pos) = self.unconfirmed_txs.iter().position(|txs| *txs == tx) {
-                self.unconfirmed_txs.remove(pos);
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Provided an index, node checks if chain can be finalized.
-    /// Consensus finalization logic: If node has observed the notarization of 3 consecutive
-    /// proposals in a fork chain, it finalizes (appends to canonical blockchain) all proposals up to the middle block.
-    /// When fork chain proposals are finalized, rest fork chains not starting by those proposals are removed.
-    pub fn chain_finalization(&mut self, chain_index: i64) -> Result<Vec<BlockInfo>> {
-        let mut to_broadcast = Vec::new();
-        let chain = &mut self.consensus.proposals[chain_index as usize];
-        let len = chain.proposals.len();
-        if len > 2 {
-            let mut consecutive = 0;
-            for proposal in &chain.proposals {
-                if proposal.sm.notarized {
-                    consecutive += 1;
-                } else {
-                    break
-                }
-            }
-
-            if consecutive > 2 {
-                let mut finalized = Vec::new();
-                for proposal in &mut chain.proposals[..(consecutive - 1)] {
-                    proposal.sm.finalized = true;
-                    finalized.push(proposal.clone());
-                }
-                chain.proposals.drain(0..(consecutive - 1));
-                for proposal in &finalized {
-                    self.blockchain.add_by_proposal(proposal.clone())?;
-                    self.remove_txs(proposal.txs.clone())?;
-                    to_broadcast.push(BlockInfo::new(
-                        proposal.st,
-                        proposal.sl,
-                        proposal.txs.clone(),
-                        proposal.metadata.clone(),
-                        proposal.sm.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 != last_block || first.sl <= last_sl {
-                        dropped.push(chain.clone());
-                    }
-                }
-                for chain in dropped {
-                    self.consensus.proposals.retain(|c| *c != chain);
-                }
-
-                // Remove orphan votes
-                let mut orphans = Vec::new();
-                for vote in self.consensus.orphan_votes.iter() {
-                    if vote.sl <= last_sl {
-                        orphans.push(vote.clone());
-                    }
-                }
-                for vote in orphans {
-                    self.consensus.orphan_votes.retain(|v| *v != vote);
-                }
-            }
-        }
-
-        Ok(to_broadcast)
-    }
-    
-    /// Append node participant identity to the pending participants list.
-    pub fn append_self_participant(&mut self, participant: Participant) {
-        self.consensus.participant = Some(participant.clone());
-        self.append_participant(participant);
-    }
-
-    /// Node retreives a new participant and appends it to the pending participants list.
-    pub fn append_participant(&mut self, participant: Participant) -> bool {
-        if self.consensus.pending_participants.contains(&participant) {
-            return false
-        }
-        self.consensus.pending_participants.push(participant);
-        true
-    }
-
-    /// Refresh the participants map, to retain only the active ones.
-    /// Active nodes are considered those that on the epoch the last proposal
-    /// was generated, either voted or joined the previous epoch.
-    /// That ensures we cover the case of chosen leader beign inactive.
-    pub fn refresh_participants(&mut self) -> Result<()> {
-        // Node checks if it should refresh its participants list
-        let epoch = self.current_epoch();
-        if epoch <= self.consensus.refreshed {
-            debug!("refresh_participants(): Participants have been refreshed this epoch.");
-            return Ok(())
-        }
-
-        debug!("refresh_participants(): Adding pending participants");
-        for participant in &self.consensus.pending_participants {
-            self.consensus.participants.insert(participant.id, participant.clone());
-        }
-
-        if self.consensus.participants.is_empty() {
-            debug!(
-                "refresh_participants(): Didn't manage to add any participant, pending were empty."
-            );
-        }
-
-        self.consensus.pending_participants = vec![];
-
-        let mut inactive = Vec::new();
-        let mut last_epoch = self.last_epoch()?;
-
-        // This check ensures that we don't chech the current epoch,
-        // as a node might receive the proposal of current epoch before
-        // starting refreshing participants, so the last_epoch will be
-        // the current one.
-        if last_epoch >= epoch {
-            last_epoch = epoch - 1;
-        }
-
-        let previous_epoch = last_epoch - 1;
-
-        error!(
-            "refresh_participants(): Checking epochs: previous - {:?}, last - {:?}",
-            previous_epoch, last_epoch
-        );
-
-        for (index, participant) in self.consensus.participants.clone().iter() {
-            match participant.voted {
-                Some(epoch) => {
-                    if epoch < last_epoch {
-                        warn!("refresh_participants(): Inactive participant: {:?}", participant);
-                        inactive.push(*index);
-                    }
-                }
-                None => {
-                    if participant.joined < previous_epoch {
-                        warn!("refresh_participants(): Inactive participant: {:?}", participant);
-                        inactive.push(*index);
-                    }
-                }
-            }
-        }
-
-        for index in inactive {
-            self.consensus.participants.remove(&index);
-        }
-
-        if self.consensus.participants.is_empty() {
-            // If no nodes are active, node becomes a single node network.
-            let mut participant = self.consensus.participant.clone().unwrap();
-            participant.joined = epoch;
-            self.consensus.participant = Some(participant.clone());
-            self.consensus.participants.insert(participant.id, participant.clone());
-        }
-
-        self.consensus.refreshed = epoch;
-
-        Ok(())
-    }
-
-    /// Util function to save the current consensus state to provided file path.
-    pub fn save_consensus_state(&self) -> Result<()> {
-        let tree = self.db.open_tree(SLED_CONSESUS_STATE_TREE).unwrap();
-        let serialized = serialize(&self.consensus);
-        match tree.insert(self.id.to_ne_bytes(), serialized) {
-            Err(_) => Err(Error::OperationFailed),
-            _ => Ok(()),
-        }
-    }
-
-    /// Util function to reset the current consensus state.
-    pub fn reset_consensus_state(&mut self) -> Result<()> {
-        let genesis = self.consensus.genesis.clone();
-        let consensus = ConsensusState {
-            genesis,
-            proposals: Vec::new(),
-            orphan_votes: Vec::new(),
-            participant: None,
-            participants: BTreeMap::new(),
-            pending_participants: vec![],
-            refreshed: 0,
-        };
-
-        self.consensus = consensus;
-        Ok(())
-    }
-}

+ 0 - 78
script/research/validatord/src/consensus/tx.rs

@@ -1,78 +0,0 @@
-use std::io;
-
-use darkfi::{
-    impl_vec, net,
-    util::serial::{
-        deserialize, serialize, Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt,
-    },
-    Result,
-};
-
-const SLED_TX_TREE: &[u8] = b"_transactions";
-
-/// Temporary structure used to represent transactions.
-#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)]
-pub struct Tx {
-    pub payload: String,
-}
-
-impl net::Message for Tx {
-    fn name() -> &'static str {
-        "tx"
-    }
-}
-
-impl_vec!(Tx);
-
-#[derive(Debug)]
-pub struct TxStore(sled::Tree);
-
-impl TxStore {
-    pub fn new(db: &sled::Db) -> Result<Self> {
-        let tree = db.open_tree(SLED_TX_TREE)?;
-        Ok(Self(tree))
-    }
-
-    /// Insert a tx into the txstore.
-    /// The tx is hashed with blake3 and this txhash is used as
-    /// the key, where value is the serialized tx itself.
-    pub fn insert(&self, tx: &Tx) -> Result<blake3::Hash> {
-        let serialized = serialize(tx);
-        let txhash = blake3::hash(&serialized);
-        self.0.insert(txhash.as_bytes(), serialized)?;
-
-        Ok(txhash)
-    }
-
-    /// Fetch given transactions from the txstore.
-    /// The resulting vector contains `Option` which is `Some` if the tx
-    /// was found in the txstore, and `None`, if it has not.
-    pub fn get(&self, txhashes: &[blake3::Hash]) -> Result<Vec<Option<Tx>>> {
-        let mut ret: Vec<Option<Tx>> = Vec::with_capacity(txhashes.len());
-
-        for i in txhashes {
-            if let Some(found) = self.0.get(i.as_bytes())? {
-                let tx = deserialize(&found)?;
-                ret.push(Some(tx));
-            } else {
-                ret.push(None);
-            }
-        }
-
-        Ok(ret)
-    }
-
-    /// Retrieve all transactions.
-    /// Be carefull as this will try to load everything in memory.
-    pub fn get_all(&self) -> Result<Vec<Option<(blake3::Hash, Tx)>>> {
-        let mut txs = Vec::new();
-        let mut iterator = self.0.into_iter().enumerate();
-        while let Some((_, r)) = iterator.next() {
-            let (k, v) = r.unwrap();
-            let hash_bytes: [u8; 32] = k.as_ref().try_into().unwrap();
-            let tx = deserialize(&v)?;
-            txs.push(Some((hash_bytes.into(), tx)));
-        }
-        Ok(txs)
-    }
-}

+ 0 - 28
script/research/validatord/src/consensus/util.rs

@@ -1,28 +0,0 @@
-use chrono::{NaiveDateTime, Utc};
-
-use darkfi::util::serial::{SerialDecodable, SerialEncodable};
-
-/// Serialized blake3 hash bytes for character "⊥"
-pub const EMPTY_HASH_BYTES: [u8; 32] = [
-    254, 233, 82, 102, 23, 208, 153, 87, 96, 165, 163, 194, 238, 7, 1, 88, 14, 1, 249, 118, 197,
-    29, 180, 211, 87, 66, 59, 38, 86, 54, 12, 39,
-];
-
-/// Util structure to represend chrono UTC timestamps.
-#[derive(Debug, Clone, PartialEq, SerialDecodable, SerialEncodable)]
-pub struct Timestamp(pub i64);
-
-impl Timestamp {
-    /// Calculates elapsed time of a Timestamp.
-    pub fn elapsed(self) -> u64 {
-        let start_time = NaiveDateTime::from_timestamp(self.0, 0);
-        let end_time = NaiveDateTime::from_timestamp(Utc::now().timestamp(), 0);
-        let diff = end_time - start_time;
-        diff.num_seconds().try_into().unwrap()
-    }
-}
-
-/// Util function to generate a Timestamp of current time.
-pub fn get_current_time() -> Timestamp {
-    Timestamp(Utc::now().timestamp())
-}

+ 0 - 43
script/research/validatord/src/consensus/vote.rs

@@ -1,43 +0,0 @@
-use std::io;
-
-use darkfi::{
-    crypto::{keypair::PublicKey, schnorr::Signature},
-    impl_vec, net,
-    util::serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt},
-    Result,
-};
-
-/// This struct represents a Vote, used by Streamlet consensus.
-#[derive(Debug, Clone, PartialEq, SerialDecodable, SerialEncodable)]
-pub struct Vote {
-    /// Node public key
-    pub public_key: PublicKey,
-    /// signed block
-    pub vote: Signature,
-    /// block proposal hash to vote on
-    pub proposal: blake3::Hash,
-    /// Slot uid, generated by the beacon
-    pub sl: u64,
-    /// node id
-    pub id: u64,
-}
-
-impl Vote {
-    pub fn new(
-        public_key: PublicKey,
-        vote: Signature,
-        proposal: blake3::Hash,
-        sl: u64,
-        id: u64,
-    ) -> Vote {
-        Vote { public_key, vote, proposal, sl, id }
-    }
-}
-
-impl net::Message for Vote {
-    fn name() -> &'static str {
-        "vote"
-    }
-}
-
-impl_vec!(Vote);

+ 0 - 530
script/research/validatord/src/main.rs

@@ -1,530 +0,0 @@
-use std::{net::SocketAddr, path::PathBuf, sync::Arc, thread, time::Duration};
-
-use async_executor::Executor;
-use async_trait::async_trait;
-use easy_parallel::Parallel;
-use log::{debug, error, info};
-use serde::{Deserialize, Serialize};
-use serde_json::{json, Value};
-use simplelog::{ColorChoice, TermLogger, TerminalMode};
-use structopt::StructOpt;
-use structopt_toml::StructOptToml;
-
-use darkfi::{
-    consensus2::{
-        block::{BlockOrder, BlockResponse},
-        participant::Participant,
-        state::{ConsensusRequest, ConsensusResponse, ValidatorState, ValidatorStatePtr},
-        tx::Tx,
-        proto::{ProtocolSync, ProtocolTx, ProtocolVote, ProtocolProposal, ProtocolParticipant, ProtocolSyncConsensus}
-    },
-    net,
-    rpc::{
-        jsonrpc,
-        jsonrpc::{
-            from_result,
-            ErrorCode::{InternalError, InvalidParams, InvalidRequest, MethodNotFound},
-            JsonRequest, JsonResult, ValueResult,
-        },
-        rpcserver::{listen_and_serve, RequestHandler, RpcServerConfig},
-    },
-    util::{
-        cli::{log_config, spawn_config},
-        expand_path,
-        path::get_config_path,
-    },
-    Result,
-};
-
-const CONFIG_FILE: &str = r"validatord_config.toml";
-const CONFIG_FILE_CONTENTS: &[u8] = include_bytes!("../validatord_config.toml");
-
-#[derive(Debug, Deserialize, Serialize, StructOpt, StructOptToml)]
-#[serde(default)]
-struct Opt {
-    #[structopt(short, long, default_value = CONFIG_FILE)]
-    /// Configuration file to use
-    config: String,
-    #[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")]
-    /// Connection slots
-    slots: u32,
-    #[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,
-    #[structopt(long, default_value = "127.0.0.1:6660")]
-    /// The endpoint where validatord will bind its RPC socket
-    rpc: SocketAddr,
-    #[structopt(long)]
-    /// Whether to listen with TLS or plain TCP
-    tls: bool,
-    #[structopt(long, default_value = "~/.config/darkfi/validatord_identity.pfx")]
-    /// TLS certificate to use
-    identity: PathBuf,
-    #[structopt(long, default_value = "FOOBAR")]
-    /// Password for the created TLS identity
-    password: String,
-    #[structopt(long, default_value = "1648383795")]
-    /// Timestamp of the genesis block creation
-    genesis: i64,
-    #[structopt(long, default_value = "~/.config/darkfi/validatord_db_0")]
-    /// Path to the sled database folder
-    database: String,
-    #[structopt(long, default_value = "0")]
-    /// Node ID, used only for testing
-    id: u64,
-    #[structopt(short, long, default_value = "0")]
-    /// How many threads to utilize
-    threads: usize,
-    #[structopt(short, long, parse(from_occurrences))]
-    /// Multiple levels can be used (-vv)
-    verbose: u8,
-}
-
-async fn syncing_task(p2p: net::P2pPtr, state: ValidatorStatePtr) -> Result<()> {
-    info!("Node starts syncing blockchain...");
-    // We retrieve p2p network connected channels, so we can use it to parallelize downloads
-    // Using len here because is_empty() uses unstable library feature 'exact_size_is_empty'
-    if p2p.channels().lock().await.values().len() != 0 {
-        // Currently we will use just the last channel
-        let channel = p2p.channels().lock().await.values().last().unwrap().clone();
-
-        // Communication setup
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<BlockResponse>().await;
-        let response_sub = channel
-            .subscribe_msg::<BlockResponse>()
-            .await
-            .expect("Missing BlockResponse dispatcher!");
-
-        // Nodes sends the last known block hash of the canonical blockchain
-        // and loops until the respond is the same block (used to utilize batch requests)
-        let mut last = state.read().await.blockchain.last()?.unwrap();
-        info!("Last known block: {:?} - {:?}", last.0, last.1);
-        loop {
-            // Node creates a BlockOrder and sends it
-            let order = BlockOrder { sl: last.0, block: last.1 };
-            channel.send(order).await?;
-
-            // Node stores responce data. Extra validations can be added here.
-            let response = response_sub.receive().await?;
-            for info in &response.blocks {
-                state.write().await.blockchain.add_by_info(info.clone())?;
-            }
-            let last_received = state.read().await.blockchain.last()?.unwrap();
-            info!("Last received block: {:?} - {:?}", last_received.0, last_received.1);
-            if last == last_received {
-                break
-            }
-            last = last_received;
-        }
-    } else {
-        info!("Node is not connected to other nodes.");
-    }
-
-    info!("Node synced!");
-    Ok(())
-}
-
-async fn syncing_consensus_task(p2p: net::P2pPtr, state: ValidatorStatePtr) -> Result<()> {
-    info!("Node starts syncing consensus state...");
-    // Using len here because is_empty() uses unstable library feature 'exact_size_is_empty'
-    if p2p.channels().lock().await.values().len() != 0 {
-        // Nodes ask for the consensus state of the last channel peer
-        let channel = p2p.channels().lock().await.values().last().unwrap().clone();
-
-        // Communication setup
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<ConsensusResponse>().await;
-        let response_sub = channel
-            .subscribe_msg::<ConsensusResponse>()
-            .await
-            .expect("Missing ConsensusResponse dispatcher!");
-
-        // Node creates a ConsensusRequest and sends it
-        let request = ConsensusRequest { id: state.read().await.id };
-        channel.send(request).await?;
-
-        // Node stores responce data. Extra validations can be added here.
-        let response = response_sub.receive().await?;
-        state.write().await.consensus = response.consensus.clone();
-    } else {
-        info!("Node is not connected to other nodes, resetting consensus state.");
-        state.write().await.reset_consensus_state()?;
-    }
-
-    info!("Node synced!");
-    Ok(())
-}
-
-async fn proposal_task(p2p: net::P2pPtr, state: ValidatorStatePtr) {
-    // Node waits just before the current or next epoch end,
-    // so it can start syncing latest state.
-    let mut seconds_until_next_epoch = state.read().await.next_epoch_start();
-    let one_sec = Duration::new(1, 0);
-    loop {
-        if seconds_until_next_epoch > one_sec {
-            seconds_until_next_epoch = seconds_until_next_epoch - one_sec;
-            break
-        }
-        info!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
-        thread::sleep(seconds_until_next_epoch);
-        seconds_until_next_epoch = state.read().await.next_epoch_start();
-    }
-    info!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
-    thread::sleep(seconds_until_next_epoch);
-
-    // Node syncs its consensus state
-    let result = syncing_consensus_task(p2p.clone(), state.clone()).await;
-    match result {
-        Ok(()) => (),
-        Err(e) => error!("Sync consensus state failed. Error: {:?}", e),
-    }
-
-    // Node signals the network that it will start participating
-    let participant =
-        Participant::new(state.read().await.id, state.read().await.current_epoch());
-    state.write().await.append_self_participant(participant.clone());
-    let result = p2p.broadcast(participant.clone()).await;
-    match result {
-        Ok(()) => info!("Participation message broadcasted successfuly."),
-        Err(e) => error!("Broadcast failed. Error: {:?}", e),
-    }
-
-    // After initialization node waits for next epoch to start participating
-    let seconds_until_next_epoch = state.read().await.next_epoch_start();
-    info!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
-    thread::sleep(seconds_until_next_epoch);
-
-    // Node modifies its participating flag to true
-    state.write().await.participating = true;
-
-    loop {
-        // Node refreshes participants records
-        state.write().await.refresh_participants();
-
-        // Node checks if its the epoch leader to generate a new proposal for that epoch
-        let result = if state.write().await.is_epoch_leader() {
-            state.read().await.propose()
-        } else {
-            Ok(None)
-        };
-        match result {
-            Ok(proposal) => {
-                if proposal.is_none() {
-                    info!("Node is not the epoch leader. Sleeping till next epoch...");
-                } else {
-                    // Leader creates a vote for the proposal and broadcasts them both
-                    let unwrapped = proposal.unwrap();
-                    info!("Node is the epoch leader. Proposed block: {:?}", unwrapped);
-                    let vote = state.write().await.receive_proposal(&unwrapped);
-                    match vote {
-                        Ok(x) => {
-                            if x.is_none() {
-                                error!("Node did not vote for the proposed block.");
-                            } else {
-                                let vote = x.unwrap();
-                                let result = state.write().await.receive_vote(&vote);
-                                match result {
-                                    Ok(_) => info!("Vote saved successfuly."),
-                                    Err(e) => error!("Vote save failed. Error: {:?}", e),
-                                }
-                                // Broadcasting block
-                                let result = p2p.broadcast(unwrapped).await;
-                                match result {
-                                    Ok(()) => info!("Proposal broadcasted successfuly."),
-                                    Err(e) => error!("Broadcast failed. Error: {:?}", e),
-                                }
-                                // Broadcasting leader vote
-                                let result = p2p.broadcast(vote).await;
-                                match result {
-                                    Ok(()) => info!("Leader vote broadcasted successfuly."),
-                                    Err(e) => error!("Broadcast failed. Error: {:?}", e),
-                                }
-                            }
-                        }
-                        Err(e) => {
-                            error!("Error prosessing proposal: {:?}", e)
-                        }
-                    }
-                }
-            }
-            Err(e) => error!("Block proposal failed. Error: {:?}", e),
-        }
-
-        // Current node state is flushed to sled database
-        let result = state.read().await.save_consensus_state();
-        match result {
-            Ok(()) => (),
-            Err(e) => {
-                error!("State could not be flushed: {:?}", e)
-            }
-        };
-
-        // Node waits until next epoch
-        let seconds_until_next_epoch = state.read().await.next_epoch_start();
-        info!("Waiting for next epoch({:?} sec)...", seconds_until_next_epoch);
-        thread::sleep(seconds_until_next_epoch);
-    }
-}
-
-async fn start(executor: Arc<Executor<'_>>, opts: &Opt) -> Result<()> {
-    let rpc_server_config = RpcServerConfig {
-        socket_addr: opts.rpc,
-        use_tls: opts.tls,
-        identity_path: opts.identity.clone(),
-        identity_pass: opts.password.clone(),
-    };
-
-    // Main subnet settings
-    let subnet_settings = net::Settings {
-        inbound: Some(opts.accept),
-        outbound_connections: opts.slots,
-        external_addr: Some(opts.external),
-        peers: opts.connect.clone(),
-        seeds: opts.seeds.clone(),
-        ..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();
-
-    // Main P2P registry setup
-    let main_p2p = net::P2p::new(subnet_settings).await;
-    let registry = main_p2p.protocol_registry();
-
-    // Adding ProtocolSync to the registry
-    let state2 = state.clone();
-    let consensus_mode = true; // This flag should be based on staking
-    registry
-        .register(net::SESSION_ALL, move |channel, main_p2p| {
-            let state = state2.clone();
-            async move { ProtocolSync::init(channel, state, main_p2p, consensus_mode).await }
-        })
-        .await;
-
-    // Adding ProtocolTx to the registry
-    let state2 = state.clone();
-    registry
-        .register(net::SESSION_ALL, move |channel, main_p2p| {
-            let state = state2.clone();
-            async move { ProtocolTx::init(channel, state, main_p2p).await }
-        })
-        .await;
-
-    // Performs seed session
-    main_p2p.clone().start(executor.clone()).await?;
-    // Actual main p2p session
-    let ex2 = executor.clone();
-    let p2p = main_p2p.clone();
-    executor
-        .spawn(async move {
-            if let Err(err) = p2p.run(ex2).await {
-                error!("Error: p2p run failed {}", err);
-            }
-        })
-        .detach();
-
-    // RPC interface
-    let ex2 = executor.clone();
-    let ex3 = ex2.clone();
-    let rpc_interface = Arc::new(JsonRpcInterface {
-        state: state.clone(),
-        p2p: main_p2p.clone(),
-        _rpc_listen_addr: opts.rpc,
-    });
-    executor
-        .spawn(async move { listen_and_serve(rpc_server_config, rpc_interface, ex3).await })
-        .detach();
-
-    // Node starts syncing
-    let state2 = state.clone();
-    syncing_task(main_p2p.clone(), state2).await?;
-
-    // Consensus P2P registry setup
-    let consensus_p2p = net::P2p::new(consensus_subnet_settings).await;
-    let registry = consensus_p2p.protocol_registry();
-
-    // Adding PropotolVote to the registry
-    let p2p = main_p2p.clone();
-    let state2 = state.clone();
-    registry
-        .register(net::SESSION_ALL, move |channel, consensus_p2p| {
-            let state = state2.clone();
-            let main_p2p = p2p.clone();
-            async move { ProtocolVote::init(channel, state, main_p2p, consensus_p2p).await }
-        })
-        .await;
-
-    // Adding ProtocolProposal to the registry
-    let state2 = state.clone();
-    registry
-        .register(net::SESSION_ALL, move |channel, consensus_p2p| {
-            let state = state2.clone();
-            async move { ProtocolProposal::init(channel, state, consensus_p2p).await }
-        })
-        .await;
-
-    // Adding ProtocolParticipant to the registry
-    let state2 = state.clone();
-    registry
-        .register(net::SESSION_ALL, move |channel, consensus_p2p| {
-            let state = state2.clone();
-            async move { ProtocolParticipant::init(channel, state, consensus_p2p).await }
-        })
-        .await;
-
-    // Adding ProtocolSyncForks to the registry
-    let state2 = state.clone();
-    registry
-        .register(net::SESSION_ALL, move |channel, _consensus_p2p| {
-            let state = state2.clone();
-            async move { ProtocolSyncConsensus::init(channel, state).await }
-        })
-        .await;
-
-    // Performs seed session
-    consensus_p2p.clone().start(executor.clone()).await?;
-    // Actual consensus p2p session
-    let ex2 = executor.clone();
-    let p2p = consensus_p2p.clone();
-    executor
-        .spawn(async move {
-            if let Err(err) = p2p.run(ex2).await {
-                error!("Error: p2p run failed {}", err);
-            }
-        })
-        .detach();
-
-    proposal_task(consensus_p2p, state).await;
-
-    Ok(())
-}
-
-struct JsonRpcInterface {
-    state: ValidatorStatePtr,
-    p2p: net::P2pPtr,
-    _rpc_listen_addr: SocketAddr,
-}
-
-#[async_trait]
-impl RequestHandler for JsonRpcInterface {
-    async fn handle_request(&self, req: JsonRequest, _executor: Arc<Executor<'_>>) -> JsonResult {
-        if req.params.as_array().is_none() {
-            return jsonrpc::error(InvalidRequest, None, req.id).into()
-        }
-
-        debug!(target: "RPC", "--> {}", serde_json::to_string(&req).unwrap());
-
-        from_result(
-            match req.method.as_str() {
-                Some("ping") => self.pong().await,
-                Some("get_info") => self.get_info().await,
-                Some("receive_tx") => self.receive_tx(req.params).await,
-                Some(_) | None => Err(MethodNotFound),
-            },
-            req.id,
-        )
-    }
-}
-
-impl JsonRpcInterface {
-    // --> {"jsonrpc": "2.0", "method": "ping", "params": [], "id": 42}
-    // <-- {"jsonrpc": "2.0", "result": "pong", "id": 42}
-    async fn pong(&self) -> ValueResult<Value> {
-        Ok(json!("pong"))
-    }
-
-    // --> {"jsonrpc": "2.0", "method": "get_info", "params": [], "id": 42}
-    // <-- {"jsonrpc": "2.0", "result": {"nodeID": [], "nodeinfo" [], "id": 42}
-    async fn get_info(&self) -> ValueResult<Value> {
-        Ok(self.p2p.get_info().await)
-    }
-
-    // --> {"jsonrpc": "2.0", "method": "receive_tx", "params": ["tx"], "id": 42}
-    // <-- {"jsonrpc": "2.0", "result": true, "id": 0}
-    async fn receive_tx(&self, params: Value) -> ValueResult<Value> {
-        let args = params.as_array().unwrap();
-
-        if args.len() != 1 {
-            return Err(InvalidParams)
-        }
-
-        let payload = String::from(args[0].as_str().unwrap());
-        let tx = Tx { payload };
-
-        self.state.write().await.append_tx(tx.clone());
-
-        let result = self.p2p.broadcast(tx).await;
-        match result {
-            Ok(()) => Ok(json!(true)),
-            Err(_) => Err(InternalError),
-        }
-    }
-}
-
-#[async_std::main]
-async fn main() -> Result<()> {
-    let opts = Opt::from_args_with_toml(&String::from_utf8(CONFIG_FILE_CONTENTS.to_vec()).unwrap())
-        .unwrap();
-    let config_path = get_config_path(Some(opts.config.clone()), CONFIG_FILE)?;
-    spawn_config(&config_path, CONFIG_FILE_CONTENTS)?;
-    let opts = Opt::from_args_with_toml(&String::from_utf8(CONFIG_FILE_CONTENTS.to_vec()).unwrap())
-        .unwrap();
-
-    let (lvl, conf) = log_config(opts.verbose.into())?;
-    TermLogger::init(lvl, conf, TerminalMode::Mixed, ColorChoice::Auto)?;
-
-    let ex = Arc::new(Executor::new());
-    let (signal, shutdown) = async_channel::unbounded::<()>();
-    let ex2 = ex.clone();
-    let nthreads = if opts.threads == 0 { num_cpus::get() } else { opts.threads };
-
-    debug!(target: "VALIDATOR DAEMON", "Executing with opts: {:?}", opts);
-    debug!(target: "VALIDATOR DAEMON", "Run {} executor threads", nthreads);
-    let (_, result) = Parallel::new()
-        .each(0..nthreads, |_| smol::future::block_on(ex.run(shutdown.recv())))
-        // Run the main future on the current thread.
-        .finish(|| {
-            smol::future::block_on(async move {
-                start(ex2.clone(), &opts).await?;
-                drop(signal);
-                Ok::<(), darkfi::Error>(())
-            })
-        });
-
-    result
-}

+ 0 - 13
script/research/validatord/src/protocols/mod.rs

@@ -1,13 +0,0 @@
-pub mod protocol_participant;
-pub mod protocol_proposal;
-pub mod protocol_sync;
-pub mod protocol_sync_consensus;
-pub mod protocol_tx;
-pub mod protocol_vote;
-
-pub use protocol_participant::ProtocolParticipant;
-pub use protocol_proposal::ProtocolProposal;
-pub use protocol_sync::ProtocolSync;
-pub use protocol_sync_consensus::ProtocolSyncConsensus;
-pub use protocol_tx::ProtocolTx;
-pub use protocol_vote::ProtocolVote;

+ 0 - 77
script/research/validatord/src/protocols/protocol_participant.rs

@@ -1,77 +0,0 @@
-use async_executor::Executor;
-use async_trait::async_trait;
-
-use darkfi::{   
-    consensus::{participant::Participant, state::ValidatorStatePtr}, 
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-use log::debug;
-use std::sync::Arc;
-
-pub struct ProtocolParticipant {
-    participant_sub: MessageSubscription<Participant>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    p2p: P2pPtr,
-}
-
-impl ProtocolParticipant {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        p2p: P2pPtr,
-    ) -> ProtocolBasePtr {
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<Participant>().await;
-
-        let participant_sub =
-            channel.subscribe_msg::<Participant>().await.expect("Missing Participant dispatcher!");
-
-        Arc::new(Self {
-            participant_sub,
-            jobsman: ProtocolJobsManager::new("ParticipantProtocol", channel),
-            state,
-            p2p,
-        })
-    }
-
-    async fn handle_receive_participant(self: Arc<Self>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolParticipant::handle_receive_participant() [START]");
-        loop {
-            let participant = self.participant_sub.receive().await?;
-
-            debug!(
-                target: "ircd",
-                "ProtocolParticipant::handle_receive_participant() received {:?}",
-                participant
-            );
-
-            let participant_copy = (*participant).clone();
-            if self.state.write().unwrap().append_participant(participant_copy.clone()) {
-                self.p2p.broadcast(participant_copy).await?;
-            }
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolParticipant {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolParticipant::start() [START]");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman
-            .clone()
-            .spawn(self.clone().handle_receive_participant(), executor.clone())
-            .await;
-        debug!(target: "ircd", "ProtocolParticipant::start() [END]");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolParticipant"
-    }
-}

+ 0 - 88
script/research/validatord/src/protocols/protocol_proposal.rs

@@ -1,88 +0,0 @@
-use async_executor::Executor;
-use async_trait::async_trait;
-
-use darkfi::{
-    consensus::{block::BlockProposal, state::ValidatorStatePtr},
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-use log::debug;
-use std::sync::Arc;
-
-pub struct ProtocolProposal {
-    proposal_sub: MessageSubscription<BlockProposal>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    p2p: P2pPtr,
-}
-
-impl ProtocolProposal {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        p2p: P2pPtr,
-    ) -> ProtocolBasePtr {
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<BlockProposal>().await;
-
-        let proposal_sub =
-            channel.subscribe_msg::<BlockProposal>().await.expect("Missing Proposal dispatcher!");
-
-        Arc::new(Self {
-            proposal_sub,
-            jobsman: ProtocolJobsManager::new("ProposalProtocol", channel),
-            state,
-            p2p,
-        })
-    }
-
-    async fn handle_receive_proposal(self: Arc<Self>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolBlock::handle_receive_proposal() [START]");
-        loop {
-            let proposal = self.proposal_sub.receive().await?;
-
-            debug!(
-                target: "ircd",
-                "ProtocolProposal::handle_receive_proposal() received {:?}",
-                proposal
-            );
-            let proposal_copy = (*proposal).clone();
-            let vote = self.state.write().unwrap().receive_proposal(&proposal_copy);
-            match vote {
-                Ok(x) => {
-                    if x.is_none() {
-                        debug!("Node did not vote for the proposed block.");
-                    } else {
-                        let vote = x.unwrap();
-                        self.state.write().unwrap().receive_vote(&vote)?;
-                        // Broadcasting block to rest nodes
-                        self.p2p.broadcast(proposal_copy).await?;
-                        // Broadcasting vote
-                        self.p2p.broadcast(vote).await?;
-                    }
-                }
-                Err(e) => {
-                    debug!(target: "ircd", "ProtocolBlock::handle_receive_proposal() error prosessing proposal: {:?}", e)
-                }
-            }
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolProposal {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolProposal::start() [START]");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_proposal(), executor.clone()).await;
-        debug!(target: "ircd", "ProtocolProposal::start() [END]");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolProposal"
-    }
-}

+ 0 - 119
script/research/validatord/src/protocols/protocol_sync.rs

@@ -1,119 +0,0 @@
-use async_executor::Executor;
-use async_trait::async_trait;
-
-use darkfi::{
-    consensus::{
-        block::{BlockInfo, BlockOrder, BlockResponse},
-        state::ValidatorStatePtr,
-    },
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-use log::debug;
-use std::sync::Arc;
-
-// Constant defining how many blocks we send during syncing.
-const BATCH: u64 = 10;
-
-pub struct ProtocolSync {
-    channel: ChannelPtr,
-    request_sub: MessageSubscription<BlockOrder>,
-    block_sub: MessageSubscription<BlockInfo>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    p2p: P2pPtr,
-    consensus_mode: bool,
-}
-
-impl ProtocolSync {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        p2p: P2pPtr,
-        consensus_mode: bool,
-    ) -> ProtocolBasePtr {
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<BlockOrder>().await;
-        message_subsytem.add_dispatch::<BlockInfo>().await;
-
-        let request_sub =
-            channel.subscribe_msg::<BlockOrder>().await.expect("Missing BlockOrder dispatcher!");
-        let block_sub =
-            channel.subscribe_msg::<BlockInfo>().await.expect("Missing BlockInfo dispatcher!");
-
-        Arc::new(Self {
-            channel: channel.clone(),
-            request_sub,
-            block_sub,
-            jobsman: ProtocolJobsManager::new("SyncProtocol", channel),
-            state,
-            p2p,
-            consensus_mode,
-        })
-    }
-
-    async fn handle_receive_request(self: Arc<Self>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolSync::handle_receive_request() [START]");
-        loop {
-            let order = self.request_sub.receive().await?;
-
-            debug!(
-                target: "ircd",
-                "ProtocolSync::handle_receive_request() received {:?}",
-                order
-            );
-
-            // Extra validations can be added here.
-            let key = order.sl;
-            let blocks = self.state.read().unwrap().blockchain.get_with_info(key, BATCH)?;
-            let response = BlockResponse { blocks };
-            self.channel.send(response).await?;
-        }
-    }
-
-    async fn handle_receive_block(self: Arc<Self>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolSync::handle_receive_block() [START]");
-        loop {
-            let info = self.block_sub.receive().await?;
-
-            debug!(
-                target: "ircd",
-                "ProtocolSync::handle_receive_block() received {:?}",
-                info
-            );
-
-            // Node stores finalized block, if it doesn't exists (checking by slot),
-            // and removes its transactions from the unconfirmed_txs vector.
-            // Consensus mode enabled nodes have already performed this steps,
-            // during proposal finalization.
-            // Extra validations can be added here.
-            if !self.consensus_mode {
-                let info_copy = (*info).clone();
-                if !self.state.read().unwrap().blockchain.has_block(&info_copy)? {
-                    self.state.write().unwrap().blockchain.add_by_info(info_copy.clone())?;
-                    self.state.write().unwrap().remove_txs(info_copy.txs.clone())?;
-                    self.p2p.broadcast(info_copy).await?;
-                }
-            }
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolSync {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolSync::start() [START]");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_request(), executor.clone()).await;
-        self.jobsman.clone().spawn(self.clone().handle_receive_block(), executor.clone()).await;
-        debug!(target: "ircd", "ProtocolSync::start() [END]");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolSync"
-    }
-}

+ 0 - 72
script/research/validatord/src/protocols/protocol_sync_consensus.rs

@@ -1,72 +0,0 @@
-use async_executor::Executor;
-use async_trait::async_trait;
-
-use darkfi::{
-    consensus::state::{ConsensusRequest, ConsensusResponse, ValidatorStatePtr},
-    net::{
-        ChannelPtr, MessageSubscription, ProtocolBase, ProtocolBasePtr, ProtocolJobsManager,
-        ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-use log::debug;
-use std::sync::Arc;
-
-pub struct ProtocolSyncConsensus {
-    channel: ChannelPtr,
-    request_sub: MessageSubscription<ConsensusRequest>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-}
-
-impl ProtocolSyncConsensus {
-    pub async fn init(channel: ChannelPtr, state: ValidatorStatePtr) -> ProtocolBasePtr {
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<ConsensusRequest>().await;
-
-        let request_sub = channel
-            .subscribe_msg::<ConsensusRequest>()
-            .await
-            .expect("Missing ConsensusRequest dispatcher!");
-
-        Arc::new(Self {
-            channel: channel.clone(),
-            request_sub,
-            jobsman: ProtocolJobsManager::new("SyncConsensusProtocol", channel),
-            state,
-        })
-    }
-
-    async fn handle_receive_request(self: Arc<Self>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolSyncConsensus::handle_receive_request() [START]");
-        loop {
-            let order = self.request_sub.receive().await?;
-
-            debug!(
-                target: "ircd",
-                "ProtocolSyncConsensus::handle_receive_request() received {:?}",
-                order
-            );
-
-            // Extra validations can be added here.
-            let consensus = self.state.read().unwrap().consensus.clone();
-            let response = ConsensusResponse { consensus };
-            self.channel.send(response).await?;
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolSyncConsensus {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolSyncConsensus::start() [START]");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_request(), executor.clone()).await;
-        debug!(target: "ircd", "ProtocolSyncConsensus::start() [END]");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolSyncConsensus"
-    }
-}

+ 0 - 74
script/research/validatord/src/protocols/protocol_tx.rs

@@ -1,74 +0,0 @@
-use async_executor::Executor;
-use async_trait::async_trait;
-
-use darkfi::{
-    consensus::{state::ValidatorStatePtr, tx::Tx},
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-use log::debug;
-use std::sync::Arc;
-
-pub struct ProtocolTx {
-    tx_sub: MessageSubscription<Tx>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    p2p: P2pPtr,
-}
-
-impl ProtocolTx {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        p2p: P2pPtr,
-    ) -> ProtocolBasePtr {
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<Tx>().await;
-
-        let tx_sub = channel.subscribe_msg::<Tx>().await.expect("Missing Tx dispatcher!");
-
-        Arc::new(Self {
-            tx_sub,
-            jobsman: ProtocolJobsManager::new("TxProtocol", channel),
-            state,
-            p2p,
-        })
-    }
-
-    async fn handle_receive_tx(self: Arc<Self>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolTx::handle_receive_tx() [START]");
-        loop {
-            let tx = self.tx_sub.receive().await?;
-
-            debug!(
-                target: "ircd",
-                "ProtocolTx::handle_receive_tx() received {:?}",
-                tx
-            );
-            let tx_copy = (*tx).clone();
-
-            // Nodes use unconfirmed_txs vector as seen_txs pool.
-            if self.state.write().unwrap().append_tx(tx_copy.clone()) {
-                self.p2p.broadcast(tx_copy).await?;
-            }
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolTx {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolTx::start() [START]");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_tx(), executor.clone()).await;
-        debug!(target: "ircd", "ProtocolTx::start() [END]");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolTx"
-    }
-}

+ 0 - 85
script/research/validatord/src/protocols/protocol_vote.rs

@@ -1,85 +0,0 @@
-use async_executor::Executor;
-use async_trait::async_trait;
-
-use darkfi::{
-    consensus::{state::ValidatorStatePtr, vote::Vote},
-    net::{
-        ChannelPtr, MessageSubscription, P2pPtr, ProtocolBase, ProtocolBasePtr,
-        ProtocolJobsManager, ProtocolJobsManagerPtr,
-    },
-    Result,
-};
-use log::debug;
-use std::sync::Arc;
-
-pub struct ProtocolVote {
-    vote_sub: MessageSubscription<Vote>,
-    jobsman: ProtocolJobsManagerPtr,
-    state: ValidatorStatePtr,
-    main_p2p: P2pPtr,
-    consensus_p2p: P2pPtr,
-}
-
-impl ProtocolVote {
-    pub async fn init(
-        channel: ChannelPtr,
-        state: ValidatorStatePtr,
-        main_p2p: P2pPtr,
-        consensus_p2p: P2pPtr,
-    ) -> ProtocolBasePtr {
-        let message_subsytem = channel.get_message_subsystem();
-        message_subsytem.add_dispatch::<Vote>().await;
-
-        let vote_sub = channel.subscribe_msg::<Vote>().await.expect("Missing Vote dispatcher!");
-
-        Arc::new(Self {
-            vote_sub,
-            jobsman: ProtocolJobsManager::new("VoteProtocol", channel),
-            state,
-            main_p2p,
-            consensus_p2p,
-        })
-    }
-
-    async fn handle_receive_vote(self: Arc<Self>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolVote::handle_receive_vote() [START]");
-        loop {
-            let vote = self.vote_sub.receive().await?;
-
-            debug!(
-                target: "ircd",
-                "ProtocolVote::handle_receive_vote() received {:?}",
-                vote
-            );
-            let vote_copy = (*vote).clone();
-            let (voted, to_broadcast) = self.state.write().unwrap().receive_vote(&vote_copy)?;
-            if voted {
-                self.consensus_p2p.broadcast(vote_copy).await?;
-                // Broadcasting finalized blocks info, if any
-                match to_broadcast {
-                    Some(blocks) => {
-                        for info in blocks {
-                            self.main_p2p.broadcast(info).await?;
-                        }
-                    }
-                    None => continue,
-                }
-            };
-        }
-    }
-}
-
-#[async_trait]
-impl ProtocolBase for ProtocolVote {
-    async fn start(self: Arc<Self>, executor: Arc<Executor<'_>>) -> Result<()> {
-        debug!(target: "ircd", "ProtocolVote::start() [START]");
-        self.jobsman.clone().start(executor.clone());
-        self.jobsman.clone().spawn(self.clone().handle_receive_vote(), executor.clone()).await;
-        debug!(target: "ircd", "ProtocolVote::start() [END]");
-        Ok(())
-    }
-
-    fn name(&self) -> &'static str {
-        "ProtocolVote"
-    }
-}

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

@@ -1,57 +0,0 @@
-## validatord configuration file
-##
-## Please make sure you go through all the settings so you can configure
-## your daemon properly.
-
-# Configuration file to use
-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"
-
-# Connection slots
-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"
-
-# The endpoint where validatord will bind its RPC socket
-rpc = "127.0.0.1:6660"
-
-# Whether to listen with TLS or plain TCP
-tls = false
-
-# Path to DER-formatted PKCS#12 archive. (Unused if serve_tls=false)
-# This can be created using openssl:
-# openssl pkcs12 -export -out validatord_identity.pfx -inkey key.pem -in cert.pem -certfile validator_certs.pem
-identity = "~/.config/darkfi/validatord_identity.pfx"
-
-# Password for the created TLS identity. (Unused if serve_tls=false)
-password = "FOOBAR"
-
-# Timestamp of the genesis block creation
-genesis = 1648383795
-
-# Path to the sled database folder 
-database = "~/.config/darkfi/validatord_db_0"
-
-# Node ID, used only for testing
-id = 0