| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- use std::io;
- use crate::{
- 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";
- /// 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)
- }
- /// 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)
- }
- }
- /// 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);
|