| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340 |
- 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);
|