Block header needs its own deserialization. Fixed pow verify to use the block target.

This commit is contained in:
Ignotus Peverell 2016-11-16 14:08:46 -08:00
parent 1d2b23a4a5
commit ca26f0c3f7
No known key found for this signature in database
GPG key ID: 99CD25F39F8F8211
2 changed files with 45 additions and 38 deletions

View file

@ -64,8 +64,7 @@ impl Default for BlockHeader {
} }
} }
// Only Writeable implementation is required for hashing, which is part of /// Serialization of a block header
// core. Readable is in the ser package.
impl Writeable for BlockHeader { impl Writeable for BlockHeader {
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> { fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
ser_multiwrite!(writer, ser_multiwrite!(writer,
@ -88,6 +87,37 @@ impl Writeable for BlockHeader {
} }
} }
/// Deserialization of a block header
impl Readable<BlockHeader> for BlockHeader {
fn read(reader: &mut Reader) -> Result<BlockHeader, ser::Error> {
let (height, previous, timestamp, cuckoo_len) =
ser_multiread!(reader, read_u64, read_32_bytes, read_i64, read_u8);
let target = try!(Target::read(reader));
let (utxo_merkle, tx_merkle, nonce) =
ser_multiread!(reader, read_32_bytes, read_32_bytes, read_u64);
// cuckoo cycle of 42 nodes
let mut pow = [0; PROOFSIZE];
for n in 0..PROOFSIZE {
pow[n] = try!(reader.read_u32());
}
Ok(BlockHeader {
height: height,
previous: Hash::from_vec(previous),
timestamp: time::at_utc(time::Timespec {
sec: timestamp,
nsec: 0,
}),
cuckoo_len: cuckoo_len,
target: target,
utxo_merkle: Hash::from_vec(utxo_merkle),
tx_merkle: Hash::from_vec(tx_merkle),
pow: Proof(pow),
nonce: nonce,
})
}
}
/// A block as expressed in the MimbleWimble protocol. The reward is /// A block as expressed in the MimbleWimble protocol. The reward is
/// non-explicit, assumed to be deductible from block height (similar to /// non-explicit, assumed to be deductible from block height (similar to
/// bitcoin's schedule) and expressed as a global transaction fee (added v.H), /// bitcoin's schedule) and expressed as a global transaction fee (added v.H),
@ -127,24 +157,14 @@ impl Writeable for Block {
/// from a binary stream. /// from a binary stream.
impl Readable<Block> for Block { impl Readable<Block> for Block {
fn read(reader: &mut Reader) -> Result<Block, ser::Error> { fn read(reader: &mut Reader) -> Result<Block, ser::Error> {
let (height, previous, timestamp, cuckoo_len) = let header = try!(BlockHeader::read(reader));
ser_multiread!(reader, read_u64, read_32_bytes, read_i64, read_u8);
let target = try!(Target::read(reader));
let (utxo_merkle, tx_merkle, nonce) =
ser_multiread!(reader, read_32_bytes, read_32_bytes, read_u64);
// cuckoo cycle of 42 nodes let (input_len, output_len, proof_len) =
let mut pow = [0; PROOFSIZE]; ser_multiread!(reader, read_u64, read_u64, read_u64);
for n in 0..PROOFSIZE {
pow[n] = try!(reader.read_u32());
}
let (td, input_len, output_len, proof_len) =
ser_multiread!(reader, read_u64, read_u64, read_u64, read_u64);
if input_len > MAX_IN_OUT_LEN || output_len > MAX_IN_OUT_LEN || proof_len > MAX_IN_OUT_LEN { if input_len > MAX_IN_OUT_LEN || output_len > MAX_IN_OUT_LEN || proof_len > MAX_IN_OUT_LEN {
return Err(ser::Error::TooLargeReadErr("Too many inputs, outputs or proofs." return Err(ser::Error::TooLargeReadErr(
.to_string())); "Too many inputs, outputs or proofs.".to_string()));
} }
let inputs = try!((0..input_len).map(|_| Input::read(reader)).collect()); let inputs = try!((0..input_len).map(|_| Input::read(reader)).collect());
@ -152,20 +172,7 @@ impl Readable<Block> for Block {
let proofs = try!((0..proof_len).map(|_| TxProof::read(reader)).collect()); let proofs = try!((0..proof_len).map(|_| TxProof::read(reader)).collect());
Ok(Block { Ok(Block {
header: BlockHeader { header: header,
height: height,
previous: Hash::from_vec(previous),
timestamp: time::at_utc(time::Timespec {
sec: timestamp,
nsec: 0,
}),
cuckoo_len: cuckoo_len,
target: target,
utxo_merkle: Hash::from_vec(utxo_merkle),
tx_merkle: Hash::from_vec(tx_merkle),
pow: Proof(pow),
nonce: nonce,
},
inputs: inputs, inputs: inputs,
outputs: outputs, outputs: outputs,
proofs: proofs, proofs: proofs,

View file

@ -88,21 +88,21 @@ impl PowHeader {
} }
/// Validates the proof of work of a given header. /// Validates the proof of work of a given header.
pub fn verify(b: &Block, target: Target) -> bool { pub fn verify(b: &Block) -> bool {
verify_size(b, target, b.header.cuckoo_len as u32) verify_size(b, b.header.cuckoo_len as u32)
} }
/// Same as default verify function but uses the much easier Cuckoo20 (mostly /// Same as default verify function but uses the much easier Cuckoo20 (mostly
/// for tests). /// for tests).
pub fn verify20(b: &Block, target: Target) -> bool { pub fn verify20(b: &Block) -> bool {
verify_size(b, target, 20) verify_size(b, 20)
} }
pub fn verify_size(b: &Block, target: Target, sizeshift: u32) -> bool { pub fn verify_size(b: &Block, sizeshift: u32) -> bool {
let hash = PowHeader::from_block(b).hash(); let hash = PowHeader::from_block(b).hash();
// make sure the hash is smaller than our target before going into more // make sure the hash is smaller than our target before going into more
// expensive validation // expensive validation
if target < b.header.pow.to_target() { if b.header.target < b.header.pow.to_target() {
return false; return false;
} }
Cuckoo::new(hash.to_slice(), sizeshift).verify(b.header.pow, EASINESS as u64) Cuckoo::new(hash.to_slice(), sizeshift).verify(b.header.pow, EASINESS as u64)
@ -165,6 +165,6 @@ mod test {
assert!(proof.to_target() < MAX_TARGET); assert!(proof.to_target() < MAX_TARGET);
b.header.pow = proof; b.header.pow = proof;
b.header.nonce = nonce; b.header.nonce = nonce;
assert!(verify20(&b, MAX_TARGET)); assert!(verify20(&b));
} }
} }