script/research/streamlet_rust: Modified structures based on doc/src/architecture/blockchain.md

This commit is contained in:
aggstam
2022-03-12 15:16:47 +02:00
parent 0756fbefb9
commit e82befb679
7 changed files with 118 additions and 42 deletions

View File

@@ -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

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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
}
}

View 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 }
}
}

View File

@@ -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;

View File

@@ -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);
}