HeaderEntry for storing subset of header info in the header MMR (#2137)

* HeaderEntry for storing subset of header info in the header MMR

* cleanup

* cleanup
This commit is contained in:
Antioch Peverell 2018-12-13 09:57:24 +00:00 committed by GitHub
parent 675edb4a19
commit 793e3843f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 72 additions and 7 deletions

View file

@ -204,8 +204,8 @@ impl TxHashSet {
let pos = pmmr::insertion_to_pmmr_index(height + 1);
let header_pmmr =
ReadonlyPMMR::at(&self.header_pmmr_h.backend, self.header_pmmr_h.last_pos);
if let Some(hash) = header_pmmr.get_data(pos) {
let header = self.commit_index.get_block_header(&hash)?;
if let Some(entry) = header_pmmr.get_data(pos) {
let header = self.commit_index.get_block_header(&entry.hash())?;
Ok(header)
} else {
Err(ErrorKind::Other(format!("get header by height")).into())
@ -613,7 +613,7 @@ impl<'a> HeaderExtension<'a> {
/// Get the header hash for the specified pos from the underlying MMR backend.
fn get_header_hash(&self, pos: u64) -> Option<Hash> {
self.pmmr.get_data(pos)
self.pmmr.get_data(pos).map(|x| x.hash())
}
/// Get the header at the specified height based on the current state of the header extension.
@ -989,7 +989,7 @@ impl<'a> Extension<'a> {
/// Get the header hash for the specified pos from the underlying MMR backend.
fn get_header_hash(&self, pos: u64) -> Option<Hash> {
self.header_pmmr.get_data(pos)
self.header_pmmr.get_data(pos).map(|x| x.hash())
}
/// Get the header at the specified height based on the current state of the extension.

View file

@ -34,7 +34,7 @@ use crate::core::{
use crate::global;
use crate::keychain::{self, BlindingFactor};
use crate::pow::{Difficulty, Proof, ProofOfWork};
use crate::ser::{self, PMMRable, Readable, Reader, Writeable, Writer};
use crate::ser::{self, FixedLength, PMMRable, Readable, Reader, Writeable, Writer};
use crate::util::{secp, static_secp_instance};
/// Errors thrown by Block validation
@ -109,6 +109,65 @@ impl fmt::Display for Error {
}
}
/// Header entry for storing in the header MMR.
/// Note: we hash the block header itself and maintain the hash in the entry.
/// This allows us to lookup the original header from the db as necessary.
pub struct HeaderEntry {
hash: Hash,
timestamp: u64,
total_difficulty: Difficulty,
secondary_scaling: u32,
is_secondary: bool,
}
impl Readable for HeaderEntry {
fn read(reader: &mut Reader) -> Result<HeaderEntry, ser::Error> {
let hash = Hash::read(reader)?;
let timestamp = reader.read_u64()?;
let total_difficulty = Difficulty::read(reader)?;
let secondary_scaling = reader.read_u32()?;
// Using a full byte to represent the bool for now.
let is_secondary = reader.read_u8()? != 0;
Ok(HeaderEntry {
hash,
timestamp,
total_difficulty,
secondary_scaling,
is_secondary,
})
}
}
impl Writeable for HeaderEntry {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
self.hash.write(writer)?;
writer.write_u64(self.timestamp)?;
self.total_difficulty.write(writer)?;
writer.write_u32(self.secondary_scaling)?;
// Using a full byte to represent the bool for now.
if self.is_secondary {
writer.write_u8(1)?;
} else {
writer.write_u8(0)?;
}
Ok(())
}
}
impl FixedLength for HeaderEntry {
const LEN: usize = Hash::LEN + 8 + Difficulty::LEN + 4 + 1;
}
impl HeaderEntry {
/// The hash of the underlying block.
pub fn hash(&self) -> Hash {
self.hash
}
}
/// Block header, fairly standard compared to other blockchains.
#[derive(Clone, Debug, PartialEq)]
pub struct BlockHeader {
@ -160,10 +219,16 @@ impl Default for BlockHeader {
}
impl PMMRable for BlockHeader {
type E = Hash;
type E = HeaderEntry;
fn as_elmt(&self) -> Self::E {
self.hash()
HeaderEntry {
hash: self.hash(),
timestamp: self.timestamp.timestamp() as u64,
total_difficulty: self.total_difficulty(),
secondary_scaling: self.pow.secondary_scaling,
is_secondary: self.pow.is_secondary(),
}
}
}