mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 11:31:08 +03:00
compact block needs a random nonce in it (used to generate short_ids) (#709)
This commit is contained in:
parent
6fb139670e
commit
8bdf0be73e
2 changed files with 39 additions and 28 deletions
|
@ -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()],
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue