diff --git a/script/research/validatord/Cargo.toml b/script/research/validatord/Cargo.toml index af2de93e3..f09ab12f4 100644 --- a/script/research/validatord/Cargo.toml +++ b/script/research/validatord/Cargo.toml @@ -20,6 +20,9 @@ easy-parallel = "3.2.0" # Crypto rand = "0.8.5" +# Storage +sled = "0.34.7" + # Structopt dependencies for arguments parsing serde = "1.0.136" serde_derive = "1.0.136" diff --git a/script/research/validatord/simulation/simulation.sh b/script/research/validatord/simulation.sh similarity index 81% rename from script/research/validatord/simulation/simulation.sh rename to script/research/validatord/simulation.sh index 204c477b8..016b21848 100755 --- a/script/research/validatord/simulation/simulation.sh +++ b/script/research/validatord/simulation.sh @@ -1,7 +1,6 @@ #!/bin/bash # Simulation of the consensus network for n validator nodes. -# Note: state files should be generated before executing. nodes=4 @@ -9,7 +8,7 @@ nodes=4 bound=$(($nodes - 1)) for i in $(eval echo "{0..$bound}") do - cp validatord_state_$i ~/.config/darkfi/validatord_state_$i + rmdir ~/.config/darkfi/validatord_db_$i done # PIDs array @@ -26,7 +25,7 @@ sleep 2 bound=$(($nodes-2)) for i in $(eval echo "{1..$bound}") do - cargo run -- --accept 0.0.0.0:1100$i --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$i --external 127.0.0.1:1100$i --id $i --state ~/.config/darkfi/validatord_state_$i & + cargo run -- --accept 0.0.0.0:1100$i --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$i --external 127.0.0.1:1100$i --id $i --database ~/.config/darkfi/validatord_db_$i & pids[${#pids[@]}]=$! # waiting for node to setup sleep 2 @@ -45,7 +44,7 @@ function ctrl_c() { bound=$(($nodes-1)) # Starting last node -cargo run -- --accept 0.0.0.0:1100$bound --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$bound --external 127.0.0.1:1100$bound --id $bound --state ~/.config/darkfi/validatord_state_$bound +cargo run -- --accept 0.0.0.0:1100$bound --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$bound --external 127.0.0.1:1100$bound --id $bound --database ~/.config/darkfi/validatord_db_$bound # 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: diff --git a/script/research/validatord/simulation/sim10/simulation.sh b/script/research/validatord/simulation/sim10/simulation.sh deleted file mode 100755 index 3da861c7a..000000000 --- a/script/research/validatord/simulation/sim10/simulation.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -# Simulation of the consensus network for n validator nodes. -# Note: state files should be generated before executing. - -nodes=10 - -# Copying the node state files with a blockchain containing only the genesis block. -bound=$(($nodes - 1)) -for i in $(eval echo "{0..$bound}") -do - cp validatord_state_$i ~/.config/darkfi/validatord_state_$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 --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$i --external 127.0.0.1:1100$i --id $i --state ~/.config/darkfi/validatord_state_$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 --seeds 127.0.0.1:11000 --rpc 127.0.0.1:666$bound --external 127.0.0.1:1100$bound --id $bound --state ~/.config/darkfi/validatord_state_$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} diff --git a/script/research/validatord/simulation/sim10/validatord_state_0 b/script/research/validatord/simulation/sim10/validatord_state_0 deleted file mode 100644 index 1b8bdfd8d..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_0 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 0, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_1 b/script/research/validatord/simulation/sim10/validatord_state_1 deleted file mode 100644 index 39830dcfc..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_1 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 1, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_2 b/script/research/validatord/simulation/sim10/validatord_state_2 deleted file mode 100644 index 95b44502b..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_2 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 2, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_3 b/script/research/validatord/simulation/sim10/validatord_state_3 deleted file mode 100644 index 18491ff35..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_3 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 3, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_4 b/script/research/validatord/simulation/sim10/validatord_state_4 deleted file mode 100644 index 5bf634d9f..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_4 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 4, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_5 b/script/research/validatord/simulation/sim10/validatord_state_5 deleted file mode 100644 index 7c949c353..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_5 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 5, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_6 b/script/research/validatord/simulation/sim10/validatord_state_6 deleted file mode 100644 index 4202dd29d..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_6 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 6, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_7 b/script/research/validatord/simulation/sim10/validatord_state_7 deleted file mode 100644 index da9f0e610..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_7 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 7, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_8 b/script/research/validatord/simulation/sim10/validatord_state_8 deleted file mode 100644 index 3c801b0d2..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_8 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 8, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/sim10/validatord_state_9 b/script/research/validatord/simulation/sim10/validatord_state_9 deleted file mode 100644 index 7a1ad965c..000000000 --- a/script/research/validatord/simulation/sim10/validatord_state_9 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 9, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/validatord_state_0 b/script/research/validatord/simulation/validatord_state_0 deleted file mode 100644 index 1b8bdfd8d..000000000 --- a/script/research/validatord/simulation/validatord_state_0 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 0, - "genesis_time": 1648383795, - "secret_key": "22c1a9eae232ec84096c90896e763087a36b3eb55f3de599d5d3f7bba280a11e", - "public_key": "ad50d94b531da6864b32bed5001fde813e745841202b45d9f892e05d57593d19", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/validatord_state_1 b/script/research/validatord/simulation/validatord_state_1 deleted file mode 100644 index a24fcb5b4..000000000 --- a/script/research/validatord/simulation/validatord_state_1 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 1, - "genesis_time": 1648383795, - "secret_key": "56d954a063168d30e93e3c1afc16d12af3e8c048fca87b930146efb02f7f4c26", - "public_key": "4537911dc67e1dc828fe507d3fd25dcaf0b5c10a4b8dce5cee9aef8c91057fab", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/validatord_state_2 b/script/research/validatord/simulation/validatord_state_2 deleted file mode 100644 index d435b0af1..000000000 --- a/script/research/validatord/simulation/validatord_state_2 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 2, - "genesis_time": 1648383795, - "secret_key": "840a0e56c7bf4fa88e677244e3a3a8bd7c7cc9b0f591bb1ab6a5c9ac95d2f015", - "public_key": "469e7cdf2b72c2a6be5cfcec4a7694137660bc8d57f6f961b630c397b07bbf14", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/simulation/validatord_state_3 b/script/research/validatord/simulation/validatord_state_3 deleted file mode 100644 index 2b4bcdaf6..000000000 --- a/script/research/validatord/simulation/validatord_state_3 +++ /dev/null @@ -1,34 +0,0 @@ -{ - "id": 3, - "genesis_time": 1648383795, - "secret_key": "8403caeceb6b91284363ed3074af5a565bd9eeb75a5ad46b7522d3ac4074c400", - "public_key": "6e487af2f92f37b29b5bf05f75670c0f6b5813fd7d16a6f7b8bed6325370a5af", - "canonical_blockchain": { - "blocks": [ - { - "st": "⊥", - "sl": 0, - "txs": [], - "metadata": { - "om": { - "proof": "proof", - "r": "r", - "s": "s" - }, - "sm": { - "votes": [], - "notarized": true, - "finalized": true, - "participants": [] - }, - "timestamp": 1648383795 - } - } - ] - }, - "node_blockchains": [], - "unconfirmed_txs": [], - "orphan_votes": [], - "participants": {}, - "pending_participants": [] -} diff --git a/script/research/validatord/src/main.rs b/script/research/validatord/src/main.rs index 996575a14..e86a491f6 100644 --- a/script/research/validatord/src/main.rs +++ b/script/research/validatord/src/main.rs @@ -79,9 +79,12 @@ struct Opt { #[structopt(long, default_value = "FOOBAR")] /// Password for the created TLS identity password: String, - #[structopt(long, default_value = "~/.config/darkfi/validatord_state_0")] - /// Path to the state file - state: 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, @@ -93,7 +96,7 @@ struct Opt { verbose: u8, } -async fn proposal_task(p2p: net::P2pPtr, state: StatePtr, state_path: &PathBuf) { +async fn proposal_task(p2p: net::P2pPtr, state: StatePtr, database: &sled::Db) { // Node signals the network that it starts participating let participant = Participant::new(state.read().unwrap().id, state.read().unwrap().get_current_epoch()); @@ -155,7 +158,7 @@ async fn proposal_task(p2p: net::P2pPtr, state: StatePtr, state_path: &PathBuf) Err(e) => error!("Broadcast failed. Error: {:?}", e), } - let result = state.read().unwrap().save(state_path); + let result = state.read().unwrap().save(database); match result { Ok(()) => (), Err(e) => { @@ -186,9 +189,11 @@ async fn start(executor: Arc>, opts: &Opt) -> Result<()> { }; // State setup - let state_path = expand_path(&opts.state).unwrap(); + let genesis = opts.genesis; + let database_path = expand_path(&opts.database).unwrap(); + let database = sled::open(database_path).unwrap(); let id = opts.id.clone(); - let state = State::load_current_state(id, &state_path).unwrap(); + let state = State::load_current_state(genesis, id, &database).unwrap(); // P2P registry setup let p2p = net::P2p::new(network_settings).await; @@ -255,7 +260,7 @@ async fn start(executor: Arc>, opts: &Opt) -> Result<()> { .spawn(async move { listen_and_serve(rpc_server_config, rpc_interface, ex3).await }) .detach(); - proposal_task(p2p, state, &state_path).await; + proposal_task(p2p, state, &database).await; Ok(()) } diff --git a/script/research/validatord/validatord_config.toml b/script/research/validatord/validatord_config.toml index 8db3e62f9..09f6f89dc 100644 --- a/script/research/validatord/validatord_config.toml +++ b/script/research/validatord/validatord_config.toml @@ -38,8 +38,11 @@ identity = "~/.config/darkfi/validatord_identity.pfx" # Password for the created TLS identity. (Unused if serve_tls=false) password = "FOOBAR" -# Path to the state file -state = "~/.config/darkfi/validatord_state_0" +# 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 diff --git a/src/consensus/block.rs b/src/consensus/block.rs index 4e27bb908..d70feefe4 100644 --- a/src/consensus/block.rs +++ b/src/consensus/block.rs @@ -1,17 +1,21 @@ use serde::{Deserialize, Serialize}; -use std::hash::{Hash, Hasher}; +use std::{ + hash::{Hash, Hasher}, + io, +}; use super::{metadata::Metadata, participant::Participant, tx::Tx}; use crate::{ crypto::{keypair::PublicKey, schnorr::Signature}, - net, - util::serial::{SerialDecodable, SerialEncodable}, + impl_vec, net, + util::serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt}, + Result, }; /// 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)] +#[derive(Debug, Clone, Deserialize, Serialize, SerialEncodable, SerialDecodable)] pub struct Block { /// Previous block hash pub st: String, // Change this to a proper hash type @@ -87,3 +91,5 @@ impl net::Message for BlockProposal { pub fn proposal_eq_block(proposal: &BlockProposal, block: &Block) -> bool { proposal.st == block.st && proposal.sl == block.sl && proposal.txs == block.txs } + +impl_vec!(Block); diff --git a/src/consensus/blockchain.rs b/src/consensus/blockchain.rs index 7af3d587a..e62d5f4f1 100644 --- a/src/consensus/blockchain.rs +++ b/src/consensus/blockchain.rs @@ -1,14 +1,19 @@ use std::{ collections::hash_map::DefaultHasher, hash::{Hash, Hasher}, + io, }; -use serde::{Deserialize, Serialize}; +use crate::{ + impl_vec, + util::serial::{Decodable, Encodable, SerialDecodable, SerialEncodable, VarInt}, + Result, +}; use super::block::Block; /// This struct represents a sequence of blocks starting with the genesis block. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[derive(Debug, Clone, PartialEq, SerialEncodable, SerialDecodable)] pub struct Blockchain { pub blocks: Vec, } @@ -54,3 +59,5 @@ impl Blockchain { true } } + +impl_vec!(Blockchain); diff --git a/src/consensus/participant.rs b/src/consensus/participant.rs index f8c6fe003..f0be5bd10 100644 --- a/src/consensus/participant.rs +++ b/src/consensus/participant.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::io; +use std::{collections::BTreeMap, io}; use crate::{ impl_vec, net, @@ -30,4 +30,27 @@ impl net::Message for Participant { } } +impl Encodable for BTreeMap { + fn encode(&self, mut s: S) -> Result { + 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 { + fn decode(mut d: D) -> Result { + 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); diff --git a/src/consensus/state.rs b/src/consensus/state.rs index a5ff19f93..3d27ad9b3 100644 --- a/src/consensus/state.rs +++ b/src/consensus/state.rs @@ -1,10 +1,8 @@ use chrono::{NaiveDateTime, Utc}; use log::{debug, error}; -use serde::{Deserialize, Serialize}; use std::{ collections::{hash_map::DefaultHasher, BTreeMap}, hash::{Hash, Hasher}, - path::Path, sync::{Arc, RwLock}, time::Duration, }; @@ -14,8 +12,8 @@ use crate::{ keypair::{PublicKey, SecretKey}, schnorr::{SchnorrPublic, SchnorrSecret}, }, - util::serial::Encodable, - Result, + util::serial::{deserialize, serialize, Encodable, SerialDecodable, SerialEncodable}, + Error, Result, }; use rand::rngs::OsRng; @@ -24,11 +22,12 @@ use super::{ blockchain::Blockchain, participant::Participant, tx::Tx, - util::{get_current_time, load, save, Timestamp}, + util::Timestamp, vote::Vote, }; const DELTA: u64 = 60; +const SLED_STATE_TREE: &[u8] = b"_state"; /// Atomic pointer to state. pub type StatePtr = Arc>; @@ -37,7 +36,7 @@ pub type StatePtr = Arc>; /// 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)] +#[derive(SerialEncodable, SerialDecodable)] pub struct State { pub id: u64, pub genesis_time: Timestamp, @@ -464,27 +463,34 @@ impl State { } /// Util function to save the current node state to provided file path. - pub fn save(&self, path: &Path) -> Result<()> { - save::(path, self) + pub fn save(&self, db: &sled::Db) -> Result<()> { + let tree = db.open_tree(SLED_STATE_TREE).unwrap(); + let serialized = serialize(self); + match tree.insert(self.id.to_ne_bytes(), serialized) { + Err(_) => Err(Error::OperationFailed), + _ => Ok(()), + } } /// 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: &Path) -> Result { - match load::(path) { - Ok(state) => Ok(state), - Err(_) => Self::reset(id, path), + pub fn load_or_create(genesis: i64, id: u64, db: &sled::Db) -> Result { + let tree = db.open_tree(SLED_STATE_TREE).unwrap(); + if let Some(found) = tree.get(id.to_ne_bytes()).unwrap() { + Ok(deserialize(&found).unwrap()) + } else { + Self::reset(genesis, id, db) } } - /// Util function to load the current node state by the provided file path. - pub fn load_current_state(id: u64, path: &Path) -> Result { - let state = Self::load_or_create(id, path)?; + /// Util function to load the current node state by the provided folder path. + pub fn load_current_state(genesis: i64, id: u64, db: &sled::Db) -> Result { + let state = Self::load_or_create(genesis, id, db)?; Ok(Arc::new(RwLock::new(state))) } /// Util function to reset node state. - pub fn reset(id: u64, path: &Path) -> Result { + pub fn reset(genesis: i64, id: u64, db: &sled::Db) -> Result { // Genesis block is generated. let mut genesis_block = Block::new( String::from("⊥"), @@ -498,10 +504,10 @@ impl State { genesis_block.metadata.sm.notarized = true; genesis_block.metadata.sm.finalized = true; - let genesis_time = get_current_time(); + let genesis_time = Timestamp(genesis); let state = Self::new(id, genesis_time, genesis_block); - state.save(path)?; + state.save(db)?; Ok(state) } } diff --git a/src/consensus/util.rs b/src/consensus/util.rs index a467fcd9e..f7fd6118e 100644 --- a/src/consensus/util.rs +++ b/src/consensus/util.rs @@ -1,28 +1,7 @@ -use std::{fs::File, io::BufReader, path::Path}; - use chrono::{NaiveDateTime, Utc}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +use serde::{Deserialize, Serialize}; -use crate::{ - util::serial::{SerialDecodable, SerialEncodable}, - Result, -}; - -/// Util function to load a structure saved as a JSON in the provided path file, using serde crate. -pub fn load(path: &Path) -> Result { - 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(path: &Path, value: &T) -> Result<()> { - let file = File::create(path)?; - serde_json::to_writer_pretty(file, value)?; - Ok(()) -} +use crate::util::serial::{SerialDecodable, SerialEncodable}; /// Util structure to represend chrono UTC timestamps. #[derive(Debug, Clone, Serialize, Deserialize, SerialDecodable, SerialEncodable)]