mirror of
https://github.com/mimblewimble/grin.git
synced 2025-05-09 10:41:17 +03:00
unit tests for coinbase flags (output and tx kernel) (#99)
* add tests around flipping COINBASE_OUTPUT and COINBASE_KERNEL flags * add serialize_deserialize test for a minimal block
This commit is contained in:
parent
045f5bb4da
commit
babb6110c4
2 changed files with 97 additions and 10 deletions
core/src/core
|
@ -38,6 +38,7 @@ bitflags! {
|
|||
}
|
||||
|
||||
/// Block header, fairly standard compared to other blockchains.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct BlockHeader {
|
||||
/// Height of this block since the genesis block (height 0)
|
||||
pub height: u64,
|
||||
|
@ -136,6 +137,7 @@ impl Readable for BlockHeader {
|
|||
/// non-explicit, assumed to be deducible from block height (similar to
|
||||
/// bitcoin's schedule) and expressed as a global transaction fee (added v.H),
|
||||
/// additive to the total of fees ever collected.
|
||||
#[derive(Debug)]
|
||||
pub struct Block {
|
||||
/// The header with metadata and commitments to the rest of the data
|
||||
pub header: BlockHeader,
|
||||
|
@ -381,16 +383,20 @@ impl Block {
|
|||
pub fn validate(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
|
||||
self.verify_coinbase(secp)?;
|
||||
self.verify_kernels(secp)?;
|
||||
|
||||
// verify the transaction Merkle root
|
||||
let tx_merkle = merkle_inputs_outputs(&self.inputs, &self.outputs);
|
||||
if tx_merkle != self.header.tx_merkle {
|
||||
// TODO more specific error
|
||||
return Err(secp::Error::IncorrectCommitSum);
|
||||
}
|
||||
Ok(())
|
||||
self.verify_merkle_inputs_outputs()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify the transaction Merkle root
|
||||
pub fn verify_merkle_inputs_outputs(&self) -> Result<(), secp::Error> {
|
||||
let tx_merkle = merkle_inputs_outputs(&self.inputs, &self.outputs);
|
||||
if tx_merkle != self.header.tx_merkle {
|
||||
// TODO more specific error
|
||||
return Err(secp::Error::IncorrectCommitSum);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate the sum of input/output commitments match the sum in kernels
|
||||
/// and
|
||||
/// that all kernel signatures are valid.
|
||||
|
@ -551,4 +557,85 @@ mod test {
|
|||
assert_eq!(b3.inputs.len(), 3);
|
||||
assert_eq!(b3.outputs.len(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_block_with_coinbase_is_valid() {
|
||||
let ref secp = new_secp();
|
||||
let b = new_block(vec![], secp);
|
||||
|
||||
assert_eq!(b.inputs.len(), 0);
|
||||
assert_eq!(b.outputs.len(), 1);
|
||||
assert_eq!(b.kernels.len(), 1);
|
||||
|
||||
let coinbase_outputs = b.outputs
|
||||
.iter()
|
||||
.filter(|out| out.features.contains(COINBASE_OUTPUT))
|
||||
.map(|o| o.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(coinbase_outputs.len(), 1);
|
||||
|
||||
let coinbase_kernels = b.kernels
|
||||
.iter()
|
||||
.filter(|out| out.features.contains(COINBASE_KERNEL))
|
||||
.map(|o| o.clone())
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(coinbase_kernels.len(), 1);
|
||||
|
||||
// the block should be valid here (single coinbase output with corresponding txn kernel)
|
||||
assert_eq!(b.validate(&secp), Ok(()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
// test that flipping the COINBASE_OUTPUT flag on the output features
|
||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||
// additionally verifying the merkle_inputs_outputs also fails
|
||||
fn remove_coinbase_output_flag() {
|
||||
let ref secp = new_secp();
|
||||
let mut b = new_block(vec![], secp);
|
||||
|
||||
assert!(b.outputs[0].features.contains(COINBASE_OUTPUT));
|
||||
b.outputs[0].features.remove(COINBASE_OUTPUT);
|
||||
|
||||
assert_eq!(b.verify_coinbase(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
assert_eq!(b.verify_kernels(&secp), Ok(()));
|
||||
assert_eq!(b.verify_merkle_inputs_outputs(), Err(secp::Error::IncorrectCommitSum));
|
||||
|
||||
assert_eq!(b.validate(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
}
|
||||
|
||||
#[test]
|
||||
// test that flipping the COINBASE_KERNEL flag on the kernel features
|
||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||
fn remove_coinbase_kernel_flag() {
|
||||
let ref secp = new_secp();
|
||||
let mut b = new_block(vec![], secp);
|
||||
|
||||
assert!(b.kernels[0].features.contains(COINBASE_KERNEL));
|
||||
b.kernels[0].features.remove(COINBASE_KERNEL);
|
||||
|
||||
assert_eq!(b.verify_coinbase(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
assert_eq!(b.verify_kernels(&secp), Ok(()));
|
||||
assert_eq!(b.verify_merkle_inputs_outputs(), Ok(()));
|
||||
|
||||
assert_eq!(b.validate(&secp), Err(secp::Error::IncorrectCommitSum));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_deserialize_block() {
|
||||
let ref secp = new_secp();
|
||||
let b = new_block(vec![], secp);
|
||||
|
||||
let mut vec = Vec::new();
|
||||
ser::serialize(&mut vec, &b).expect("serialization failed");
|
||||
let b2: Block = ser::deserialize(&mut &vec[..]).unwrap();
|
||||
|
||||
assert_eq!(b.inputs, b2.inputs);
|
||||
assert_eq!(b.outputs, b2.outputs);
|
||||
assert_eq!(b.kernels, b2.kernels);
|
||||
|
||||
// TODO - timestamps are not coming back equal here (UTC related?) -
|
||||
// assert_eq!(b.header, b2.header);
|
||||
// timestamp: Tm { tm_sec: 51, tm_min: 7, tm_hour: 23, tm_mday: 20, tm_mon: 7, tm_year: 117, tm_wday: 0, tm_yday: 231, tm_isdst: 1, tm_utcoff: -14400, tm_nsec: 780878000 },
|
||||
// timestamp: Tm { tm_sec: 51, tm_min: 7, tm_hour: 3, tm_mday: 21, tm_mon: 7, tm_year: 117, tm_wday: 1, tm_yday: 232, tm_isdst: 0, tm_utcoff: 0, tm_nsec: 0 },
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ bitflags! {
|
|||
/// Pedersen commitment and the signature, that guarantees that the commitments
|
||||
/// amount to zero. The signature signs the fee, which is retained for
|
||||
/// signature validation.
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct TxKernel {
|
||||
/// Options for a kernel's structure or use
|
||||
pub features: KernelFeatures,
|
||||
|
@ -239,7 +239,7 @@ impl Transaction {
|
|||
|
||||
/// A transaction input, mostly a reference to an output being spent by the
|
||||
/// transaction.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub struct Input(pub Commitment);
|
||||
|
||||
/// Implementation of Writeable for a transaction Input, defines how to write
|
||||
|
|
Loading…
Add table
Reference in a new issue