Build block header from pre pow data and proof (#3178)

* Implement validation and generation of block header by proof and pre pow

* Optimize

* handle missed ser result errors and test invalid pre_pow

* switch to specific error mapping

* clean import
This commit is contained in:
Austin Abell 2020-01-23 09:29:54 -05:00 committed by Antioch Peverell
parent 4449c91c04
commit 4152d9fc0c
2 changed files with 56 additions and 1 deletions

View file

@ -25,7 +25,10 @@ use crate::core::{
};
use crate::global;
use crate::pow::{verify_size, Difficulty, Proof, ProofOfWork};
use crate::ser::{self, FixedLength, PMMRable, Readable, Reader, Writeable, Writer};
use crate::ser::{
self, deserialize_default, serialize_default, FixedLength, PMMRable, Readable, Reader,
Writeable, Writer,
};
use chrono::naive::{MAX_DATE, MIN_DATE};
use chrono::prelude::{DateTime, NaiveDateTime, Utc};
use chrono::Duration;
@ -34,6 +37,7 @@ use std::collections::HashSet;
use std::fmt;
use std::iter::FromIterator;
use std::sync::Arc;
use util::from_hex;
use util::RwLock;
use util::{secp, static_secp_instance};
@ -350,6 +354,23 @@ impl BlockHeader {
header_buf
}
/// Constructs a header given pre_pow string, nonce, and proof
pub fn from_pre_pow_and_proof(
pre_pow: String,
nonce: u64,
proof: Proof,
) -> Result<Self, Error> {
// Convert hex pre pow string
let mut header_bytes = from_hex(pre_pow)
.map_err(|e| Error::Serialization(ser::Error::HexError(e.to_string())))?;
// Serialize and append serialized nonce and proof
serialize_default(&mut header_bytes, &nonce)?;
serialize_default(&mut header_bytes, &proof)?;
// Deserialize header from constructed bytes
Ok(deserialize_default(&mut &header_bytes[..])?)
}
/// Total difficulty accumulated by the proof of work on this header
pub fn total_difficulty(&self) -> Difficulty {
self.pow.total_difficulty

View file

@ -26,6 +26,7 @@ use crate::core::core::{
};
use crate::core::libtx::build::{self, input, output};
use crate::core::libtx::ProofBuilder;
use crate::core::pow::Proof;
use crate::core::{global, ser};
use chrono::Duration;
use grin_core as core;
@ -569,3 +570,36 @@ fn wrong_amount_range_proof() {
_ => panic!("Bad range proof should be invalid"),
}
}
#[test]
fn validate_header_proof() {
let keychain = ExtKeychain::from_random_seed(false).unwrap();
let builder = ProofBuilder::new(&keychain);
let prev = BlockHeader::default();
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
let b = new_block(vec![], &keychain, &builder, &prev, &key_id);
let mut header_buf = vec![];
{
let mut writer = ser::BinWriter::default(&mut header_buf);
b.header.write_pre_pow(&mut writer).unwrap();
b.header.pow.write_pre_pow(&mut writer).unwrap();
}
let pre_pow = util::to_hex(header_buf);
let reconstructed = BlockHeader::from_pre_pow_and_proof(
pre_pow,
b.header.pow.nonce,
b.header.pow.proof.clone(),
)
.unwrap();
assert_eq!(reconstructed, b.header);
// assert invalid pre_pow returns error
assert!(BlockHeader::from_pre_pow_and_proof(
"0xaf1678".to_string(),
b.header.pow.nonce,
b.header.pow.proof.clone(),
)
.is_err());
}