compact block needs a random nonce in it (used to generate short_ids) (#709)

This commit is contained in:
Antioch Peverell 2018-02-14 09:19:24 -05:00 committed by GitHub
parent 6fb139670e
commit 8bdf0be73e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 28 deletions

View file

@ -15,8 +15,7 @@
//! Blocks and blockheaders //! Blocks and blockheaders
use time; use time;
use util; use rand::{thread_rng, Rng};
use util::{secp, static_secp_instance};
use std::collections::HashSet; use std::collections::HashSet;
use core::{ use core::{
@ -39,11 +38,13 @@ use core::id::ShortIdentifiable;
use core::target::Difficulty; use core::target::Difficulty;
use core::transaction; use core::transaction;
use ser::{self, Readable, Reader, Writeable, Writer, WriteableSorted, read_and_verify_sorted}; use ser::{self, Readable, Reader, Writeable, Writer, WriteableSorted, read_and_verify_sorted};
use util::kernel_sig_msg;
use util::LOGGER;
use global; use global;
use keychain; use keychain;
use keychain::BlindingFactor; use keychain::BlindingFactor;
use util;
use util::kernel_sig_msg;
use util::LOGGER;
use util::{secp, static_secp_instance};
/// Errors thrown by Block validation /// Errors thrown by Block validation
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -221,6 +222,8 @@ impl Readable for BlockHeader {
pub struct CompactBlock { pub struct CompactBlock {
/// The header with metadata and commitments to the rest of the data /// The header with metadata and commitments to the rest of the data
pub header: BlockHeader, pub header: BlockHeader,
/// Nonce for connection specific short_ids
pub nonce: u64,
/// List of full outputs - specifically the coinbase output(s) /// List of full outputs - specifically the coinbase output(s)
pub out_full: Vec<Output>, pub out_full: Vec<Output>,
/// List of full kernels - specifically the coinbase kernel(s) /// List of full kernels - specifically the coinbase kernel(s)
@ -235,10 +238,10 @@ pub struct CompactBlock {
impl Writeable for CompactBlock { impl Writeable for CompactBlock {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> { fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
try!(self.header.write(writer)); try!(self.header.write(writer));
if writer.serialization_mode() != ser::SerializationMode::Hash { if writer.serialization_mode() != ser::SerializationMode::Hash {
ser_multiwrite!( ser_multiwrite!(
writer, writer,
[write_u64, self.nonce],
[write_u64, self.out_full.len() as u64], [write_u64, self.out_full.len() as u64],
[write_u64, self.kern_full.len() as u64], [write_u64, self.kern_full.len() as u64],
[write_u64, self.kern_ids.len() as u64] [write_u64, self.kern_ids.len() as u64]
@ -263,8 +266,8 @@ impl Readable for CompactBlock {
fn read(reader: &mut Reader) -> Result<CompactBlock, ser::Error> { fn read(reader: &mut Reader) -> Result<CompactBlock, ser::Error> {
let header = try!(BlockHeader::read(reader)); let header = try!(BlockHeader::read(reader));
let (out_full_len, kern_full_len, kern_id_len) = let (nonce, out_full_len, kern_full_len, kern_id_len) =
ser_multiread!(reader, read_u64, read_u64, read_u64); ser_multiread!(reader, read_u64, read_u64, read_u64, read_u64);
let out_full = read_and_verify_sorted(reader, out_full_len as u64)?; let out_full = read_and_verify_sorted(reader, out_full_len as u64)?;
let kern_full = read_and_verify_sorted(reader, kern_full_len as u64)?; let kern_full = read_and_verify_sorted(reader, kern_full_len as u64)?;
@ -272,6 +275,7 @@ impl Readable for CompactBlock {
Ok(CompactBlock { Ok(CompactBlock {
header, header,
nonce,
out_full, out_full,
kern_full, kern_full,
kern_ids, kern_ids,
@ -447,24 +451,27 @@ impl Block {
/// Generate the compact block representation. /// Generate the compact block representation.
pub fn as_compact_block(&self) -> CompactBlock { pub fn as_compact_block(&self) -> CompactBlock {
let header = self.header.clone(); let header = self.header.clone();
let block_hash = self.hash(); let nonce = thread_rng().next_u64();
// concatenate the nonce with our block_header to build the hash
let hash = (self, nonce).hash();
let mut out_full = self.outputs let mut out_full = self.outputs
.iter() .iter()
.filter(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT)) .filter(|x| x.features.contains(OutputFeatures::COINBASE_OUTPUT))
.cloned() .cloned()
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let mut kern_full = self.kernels
.iter()
.filter(|x| x.features.contains(KernelFeatures::COINBASE_KERNEL))
.cloned()
.collect::<Vec<_>>();
let mut kern_ids = self.kernels let mut kern_full = vec![];
.iter() let mut kern_ids = vec![];
.filter(|x| !x.features.contains(KernelFeatures::COINBASE_KERNEL))
.map(|x| x.short_id(&block_hash)) for k in &self.kernels {
.collect::<Vec<_>>(); if k.features.contains(KernelFeatures::COINBASE_KERNEL) {
kern_full.push(k.clone());
} else {
kern_ids.push(k.short_id(&hash));
}
}
// sort all the lists // sort all the lists
out_full.sort(); out_full.sort();
@ -473,6 +480,7 @@ impl Block {
CompactBlock { CompactBlock {
header, header,
nonce,
out_full, out_full,
kern_full, kern_full,
kern_ids, kern_ids,
@ -1081,7 +1089,7 @@ mod test {
ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed"); ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed");
assert_eq!( assert_eq!(
vec.len(), vec.len(),
5_708, 5_716,
); );
} }
@ -1094,7 +1102,7 @@ mod test {
ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed"); ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed");
assert_eq!( assert_eq!(
vec.len(), vec.len(),
5_714, 5_722,
); );
} }
@ -1138,7 +1146,7 @@ mod test {
ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed"); ser::serialize(&mut vec, &b.as_compact_block()).expect("serialization failed");
assert_eq!( assert_eq!(
vec.len(), vec.len(),
5_768, 5_776,
); );
} }
@ -1147,9 +1155,10 @@ mod test {
let keychain = Keychain::from_random_seed().unwrap(); let keychain = Keychain::from_random_seed().unwrap();
let tx1 = tx1i2o(); let tx1 = tx1i2o();
let b = new_block(vec![&tx1], &keychain); let b = new_block(vec![&tx1], &keychain);
let cb = b.as_compact_block(); let cb = b.as_compact_block();
let hash = (b.header, cb.nonce).hash();
assert_eq!(cb.out_full.len(), 1); assert_eq!(cb.out_full.len(), 1);
assert_eq!(cb.kern_full.len(), 1); assert_eq!(cb.kern_full.len(), 1);
assert_eq!(cb.kern_ids.len(), 1); assert_eq!(cb.kern_ids.len(), 1);
@ -1160,7 +1169,7 @@ mod test {
.iter() .iter()
.find(|x| !x.features.contains(KernelFeatures::COINBASE_KERNEL)) .find(|x| !x.features.contains(KernelFeatures::COINBASE_KERNEL))
.unwrap() .unwrap()
.short_id(&b.hash()) .short_id(&hash)
); );
} }
@ -1179,6 +1188,7 @@ mod test {
fn serialize_deserialize_compact_block() { fn serialize_deserialize_compact_block() {
let b = CompactBlock { let b = CompactBlock {
header: BlockHeader::default(), header: BlockHeader::default(),
nonce: 0,
out_full: vec![], out_full: vec![],
kern_full: vec![], kern_full: vec![],
kern_ids: vec![ShortId::zero()], kern_ids: vec![ShortId::zero()],

View file

@ -30,8 +30,9 @@ pub const SHORT_ID_SIZE: usize = 6;
/// A trait for types that have a short_id (inputs/outputs/kernels) /// A trait for types that have a short_id (inputs/outputs/kernels)
pub trait ShortIdentifiable { pub trait ShortIdentifiable {
/// The short_id of the instance. /// The short_id of a kernel uses a hash built from the block_header *and* a
fn short_id(&self, block_hash: &Hash) -> ShortId; /// connection specific nonce to minimize the effect of collisions.
fn short_id(&self, hash: &Hash) -> ShortId;
} }
impl<H: Hashed> ShortIdentifiable for H { impl<H: Hashed> ShortIdentifiable for H {
@ -42,14 +43,14 @@ impl<H: Hashed> ShortIdentifiable for H {
/// * self.hash() passing in the siphasher24 instance /// * self.hash() passing in the siphasher24 instance
/// * drop the 2 most significant bytes (to return a 6 byte short_id) /// * drop the 2 most significant bytes (to return a 6 byte short_id)
/// ///
fn short_id(&self, block_hash: &Hash) -> ShortId { fn short_id(&self, hash: &Hash) -> ShortId {
// we "use" core::hash::Hash in the outer namespace // we "use" core::hash::Hash in the outer namespace
// so doing this here in the fn to minimize collateral damage/confusion // so doing this here in the fn to minimize collateral damage/confusion
use std::hash::Hasher; use std::hash::Hasher;
// extract k0/k1 from the block_hash // extract k0/k1 from the block_hash
let k0 = LittleEndian::read_u64(&block_hash.0[0..8]); let k0 = LittleEndian::read_u64(&hash.0[0..8]);
let k1 = LittleEndian::read_u64(&block_hash.0[8..16]); let k1 = LittleEndian::read_u64(&hash.0[8..16]);
// initialize a siphasher24 with k0/k1 // initialize a siphasher24 with k0/k1
let mut sip_hasher = SipHasher24::new_with_keys(k0, k1); let mut sip_hasher = SipHasher24::new_with_keys(k0, k1);