mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
script/research/streamlet_rust: Modified structures based on doc/src/architecture/blockchain.md
This commit is contained in:
@@ -82,9 +82,9 @@ This section gives further details about the structures that will be used by the
|
||||
\hline
|
||||
Field & Type & Description \\ [0.5ex]
|
||||
\hline\hline
|
||||
om & Ouroboros\_Metadata & Block information used by Ouroboros consensus. \\
|
||||
om & OuroborosMetadata & Block information used by Ouroboros consensus. \\
|
||||
\hline
|
||||
sm & Streamlet\_Metadata & Block information used by Streamlet consenus. \\
|
||||
sm & StreamletMetadata & Block information used by Streamlet consensus. \\
|
||||
\hline
|
||||
timestamp & Timestamp & Block creation timestamp. \\ [1ex]
|
||||
\hline
|
||||
@@ -95,7 +95,7 @@ This section gives further details about the structures that will be used by the
|
||||
\hline
|
||||
Field & Type & Description \\ [0.5ex]
|
||||
\hline\hline
|
||||
proof & VRF\_Output & Proof the stakeholder is the block owner. \\
|
||||
proof & VRFOutput & Proof the stakeholder is the block owner. \\
|
||||
\hline
|
||||
r & Seed & Random seed for VRF. \\
|
||||
\hline
|
||||
|
||||
@@ -14,9 +14,16 @@ mod tests {
|
||||
#[test]
|
||||
fn protocol_execution() {
|
||||
// Genesis block is generated.
|
||||
let mut genesis_block = Block::new(String::from("⊥"), 0, vec![]);
|
||||
genesis_block.notarized = true;
|
||||
genesis_block.finalized = true;
|
||||
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();
|
||||
|
||||
|
||||
@@ -1,37 +1,40 @@
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use super::vote::Vote;
|
||||
use super::metadata::Metadata;
|
||||
|
||||
use darkfi::{tx::Transaction, util::serial::Encodable};
|
||||
|
||||
/// This struct represents a tuple of the form (h, e, txs).
|
||||
/// 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 {
|
||||
/// parent hash
|
||||
pub h: String,
|
||||
/// epoch number
|
||||
pub e: u64,
|
||||
/// transactions payload
|
||||
/// Previous block hash
|
||||
pub st: String,
|
||||
/// Slot uid, generated by the beacon
|
||||
pub sl: u64,
|
||||
/// Transactions payload
|
||||
pub txs: Vec<Transaction>,
|
||||
/// Epoch votes
|
||||
pub votes: Vec<Vote>,
|
||||
/// block notarization flag
|
||||
pub notarized: bool,
|
||||
/// block finalization flag
|
||||
pub finalized: bool,
|
||||
/// Additional block information
|
||||
pub metadata: Metadata,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
pub fn new(h: String, e: u64, txs: Vec<Transaction>) -> Block {
|
||||
Block { h, e, txs, votes: Vec::new(), notarized: false, finalized: false }
|
||||
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.h.encode(&mut encoded_block).unwrap();
|
||||
len += self.e.encode(&mut encoded_block).unwrap();
|
||||
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
|
||||
@@ -40,12 +43,12 @@ impl Block {
|
||||
|
||||
impl PartialEq for Block {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.h == other.h && self.e == other.e && self.txs == other.txs
|
||||
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.h, self.e, self.txs).hash(hasher);
|
||||
format!("{:?}{:?}{:?}", self.st, self.sl, self.txs).hash(hasher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@ impl Blockchain {
|
||||
/// 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.h != "⊥", "Genesis block provided.");
|
||||
assert!(block.st != "⊥", "Genesis block provided.");
|
||||
let mut hasher = DefaultHasher::new();
|
||||
previous_block.hash(&mut hasher);
|
||||
assert!(
|
||||
block.h == hasher.finish().to_string() && block.e > previous_block.e,
|
||||
block.st == hasher.finish().to_string() && block.sl > previous_block.sl,
|
||||
"Provided block is invalid."
|
||||
);
|
||||
}
|
||||
@@ -45,7 +45,7 @@ impl Blockchain {
|
||||
/// Blockchain notarization check.
|
||||
pub fn is_notarized(&self) -> bool {
|
||||
for block in &self.blocks {
|
||||
if !block.notarized {
|
||||
if !block.metadata.sm.notarized {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
58
script/research/streamlet_rust/src/structures/metadata.rs
Normal file
58
script/research/streamlet_rust/src/structures/metadata.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
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 }
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,12 @@
|
||||
|
||||
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;
|
||||
|
||||
@@ -143,8 +143,14 @@ impl Node {
|
||||
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);
|
||||
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))
|
||||
}
|
||||
@@ -189,7 +195,7 @@ impl Node {
|
||||
/// 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.notarized {
|
||||
if !block.metadata.sm.notarized {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -202,14 +208,14 @@ impl Node {
|
||||
for (index, blockchain) in self.node_blockchains.iter().enumerate() {
|
||||
let last_block = blockchain.blocks.last().unwrap();
|
||||
last_block.hash(&mut hasher);
|
||||
if block.h == hasher.finish().to_string() && block.e > last_block.e {
|
||||
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.h != hasher.finish().to_string() || block.e <= last_block.e {
|
||||
if block.st != hasher.finish().to_string() || block.sl <= last_block.sl {
|
||||
panic!("Proposed block doesn't extend any known chains.");
|
||||
}
|
||||
-1
|
||||
@@ -245,14 +251,14 @@ impl Node {
|
||||
}
|
||||
|
||||
let (unwrapped_vote_block, blockchain_index) = vote_block.unwrap();
|
||||
if !unwrapped_vote_block.votes.contains(vote) {
|
||||
unwrapped_vote_block.votes.push(vote.clone());
|
||||
if !unwrapped_vote_block.metadata.sm.votes.contains(vote) {
|
||||
unwrapped_vote_block.metadata.sm.votes.push(vote.clone());
|
||||
}
|
||||
|
||||
if !unwrapped_vote_block.notarized &&
|
||||
unwrapped_vote_block.votes.len() > (2 * nodes_count / 3)
|
||||
if !unwrapped_vote_block.metadata.sm.notarized &&
|
||||
unwrapped_vote_block.metadata.sm.votes.len() > (2 * nodes_count / 3)
|
||||
{
|
||||
unwrapped_vote_block.notarized = true;
|
||||
unwrapped_vote_block.metadata.sm.notarized = true;
|
||||
self.check_blockchain_finalization(blockchain_index);
|
||||
}
|
||||
}
|
||||
@@ -290,7 +296,7 @@ impl Node {
|
||||
if blockchain_len > 2 {
|
||||
let mut consecutive_notarized = 0;
|
||||
for block in &blockchain.blocks {
|
||||
if block.notarized {
|
||||
if block.metadata.sm.notarized {
|
||||
consecutive_notarized = consecutive_notarized + 1;
|
||||
} else {
|
||||
break
|
||||
@@ -300,7 +306,7 @@ impl Node {
|
||||
if consecutive_notarized > 2 {
|
||||
let mut finalized_blocks = Vec::new();
|
||||
for block in &mut blockchain.blocks[..(consecutive_notarized - 1)] {
|
||||
block.finalized = true;
|
||||
block.metadata.sm.finalized = true;
|
||||
finalized_blocks.push(block.clone());
|
||||
for transaction in block.txs.clone() {
|
||||
if let Some(pos) =
|
||||
@@ -322,8 +328,8 @@ impl Node {
|
||||
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.h != last_finalized_block_hash ||
|
||||
first_block.e <= last_finalized_block.e
|
||||
if first_block.st != last_finalized_block_hash ||
|
||||
first_block.sl <= last_finalized_block.sl
|
||||
{
|
||||
dropped_blockchains.push(index);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user