mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
Add features bitmask to Block, Output, Kernel; coinbase validation
Block, Output and Kernel now have bitmasks to hold supported features and eventually versioning. Will make adding features and updates easier and open the possibility of soft forks. First added feature for Output and Kernel is the marking of coinbase related ones. Allows the validation of the coinbase part of a block.
This commit is contained in:
parent
a57c4e8f04
commit
38d5d67e79
10 changed files with 191 additions and 105 deletions
|
@ -213,7 +213,7 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E
|
|||
/// Fully validate the block content.
|
||||
fn validate_block(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
|
||||
let curve = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||
try!(b.verify(&curve).map_err(&Error::InvalidBlockProof));
|
||||
try!(b.validate(&curve).map_err(&Error::InvalidBlockProof));
|
||||
|
||||
if !ctx.opts.intersects(SYNC) {
|
||||
// TODO check every input exists as a UTXO using the UXTO index
|
||||
|
|
|
@ -4,6 +4,7 @@ version = "0.1.0"
|
|||
authors = ["Ignotus Peverell <igno.peverell@protonmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
bitflags = "~0.7.0"
|
||||
byteorder = "^0.5"
|
||||
num-bigint = "^0.1.35"
|
||||
rust-crypto = "^0.2"
|
||||
|
|
|
@ -21,13 +21,20 @@ use secp::key::SecretKey;
|
|||
use std::collections::HashSet;
|
||||
|
||||
use core::Committed;
|
||||
use core::{Input, Output, Proof, TxKernel, Transaction};
|
||||
use core::{Input, Output, Proof, TxKernel, Transaction, COINBASE_KERNEL, COINBASE_OUTPUT};
|
||||
use core::transaction::merkle_inputs_outputs;
|
||||
use consensus::{REWARD, DEFAULT_SIZESHIFT};
|
||||
use core::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use core::target::Difficulty;
|
||||
use ser::{self, Readable, Reader, Writeable, Writer};
|
||||
|
||||
bitflags! {
|
||||
/// Options for block validation
|
||||
pub flags BlockFeatures: u8 {
|
||||
const DEFAULT_BLOCK = 0b00000000,
|
||||
}
|
||||
}
|
||||
|
||||
/// Block header, fairly standard compared to other blockchains.
|
||||
pub struct BlockHeader {
|
||||
/// Height of this block since the genesis block (height 0)
|
||||
|
@ -39,7 +46,10 @@ pub struct BlockHeader {
|
|||
/// Length of the cuckoo cycle used to mine this block.
|
||||
pub cuckoo_len: u8,
|
||||
pub utxo_merkle: Hash,
|
||||
/// Merkle tree of hashes for all inputs, outputs and kernels in the block
|
||||
pub tx_merkle: Hash,
|
||||
/// Features specific to this block, allowing possible future extensions
|
||||
pub features: BlockFeatures,
|
||||
/// Nonce increment used to mine this block.
|
||||
pub nonce: u64,
|
||||
/// Proof of work data.
|
||||
|
@ -61,6 +71,7 @@ impl Default for BlockHeader {
|
|||
total_difficulty: Difficulty::one(),
|
||||
utxo_merkle: ZERO_HASH,
|
||||
tx_merkle: ZERO_HASH,
|
||||
features: DEFAULT_BLOCK,
|
||||
nonce: 0,
|
||||
pow: Proof::zero(),
|
||||
}
|
||||
|
@ -76,7 +87,8 @@ impl Writeable for BlockHeader {
|
|||
[write_i64, self.timestamp.to_timespec().sec],
|
||||
[write_u8, self.cuckoo_len],
|
||||
[write_fixed_bytes, &self.utxo_merkle],
|
||||
[write_fixed_bytes, &self.tx_merkle]);
|
||||
[write_fixed_bytes, &self.tx_merkle],
|
||||
[write_u8, self.features.bits()]);
|
||||
|
||||
try!(writer.write_u64(self.nonce));
|
||||
try!(self.difficulty.write(writer));
|
||||
|
@ -97,7 +109,7 @@ impl Readable<BlockHeader> for BlockHeader {
|
|||
let (timestamp, cuckoo_len) = ser_multiread!(reader, read_i64, read_u8);
|
||||
let utxo_merkle = try!(Hash::read(reader));
|
||||
let tx_merkle = try!(Hash::read(reader));
|
||||
let nonce = try!(reader.read_u64());
|
||||
let (features, nonce) = ser_multiread!(reader, read_u8, read_u64);
|
||||
let difficulty = try!(Difficulty::read(reader));
|
||||
let total_difficulty = try!(Difficulty::read(reader));
|
||||
let pow = try!(Proof::read(reader));
|
||||
|
@ -112,6 +124,7 @@ impl Readable<BlockHeader> for BlockHeader {
|
|||
cuckoo_len: cuckoo_len,
|
||||
utxo_merkle: utxo_merkle,
|
||||
tx_merkle: tx_merkle,
|
||||
features: BlockFeatures::from_bits(features).ok_or(ser::Error::CorruptedData)?,
|
||||
pow: pow,
|
||||
nonce: nonce,
|
||||
difficulty: difficulty,
|
||||
|
@ -344,15 +357,32 @@ impl Block {
|
|||
.compact()
|
||||
}
|
||||
|
||||
/// Checks the block is valid by verifying the overall commitments sums and
|
||||
/// kernels.
|
||||
pub fn verify(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
|
||||
/// Validates all the elements in a block that can be checked without
|
||||
/// additional
|
||||
/// data. Includes commitment sums and kernels, Merkle trees, reward, etc.
|
||||
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(())
|
||||
}
|
||||
|
||||
/// Validate the sum of input/output commitments match the sum in kernels
|
||||
/// and
|
||||
/// that all kernel signatures are valid.
|
||||
pub fn verify_kernels(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
|
||||
// sum all inputs and outs commitments
|
||||
let io_sum = try!(self.sum_commitments(secp));
|
||||
let io_sum = self.sum_commitments(secp)?;
|
||||
|
||||
// sum all kernels commitments
|
||||
let proof_commits = map_vec!(self.kernels, |proof| proof.excess);
|
||||
let proof_sum = try!(secp.commit_sum(proof_commits, vec![]));
|
||||
let proof_sum = secp.commit_sum(proof_commits, vec![])?;
|
||||
|
||||
// both should be the same
|
||||
if proof_sum != io_sum {
|
||||
|
@ -362,19 +392,39 @@ impl Block {
|
|||
|
||||
// verify all signatures with the commitment as pk
|
||||
for proof in &self.kernels {
|
||||
try!(proof.verify(secp));
|
||||
proof.verify(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(())
|
||||
}
|
||||
|
||||
// Validate the coinbase outputs generated by miners. Entails 2 main checks:
|
||||
//
|
||||
// * That the sum of all coinbase-marked outputs equal the supply.
|
||||
// * That the sum of blinding factors for all coinbase-marked outputs match
|
||||
// the coinbase-marked kernels.
|
||||
fn verify_coinbase(&self, secp: &Secp256k1) -> Result<(), secp::Error> {
|
||||
let cb_outs = self.outputs
|
||||
.iter()
|
||||
.filter(|out| out.features.intersects(COINBASE_OUTPUT))
|
||||
.map(|o| o.clone())
|
||||
.collect::<Vec<_>>();
|
||||
let cb_kerns = self.kernels
|
||||
.iter()
|
||||
.filter(|k| k.features.intersects(COINBASE_KERNEL))
|
||||
.map(|k| k.clone())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// verifying the kernels on a block composed of just the coinbase outputs
|
||||
// and kernels checks all we need
|
||||
Block {
|
||||
header: BlockHeader::default(),
|
||||
inputs: vec![],
|
||||
outputs: cb_outs,
|
||||
kernels: cb_kerns,
|
||||
}
|
||||
.verify_kernels(secp)
|
||||
}
|
||||
|
||||
// Builds the blinded output and related signature proof for the block reward.
|
||||
fn reward_output(skey: secp::key::SecretKey,
|
||||
secp: &Secp256k1)
|
||||
|
@ -385,6 +435,7 @@ impl Block {
|
|||
let rproof = secp.range_proof(0, REWARD, skey, commit);
|
||||
|
||||
let output = Output {
|
||||
features: COINBASE_OUTPUT,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
};
|
||||
|
@ -394,6 +445,7 @@ impl Block {
|
|||
let excess = try!(secp.commit_sum(vec![over_commit], vec![out_commit]));
|
||||
|
||||
let proof = TxKernel {
|
||||
features: COINBASE_KERNEL,
|
||||
excess: excess,
|
||||
excess_sig: sig.serialize_der(&secp),
|
||||
fee: 0,
|
||||
|
@ -402,80 +454,84 @@ impl Block {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use core::{Input, Output, Transaction};
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use core::{Input, Output, Transaction};
|
||||
use core::build::{self, input, output, input_rand, output_rand, with_fee};
|
||||
use core::hash::{Hash, Hashed};
|
||||
use core::test::{tx1i1o, tx2i1o};
|
||||
use core::hash::{Hash, Hashed};
|
||||
use core::test::{tx1i1o, tx2i1o};
|
||||
|
||||
use secp::{self, Secp256k1};
|
||||
use secp::key::SecretKey;
|
||||
use rand::Rng;
|
||||
use rand::os::OsRng;
|
||||
use secp::{self, Secp256k1};
|
||||
use secp::key::SecretKey;
|
||||
use rand::Rng;
|
||||
use rand::os::OsRng;
|
||||
|
||||
fn new_secp() -> Secp256k1 {
|
||||
secp::Secp256k1::with_caps(secp::ContextFlag::Commit)
|
||||
}
|
||||
fn new_secp() -> Secp256k1 {
|
||||
secp::Secp256k1::with_caps(secp::ContextFlag::Commit)
|
||||
}
|
||||
|
||||
// utility to create a block without worrying about the key or previous
|
||||
//header
|
||||
fn new_block(txs: Vec<&mut Transaction>, secp: &Secp256k1) -> Block {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let skey = SecretKey::new(secp, &mut rng);
|
||||
Block::new(&BlockHeader::default(), txs, skey).unwrap()
|
||||
}
|
||||
|
||||
// utility producing a transaction that spends an output with the provided
|
||||
// value and blinding key
|
||||
fn txspend1i1o(v: u64, b: SecretKey) -> Transaction {
|
||||
build::transaction(vec![input(v, b), output_rand(3), with_fee(1)]).map(|(tx, _)| tx).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
// builds a block with a tx spending another and check if merging occurred
|
||||
fn compactable_block() {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let ref secp = new_secp();
|
||||
|
||||
let mut btx1 = tx2i1o();
|
||||
// utility to create a block without worrying about the key or previous
|
||||
// header
|
||||
fn new_block(txs: Vec<&mut Transaction>, secp: &Secp256k1) -> Block {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let skey = SecretKey::new(secp, &mut rng);
|
||||
let (mut btx2, _) = build::transaction(vec![input_rand(5), output(4, skey), with_fee(1)]).unwrap();
|
||||
Block::new(&BlockHeader::default(), txs, skey).unwrap()
|
||||
}
|
||||
|
||||
// spending tx2
|
||||
let mut btx3 = txspend1i1o(4, skey);
|
||||
let b = new_block(vec![&mut btx1, &mut btx2, &mut btx3], secp);
|
||||
// utility producing a transaction that spends an output with the provided
|
||||
// value and blinding key
|
||||
fn txspend1i1o(v: u64, b: SecretKey) -> Transaction {
|
||||
build::transaction(vec![input(v, b), output_rand(3), with_fee(1)])
|
||||
.map(|(tx, _)| tx)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
// block should have been automatically compacted (including reward
|
||||
// output) and should still be valid
|
||||
b.verify(&secp).unwrap();
|
||||
assert_eq!(b.inputs.len(), 3);
|
||||
assert_eq!(b.outputs.len(), 3);
|
||||
}
|
||||
#[test]
|
||||
// builds a block with a tx spending another and check if merging occurred
|
||||
fn compactable_block() {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let ref secp = new_secp();
|
||||
|
||||
#[test]
|
||||
// builds 2 different blocks with a tx spending another and check if merging
|
||||
// occurs
|
||||
fn mergeable_blocks() {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let ref secp = new_secp();
|
||||
|
||||
let mut btx1 = tx2i1o();
|
||||
let mut btx1 = tx2i1o();
|
||||
let skey = SecretKey::new(secp, &mut rng);
|
||||
let (mut btx2, _) = build::transaction(vec![input_rand(5), output(4, skey), with_fee(1)]).unwrap();
|
||||
let (mut btx2, _) = build::transaction(vec![input_rand(5), output(4, skey), with_fee(1)])
|
||||
.unwrap();
|
||||
|
||||
// spending tx2
|
||||
let mut btx3 = txspend1i1o(4, skey);
|
||||
// spending tx2
|
||||
let mut btx3 = txspend1i1o(4, skey);
|
||||
let b = new_block(vec![&mut btx1, &mut btx2, &mut btx3], secp);
|
||||
|
||||
let b1 = new_block(vec![&mut btx1, &mut btx2], secp);
|
||||
b1.verify(&secp).unwrap();
|
||||
let b2 = new_block(vec![&mut btx3], secp);
|
||||
b2.verify(&secp).unwrap();
|
||||
// block should have been automatically compacted (including reward
|
||||
// output) and should still be valid
|
||||
b.validate(&secp).unwrap();
|
||||
assert_eq!(b.inputs.len(), 3);
|
||||
assert_eq!(b.outputs.len(), 3);
|
||||
}
|
||||
|
||||
// block should have been automatically compacted and should still be valid
|
||||
let b3 = b1.merge(b2);
|
||||
assert_eq!(b3.inputs.len(), 3);
|
||||
assert_eq!(b3.outputs.len(), 4);
|
||||
}
|
||||
#[test]
|
||||
// builds 2 different blocks with a tx spending another and check if merging
|
||||
// occurs
|
||||
fn mergeable_blocks() {
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let ref secp = new_secp();
|
||||
|
||||
let mut btx1 = tx2i1o();
|
||||
let skey = SecretKey::new(secp, &mut rng);
|
||||
let (mut btx2, _) = build::transaction(vec![input_rand(5), output(4, skey), with_fee(1)])
|
||||
.unwrap();
|
||||
|
||||
// spending tx2
|
||||
let mut btx3 = txspend1i1o(4, skey);
|
||||
|
||||
let b1 = new_block(vec![&mut btx1, &mut btx2], secp);
|
||||
b1.validate(&secp).unwrap();
|
||||
let b2 = new_block(vec![&mut btx3], secp);
|
||||
b2.validate(&secp).unwrap();
|
||||
|
||||
// block should have been automatically compacted and should still be valid
|
||||
let b3 = b1.merge(b2);
|
||||
assert_eq!(b3.inputs.len(), 3);
|
||||
assert_eq!(b3.outputs.len(), 4);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ use secp::key::SecretKey;
|
|||
use secp::pedersen::*;
|
||||
use rand::os::OsRng;
|
||||
|
||||
use core::{Transaction, Input, Output};
|
||||
use core::{Transaction, Input, Output, DEFAULT_OUTPUT};
|
||||
|
||||
/// Context information available to transaction combinators.
|
||||
pub struct Context {
|
||||
|
@ -113,6 +113,7 @@ pub fn output(value: u64, blinding: SecretKey) -> Box<Append> {
|
|||
let commit = build.secp.commit(value, blinding).unwrap();
|
||||
let rproof = build.secp.range_proof(0, value, blinding, commit);
|
||||
(tx.with_output(Output {
|
||||
features: DEFAULT_OUTPUT,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
}),
|
||||
|
@ -129,6 +130,7 @@ pub fn output_rand(value: u64) -> Box<Append> {
|
|||
let commit = build.secp.commit(value, blinding).unwrap();
|
||||
let rproof = build.secp.range_proof(0, value, blinding, commit);
|
||||
(tx.with_output(Output {
|
||||
features: DEFAULT_OUTPUT,
|
||||
commit: commit,
|
||||
proof: rproof,
|
||||
}),
|
||||
|
|
|
@ -28,8 +28,9 @@ use secp::{self, Secp256k1};
|
|||
use secp::pedersen::*;
|
||||
|
||||
use consensus::PROOFSIZE;
|
||||
pub use self::block::{Block, BlockHeader};
|
||||
pub use self::transaction::{Transaction, Input, Output, TxKernel};
|
||||
pub use self::block::{Block, BlockHeader, DEFAULT_BLOCK};
|
||||
pub use self::transaction::{Transaction, Input, Output, TxKernel, COINBASE_KERNEL,
|
||||
COINBASE_OUTPUT, DEFAULT_OUTPUT};
|
||||
use self::hash::{Hash, Hashed, HashWriter, ZERO_HASH};
|
||||
use ser::{Writeable, Writer, Reader, Readable, Error};
|
||||
|
||||
|
@ -344,7 +345,7 @@ mod test {
|
|||
let skey = SecretKey::new(secp, &mut rng);
|
||||
|
||||
let b = Block::new(&BlockHeader::default(), vec![], skey).unwrap();
|
||||
b.compact().verify(&secp).unwrap();
|
||||
b.compact().validate(&secp).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -357,7 +358,7 @@ mod test {
|
|||
tx1.verify_sig(&secp).unwrap();
|
||||
|
||||
let b = Block::new(&BlockHeader::default(), vec![&mut tx1], skey).unwrap();
|
||||
b.compact().verify(&secp).unwrap();
|
||||
b.compact().validate(&secp).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -373,7 +374,7 @@ mod test {
|
|||
tx2.verify_sig(&secp).unwrap();
|
||||
|
||||
let b = Block::new(&BlockHeader::default(), vec![&mut tx1, &mut tx2], skey).unwrap();
|
||||
b.verify(&secp).unwrap();
|
||||
b.validate(&secp).unwrap();
|
||||
}
|
||||
|
||||
// utility producing a transaction with 2 inputs and a single outputs
|
||||
|
|
|
@ -24,12 +24,22 @@ use core::MerkleRow;
|
|||
use core::hash::{Hash, Hashed};
|
||||
use ser::{self, Reader, Writer, Readable, Writeable};
|
||||
|
||||
bitflags! {
|
||||
/// Options for a kernel's structure or use
|
||||
pub flags KernelFeatures: u8 {
|
||||
const DEFAULT_KERNEL = 0b00000000,
|
||||
const COINBASE_KERNEL = 0b00000001,
|
||||
}
|
||||
}
|
||||
|
||||
/// A proof that a transaction sums to zero. Includes both the transaction's
|
||||
/// 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)]
|
||||
pub struct TxKernel {
|
||||
/// Options for a kernel's structure or use
|
||||
pub features: KernelFeatures,
|
||||
/// Remainder of the sum of all transaction commitments. If the transaction
|
||||
/// is well formed, amounts components should sum to zero and the excess
|
||||
/// is hence a valid public key.
|
||||
|
@ -43,20 +53,23 @@ pub struct TxKernel {
|
|||
|
||||
impl Writeable for TxKernel {
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
try!(writer.write_fixed_bytes(&self.excess));
|
||||
try!(writer.write_bytes(&self.excess_sig));
|
||||
writer.write_u64(self.fee)
|
||||
ser_multiwrite!(writer,
|
||||
[write_u8, self.features.bits()],
|
||||
[write_fixed_bytes, &self.excess],
|
||||
[write_bytes, &self.excess_sig],
|
||||
[write_u64, self.fee]);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable<TxKernel> for TxKernel {
|
||||
fn read(reader: &mut Reader) -> Result<TxKernel, ser::Error> {
|
||||
let excess = try!(Commitment::read(reader));
|
||||
let (sig, fee) = ser_multiread!(reader, read_vec, read_u64);
|
||||
Ok(TxKernel {
|
||||
excess: excess,
|
||||
excess_sig: sig,
|
||||
fee: fee,
|
||||
features:
|
||||
KernelFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
|
||||
excess: Commitment::read(reader)?,
|
||||
excess_sig: reader.read_vec()?,
|
||||
fee: reader.read_u64()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -212,6 +225,7 @@ impl Transaction {
|
|||
try!(secp.verify(&msg, &sig, &pubk));
|
||||
|
||||
Ok(TxKernel {
|
||||
features: DEFAULT_KERNEL,
|
||||
excess: rsum,
|
||||
excess_sig: self.excess_sig.clone(),
|
||||
fee: self.fee,
|
||||
|
@ -258,6 +272,14 @@ impl Input {
|
|||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Options for block validation
|
||||
pub flags OutputFeatures: u8 {
|
||||
const DEFAULT_OUTPUT = 0b00000000,
|
||||
const COINBASE_OUTPUT = 0b00000001,
|
||||
}
|
||||
}
|
||||
|
||||
/// Output for a transaction, defining the new ownership of coins that are being
|
||||
/// transferred. The commitment is a blinded value for the output while the
|
||||
/// range
|
||||
|
@ -265,6 +287,7 @@ impl Input {
|
|||
/// and the ownership of the private key.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Output {
|
||||
pub features: OutputFeatures,
|
||||
pub commit: Commitment,
|
||||
pub proof: RangeProof,
|
||||
}
|
||||
|
@ -273,10 +296,10 @@ pub struct Output {
|
|||
/// an Output as binary.
|
||||
impl Writeable for Output {
|
||||
fn write(&self, writer: &mut Writer) -> Result<(), ser::Error> {
|
||||
// The hash of an output is only the hash of its commitment.
|
||||
try!(writer.write_fixed_bytes(&self.commit));
|
||||
ser_multiwrite!(writer, [write_u8, self.features.bits()], [write_fixed_bytes, &self.commit]);
|
||||
// The hash of an output doesn't include the range proof
|
||||
if writer.serialization_mode() == ser::SerializationMode::Full {
|
||||
try!(writer.write_bytes(&self.proof.bytes()))
|
||||
writer.write_bytes(&self.proof.bytes())?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -286,11 +309,11 @@ impl Writeable for Output {
|
|||
/// an Output from a binary stream.
|
||||
impl Readable<Output> for Output {
|
||||
fn read(reader: &mut Reader) -> Result<Output, ser::Error> {
|
||||
let commit = try!(Commitment::read(reader));
|
||||
let proof = try!(RangeProof::read(reader));
|
||||
Ok(Output {
|
||||
commit: commit,
|
||||
proof: proof,
|
||||
features:
|
||||
OutputFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?,
|
||||
commit: Commitment::read(reader)?,
|
||||
proof: RangeProof::read(reader)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ pub fn genesis() -> core::Block {
|
|||
total_difficulty: Difficulty::one(),
|
||||
utxo_merkle: [].hash(),
|
||||
tx_merkle: [].hash(),
|
||||
features: core::DEFAULT_BLOCK,
|
||||
nonce: 0,
|
||||
pow: core::Proof::zero(), // TODO get actual PoW solution
|
||||
},
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#![deny(unused_mut)]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate byteorder;
|
||||
extern crate crypto;
|
||||
extern crate num_bigint as bigint;
|
||||
|
|
|
@ -13,7 +13,7 @@ cryptocurrency deployment.
|
|||
The main goal and characteristics of the Grin project are:
|
||||
|
||||
* Privacy by default. This enables complete fungibility without precluding
|
||||
the possibility to ability to selectively disclose information as needed.
|
||||
the ability to selectively disclose information as needed.
|
||||
* Scales with the number of users and not the number of transactions, with very
|
||||
large space savings compared to other blockchains.
|
||||
* Strong and proven cryptography. MimbleWimble only relies on Elliptic Curve
|
||||
|
|
|
@ -81,7 +81,7 @@ impl Default for P2PConfig {
|
|||
}
|
||||
|
||||
bitflags! {
|
||||
/// Options for block validation
|
||||
/// Options for what type of interaction a peer supports
|
||||
pub flags Capabilities: u32 {
|
||||
/// We don't know (yet) what the peer can do.
|
||||
const UNKNOWN = 0b00000000,
|
||||
|
|
Loading…
Reference in a new issue