From 75966e6017d006976d3becdb3b7865df30e804c4 Mon Sep 17 00:00:00 2001 From: austinabell Date: Wed, 15 Jan 2020 18:54:33 -0500 Subject: [PATCH 1/9] Implement (de)serialization for block headers (not matching lotus implementation) --- blockchain/blocks/Cargo.toml | 3 ++- blockchain/blocks/src/block.rs | 8 ++++++-- blockchain/blocks/src/ticket.rs | 3 ++- blockchain/blocks/src/tipset.rs | 3 ++- crypto/Cargo.toml | 1 + crypto/src/vrf.rs | 5 +++-- node/clock/Cargo.toml | 1 + node/clock/src/lib.rs | 3 ++- 8 files changed, 19 insertions(+), 8 deletions(-) diff --git a/blockchain/blocks/Cargo.toml b/blockchain/blocks/Cargo.toml index 09494f89b96e..1e84f8480385 100644 --- a/blockchain/blocks/Cargo.toml +++ b/blockchain/blocks/Cargo.toml @@ -12,4 +12,5 @@ clock = { path = "../../node/clock" } cid = { package = "ferret_cid", path = "../../ipld/cid" } multihash = "0.9.3" derive_builder = "0.9" -serde_cbor = "0.11.0" +serde = { version = "1.0", features = ["derive"] } +encoding = { path = "../../encoding" } diff --git a/blockchain/blocks/src/block.rs b/blockchain/blocks/src/block.rs index 6bb6ccf7e62d..6e86cb8a875c 100644 --- a/blockchain/blocks/src/block.rs +++ b/blockchain/blocks/src/block.rs @@ -10,8 +10,10 @@ use cid::Cid; use clock::ChainEpoch; use crypto::Signature; use derive_builder::Builder; +use encoding::Cbor; use message::{SignedMessage, UnsignedMessage}; use multihash::Hash; +use serde::{Deserialize, Serialize}; use std::fmt; // DefaultHashFunction represents the default hashing function to use @@ -46,7 +48,7 @@ struct PoStProof {} /// .build() /// .unwrap(); /// ``` -#[derive(Clone, Debug, PartialEq, Builder)] +#[derive(Clone, Debug, PartialEq, Builder, Serialize, Deserialize)] #[builder(name = "BlockHeaderBuilder")] pub struct BlockHeader { // CHAIN LINKING @@ -102,6 +104,8 @@ pub struct BlockHeader { pub cached_bytes: Vec, } +impl Cbor for BlockHeader {} + impl BlockHeader { pub fn builder() -> BlockHeaderBuilder { BlockHeaderBuilder::default() @@ -156,7 +160,7 @@ impl fmt::Display for Block { } /// Tracks the merkleroots of both secp and bls messages separately -#[derive(Clone, Debug, PartialEq, Default)] +#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)] pub struct TxMeta { pub bls_messages: Cid, pub secp_messages: Cid, diff --git a/blockchain/blocks/src/ticket.rs b/blockchain/blocks/src/ticket.rs index 47d0494faf4a..123bfe87fe24 100644 --- a/blockchain/blocks/src/ticket.rs +++ b/blockchain/blocks/src/ticket.rs @@ -2,11 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use crypto::VRFResult; +use serde::{Serialize, Deserialize}; /// A Ticket is a marker of a tick of the blockchain's clock. It is the source /// of randomness for proofs of storage and leader election. It is generated /// by the miner of a block using a VRF and a VDF. -#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Default)] +#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Default, Serialize, Deserialize)] pub struct Ticket { /// A proof output by running a VRF on the VDFResult of the parent ticket pub vrfproof: VRFResult, diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 15ca9eeb030e..6c3c9d6299b6 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -9,11 +9,12 @@ use super::errors::Error; use super::ticket::Ticket; use cid::Cid; use clock::ChainEpoch; +use serde::{Deserialize, Serialize}; /// A set of CIDs forming a unique key for a TipSet. /// Equal keys will have equivalent iteration order, but note that the CIDs are *not* maintained in /// the same order as the canonical iteration order of blocks in a tipset (which is by ticket) -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub struct TipSetKeys { pub cids: Vec, } diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index 95e3f4416e46..228ffdd8d2c0 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -12,6 +12,7 @@ address = {path = "../vm/address"} encoding = {path = "../encoding"} libsecp256k1 = "0.2.1" bls-signatures = "0.2.0" +serde = { version = "1.0", features = ["derive"] } [dev-dependencies] rand = "0.4" diff --git a/crypto/src/vrf.rs b/crypto/src/vrf.rs index 9e76398960e9..e66a12efc2cd 100644 --- a/crypto/src/vrf.rs +++ b/crypto/src/vrf.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 use crate::signature::{verify_bls_sig, BLS_SIG_LEN}; -use bls_signatures::{Serialize, Signature}; +use bls_signatures::{Serialize as BlsSerialize, Signature}; +use serde::{Deserialize, Serialize}; pub struct VRFPublicKey(Vec); @@ -14,7 +15,7 @@ impl VRFPublicKey { } /// The output from running a VRF -#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Default, Serialize, Deserialize)] pub struct VRFResult(Vec); impl VRFResult { diff --git a/node/clock/Cargo.toml b/node/clock/Cargo.toml index 4c45a076b2ea..52ea89a3a903 100644 --- a/node/clock/Cargo.toml +++ b/node/clock/Cargo.toml @@ -6,3 +6,4 @@ edition = "2018" [dependencies] chrono = "0.4.9" +serde = { version = "1.0", features = ["derive"] } diff --git a/node/clock/src/lib.rs b/node/clock/src/lib.rs index fbd1c798ab1c..46c155a1844c 100644 --- a/node/clock/src/lib.rs +++ b/node/clock/src/lib.rs @@ -2,11 +2,12 @@ // SPDX-License-Identifier: Apache-2.0 use chrono::{DateTime, NaiveDateTime, SecondsFormat, Utc}; +use serde::{Deserialize, Serialize}; const _ISO_FORMAT: &str = "%FT%X.%.9F"; const EPOCH_DURATION: i32 = 15; -#[derive(Clone, Debug, PartialEq, Eq, Hash, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] /// An epoch represents a single valid state in the blockchain pub struct ChainEpoch(i64); From 22e1612d32639bd9d1c6cf85b48feb098c19ce60 Mon Sep 17 00:00:00 2001 From: austinabell Date: Wed, 15 Jan 2020 21:19:03 -0500 Subject: [PATCH 2/9] refactor block structures and tests (to be cleaned up) --- blockchain/blocks/src/block.rs | 128 ++----------- blockchain/blocks/src/header.rs | 172 ++++++++++++++++++ blockchain/blocks/src/lib.rs | 4 + blockchain/blocks/src/raw_block.rs | 13 ++ blockchain/blocks/src/ticket.rs | 2 +- blockchain/blocks/src/tipset.rs | 89 +++++---- blockchain/chain/src/store/tip_index.rs | 53 ++---- blockchain/sync_manager/src/bucket.rs | 34 +++- blockchain/sync_manager/tests/manager_test.rs | 8 +- ipld/cid/src/error.rs | 18 +- 10 files changed, 306 insertions(+), 215 deletions(-) create mode 100644 blockchain/blocks/src/header.rs create mode 100644 blockchain/blocks/src/raw_block.rs diff --git a/blockchain/blocks/src/block.rs b/blockchain/blocks/src/block.rs index 6e86cb8a875c..3ba164f56c47 100644 --- a/blockchain/blocks/src/block.rs +++ b/blockchain/blocks/src/block.rs @@ -3,159 +3,55 @@ #![allow(dead_code)] -use super::ticket::Ticket; -use super::TipSetKeys; -use address::Address; +use super::BlockHeader; +use super::RawBlock; use cid::Cid; -use clock::ChainEpoch; -use crypto::Signature; -use derive_builder::Builder; use encoding::Cbor; +use encoding::Error as EncodingError; use message::{SignedMessage, UnsignedMessage}; use multihash::Hash; use serde::{Deserialize, Serialize}; use std::fmt; // DefaultHashFunction represents the default hashing function to use -// TODO SHOULD BE BLAKE2B -const DEFAULT_HASH_FUNCTION: Hash = Hash::Keccak256; +// TODO SHOULD BE BLAKE2B256 (256 hashing not implemented) +const DEFAULT_HASH_FUNCTION: Hash = Hash::Blake2b512; // TODO determine the purpose for these structures, currently spec includes them but with no definition struct ChallengeTicketsCommitment {} struct PoStCandidate {} struct PoStRandomness {} struct PoStProof {} -/// Header of a block -/// -/// Usage: -/// ``` -/// use blocks::{BlockHeader, TipSetKeys, Ticket, TxMeta}; -/// use address::Address; -/// use cid::{Cid, Codec, Prefix, Version}; -/// use clock::ChainEpoch; -/// -/// BlockHeader::builder() -/// .parents(TipSetKeys::default()) -/// .miner_address(Address::new_id(0).unwrap()) -/// .bls_aggregate(vec![]) -/// .weight(0) //optional -/// .epoch(ChainEpoch::default()) //optional -/// .messages(TxMeta::default()) //optional -/// .message_receipts(Cid::default()) //optional -/// .state_root(Cid::default()) //optional -/// .timestamp(0) //optional -/// .ticket(Ticket::default()) //optional -/// .build() -/// .unwrap(); -/// ``` -#[derive(Clone, Debug, PartialEq, Builder, Serialize, Deserialize)] -#[builder(name = "BlockHeaderBuilder")] -pub struct BlockHeader { - // CHAIN LINKING - /// Parents is the set of parents this block was based on. Typically one, - /// but can be several in the case where there were multiple winning ticket- - /// holders for an epoch - pub parents: TipSetKeys, - - /// weight is the aggregate chain weight of the parent set - #[builder(default)] - pub weight: u64, - - /// epoch is the period in which a new block is generated. There may be multiple rounds in an epoch - #[builder(default)] - pub epoch: ChainEpoch, - - // MINER INFO - /// miner_address is the address of the miner actor that mined this block - pub miner_address: Address, - - // STATE - /// messages contains the merkle links for bls_messages and secp_messages - #[builder(default)] - pub messages: TxMeta, - - /// message_receipts is the Cid of the root of an array of MessageReceipts - #[builder(default)] - pub message_receipts: Cid, - - /// state_root is a cid pointer to the state tree after application of the transactions state transitions - #[builder(default)] - pub state_root: Cid, - - // CONSENSUS - /// timestamp, in seconds since the Unix epoch, at which this block was created - #[builder(default)] - pub timestamp: u64, - - /// the ticket submitted with this block - #[builder(default)] - pub ticket: Ticket, - - // SIGNATURES - /// aggregate signature of miner in block - pub bls_aggregate: Signature, - - // CACHE - /// stores the cid for the block after the first call to `cid()` - #[builder(default)] - pub cached_cid: Cid, - /// stores the hashed bytes of the block after the fist call to `cid()` - #[builder(default)] - pub cached_bytes: Vec, -} - -impl Cbor for BlockHeader {} - -impl BlockHeader { - pub fn builder() -> BlockHeaderBuilder { - BlockHeaderBuilder::default() - } - /// cid returns the content id of this header - pub fn cid(&mut self) -> Cid { - // TODO Encode blockheader using CBOR into cache_bytes - // Change DEFAULT_HASH_FUNCTION to utilize blake2b - // - // Currently content id for headers will be incomplete until encoding and supporting libraries are completed - let new_cid = Cid::from_bytes_default(&self.cached_bytes).unwrap(); - self.cached_cid = new_cid; - self.cached_cid.clone() - } -} - /// A complete block +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] pub struct Block { header: BlockHeader, bls_messages: UnsignedMessage, secp_messages: SignedMessage, } -/// Used to extract required encoded data and cid for persistent block storage -pub trait RawBlock { - fn raw_data(&self) -> Vec; - fn cid(&self) -> Cid; - fn multihash(&self) -> Hash; -} +impl Cbor for Block {} impl RawBlock for Block { /// returns the block raw contents as a byte array - fn raw_data(&self) -> Vec { + fn raw_data(&self) -> Result, EncodingError> { // TODO should serialize block header using CBOR encoding - self.header.cached_bytes.clone() + self.marshal_cbor() } /// returns the content identifier of the block fn cid(&self) -> Cid { - self.header.clone().cid() + self.header.cached_cid() } /// returns the hash contained in the block CID fn multihash(&self) -> Hash { - self.header.cached_cid.prefix().mh_type + self.cid().prefix().mh_type } } /// human-readable string representation of a block CID impl fmt::Display for Block { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "block: {:?}", self.header.cached_cid.clone()) + write!(f, "block: {:?}", self.cid()) } } diff --git a/blockchain/blocks/src/header.rs b/blockchain/blocks/src/header.rs new file mode 100644 index 000000000000..f83b95531776 --- /dev/null +++ b/blockchain/blocks/src/header.rs @@ -0,0 +1,172 @@ +// Copyright 2020 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0 + +use super::ticket::Ticket; +use super::TipSetKeys; +use super::TxMeta; +use address::Address; +use cid::{Cid, Error as CidError}; +use clock::ChainEpoch; +use crypto::Signature; +use derive_builder::Builder; +use encoding::Cbor; +use serde::{Deserialize, Serialize}; + +/// Header of a block +/// +/// Usage: +/// ``` +/// use blocks::{BlockHeader, TipSetKeys, Ticket, TxMeta}; +/// use address::Address; +/// use cid::{Cid, Codec, Prefix, Version}; +/// use clock::ChainEpoch; +/// +/// BlockHeader::builder() +/// .parents(TipSetKeys::default()) +/// .miner_address(Address::new_id(0).unwrap()) +/// .bls_aggregate(vec![]) +/// .weight(0) //optional +/// .epoch(ChainEpoch::default()) //optional +/// .messages(TxMeta::default()) //optional +/// .message_receipts(Cid::default()) //optional +/// .state_root(Cid::default()) //optional +/// .timestamp(0) //optional +/// .ticket(Ticket::default()) //optional +/// .build() +/// .unwrap(); +/// ``` +#[derive(Clone, Debug, PartialEq, Builder, Serialize, Deserialize)] +#[builder(name = "BlockHeaderBuilder")] +pub struct BlockHeader { + // CHAIN LINKING + /// Parents is the set of parents this block was based on. Typically one, + /// but can be several in the case where there were multiple winning ticket- + /// holders for an epoch + parents: TipSetKeys, + + /// weight is the aggregate chain weight of the parent set + #[builder(default)] + weight: u64, + + /// epoch is the period in which a new block is generated. + /// There may be multiple rounds in an epoch + #[builder(default)] + epoch: ChainEpoch, + + // MINER INFO + /// miner_address is the address of the miner actor that mined this block + miner_address: Address, + + // STATE + /// messages contains the merkle links for bls_messages and secp_messages + #[builder(default)] + messages: TxMeta, + + /// message_receipts is the Cid of the root of an array of MessageReceipts + #[builder(default)] + message_receipts: Cid, + + /// state_root is a cid pointer to the state tree after application of + /// the transactions state transitions + #[builder(default)] + state_root: Cid, + + // CONSENSUS + /// timestamp, in seconds since the Unix epoch, at which this block was created + #[builder(default)] + timestamp: u64, + + /// the ticket submitted with this block + #[builder(default)] + ticket: Ticket, + + // SIGNATURES + /// aggregate signature of miner in block + bls_aggregate: Signature, + + // CACHE + /// stores the cid for the block after the first call to `cid()` + #[builder(setter(skip))] + #[serde(skip_serializing)] + // TODO remove public visibility on cache values once tests reliance on them are removed + pub cached_cid: Option, + /// stores the hashed bytes of the block after the fist call to `cid()` + #[builder(setter(skip))] + #[serde(skip_serializing)] + pub cached_bytes: Option>, +} + +impl Cbor for BlockHeader {} + +impl BlockHeader { + /// Generates a BlockHeader builder as a constructor + pub fn builder() -> BlockHeaderBuilder { + BlockHeaderBuilder::default() + } + /// Getter for BlockHeader parents + pub fn parents(&self) -> &TipSetKeys { + &self.parents + } + /// Getter for BlockHeader weight + pub fn weight(&self) -> u64 { + self.weight + } + /// Getter for BlockHeader epoch + pub fn epoch(&self) -> &ChainEpoch { + &self.epoch + } + /// Getter for BlockHeader miner_address + pub fn miner_address(&self) -> &Address { + &self.miner_address + } + /// Getter for BlockHeader messages + pub fn messages(&self) -> &TxMeta { + &self.messages + } + /// Getter for BlockHeader message_receipts + pub fn message_receipts(&self) -> &Cid { + &self.message_receipts + } + /// Getter for BlockHeader state_root + pub fn state_root(&self) -> &Cid { + &self.state_root + } + /// Getter for BlockHeader timestamp + pub fn timestamp(&self) -> u64 { + self.timestamp + } + /// Getter for BlockHeader ticket + pub fn ticket(&self) -> &Ticket { + &self.ticket + } + /// Getter for BlockHeader bls_aggregate + pub fn bls_aggregate(&self) -> &Signature { + &self.bls_aggregate + } + /// Getter for BlockHeader cid + pub fn cid(&self) -> Result { + // TODO Encode blockheader using CBOR into cache_bytes + // Currently content id for headers will be incomplete until encoding and supporting libraries are completed + if let Some(cache_cid) = self.cached_cid.clone() { + Ok(cache_cid) + } else { + Ok(Cid::from_bytes_default(&self.marshal_cbor()?)?) + } + } + /// Updates cache and returns mutable reference of header back + pub fn update_cache(&mut self) -> &mut Self { + self.cached_bytes = self.marshal_cbor().ok(); + if let Some(bz) = &self.cached_bytes { + self.cached_cid = Cid::from_bytes_default(&bz).ok(); + } + self + } + /// Returns the cached id + pub fn cached_cid(&self) -> Cid { + if let Some(cid) = &self.cached_cid { + cid.clone() + } else { + Cid::default() + } + } +} diff --git a/blockchain/blocks/src/lib.rs b/blockchain/blocks/src/lib.rs index 14f38593579e..bd065b7d91ff 100644 --- a/blockchain/blocks/src/lib.rs +++ b/blockchain/blocks/src/lib.rs @@ -3,10 +3,14 @@ mod block; mod errors; +mod header; +mod raw_block; mod ticket; mod tipset; pub use block::*; pub use errors::*; +pub use header::*; +pub use raw_block::*; pub use ticket::*; pub use tipset::*; diff --git a/blockchain/blocks/src/raw_block.rs b/blockchain/blocks/src/raw_block.rs new file mode 100644 index 000000000000..13368f659ddd --- /dev/null +++ b/blockchain/blocks/src/raw_block.rs @@ -0,0 +1,13 @@ +// Copyright 2020 ChainSafe Systems +// SPDX-License-Identifier: Apache-2.0 + +use cid::Cid; +use encoding::Error as EncodingError; +use multihash::Hash; + +/// Used to extract required encoded data and cid for persistent block storage +pub trait RawBlock { + fn raw_data(&self) -> Result, EncodingError>; + fn cid(&self) -> Cid; + fn multihash(&self) -> Hash; +} diff --git a/blockchain/blocks/src/ticket.rs b/blockchain/blocks/src/ticket.rs index 123bfe87fe24..5aae1e8a986e 100644 --- a/blockchain/blocks/src/ticket.rs +++ b/blockchain/blocks/src/ticket.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crypto::VRFResult; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; /// A Ticket is a marker of a tick of the blockchain's clock. It is the source /// of randomness for proofs of storage and leader election. It is generated diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 6c3c9d6299b6..f63fcae9860e 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -4,9 +4,8 @@ #![allow(unused_variables)] #![allow(dead_code)] -use super::block::BlockHeader; use super::errors::Error; -use super::ticket::Ticket; +use super::{BlockHeader, Ticket}; use cid::Cid; use clock::ChainEpoch; use serde::{Deserialize, Serialize}; @@ -62,36 +61,37 @@ impl Tipset { // loop through headers and validate conditions against 0th header for i in 0..headers.len() { + // TODO Should verify headers' caches are updated if i > 0 { // Skip redundant check // check parent cids are equal - if !headers[i].parents.equals(headers[0].parents.clone()) { + if headers[i].parents() != headers[0].parents() { return Err(Error::InvalidTipSet( "parent cids are not equal".to_string(), )); } // check weights are equal - if headers[i].weight != headers[0].weight { + if headers[i].weight() != headers[0].weight() { return Err(Error::InvalidTipSet("weights are not equal".to_string())); } // check state_roots are equal - if headers[i].state_root != headers[0].state_root.clone() { + if headers[i].state_root() != headers[0].state_root() { return Err(Error::InvalidTipSet( "state_roots are not equal".to_string(), )); } // check epochs are equal - if headers[i].epoch != headers[0].epoch { + if headers[i].epoch() != headers[0].epoch() { return Err(Error::InvalidTipSet("epochs are not equal".to_string())); } // check message_receipts are equal - if headers[i].message_receipts != headers[0].message_receipts.clone() { + if headers[i].message_receipts() != headers[0].message_receipts() { return Err(Error::InvalidTipSet( "message_receipts are not equal".to_string(), )); } // check miner_addresses are distinct - if headers[i].miner_address == headers[0].miner_address.clone() { + if headers[i].miner_address() == headers[0].miner_address() { return Err(Error::InvalidTipSet( "miner_addresses are not distinct".to_string(), )); @@ -100,19 +100,21 @@ impl Tipset { // push headers into vec for sorting sorted_headers.push(headers[i].clone()); // push header cid into vec for unique check - cids.push(headers[i].clone().cid()); + // TODO make sure header + cids.push(headers[i].cached_cid()); } // sort headers by ticket size // break ticket ties with the header CIDs, which are distinct sorted_headers.sort_by_key(|header| { - let mut h = header.clone(); - (h.ticket.vrfproof.clone(), h.cid().to_bytes()) + ( + header.ticket().vrfproof.clone(), + header.cached_cid().to_bytes(), + ) }); - // TODO - // Have a check the ensures CIDs are distinct - // blocked by CBOR encoding + // TODO Have a check the ensures CIDs are distinct + // blocked by cid generation/ caching // return tipset where sorted headers have smallest ticket size is in the 0th index // and the distinct keys @@ -130,17 +132,17 @@ impl Tipset { if self.blocks.is_empty() { return Err(Error::NoBlocks); } - Ok(self.blocks[0].ticket.clone()) + Ok(self.blocks[0].ticket().clone()) } /// Returns the smallest timestamp of all blocks in the tipset fn min_timestamp(&self) -> Result { if self.blocks.is_empty() { return Err(Error::NoBlocks); } - let mut min = self.blocks[0].timestamp; + let mut min = self.blocks[0].timestamp(); for i in 1..self.blocks.len() { - if self.blocks[i].timestamp < min { - min = self.blocks[i].timestamp + if self.blocks[i].timestamp() < min { + min = self.blocks[i].timestamp() } } Ok(min) @@ -154,30 +156,28 @@ impl Tipset { self.blocks.is_empty() } /// Returns a key for the tipset. - pub fn key(&self) -> TipSetKeys { - self.key.clone() + pub fn key(&self) -> &TipSetKeys { + &self.key } /// Returns the CIDs of the parents of the blocks in the tipset - pub fn parents(&self) -> TipSetKeys { - self.blocks[0].parents.clone() + pub fn parents(&self) -> &TipSetKeys { + &self.blocks[0].parents() } /// Returns the tipset's calculated weight pub fn weight(&self) -> u64 { - self.blocks[0].weight + self.blocks[0].weight() } /// Returns the tipset's epoch pub fn tip_epoch(&self) -> ChainEpoch { - self.blocks[0].epoch.clone() + self.blocks[0].epoch().clone() } } #[cfg(test)] mod tests { use super::*; - use crate::block::TxMeta; use address::Address; use cid::Cid; - use clock::ChainEpoch; use crypto::VRFResult; const WEIGHT: u64 = 1; @@ -200,27 +200,22 @@ mod tests { // template_header defines a block header used in testing fn template_header(ticket_p: Vec, cid: Cid, timestamp: u64) -> BlockHeader { let cids = key_setup(); - BlockHeader { - parents: TipSetKeys { + let mut header = BlockHeader::builder() + .parents(TipSetKeys { cids: vec![cids[3].clone()], - }, - weight: WEIGHT, - epoch: ChainEpoch::new(1), - miner_address: Address::new_secp256k1(ticket_p.clone()).unwrap(), - messages: TxMeta { - bls_messages: cids[0].clone(), - secp_messages: cids[0].clone(), - }, - message_receipts: cids[0].clone(), - state_root: cids[0].clone(), - timestamp, - ticket: Ticket { + }) + .miner_address(Address::new_secp256k1(ticket_p.clone()).unwrap()) + .bls_aggregate(vec![]) + .timestamp(timestamp) + .ticket(Ticket { vrfproof: VRFResult::new(ticket_p), - }, - bls_aggregate: vec![1, 2, 3], - cached_cid: cid, - cached_bytes: CACHED_BYTES.to_vec(), - } + }) + .weight(WEIGHT) + .build() + .unwrap(); + header.cached_cid = Some(cid); + + header } // header_setup returns a vec of block headers to be used for testing purposes @@ -279,7 +274,7 @@ mod tests { let tipset = setup(); let expected_value = template_key(b"the best test content out there"); assert_eq!( - Tipset::parents(&tipset), + *tipset.parents(), TipSetKeys { cids: vec!(expected_value) } @@ -289,7 +284,7 @@ mod tests { #[test] fn weight_test() { let tipset = setup(); - assert_eq!(Tipset::weight(&tipset), 1); + assert_eq!(tipset.weight(), WEIGHT); } #[test] diff --git a/blockchain/chain/src/store/tip_index.rs b/blockchain/chain/src/store/tip_index.rs index 64a8e57a0cb7..354a897f6c87 100644 --- a/blockchain/chain/src/store/tip_index.rs +++ b/blockchain/chain/src/store/tip_index.rs @@ -101,14 +101,10 @@ impl TipIndex { mod tests { use super::*; use address::Address; - use blocks::{BlockHeader, Ticket, Tipset, TxMeta}; + use blocks::{BlockHeader, Ticket, Tipset}; use cid::Cid; - use clock::ChainEpoch; use crypto::VRFResult; - const WEIGHT: u64 = 1; - const CACHED_BYTES: [u8; 1] = [0]; - fn template_key(data: &[u8]) -> Cid { Cid::from_bytes_default(data).unwrap() } @@ -120,28 +116,19 @@ mod tests { // template_header defines a block header used in testing fn template_header(ticket_p: Vec, cid: Cid, timestamp: u64) -> BlockHeader { - let cids = key_setup(); - BlockHeader { - parents: TipSetKeys { - cids: vec![cids[0].clone()], - }, - weight: WEIGHT, - epoch: ChainEpoch::new(1), - miner_address: Address::new_secp256k1(ticket_p.clone()).unwrap(), - messages: TxMeta { - bls_messages: cids[0].clone(), - secp_messages: cids[0].clone(), - }, - message_receipts: cids[0].clone(), - state_root: cids[0].clone(), - timestamp, - ticket: Ticket { + let mut header = BlockHeader::builder() + .parents(TipSetKeys::default()) + .miner_address(Address::new_id(0).unwrap()) + .bls_aggregate(vec![]) + .timestamp(timestamp) + .ticket(Ticket { vrfproof: VRFResult::new(ticket_p), - }, - bls_aggregate: vec![1, 2, 3], - cached_cid: cid, - cached_bytes: CACHED_BYTES.to_vec(), - } + }) + .build() + .unwrap(); + header.cached_cid = Some(cid); + + header } // header_setup returns a vec of block headers to be used for testing purposes @@ -159,8 +146,8 @@ mod tests { fn meta_setup() -> TipSetMetadata { let tip_set = setup(); TipSetMetadata { - tipset_state_root: tip_set.blocks()[0].state_root.clone(), - tipset_receipts_root: tip_set.blocks()[0].message_receipts.clone(), + tipset_state_root: tip_set.blocks()[0].state_root().clone(), + tipset_receipts_root: tip_set.blocks()[0].message_receipts().clone(), tipset: tip_set, } } @@ -188,7 +175,7 @@ mod tests { let meta = meta_setup(); let mut tip = TipIndex::new(); tip.put(&meta).unwrap(); - let result = tip.get_tipset(&meta.tipset.parents()).unwrap(); + let result = tip.get_tipset(meta.tipset.parents()).unwrap(); assert_eq!(result, meta.tipset); } @@ -197,9 +184,7 @@ mod tests { let meta = meta_setup(); let mut tip = TipIndex::new(); tip.put(&meta).unwrap(); - let result = tip - .get_tipset_receipts_root(&meta.tipset.parents()) - .unwrap(); + let result = tip.get_tipset_receipts_root(meta.tipset.parents()).unwrap(); assert_eq!(result, meta.tipset_state_root); } @@ -208,9 +193,7 @@ mod tests { let meta = meta_setup(); let mut tip = TipIndex::new(); tip.put(&meta).unwrap(); - let result = tip - .get_tipset_receipts_root(&meta.tipset.parents()) - .unwrap(); + let result = tip.get_tipset_receipts_root(meta.tipset.parents()).unwrap(); assert_eq!(result, meta.tipset_receipts_root); } diff --git a/blockchain/sync_manager/src/bucket.rs b/blockchain/sync_manager/src/bucket.rs index 377cd8300109..ac373acbdd67 100644 --- a/blockchain/sync_manager/src/bucket.rs +++ b/blockchain/sync_manager/src/bucket.rs @@ -77,17 +77,16 @@ mod tests { use cid::Cid; fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHeader { - let x = TipSetKeys { - cids: vec![Cid::from_bytes_default(parent_bz).unwrap()], - }; - BlockHeader::builder() - .parents(x) - .cached_bytes(cached_bytes.to_vec()) // TODO change to however cached bytes are generated in future + let mut header = BlockHeader::builder() + .parents(TipSetKeys::default()) .miner_address(Address::new_id(0).unwrap()) .bls_aggregate(vec![]) .weight(weight) .build() - .unwrap() + .unwrap(); + header.cached_bytes = Some(cached_bytes.to_vec()); + header.cached_cid = Some(Cid::from_bytes_default(parent_bz).unwrap()); + header } #[test] @@ -120,15 +119,30 @@ mod tests { // Assert a tipset on non relating chain is put in another bucket let tipset2 = Tipset::new(vec![create_header(2, b"2", b"2")]).unwrap(); + println!("1{:?}\n{:?}\n", tipset1.parents(), tipset1.key()); + println!("2{:?}\n{:?}\n", tipset2.parents(), tipset2.key()); set.insert(&tipset2); - assert_eq!(set.buckets.len(), 2); + assert_eq!( + set.buckets.len(), + 2, + "Inserting seperate tipset should create new bucket" + ); assert_eq!(set.buckets[1].tips.len(), 1); // Assert a tipset connected to the first let tipset3 = Tipset::new(vec![create_header(3, b"1", b"1")]).unwrap(); + assert_eq!(tipset1.key(), tipset3.key()); set.insert(&tipset3); - assert_eq!(set.buckets.len(), 2); - assert_eq!(set.buckets[0].tips.len(), 2); + assert_eq!( + set.buckets.len(), + 2, + "Inserting into first chain should not create 3rd bucket" + ); + assert_eq!( + set.buckets[0].tips.len(), + 2, + "Should be 2 tipsets in bucket 0" + ); // Assert that tipsets that are already added are not added twice set.insert(&tipset1); diff --git a/blockchain/sync_manager/tests/manager_test.rs b/blockchain/sync_manager/tests/manager_test.rs index a1a257ba037c..358480bfd790 100644 --- a/blockchain/sync_manager/tests/manager_test.rs +++ b/blockchain/sync_manager/tests/manager_test.rs @@ -10,14 +10,16 @@ fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHea let x = TipSetKeys { cids: vec![Cid::from_bytes_default(parent_bz).unwrap()], }; - BlockHeader::builder() + let mut header = BlockHeader::builder() .parents(x) - .cached_bytes(cached_bytes.to_vec()) // TODO change to however cached bytes are generated in future .miner_address(Address::new_id(0).unwrap()) .bls_aggregate(vec![]) .weight(weight) .build() - .unwrap() + .unwrap(); + // TODO remove reliance on setting cached bytes specifically + header.cached_bytes = Some(cached_bytes.to_vec()); + header } #[test] diff --git a/ipld/cid/src/error.rs b/ipld/cid/src/error.rs index b8319633bca0..3eef7de10cc5 100644 --- a/ipld/cid/src/error.rs +++ b/ipld/cid/src/error.rs @@ -1,22 +1,27 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0 +use encoding::Error as EncodingError; use multibase; use multihash; use std::{error, fmt, io}; /// Error types -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Debug)] pub enum Error { UnknownCodec, InputTooShort, ParsingError, InvalidCidVersion, + Other(String), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(error::Error::description(self)) + match self { + Error::Other(err) => write!(f, "Other cid Error: {}", err.clone()), + _ => f.write_str(error::Error::description(self)), + } } } @@ -24,11 +29,12 @@ impl error::Error for Error { fn description(&self) -> &str { use self::Error::*; - match *self { + match self { UnknownCodec => "Unknown codec", InputTooShort => "Input too short", ParsingError => "Failed to parse multihash", InvalidCidVersion => "Unrecognized CID version", + Other(_) => "Other Cid Error", } } } @@ -68,3 +74,9 @@ impl From for fmt::Error { fmt::Error {} } } + +impl From for Error { + fn from(err: EncodingError) -> Error { + Error::Other(err.to_string()) + } +} From 87bb6cbedbdb6fedb5cd4af783ec5c7bf661e5ec Mon Sep 17 00:00:00 2001 From: austinabell Date: Wed, 15 Jan 2020 21:43:01 -0500 Subject: [PATCH 3/9] clean up changes for PR --- blockchain/blocks/src/block.rs | 2 +- blockchain/blocks/src/header.rs | 22 +++++-------------- blockchain/blocks/src/tipset.rs | 10 +++------ blockchain/sync_manager/src/bucket.rs | 2 -- blockchain/sync_manager/tests/manager_test.rs | 6 ++--- 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/blockchain/blocks/src/block.rs b/blockchain/blocks/src/block.rs index 3ba164f56c47..088a008567eb 100644 --- a/blockchain/blocks/src/block.rs +++ b/blockchain/blocks/src/block.rs @@ -40,7 +40,7 @@ impl RawBlock for Block { } /// returns the content identifier of the block fn cid(&self) -> Cid { - self.header.cached_cid() + self.header.cid() } /// returns the hash contained in the block CID fn multihash(&self) -> Hash { diff --git a/blockchain/blocks/src/header.rs b/blockchain/blocks/src/header.rs index f83b95531776..21dae5577af5 100644 --- a/blockchain/blocks/src/header.rs +++ b/blockchain/blocks/src/header.rs @@ -5,7 +5,7 @@ use super::ticket::Ticket; use super::TipSetKeys; use super::TxMeta; use address::Address; -use cid::{Cid, Error as CidError}; +use cid::Cid; use clock::ChainEpoch; use crypto::Signature; use derive_builder::Builder; @@ -144,14 +144,10 @@ impl BlockHeader { &self.bls_aggregate } /// Getter for BlockHeader cid - pub fn cid(&self) -> Result { - // TODO Encode blockheader using CBOR into cache_bytes - // Currently content id for headers will be incomplete until encoding and supporting libraries are completed - if let Some(cache_cid) = self.cached_cid.clone() { - Ok(cache_cid) - } else { - Ok(Cid::from_bytes_default(&self.marshal_cbor()?)?) - } + pub fn cid(&self) -> Cid { + // TODO determine another way to remove need to keep cid as option + // Cache should be initialized, so unwrapping here is fine + self.cached_cid.as_ref().unwrap().clone() } /// Updates cache and returns mutable reference of header back pub fn update_cache(&mut self) -> &mut Self { @@ -161,12 +157,4 @@ impl BlockHeader { } self } - /// Returns the cached id - pub fn cached_cid(&self) -> Cid { - if let Some(cid) = &self.cached_cid { - cid.clone() - } else { - Cid::default() - } - } } diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index f63fcae9860e..04a19199a2ff 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -101,17 +101,13 @@ impl Tipset { sorted_headers.push(headers[i].clone()); // push header cid into vec for unique check // TODO make sure header - cids.push(headers[i].cached_cid()); + cids.push(headers[i].cid()); } // sort headers by ticket size // break ticket ties with the header CIDs, which are distinct - sorted_headers.sort_by_key(|header| { - ( - header.ticket().vrfproof.clone(), - header.cached_cid().to_bytes(), - ) - }); + sorted_headers + .sort_by_key(|header| (header.ticket().vrfproof.clone(), header.cid().to_bytes())); // TODO Have a check the ensures CIDs are distinct // blocked by cid generation/ caching diff --git a/blockchain/sync_manager/src/bucket.rs b/blockchain/sync_manager/src/bucket.rs index ac373acbdd67..ba6e38613456 100644 --- a/blockchain/sync_manager/src/bucket.rs +++ b/blockchain/sync_manager/src/bucket.rs @@ -119,8 +119,6 @@ mod tests { // Assert a tipset on non relating chain is put in another bucket let tipset2 = Tipset::new(vec![create_header(2, b"2", b"2")]).unwrap(); - println!("1{:?}\n{:?}\n", tipset1.parents(), tipset1.key()); - println!("2{:?}\n{:?}\n", tipset2.parents(), tipset2.key()); set.insert(&tipset2); assert_eq!( set.buckets.len(), diff --git a/blockchain/sync_manager/tests/manager_test.rs b/blockchain/sync_manager/tests/manager_test.rs index 358480bfd790..44aab847f4bd 100644 --- a/blockchain/sync_manager/tests/manager_test.rs +++ b/blockchain/sync_manager/tests/manager_test.rs @@ -7,11 +7,8 @@ use cid::Cid; use sync_manager::SyncManager; fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHeader { - let x = TipSetKeys { - cids: vec![Cid::from_bytes_default(parent_bz).unwrap()], - }; let mut header = BlockHeader::builder() - .parents(x) + .parents(TipSetKeys::default()) .miner_address(Address::new_id(0).unwrap()) .bls_aggregate(vec![]) .weight(weight) @@ -19,6 +16,7 @@ fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHea .unwrap(); // TODO remove reliance on setting cached bytes specifically header.cached_bytes = Some(cached_bytes.to_vec()); + header.cached_cid = Some(Cid::from_bytes_default(parent_bz).unwrap()); header } From 220c22fabd4d4e66f35008964469a3a11c005a19 Mon Sep 17 00:00:00 2001 From: austinabell Date: Thu, 16 Jan 2020 10:28:46 -0500 Subject: [PATCH 4/9] refactor and implement header validation structure --- blockchain/blocks/src/block.rs | 2 +- blockchain/blocks/src/header.rs | 63 +++++++++++-------- blockchain/blocks/src/raw_block.rs | 1 + blockchain/blocks/src/tipset.rs | 6 +- blockchain/chain/src/store/tip_index.rs | 4 +- blockchain/sync_manager/src/bucket.rs | 10 ++- blockchain/sync_manager/tests/manager_test.rs | 7 +-- 7 files changed, 50 insertions(+), 43 deletions(-) diff --git a/blockchain/blocks/src/block.rs b/blockchain/blocks/src/block.rs index 088a008567eb..ed1e40bc9f7d 100644 --- a/blockchain/blocks/src/block.rs +++ b/blockchain/blocks/src/block.rs @@ -40,7 +40,7 @@ impl RawBlock for Block { } /// returns the content identifier of the block fn cid(&self) -> Cid { - self.header.cid() + self.header.cid().clone() } /// returns the hash contained in the block CID fn multihash(&self) -> Hash { diff --git a/blockchain/blocks/src/header.rs b/blockchain/blocks/src/header.rs index 21dae5577af5..eed951c275b9 100644 --- a/blockchain/blocks/src/header.rs +++ b/blockchain/blocks/src/header.rs @@ -22,16 +22,16 @@ use serde::{Deserialize, Serialize}; /// use clock::ChainEpoch; /// /// BlockHeader::builder() -/// .parents(TipSetKeys::default()) -/// .miner_address(Address::new_id(0).unwrap()) -/// .bls_aggregate(vec![]) -/// .weight(0) //optional -/// .epoch(ChainEpoch::default()) //optional -/// .messages(TxMeta::default()) //optional -/// .message_receipts(Cid::default()) //optional -/// .state_root(Cid::default()) //optional -/// .timestamp(0) //optional -/// .ticket(Ticket::default()) //optional +/// .miner_address(Address::new_id(0).unwrap()) // optional +/// .bls_aggregate(vec![]) // optional +/// .parents(TipSetKeys::default()) // optional +/// .weight(0) // optional +/// .epoch(ChainEpoch::default()) // optional +/// .messages(TxMeta::default()) // optional +/// .message_receipts(Cid::default()) // optional +/// .state_root(Cid::default()) // optional +/// .timestamp(0) // optional +/// .ticket(Ticket::default()) // optional /// .build() /// .unwrap(); /// ``` @@ -42,6 +42,7 @@ pub struct BlockHeader { /// Parents is the set of parents this block was based on. Typically one, /// but can be several in the case where there were multiple winning ticket- /// holders for an epoch + #[builder(default)] parents: TipSetKeys, /// weight is the aggregate chain weight of the parent set @@ -52,7 +53,6 @@ pub struct BlockHeader { /// There may be multiple rounds in an epoch #[builder(default)] epoch: ChainEpoch, - // MINER INFO /// miner_address is the address of the miner actor that mined this block miner_address: Address, @@ -75,25 +75,22 @@ pub struct BlockHeader { /// timestamp, in seconds since the Unix epoch, at which this block was created #[builder(default)] timestamp: u64, - /// the ticket submitted with this block #[builder(default)] ticket: Ticket, - // SIGNATURES /// aggregate signature of miner in block + #[builder(default)] bls_aggregate: Signature, - // CACHE /// stores the cid for the block after the first call to `cid()` - #[builder(setter(skip))] #[serde(skip_serializing)] - // TODO remove public visibility on cache values once tests reliance on them are removed - pub cached_cid: Option, + #[builder(default)] + cached_cid: Cid, /// stores the hashed bytes of the block after the fist call to `cid()` - #[builder(setter(skip))] #[serde(skip_serializing)] - pub cached_bytes: Option>, + #[builder(default)] + cached_bytes: Vec, } impl Cbor for BlockHeader {} @@ -144,17 +141,29 @@ impl BlockHeader { &self.bls_aggregate } /// Getter for BlockHeader cid - pub fn cid(&self) -> Cid { + pub fn cid(&self) -> &Cid { // TODO determine another way to remove need to keep cid as option // Cache should be initialized, so unwrapping here is fine - self.cached_cid.as_ref().unwrap().clone() + &self.cached_cid } /// Updates cache and returns mutable reference of header back - pub fn update_cache(&mut self) -> &mut Self { - self.cached_bytes = self.marshal_cbor().ok(); - if let Some(bz) = &self.cached_bytes { - self.cached_cid = Cid::from_bytes_default(&bz).ok(); - } - self + fn update_cache(&mut self) -> Result<(), String> { + self.cached_bytes = self.marshal_cbor().map_err(|e| e.to_string())?; + self.cached_cid = Cid::from_bytes_default(&self.cached_bytes).map_err(|e| e.to_string())?; + Ok(()) + } +} + +impl BlockHeaderBuilder { + pub fn build_and_validate(&self) -> Result { + // Convert header builder into header struct + let mut header = self.build()?; + + // TODO add validation function + + // Fill header cache with raw bytes and cid + header.update_cache()?; + + Ok(header) } } diff --git a/blockchain/blocks/src/raw_block.rs b/blockchain/blocks/src/raw_block.rs index 13368f659ddd..204e06290f13 100644 --- a/blockchain/blocks/src/raw_block.rs +++ b/blockchain/blocks/src/raw_block.rs @@ -5,6 +5,7 @@ use cid::Cid; use encoding::Error as EncodingError; use multihash::Hash; +// TODO move raw block to own crate /// Used to extract required encoded data and cid for persistent block storage pub trait RawBlock { fn raw_data(&self) -> Result, EncodingError>; diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 04a19199a2ff..dacd6ef61bef 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -101,7 +101,7 @@ impl Tipset { sorted_headers.push(headers[i].clone()); // push header cid into vec for unique check // TODO make sure header - cids.push(headers[i].cid()); + cids.push(headers[i].cid().clone()); } // sort headers by ticket size @@ -196,7 +196,7 @@ mod tests { // template_header defines a block header used in testing fn template_header(ticket_p: Vec, cid: Cid, timestamp: u64) -> BlockHeader { let cids = key_setup(); - let mut header = BlockHeader::builder() + let header = BlockHeader::builder() .parents(TipSetKeys { cids: vec![cids[3].clone()], }) @@ -207,9 +207,9 @@ mod tests { vrfproof: VRFResult::new(ticket_p), }) .weight(WEIGHT) + .cached_cid(cid) .build() .unwrap(); - header.cached_cid = Some(cid); header } diff --git a/blockchain/chain/src/store/tip_index.rs b/blockchain/chain/src/store/tip_index.rs index 354a897f6c87..a74c34cc3641 100644 --- a/blockchain/chain/src/store/tip_index.rs +++ b/blockchain/chain/src/store/tip_index.rs @@ -116,7 +116,7 @@ mod tests { // template_header defines a block header used in testing fn template_header(ticket_p: Vec, cid: Cid, timestamp: u64) -> BlockHeader { - let mut header = BlockHeader::builder() + let header = BlockHeader::builder() .parents(TipSetKeys::default()) .miner_address(Address::new_id(0).unwrap()) .bls_aggregate(vec![]) @@ -124,9 +124,9 @@ mod tests { .ticket(Ticket { vrfproof: VRFResult::new(ticket_p), }) + .cached_cid(cid) .build() .unwrap(); - header.cached_cid = Some(cid); header } diff --git a/blockchain/sync_manager/src/bucket.rs b/blockchain/sync_manager/src/bucket.rs index ba6e38613456..af35710cf841 100644 --- a/blockchain/sync_manager/src/bucket.rs +++ b/blockchain/sync_manager/src/bucket.rs @@ -73,19 +73,17 @@ impl<'a> SyncBucketSet<'a> { mod tests { use super::*; use address::Address; - use blocks::{BlockHeader, TipSetKeys}; + use blocks::BlockHeader; use cid::Cid; fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHeader { - let mut header = BlockHeader::builder() - .parents(TipSetKeys::default()) + let header = BlockHeader::builder() .miner_address(Address::new_id(0).unwrap()) - .bls_aggregate(vec![]) .weight(weight) + .cached_bytes(cached_bytes.to_vec()) + .cached_cid(Cid::from_bytes_default(parent_bz).unwrap()) .build() .unwrap(); - header.cached_bytes = Some(cached_bytes.to_vec()); - header.cached_cid = Some(Cid::from_bytes_default(parent_bz).unwrap()); header } diff --git a/blockchain/sync_manager/tests/manager_test.rs b/blockchain/sync_manager/tests/manager_test.rs index 44aab847f4bd..a90015cfa8eb 100644 --- a/blockchain/sync_manager/tests/manager_test.rs +++ b/blockchain/sync_manager/tests/manager_test.rs @@ -7,16 +7,15 @@ use cid::Cid; use sync_manager::SyncManager; fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHeader { - let mut header = BlockHeader::builder() + let header = BlockHeader::builder() .parents(TipSetKeys::default()) .miner_address(Address::new_id(0).unwrap()) .bls_aggregate(vec![]) .weight(weight) + .cached_bytes(cached_bytes.to_vec()) + .cached_cid(Cid::from_bytes_default(parent_bz).unwrap()) .build() .unwrap(); - // TODO remove reliance on setting cached bytes specifically - header.cached_bytes = Some(cached_bytes.to_vec()); - header.cached_cid = Some(Cid::from_bytes_default(parent_bz).unwrap()); header } From bd594b6bd5e70eb38a177ec7a476d1f0d7495da8 Mon Sep 17 00:00:00 2001 From: austinabell Date: Thu, 16 Jan 2020 12:02:24 -0500 Subject: [PATCH 5/9] add TODO comments for unverified cbor encoded types --- blockchain/blocks/src/block.rs | 6 ++++++ blockchain/blocks/src/header.rs | 3 +++ blockchain/blocks/src/ticket.rs | 3 +++ blockchain/blocks/src/tipset.rs | 3 +++ crypto/src/vrf.rs | 6 ++++++ node/clock/src/lib.rs | 3 +++ vm/actor/src/lib.rs | 3 +++ vm/message/src/signed_message.rs | 3 +++ vm/message/src/unsigned_message.rs | 3 +++ vm/src/method.rs | 9 +++++++++ 10 files changed, 42 insertions(+) diff --git a/blockchain/blocks/src/block.rs b/blockchain/blocks/src/block.rs index ed1e40bc9f7d..5b1a11853c05 100644 --- a/blockchain/blocks/src/block.rs +++ b/blockchain/blocks/src/block.rs @@ -30,6 +30,9 @@ pub struct Block { secp_messages: SignedMessage, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl Cbor for Block {} impl RawBlock for Block { @@ -62,6 +65,9 @@ pub struct TxMeta { pub secp_messages: Cid, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + /// ElectionPoStVerifyInfo seems to be connected to VRF /// see https://github.com/filecoin-project/lotus/blob/master/chain/sync.go#L1099 struct ElectionPoStVerifyInfo { diff --git a/blockchain/blocks/src/header.rs b/blockchain/blocks/src/header.rs index eed951c275b9..db5a34cd08fc 100644 --- a/blockchain/blocks/src/header.rs +++ b/blockchain/blocks/src/header.rs @@ -93,6 +93,9 @@ pub struct BlockHeader { cached_bytes: Vec, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl Cbor for BlockHeader {} impl BlockHeader { diff --git a/blockchain/blocks/src/ticket.rs b/blockchain/blocks/src/ticket.rs index 5aae1e8a986e..6d480e654e7a 100644 --- a/blockchain/blocks/src/ticket.rs +++ b/blockchain/blocks/src/ticket.rs @@ -13,6 +13,9 @@ pub struct Ticket { pub vrfproof: VRFResult, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl Ticket { /// Ticket constructor pub fn new(vrfproof: VRFResult) -> Self { diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index dacd6ef61bef..0d9932b37885 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -18,6 +18,9 @@ pub struct TipSetKeys { pub cids: Vec, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl TipSetKeys { /// checks whether the set contains exactly the same CIDs as another. fn equals(&self, key: TipSetKeys) -> bool { diff --git a/crypto/src/vrf.rs b/crypto/src/vrf.rs index e66a12efc2cd..65bc2bc836d8 100644 --- a/crypto/src/vrf.rs +++ b/crypto/src/vrf.rs @@ -18,6 +18,9 @@ impl VRFPublicKey { #[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Default, Serialize, Deserialize)] pub struct VRFResult(Vec); +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl VRFResult { /// Creates a VRFResult from a raw vector pub fn new(output: Vec) -> Self { @@ -44,6 +47,9 @@ impl VRFResult { } } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + #[cfg(test)] mod tests { use super::*; diff --git a/node/clock/src/lib.rs b/node/clock/src/lib.rs index 46c155a1844c..be92ce891e02 100644 --- a/node/clock/src/lib.rs +++ b/node/clock/src/lib.rs @@ -11,6 +11,9 @@ const EPOCH_DURATION: i32 = 15; /// An epoch represents a single valid state in the blockchain pub struct ChainEpoch(i64); +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + /// ChainEpochClock is used by the system node to assume weak clock synchrony amongst the other /// systems. pub struct ChainEpochClock { diff --git a/vm/actor/src/lib.rs b/vm/actor/src/lib.rs index 5868cac2c46c..ce28c8fc745f 100644 --- a/vm/actor/src/lib.rs +++ b/vm/actor/src/lib.rs @@ -16,6 +16,9 @@ use serde::{Deserialize, Serialize}; #[derive(PartialEq, Eq, Copy, Clone, Debug, Default, Serialize, Deserialize)] pub struct ActorID(u64); +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl Cbor for ActorID {} /// State of all actor implementations diff --git a/vm/message/src/signed_message.rs b/vm/message/src/signed_message.rs index 1db8003552c5..03170edb0859 100644 --- a/vm/message/src/signed_message.rs +++ b/vm/message/src/signed_message.rs @@ -16,6 +16,9 @@ pub struct SignedMessage { signature: Signature, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl SignedMessage { pub fn new(msg: &UnsignedMessage, s: &impl Signer) -> Result { let bz = msg.marshal_cbor()?; diff --git a/vm/message/src/unsigned_message.rs b/vm/message/src/unsigned_message.rs index 9ea09da1e0fd..432a53f3c63f 100644 --- a/vm/message/src/unsigned_message.rs +++ b/vm/message/src/unsigned_message.rs @@ -60,6 +60,9 @@ pub struct UnsignedMessage { gas_limit: BigUint, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl UnsignedMessage { pub fn builder() -> MessageBuilder { MessageBuilder::default() diff --git a/vm/src/method.rs b/vm/src/method.rs index fffcd11e0efe..7d5993a1bf29 100644 --- a/vm/src/method.rs +++ b/vm/src/method.rs @@ -9,6 +9,9 @@ use std::ops::{Deref, DerefMut}; #[derive(Default, Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct MethodNum(i32); // TODO: add constraints to this +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl MethodNum { /// Constructor for new MethodNum pub fn new(num: i32) -> Self { @@ -39,6 +42,9 @@ pub struct Serialized { bytes: Vec, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl Deref for Serialized { type Target = Vec; fn deref(&self) -> &Self::Target { @@ -71,6 +77,9 @@ pub struct MethodParams { params: Vec, } +// TODO verify format or implement custom serialize/deserialize function (if necessary): +// https://github.com/ChainSafe/ferret/issues/143 + impl Deref for MethodParams { type Target = Vec; fn deref(&self) -> &Self::Target { From 5e81b26bfc395dc50942ee43e46fa3830b5c811c Mon Sep 17 00:00:00 2001 From: austinabell Date: Thu, 16 Jan 2020 12:20:00 -0500 Subject: [PATCH 6/9] updating defaulting and usage --- blockchain/blocks/src/header.rs | 1 + blockchain/blocks/src/tipset.rs | 1 - blockchain/chain/src/store/tip_index.rs | 4 ---- blockchain/sync_manager/src/bucket.rs | 2 -- blockchain/sync_manager/tests/manager_test.rs | 6 +----- vm/address/src/lib.rs | 2 +- vm/address/src/network.rs | 6 ++++++ vm/address/src/protocol.rs | 6 ++++++ 8 files changed, 15 insertions(+), 13 deletions(-) diff --git a/blockchain/blocks/src/header.rs b/blockchain/blocks/src/header.rs index db5a34cd08fc..8dfa2c4cc007 100644 --- a/blockchain/blocks/src/header.rs +++ b/blockchain/blocks/src/header.rs @@ -55,6 +55,7 @@ pub struct BlockHeader { epoch: ChainEpoch, // MINER INFO /// miner_address is the address of the miner actor that mined this block + #[builder(default)] miner_address: Address, // STATE diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 0d9932b37885..8b5ba5015f11 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -204,7 +204,6 @@ mod tests { cids: vec![cids[3].clone()], }) .miner_address(Address::new_secp256k1(ticket_p.clone()).unwrap()) - .bls_aggregate(vec![]) .timestamp(timestamp) .ticket(Ticket { vrfproof: VRFResult::new(ticket_p), diff --git a/blockchain/chain/src/store/tip_index.rs b/blockchain/chain/src/store/tip_index.rs index a74c34cc3641..54c09a5a87a8 100644 --- a/blockchain/chain/src/store/tip_index.rs +++ b/blockchain/chain/src/store/tip_index.rs @@ -100,7 +100,6 @@ impl TipIndex { #[cfg(test)] mod tests { use super::*; - use address::Address; use blocks::{BlockHeader, Ticket, Tipset}; use cid::Cid; use crypto::VRFResult; @@ -117,9 +116,6 @@ mod tests { // template_header defines a block header used in testing fn template_header(ticket_p: Vec, cid: Cid, timestamp: u64) -> BlockHeader { let header = BlockHeader::builder() - .parents(TipSetKeys::default()) - .miner_address(Address::new_id(0).unwrap()) - .bls_aggregate(vec![]) .timestamp(timestamp) .ticket(Ticket { vrfproof: VRFResult::new(ticket_p), diff --git a/blockchain/sync_manager/src/bucket.rs b/blockchain/sync_manager/src/bucket.rs index af35710cf841..eaf94a8abbdb 100644 --- a/blockchain/sync_manager/src/bucket.rs +++ b/blockchain/sync_manager/src/bucket.rs @@ -72,13 +72,11 @@ impl<'a> SyncBucketSet<'a> { #[cfg(test)] mod tests { use super::*; - use address::Address; use blocks::BlockHeader; use cid::Cid; fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHeader { let header = BlockHeader::builder() - .miner_address(Address::new_id(0).unwrap()) .weight(weight) .cached_bytes(cached_bytes.to_vec()) .cached_cid(Cid::from_bytes_default(parent_bz).unwrap()) diff --git a/blockchain/sync_manager/tests/manager_test.rs b/blockchain/sync_manager/tests/manager_test.rs index a90015cfa8eb..bedcf1ab38f0 100644 --- a/blockchain/sync_manager/tests/manager_test.rs +++ b/blockchain/sync_manager/tests/manager_test.rs @@ -1,16 +1,12 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0 -use address::Address; -use blocks::{BlockHeader, TipSetKeys, Tipset}; +use blocks::{BlockHeader, Tipset}; use cid::Cid; use sync_manager::SyncManager; fn create_header(weight: u64, parent_bz: &[u8], cached_bytes: &[u8]) -> BlockHeader { let header = BlockHeader::builder() - .parents(TipSetKeys::default()) - .miner_address(Address::new_id(0).unwrap()) - .bls_aggregate(vec![]) .weight(weight) .cached_bytes(cached_bytes.to_vec()) .cached_cid(Cid::from_bytes_default(parent_bz).unwrap()) diff --git a/vm/address/src/lib.rs b/vm/address/src/lib.rs index 5843b09844e5..e98eebdb150b 100644 --- a/vm/address/src/lib.rs +++ b/vm/address/src/lib.rs @@ -37,7 +37,7 @@ const NETWORK_DEFAULT: Network = Network::Testnet; /// Address is the struct that defines the protocol and data payload conversion from either /// a public key or value -#[derive(PartialEq, Eq, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Clone, Debug, Hash, Default)] pub struct Address { network: Network, protocol: Protocol, diff --git a/vm/address/src/network.rs b/vm/address/src/network.rs index 640a1be4d79e..cdeff0bf546e 100644 --- a/vm/address/src/network.rs +++ b/vm/address/src/network.rs @@ -10,6 +10,12 @@ pub enum Network { Testnet, } +impl Default for Network { + fn default() -> Self { + Network::Testnet + } +} + impl Network { /// to_prefix is used to convert the network into a string /// used when converting address to string diff --git a/vm/address/src/protocol.rs b/vm/address/src/protocol.rs index c8ed4096bfc4..ba9ba902cb43 100644 --- a/vm/address/src/protocol.rs +++ b/vm/address/src/protocol.rs @@ -18,6 +18,12 @@ pub enum Protocol { BLS = 3, } +impl Default for Protocol { + fn default() -> Self { + Protocol::ID + } +} + impl Protocol { /// from_byte allows referencing back to Protocol from encoded byte pub(super) fn from_byte(b: u8) -> Option { From a6df4d8fe3fb7c6d759b18fe465a7907a32ae05f Mon Sep 17 00:00:00 2001 From: austinabell Date: Thu, 16 Jan 2020 12:36:21 -0500 Subject: [PATCH 7/9] clean up for PR --- blockchain/blocks/src/block.rs | 6 ++---- blockchain/blocks/src/header.rs | 9 +++------ blockchain/blocks/src/tipset.rs | 12 ++++-------- blockchain/chain/src/store/tip_index.rs | 6 +++--- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/blockchain/blocks/src/block.rs b/blockchain/blocks/src/block.rs index 5b1a11853c05..e6ab841917a5 100644 --- a/blockchain/blocks/src/block.rs +++ b/blockchain/blocks/src/block.rs @@ -3,11 +3,9 @@ #![allow(dead_code)] -use super::BlockHeader; -use super::RawBlock; +use super::{BlockHeader, RawBlock}; use cid::Cid; -use encoding::Cbor; -use encoding::Error as EncodingError; +use encoding::{Cbor, Error as EncodingError}; use message::{SignedMessage, UnsignedMessage}; use multihash::Hash; use serde::{Deserialize, Serialize}; diff --git a/blockchain/blocks/src/header.rs b/blockchain/blocks/src/header.rs index 8dfa2c4cc007..bd59e0c1a030 100644 --- a/blockchain/blocks/src/header.rs +++ b/blockchain/blocks/src/header.rs @@ -1,9 +1,7 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0 -use super::ticket::Ticket; -use super::TipSetKeys; -use super::TxMeta; +use super::{Ticket, TipSetKeys, TxMeta}; use address::Address; use cid::Cid; use clock::ChainEpoch; @@ -32,7 +30,7 @@ use serde::{Deserialize, Serialize}; /// .state_root(Cid::default()) // optional /// .timestamp(0) // optional /// .ticket(Ticket::default()) // optional -/// .build() +/// .build_and_validate() /// .unwrap(); /// ``` #[derive(Clone, Debug, PartialEq, Builder, Serialize, Deserialize)] @@ -146,8 +144,7 @@ impl BlockHeader { } /// Getter for BlockHeader cid pub fn cid(&self) -> &Cid { - // TODO determine another way to remove need to keep cid as option - // Cache should be initialized, so unwrapping here is fine + // Cache should be initialized, otherwise will return default Cid &self.cached_cid } /// Updates cache and returns mutable reference of header back diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index 8b5ba5015f11..c62f881713d4 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -4,8 +4,7 @@ #![allow(unused_variables)] #![allow(dead_code)] -use super::errors::Error; -use super::{BlockHeader, Ticket}; +use super::{BlockHeader, Error, Ticket}; use cid::Cid; use clock::ChainEpoch; use serde::{Deserialize, Serialize}; @@ -64,7 +63,6 @@ impl Tipset { // loop through headers and validate conditions against 0th header for i in 0..headers.len() { - // TODO Should verify headers' caches are updated if i > 0 { // Skip redundant check // check parent cids are equal @@ -102,8 +100,7 @@ impl Tipset { } // push headers into vec for sorting sorted_headers.push(headers[i].clone()); - // push header cid into vec for unique check - // TODO make sure header + // push header cid into vec for unique check (can be changed to hashset later) cids.push(headers[i].cid().clone()); } @@ -113,7 +110,6 @@ impl Tipset { .sort_by_key(|header| (header.ticket().vrfproof.clone(), header.cid().to_bytes())); // TODO Have a check the ensures CIDs are distinct - // blocked by cid generation/ caching // return tipset where sorted headers have smallest ticket size is in the 0th index // and the distinct keys @@ -167,8 +163,8 @@ impl Tipset { self.blocks[0].weight() } /// Returns the tipset's epoch - pub fn tip_epoch(&self) -> ChainEpoch { - self.blocks[0].epoch().clone() + pub fn tip_epoch(&self) -> &ChainEpoch { + self.blocks[0].epoch() } } diff --git a/blockchain/chain/src/store/tip_index.rs b/blockchain/chain/src/store/tip_index.rs index 54c09a5a87a8..67c942d9cfc9 100644 --- a/blockchain/chain/src/store/tip_index.rs +++ b/blockchain/chain/src/store/tip_index.rs @@ -198,7 +198,7 @@ mod tests { let meta = meta_setup(); let mut tip = TipIndex::new(); tip.put(&meta).unwrap(); - let result = tip.get_tipset(&meta.tipset.tip_epoch()).unwrap(); + let result = tip.get_tipset(&meta.tipset.tip_epoch().clone()).unwrap(); assert_eq!(result, meta.tipset); } @@ -207,7 +207,7 @@ mod tests { let meta = meta_setup(); let mut tip = TipIndex::new(); tip.put(&meta).unwrap(); - let result = tip.get_tipset_state_root(&meta.tipset.tip_epoch()).unwrap(); + let result = tip.get_tipset_state_root(&meta.tipset.tip_epoch().clone()).unwrap(); assert_eq!(result, meta.tipset_state_root); } @@ -217,7 +217,7 @@ mod tests { let mut tip = TipIndex::new(); tip.put(&meta).unwrap(); let result = tip - .get_tipset_receipts_root(&meta.tipset.tip_epoch()) + .get_tipset_receipts_root(&meta.tipset.tip_epoch().clone()) .unwrap(); assert_eq!(result, meta.tipset_receipts_root); } From 905e850571a5e4a4cf500c0009f1658d92fd2383 Mon Sep 17 00:00:00 2001 From: austinabell Date: Thu, 16 Jan 2020 12:52:23 -0500 Subject: [PATCH 8/9] lint --- blockchain/chain/src/store/tip_index.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/blockchain/chain/src/store/tip_index.rs b/blockchain/chain/src/store/tip_index.rs index 67c942d9cfc9..8af381dd232d 100644 --- a/blockchain/chain/src/store/tip_index.rs +++ b/blockchain/chain/src/store/tip_index.rs @@ -207,7 +207,9 @@ mod tests { let meta = meta_setup(); let mut tip = TipIndex::new(); tip.put(&meta).unwrap(); - let result = tip.get_tipset_state_root(&meta.tipset.tip_epoch().clone()).unwrap(); + let result = tip + .get_tipset_state_root(&meta.tipset.tip_epoch().clone()) + .unwrap(); assert_eq!(result, meta.tipset_state_root); } From 6f4ee6abc20390b408c20adf590a26436856cfe1 Mon Sep 17 00:00:00 2001 From: austinabell Date: Thu, 16 Jan 2020 13:28:56 -0500 Subject: [PATCH 9/9] addr comments --- blockchain/blocks/src/block.rs | 22 +++------------------- blockchain/blocks/src/header.rs | 21 +++++++++++++++++++-- blockchain/blocks/src/tipset.rs | 9 ++++++--- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/blockchain/blocks/src/block.rs b/blockchain/blocks/src/block.rs index e6ab841917a5..86dcda0fc37f 100644 --- a/blockchain/blocks/src/block.rs +++ b/blockchain/blocks/src/block.rs @@ -3,9 +3,9 @@ #![allow(dead_code)] -use super::{BlockHeader, RawBlock}; +use super::BlockHeader; use cid::Cid; -use encoding::{Cbor, Error as EncodingError}; +use encoding::Cbor; use message::{SignedMessage, UnsignedMessage}; use multihash::Hash; use serde::{Deserialize, Serialize}; @@ -33,26 +33,10 @@ pub struct Block { impl Cbor for Block {} -impl RawBlock for Block { - /// returns the block raw contents as a byte array - fn raw_data(&self) -> Result, EncodingError> { - // TODO should serialize block header using CBOR encoding - self.marshal_cbor() - } - /// returns the content identifier of the block - fn cid(&self) -> Cid { - self.header.cid().clone() - } - /// returns the hash contained in the block CID - fn multihash(&self) -> Hash { - self.cid().prefix().mh_type - } -} - /// human-readable string representation of a block CID impl fmt::Display for Block { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "block: {:?}", self.cid()) + write!(f, "block: {:?}", self.header.cid()) } } diff --git a/blockchain/blocks/src/header.rs b/blockchain/blocks/src/header.rs index bd59e0c1a030..03b06e87acbc 100644 --- a/blockchain/blocks/src/header.rs +++ b/blockchain/blocks/src/header.rs @@ -1,13 +1,14 @@ // Copyright 2020 ChainSafe Systems // SPDX-License-Identifier: Apache-2.0 -use super::{Ticket, TipSetKeys, TxMeta}; +use super::{RawBlock, Ticket, TipSetKeys, TxMeta}; use address::Address; use cid::Cid; use clock::ChainEpoch; use crypto::Signature; use derive_builder::Builder; -use encoding::Cbor; +use encoding::{Cbor, Error as EncodingError}; +use multihash::Hash; use serde::{Deserialize, Serialize}; /// Header of a block @@ -97,6 +98,22 @@ pub struct BlockHeader { impl Cbor for BlockHeader {} +impl RawBlock for BlockHeader { + /// returns the block raw contents as a byte array + fn raw_data(&self) -> Result, EncodingError> { + // TODO should serialize block header using CBOR encoding + self.marshal_cbor() + } + /// returns the content identifier of the block + fn cid(&self) -> Cid { + self.cid().clone() + } + /// returns the hash contained in the block CID + fn multihash(&self) -> Hash { + self.cid().prefix().mh_type + } +} + impl BlockHeader { /// Generates a BlockHeader builder as a constructor pub fn builder() -> BlockHeaderBuilder { diff --git a/blockchain/blocks/src/tipset.rs b/blockchain/blocks/src/tipset.rs index c62f881713d4..1577b5d1b388 100644 --- a/blockchain/blocks/src/tipset.rs +++ b/blockchain/blocks/src/tipset.rs @@ -22,7 +22,7 @@ pub struct TipSetKeys { impl TipSetKeys { /// checks whether the set contains exactly the same CIDs as another. - fn equals(&self, key: TipSetKeys) -> bool { + fn equals(&self, key: &TipSetKeys) -> bool { if self.cids.len() != key.cids.len() { return false; } @@ -66,7 +66,7 @@ impl Tipset { if i > 0 { // Skip redundant check // check parent cids are equal - if headers[i].parents() != headers[0].parents() { + if !headers[i].parents().equals(headers[0].parents()) { return Err(Error::InvalidTipSet( "parent cids are not equal".to_string(), )); @@ -286,6 +286,9 @@ mod tests { let tipset_keys = TipSetKeys { cids: key_setup().clone(), }; - assert_eq!(TipSetKeys::equals(&tipset_keys, tipset_keys.clone()), true); + let tipset_keys2 = TipSetKeys { + cids: key_setup().clone(), + }; + assert_eq!(tipset_keys.equals(&tipset_keys2), true); } }