mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
Commit to prev_root in block headers (#1764)
* commit to prev_root in block headers * prev_root ready to go, mergeable onto testnet4
This commit is contained in:
parent
fffe5154d2
commit
fbf955dd11
6 changed files with 100 additions and 57 deletions
|
@ -486,23 +486,37 @@ impl Chain {
|
||||||
/// the current txhashset state.
|
/// the current txhashset state.
|
||||||
pub fn set_txhashset_roots(&self, b: &mut Block, is_fork: bool) -> Result<(), Error> {
|
pub fn set_txhashset_roots(&self, b: &mut Block, is_fork: bool) -> Result<(), Error> {
|
||||||
let mut txhashset = self.txhashset.write().unwrap();
|
let mut txhashset = self.txhashset.write().unwrap();
|
||||||
let (roots, sizes) = txhashset::extending_readonly(&mut txhashset, |extension| {
|
let (prev_root, roots, sizes) =
|
||||||
if is_fork {
|
txhashset::extending_readonly(&mut txhashset, |extension| {
|
||||||
pipe::rewind_and_apply_fork(b, extension)?;
|
if is_fork {
|
||||||
}
|
pipe::rewind_and_apply_fork(b, extension)?;
|
||||||
extension.apply_block(b)?;
|
}
|
||||||
Ok((extension.roots(), extension.sizes()))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Carefully destructure these correctly...
|
// Retrieve the header root before we apply the new block
|
||||||
// TODO - Maybe sizes should be a struct to add some type safety here...
|
let prev_root = extension.header_root();
|
||||||
let (_, output_mmr_size, _, kernel_mmr_size) = sizes;
|
|
||||||
|
|
||||||
|
// Apply the latest block to the chain state via the extension.
|
||||||
|
extension.apply_block(b)?;
|
||||||
|
|
||||||
|
Ok((prev_root, extension.roots(), extension.sizes()))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Set the prev_root on the header.
|
||||||
|
b.header.prev_root = prev_root;
|
||||||
|
|
||||||
|
// Set the output, rangeproof and kernel MMR roots.
|
||||||
b.header.output_root = roots.output_root;
|
b.header.output_root = roots.output_root;
|
||||||
b.header.range_proof_root = roots.rproof_root;
|
b.header.range_proof_root = roots.rproof_root;
|
||||||
b.header.kernel_root = roots.kernel_root;
|
b.header.kernel_root = roots.kernel_root;
|
||||||
b.header.output_mmr_size = output_mmr_size;
|
|
||||||
b.header.kernel_mmr_size = kernel_mmr_size;
|
// Set the output and kernel MMR sizes.
|
||||||
|
{
|
||||||
|
// Carefully destructure these correctly...
|
||||||
|
let (_, output_mmr_size, _, kernel_mmr_size) = sizes;
|
||||||
|
b.header.output_mmr_size = output_mmr_size;
|
||||||
|
b.header.kernel_mmr_size = kernel_mmr_size;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -218,6 +218,7 @@ pub fn sync_block_headers(
|
||||||
extension.rewind(&prev_header)?;
|
extension.rewind(&prev_header)?;
|
||||||
|
|
||||||
for header in headers {
|
for header in headers {
|
||||||
|
extension.validate_root(header)?;
|
||||||
extension.apply_header(header)?;
|
extension.apply_header(header)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,6 +501,7 @@ fn verify_block_sums(b: &Block, ext: &mut txhashset::Extension) -> Result<(), Er
|
||||||
/// Fully validate the block by applying it to the txhashset extension.
|
/// Fully validate the block by applying it to the txhashset extension.
|
||||||
/// Check both the txhashset roots and sizes are correct after applying the block.
|
/// Check both the txhashset roots and sizes are correct after applying the block.
|
||||||
fn apply_block_to_txhashset(block: &Block, ext: &mut txhashset::Extension) -> Result<(), Error> {
|
fn apply_block_to_txhashset(block: &Block, ext: &mut txhashset::Extension) -> Result<(), Error> {
|
||||||
|
ext.validate_header_root(&block.header)?;
|
||||||
ext.apply_block(block)?;
|
ext.apply_block(block)?;
|
||||||
ext.validate_roots()?;
|
ext.validate_roots()?;
|
||||||
ext.validate_sizes()?;
|
ext.validate_sizes()?;
|
||||||
|
|
|
@ -701,28 +701,51 @@ impl<'a> HeaderExtension<'a> {
|
||||||
header_hashes.push(current.hash());
|
header_hashes.push(current.hash());
|
||||||
current = self.batch.get_block_header(¤t.previous)?;
|
current = self.batch.get_block_header(¤t.previous)?;
|
||||||
}
|
}
|
||||||
// Include the genesis header as we will re-apply it after truncating the extension.
|
|
||||||
header_hashes.push(genesis.hash());
|
|
||||||
header_hashes.reverse();
|
header_hashes.reverse();
|
||||||
|
|
||||||
// Trucate the extension (back to pos 0).
|
// Trucate the extension (back to pos 0).
|
||||||
self.truncate()?;
|
self.truncate()?;
|
||||||
|
|
||||||
debug!(
|
// Re-apply the genesis header after truncation.
|
||||||
LOGGER,
|
self.apply_header(&genesis)?;
|
||||||
"Re-applying {} headers to extension, from {:?} to {:?}.",
|
|
||||||
header_hashes.len(),
|
|
||||||
header_hashes.first().unwrap(),
|
|
||||||
header_hashes.last().unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
for h in header_hashes {
|
if header_hashes.len() > 0 {
|
||||||
let header = self.batch.get_block_header(&h)?;
|
debug!(
|
||||||
// self.validate_header_root()?;
|
LOGGER,
|
||||||
self.apply_header(&header)?;
|
"Re-applying {} headers to extension, from {:?} to {:?}.",
|
||||||
|
header_hashes.len(),
|
||||||
|
header_hashes.first().unwrap(),
|
||||||
|
header_hashes.last().unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
for h in header_hashes {
|
||||||
|
let header = self.batch.get_block_header(&h)?;
|
||||||
|
self.validate_root(&header)?;
|
||||||
|
self.apply_header(&header)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The root of the header MMR for convenience.
|
||||||
|
pub fn root(&self) -> Hash {
|
||||||
|
self.pmmr.root()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Validate the prev_root of the header against the root of the current header MMR.
|
||||||
|
pub fn validate_root(&self, header: &BlockHeader) -> Result<(), Error> {
|
||||||
|
// If we are validating the genesis block then we have no prev_root.
|
||||||
|
// So we are done here.
|
||||||
|
if header.height == 1 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.root() != header.prev_root {
|
||||||
|
Err(ErrorKind::InvalidRoot.into())
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows the application of new blocks on top of the sum trees in a
|
/// Allows the application of new blocks on top of the sum trees in a
|
||||||
|
@ -1078,14 +1101,19 @@ impl<'a> Extension<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the root of the current header MMR.
|
||||||
|
pub fn header_root(&self) -> Hash {
|
||||||
|
self.header_pmmr.root()
|
||||||
|
}
|
||||||
|
|
||||||
/// Validate the following MMR roots against the latest header applied -
|
/// Validate the following MMR roots against the latest header applied -
|
||||||
/// * output
|
/// * output
|
||||||
/// * rangeproof
|
/// * rangeproof
|
||||||
/// * kernel
|
/// * kernel
|
||||||
///
|
///
|
||||||
/// Note we do not validate the header MMR roots here as we need to validate
|
/// Note we do not validate the header MMR root here as we need to validate
|
||||||
/// a header against the state of the MMR *prior* to applying it as
|
/// a header against the state of the MMR *prior* to applying it.
|
||||||
/// each header commits to the root of the MMR of all previous headers,
|
/// Each header commits to the root of the MMR of all previous headers,
|
||||||
/// not including the header itself.
|
/// not including the header itself.
|
||||||
///
|
///
|
||||||
pub fn validate_roots(&self) -> Result<(), Error> {
|
pub fn validate_roots(&self) -> Result<(), Error> {
|
||||||
|
@ -1107,23 +1135,19 @@ impl<'a> Extension<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate the provided header by comparing its "prev_root" to the
|
/// Validate the provided header by comparing its prev_root to the
|
||||||
/// root of the current header MMR.
|
/// root of the current header MMR.
|
||||||
///
|
pub fn validate_header_root(&self, header: &BlockHeader) -> Result<(), Error> {
|
||||||
/// TODO - Implement this once we commit to prev_root in block headers.
|
if header.height == 1 {
|
||||||
///
|
|
||||||
pub fn validate_header_root(&self, _header: &BlockHeader) -> Result<(), Error> {
|
|
||||||
if self.header.height == 0 {
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let _roots = self.roots();
|
let roots = self.roots();
|
||||||
|
if roots.header_root != header.prev_root {
|
||||||
// TODO - validate once we commit to header MMR root in the header
|
Err(ErrorKind::InvalidRoot.into())
|
||||||
// (not just previous hash)
|
} else {
|
||||||
// if roots.header_root != header.prev_root
|
Ok(())
|
||||||
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate the header, output and kernel MMR sizes against the block header.
|
/// Validate the header, output and kernel MMR sizes against the block header.
|
||||||
|
|
|
@ -118,6 +118,8 @@ pub struct BlockHeader {
|
||||||
pub height: u64,
|
pub height: u64,
|
||||||
/// Hash of the block previous to this in the chain.
|
/// Hash of the block previous to this in the chain.
|
||||||
pub previous: Hash,
|
pub previous: Hash,
|
||||||
|
/// Root hash of the header MMR at the previous header.
|
||||||
|
pub prev_root: Hash,
|
||||||
/// Timestamp at which the block was built.
|
/// Timestamp at which the block was built.
|
||||||
pub timestamp: DateTime<Utc>,
|
pub timestamp: DateTime<Utc>,
|
||||||
/// Merklish root of all the commitments in the TxHashSet
|
/// Merklish root of all the commitments in the TxHashSet
|
||||||
|
@ -143,8 +145,9 @@ fn fixed_size_of_serialized_header(_version: u16) -> usize {
|
||||||
let mut size: usize = 0;
|
let mut size: usize = 0;
|
||||||
size += mem::size_of::<u16>(); // version
|
size += mem::size_of::<u16>(); // version
|
||||||
size += mem::size_of::<u64>(); // height
|
size += mem::size_of::<u64>(); // height
|
||||||
|
size += mem::size_of::<i64>(); // timestamp
|
||||||
size += mem::size_of::<Hash>(); // previous
|
size += mem::size_of::<Hash>(); // previous
|
||||||
size += mem::size_of::<u64>(); // timestamp
|
size += mem::size_of::<Hash>(); // prev_root
|
||||||
size += mem::size_of::<Hash>(); // output_root
|
size += mem::size_of::<Hash>(); // output_root
|
||||||
size += mem::size_of::<Hash>(); // range_proof_root
|
size += mem::size_of::<Hash>(); // range_proof_root
|
||||||
size += mem::size_of::<Hash>(); // kernel_root
|
size += mem::size_of::<Hash>(); // kernel_root
|
||||||
|
@ -176,8 +179,9 @@ impl Default for BlockHeader {
|
||||||
BlockHeader {
|
BlockHeader {
|
||||||
version: 1,
|
version: 1,
|
||||||
height: 0,
|
height: 0,
|
||||||
previous: ZERO_HASH,
|
|
||||||
timestamp: DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc),
|
timestamp: DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(0, 0), Utc),
|
||||||
|
previous: ZERO_HASH,
|
||||||
|
prev_root: ZERO_HASH,
|
||||||
output_root: ZERO_HASH,
|
output_root: ZERO_HASH,
|
||||||
range_proof_root: ZERO_HASH,
|
range_proof_root: ZERO_HASH,
|
||||||
kernel_root: ZERO_HASH,
|
kernel_root: ZERO_HASH,
|
||||||
|
@ -211,9 +215,9 @@ impl Writeable for BlockHeader {
|
||||||
/// Deserialization of a block header
|
/// Deserialization of a block header
|
||||||
impl Readable for BlockHeader {
|
impl Readable for BlockHeader {
|
||||||
fn read(reader: &mut Reader) -> Result<BlockHeader, ser::Error> {
|
fn read(reader: &mut Reader) -> Result<BlockHeader, ser::Error> {
|
||||||
let (version, height) = ser_multiread!(reader, read_u16, read_u64);
|
let (version, height, timestamp) = ser_multiread!(reader, read_u16, read_u64, read_i64);
|
||||||
let previous = Hash::read(reader)?;
|
let previous = Hash::read(reader)?;
|
||||||
let timestamp = reader.read_i64()?;
|
let prev_root = Hash::read(reader)?;
|
||||||
let output_root = Hash::read(reader)?;
|
let output_root = Hash::read(reader)?;
|
||||||
let range_proof_root = Hash::read(reader)?;
|
let range_proof_root = Hash::read(reader)?;
|
||||||
let kernel_root = Hash::read(reader)?;
|
let kernel_root = Hash::read(reader)?;
|
||||||
|
@ -230,8 +234,9 @@ impl Readable for BlockHeader {
|
||||||
Ok(BlockHeader {
|
Ok(BlockHeader {
|
||||||
version,
|
version,
|
||||||
height,
|
height,
|
||||||
previous,
|
|
||||||
timestamp: DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(timestamp, 0), Utc),
|
timestamp: DateTime::<Utc>::from_utc(NaiveDateTime::from_timestamp(timestamp, 0), Utc),
|
||||||
|
previous,
|
||||||
|
prev_root,
|
||||||
output_root,
|
output_root,
|
||||||
range_proof_root,
|
range_proof_root,
|
||||||
kernel_root,
|
kernel_root,
|
||||||
|
@ -250,11 +255,9 @@ impl BlockHeader {
|
||||||
writer,
|
writer,
|
||||||
[write_u16, self.version],
|
[write_u16, self.version],
|
||||||
[write_u64, self.height],
|
[write_u64, self.height],
|
||||||
|
[write_i64, self.timestamp.timestamp()],
|
||||||
[write_fixed_bytes, &self.previous],
|
[write_fixed_bytes, &self.previous],
|
||||||
[write_i64, self.timestamp.timestamp()]
|
[write_fixed_bytes, &self.prev_root],
|
||||||
);
|
|
||||||
ser_multiwrite!(
|
|
||||||
writer,
|
|
||||||
[write_fixed_bytes, &self.output_root],
|
[write_fixed_bytes, &self.output_root],
|
||||||
[write_fixed_bytes, &self.range_proof_root],
|
[write_fixed_bytes, &self.range_proof_root],
|
||||||
[write_fixed_bytes, &self.kernel_root],
|
[write_fixed_bytes, &self.kernel_root],
|
||||||
|
|
|
@ -257,7 +257,7 @@ fn empty_block_serialized_size() {
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||||
let target_len = 1_223;
|
let target_len = 1_255;
|
||||||
assert_eq!(vec.len(), target_len);
|
assert_eq!(vec.len(), target_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ fn block_single_tx_serialized_size() {
|
||||||
let b = new_block(vec![&tx1], &keychain, &prev, &key_id);
|
let b = new_block(vec![&tx1], &keychain, &prev, &key_id);
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||||
let target_len = 2_805;
|
let target_len = 2_837;
|
||||||
assert_eq!(vec.len(), target_len);
|
assert_eq!(vec.len(), target_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ fn empty_compact_block_serialized_size() {
|
||||||
let cb: CompactBlock = b.into();
|
let cb: CompactBlock = b.into();
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
||||||
let target_len = 1_231;
|
let target_len = 1_263;
|
||||||
assert_eq!(vec.len(), target_len);
|
assert_eq!(vec.len(), target_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,7 +297,7 @@ fn compact_block_single_tx_serialized_size() {
|
||||||
let cb: CompactBlock = b.into();
|
let cb: CompactBlock = b.into();
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
||||||
let target_len = 1_237;
|
let target_len = 1_269;
|
||||||
assert_eq!(vec.len(), target_len);
|
assert_eq!(vec.len(), target_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,7 +316,7 @@ fn block_10_tx_serialized_size() {
|
||||||
let b = new_block(txs.iter().collect(), &keychain, &prev, &key_id);
|
let b = new_block(txs.iter().collect(), &keychain, &prev, &key_id);
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||||
let target_len = 17_043;
|
let target_len = 17_075;
|
||||||
assert_eq!(vec.len(), target_len,);
|
assert_eq!(vec.len(), target_len,);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,7 +335,7 @@ fn compact_block_10_tx_serialized_size() {
|
||||||
let cb: CompactBlock = b.into();
|
let cb: CompactBlock = b.into();
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
ser::serialize(&mut vec, &cb).expect("serialization failed");
|
||||||
let target_len = 1_291;
|
let target_len = 1_323;
|
||||||
assert_eq!(vec.len(), target_len,);
|
assert_eq!(vec.len(), target_len,);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,9 +95,9 @@ fn build_block(
|
||||||
key_id: Option<Identifier>,
|
key_id: Option<Identifier>,
|
||||||
wallet_listener_url: Option<String>,
|
wallet_listener_url: Option<String>,
|
||||||
) -> Result<(core::Block, BlockFees), Error> {
|
) -> Result<(core::Block, BlockFees), Error> {
|
||||||
// prepare the block header timestamp
|
|
||||||
let head = chain.head_header()?;
|
let head = chain.head_header()?;
|
||||||
|
|
||||||
|
// prepare the block header timestamp
|
||||||
let mut now_sec = Utc::now().timestamp();
|
let mut now_sec = Utc::now().timestamp();
|
||||||
let head_sec = head.timestamp.timestamp();
|
let head_sec = head.timestamp.timestamp();
|
||||||
if now_sec <= head_sec {
|
if now_sec <= head_sec {
|
||||||
|
|
Loading…
Reference in a new issue