feature: Add light_client_root_hash(network) to Block

* use the right variant in LightClientRootHash::from_bytes()
* make block.header.light_client_root_hash pub(super)
* add tests for LightClientRootHash and block.light_client_root_hash
This commit is contained in:
teor 2020-08-10 10:26:49 +10:00
parent ee6f0de14d
commit 7afd76f5fb
4 changed files with 53 additions and 7 deletions

View File

@ -18,9 +18,11 @@ use proptest_derive::Arbitrary;
use crate::transaction::Transaction;
use crate::types::BlockHeight;
use crate::Network;
pub use hash::BlockHeaderHash;
pub use header::BlockHeader;
pub use light_client::LightClientRootHash;
/// A block in your blockchain.
///
@ -91,6 +93,23 @@ impl Block {
pub fn hash(&self) -> BlockHeaderHash {
BlockHeaderHash::from(self)
}
/// Get the parsed light client root hash for this block.
///
/// The interpretation of the light client root hash depends on the
/// configured `network`, and this block's height.
///
/// Returns None if this block does not have a block height.
pub fn light_client_root_hash(&self, network: Network) -> Option<LightClientRootHash> {
match self.coinbase_height() {
Some(height) => Some(LightClientRootHash::from_bytes(
self.header.light_client_root_hash,
network,
height,
)),
None => None,
}
}
}
impl<'a> From<&'a Block> for BlockHeaderHash {

View File

@ -37,8 +37,9 @@ pub struct BlockHeader {
/// The light client root hash.
///
/// This field is interpreted differently, based on the current
/// block height. See LightClientRootHash for details.
pub light_client_root_hash: [u8; 32],
/// block height. Use `block.light_client_root_hash(network)` to get the
/// parsed `LightClientRootHash` for this block.
pub(super) light_client_root_hash: [u8; 32],
/// The block timestamp is a Unix epoch time (UTC) when the miner
/// started hashing the header (according to the miner).

View File

@ -2,7 +2,7 @@
use crate::note_commitment_tree::SaplingNoteTreeRootHash;
use crate::types::BlockHeight;
use crate::Network;
use crate::{Network, NetworkUpgrade, NetworkUpgrade::*};
/// Light client root hashes.
///
@ -50,12 +50,20 @@ impl LightClientRootHash {
network: Network,
height: BlockHeight,
) -> LightClientRootHash {
// TODO(teor): use the correct network upgrade here, after moving the
// network upgrades from zebra-consensus to zebra-chain.
LightClientRootHash::PreSaplingReserved(bytes)
use LightClientRootHash::*;
match NetworkUpgrade::current(network, height) {
Genesis | BeforeOverwinter | Overwinter => PreSaplingReserved(bytes),
Sapling | Blossom => FinalSaplingRoot(SaplingNoteTreeRootHash(bytes)),
Heartwood if Some(height) == Heartwood.activation_height(network) => {
ChainHistoryActivationReserved(bytes)
}
Heartwood | Canopy => ChainHistoryRoot(ChainHistoryMmrRootHash(bytes)),
}
}
/// Returns the serialized bytes for this LightClientRootHash.
#[allow(dead_code)]
pub fn to_bytes(self) -> [u8; 32] {
use LightClientRootHash::*;

View File

@ -228,6 +228,14 @@ proptest! {
prop_assert_eq![header, other_header];
}
#[test]
fn light_client_roundtrip(bytes in any::<[u8; 32]>(), network in any::<Network>(), block_height in any::<BlockHeight>()) {
let light_hash = LightClientRootHash::from_bytes(bytes, network, block_height);
let other_bytes = light_hash.to_bytes();
prop_assert_eq![bytes, other_bytes];
}
}
proptest! {
@ -239,12 +247,22 @@ proptest! {
.unwrap_or(16)))]
#[test]
fn block_roundtrip(block in any::<Block>()) {
fn block_roundtrip(block in any::<Block>(), network in any::<Network>()) {
let bytes = block.zcash_serialize_to_vec()?;
let bytes = &mut bytes.as_slice();
// Check the light client root hash
let light_hash = block.light_client_root_hash(network);
if let Some(light_hash) = light_hash {
let light_hash_bytes = light_hash.to_bytes();
prop_assert_eq![block.header.light_client_root_hash, light_hash_bytes];
} else {
prop_assert_eq![block.coinbase_height(), None];
}
// Check the block size limit
if bytes.len() <= MAX_BLOCK_BYTES as _ {
// Check deserialization
let other_block = bytes.zcash_deserialize_into()?;
prop_assert_eq![block, other_block];