Add prevHash field to CompactBlock

This enables basic verification of chain validity when CompactBlocks are
received without the full header.
This commit is contained in:
Jack Grigg 2019-05-01 13:21:48 +01:00
parent a3b85b8fe6
commit 2bbd25b36b
No known key found for this signature in database
GPG Key ID: 9E8255172BBF9898
3 changed files with 69 additions and 3 deletions

View File

@ -13,9 +13,10 @@ message CompactBlock {
uint32 protoVersion = 1; // the version of this wire format, for storage
uint64 height = 2; // the height of this block
bytes hash = 3;
uint32 time = 4;
bytes header = 5; // (hash and time) OR (full header)
repeated CompactTx vtx = 6; // compact transactions from this block
bytes prevHash = 4;
uint32 time = 5;
bytes header = 6; // (hash, prevHash, and time) OR (full header)
repeated CompactTx vtx = 7; // compact transactions from this block
}
message CompactTx {

View File

@ -1,3 +1,54 @@
//! Generated code for handling light client protobuf structs.
use zcash_primitives::block::{BlockHash, BlockHeader};
pub mod compact_formats;
impl compact_formats::CompactBlock {
/// Returns the [`BlockHash`] for this block.
///
/// # Panics
///
/// This function will panic if [`CompactBlock.header`] is not set and
/// [`CompactBlock.hash`] is not exactly 32 bytes.
///
/// [`CompactBlock.header`]: #structfield.header
/// [`CompactBlock.hash`]: #structfield.hash
pub fn hash(&self) -> BlockHash {
if let Some(header) = self.header() {
header.hash()
} else {
BlockHash::from_slice(&self.hash)
}
}
/// Returns the [`BlockHash`] for this block's parent.
///
/// # Panics
///
/// This function will panic if [`CompactBlock.header`] is not set and
/// [`CompactBlock.prevHash`] is not exactly 32 bytes.
///
/// [`CompactBlock.header`]: #structfield.header
/// [`CompactBlock.prevHash`]: #structfield.prevHash
pub fn prev_hash(&self) -> BlockHash {
if let Some(header) = self.header() {
header.prev_block
} else {
BlockHash::from_slice(&self.prevHash)
}
}
/// Returns the [`BlockHeader`] for this block if present.
///
/// A convenience method that parses [`CompactBlock.header`] if present.
///
/// [`CompactBlock.header`]: #structfield.header
pub fn header(&self) -> Option<BlockHeader> {
if self.header.is_empty() {
None
} else {
BlockHeader::read(&self.header[..]).ok()
}
}
}

View File

@ -22,6 +22,20 @@ impl fmt::Display for BlockHash {
}
}
impl BlockHash {
/// Constructs a [`BlockHash`] from the given slice.
///
/// # Panics
///
/// This function will panic if the slice is not exactly 32 bytes.
pub fn from_slice(bytes: &[u8]) -> Self {
assert_eq!(bytes.len(), 32);
let mut hash = [0; 32];
hash.copy_from_slice(&bytes);
BlockHash(hash)
}
}
/// A Zcash block header.
pub struct BlockHeader {
hash: BlockHash,