move verify_kernel_sums into committed trait (#1131)

This commit is contained in:
Antioch Peverell 2018-06-02 19:00:44 +01:00 committed by GitHub
parent 6fd2afccb4
commit 0ecadd3486
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 302 additions and 210 deletions

View file

@ -23,6 +23,7 @@ use std::time::{Duration, Instant};
use core::core::hash::{Hash, Hashed}; use core::core::hash::{Hash, Hashed};
use core::core::pmmr::MerkleProof; use core::core::pmmr::MerkleProof;
use core::core::target::Difficulty; use core::core::target::Difficulty;
use core::core::Committed;
use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel}; use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel};
use core::global; use core::global;
use grin_store::Error::NotFoundErr; use grin_store::Error::NotFoundErr;
@ -200,7 +201,14 @@ impl Chain {
header.height, header.height,
header.hash() header.hash()
); );
let (output_sum, kernel_sum) = extension.validate_sums(&header)?;
let (output_sum, kernel_sum) = extension.verify_kernel_sums(
header.total_overage(),
header.total_kernel_offset(),
None,
None,
)?;
store.save_block_sums( store.save_block_sums(
&header.hash(), &header.hash(),
&BlockSums { &BlockSums {

View file

@ -24,11 +24,11 @@ use std::time::Instant;
use util::secp::pedersen::{Commitment, RangeProof}; use util::secp::pedersen::{Commitment, RangeProof};
use core::consensus::REWARD; use core::core::committed::Committed;
use core::core::hash::{Hash, Hashed}; use core::core::hash::{Hash, Hashed};
use core::core::pmmr::{self, MerkleProof, PMMR}; use core::core::pmmr::{self, MerkleProof, PMMR};
use core::core::{Block, BlockHeader, Committed, Input, Output, OutputFeatures, OutputIdentifier, use core::core::{Block, BlockHeader, Input, Output, OutputFeatures, OutputIdentifier, Transaction,
Transaction, TxKernel}; TxKernel};
use core::global; use core::global;
use core::ser::{PMMRIndexHashable, PMMRable}; use core::ser::{PMMRIndexHashable, PMMRable};
@ -773,35 +773,6 @@ impl<'a> Extension<'a> {
Ok(()) Ok(())
} }
/// The real magicking: the sum of all kernel excess should equal the sum
/// of all output commitments, minus the total supply.
pub fn validate_sums(&self, header: &BlockHeader) -> Result<((Commitment, Commitment)), Error> {
let now = Instant::now();
// Treat the total "supply" as one huge overage that needs to be accounted for.
// If we have a supply of 6,000 grin then we should
// have a corresponding 6,000 grin in unspent outputs.
let supply = ((header.height * REWARD) as i64).checked_neg().unwrap_or(0);
let output_sum = self.sum_commitments(supply, None)?;
let (kernel_sum, kernel_sum_plus_offset) =
self.sum_kernel_excesses(&header.total_kernel_offset, None)?;
if output_sum != kernel_sum_plus_offset {
return Err(Error::InvalidTxHashSet(
"Differing Output commitment and kernel excess sums.".to_owned(),
));
}
debug!(
LOGGER,
"txhashset: validated sums, took (total) {}s",
now.elapsed().as_secs(),
);
Ok((output_sum, kernel_sum))
}
/// Validate the txhashset state against the provided block header. /// Validate the txhashset state against the provided block header.
pub fn validate( pub fn validate(
&mut self, &mut self,
@ -816,13 +787,21 @@ impl<'a> Extension<'a> {
return Ok((zero_commit.clone(), zero_commit.clone())); return Ok((zero_commit.clone(), zero_commit.clone()));
} }
let (output_sum, kernel_sum) = self.validate_sums(header)?; // The real magicking happens here.
// Sum of kernel excesses should equal sum of
// unspent outputs minus total supply.
let (output_sum, kernel_sum) = self.verify_kernel_sums(
header.total_overage(),
header.total_kernel_offset(),
None,
None,
)?;
// this is a relatively expensive verification step // This is an expensive verification step.
self.verify_kernel_signatures()?; self.verify_kernel_signatures()?;
// verify the rangeproof for each output in the sum above // Verify the rangeproof for each output in the sum above.
// this is an expensive operation (only verified if requested) // This is an expensive verification step (skip for faster verification).
if !skip_rproofs { if !skip_rproofs {
self.verify_rangeproofs()?; self.verify_rangeproofs()?;
} }

View file

@ -20,6 +20,7 @@ use util::secp;
use util::secp::pedersen::Commitment; use util::secp::pedersen::Commitment;
use util::secp_static; use util::secp_static;
use core::core::committed;
use core::core::hash::{Hash, Hashed}; use core::core::hash::{Hash, Hashed};
use core::core::target::Difficulty; use core::core::target::Difficulty;
use core::core::{block, transaction, Block, BlockHeader}; use core::core::{block, transaction, Block, BlockHeader};
@ -107,6 +108,8 @@ pub enum Error {
Transaction(transaction::Error), Transaction(transaction::Error),
/// Anything else /// Anything else
Other(String), Other(String),
/// Error from summing and verifying kernel sums via committed trait.
Committed(committed::Error),
} }
impl error::Error for Error { impl error::Error for Error {
@ -155,6 +158,12 @@ impl From<secp::Error> for Error {
} }
} }
impl From<committed::Error> for Error {
fn from(e: committed::Error) -> Error {
Error::Committed(e)
}
}
impl Error { impl Error {
/// Whether the error is due to a block that was intrinsically wrong /// Whether the error is due to a block that was intrinsically wrong
pub fn is_bad_data(&self) -> bool { pub fn is_bad_data(&self) -> bool {

View file

@ -21,12 +21,14 @@ use time;
use consensus; use consensus;
use consensus::{exceeds_weight, reward, VerifySortOrder, REWARD}; use consensus::{exceeds_weight, reward, VerifySortOrder, REWARD};
use core::committed;
use core::committed::Committed;
use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH}; use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH};
use core::id::ShortIdentifiable; use core::id::ShortIdentifiable;
use core::target::Difficulty; use core::target::Difficulty;
use core::transaction; use core::transaction;
use core::{Commitment, Committed, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId, use core::{Commitment, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId, Transaction,
Transaction, TxKernel}; TxKernel};
use global; use global;
use keychain; use keychain;
use keychain::BlindingFactor; use keychain::BlindingFactor;
@ -66,10 +68,18 @@ pub enum Error {
}, },
/// Underlying Merkle proof error /// Underlying Merkle proof error
MerkleProof, MerkleProof,
/// Error when verifying kernel sums via committed trait.
Committed(committed::Error),
/// Other unspecified error condition /// Other unspecified error condition
Other(String), Other(String),
} }
impl From<committed::Error> for Error {
fn from(e: committed::Error) -> Error {
Error::Committed(e)
}
}
impl From<transaction::Error> for Error { impl From<transaction::Error> for Error {
fn from(e: transaction::Error) -> Error { fn from(e: transaction::Error) -> Error {
Error::Transaction(e) Error::Transaction(e)
@ -219,6 +229,23 @@ impl BlockHeader {
hasher.finalize(&mut ret); hasher.finalize(&mut ret);
Hash(ret) Hash(ret)
} }
/// The "overage" to use when verifying the kernel sums.
/// For a block header the overage is 0 - reward.
pub fn overage(&self) -> i64 {
(REWARD as i64).checked_neg().unwrap_or(0)
}
/// The "total overage" to use when verifying the kernel sums for a full
/// chain state. For a full chain state this is 0 - (height * reward).
pub fn total_overage(&self) -> i64 {
((self.height * REWARD) as i64).checked_neg().unwrap_or(0)
}
/// Total kernel offset for the chain state up to and including this block.
pub fn total_kernel_offset(&self) -> BlindingFactor {
self.total_kernel_offset
}
} }
/// Compact representation of a full block. /// Compact representation of a full block.
@ -658,7 +685,17 @@ impl Block {
self.verify_coinbase()?; self.verify_coinbase()?;
self.verify_inputs()?; self.verify_inputs()?;
self.verify_kernel_lock_heights()?; self.verify_kernel_lock_heights()?;
self.verify_sums(prev_output_sum, prev_kernel_sum)
let sums = self.verify_kernel_sums(
self.header.overage(),
self.header.total_kernel_offset(),
Some(prev_output_sum),
Some(prev_kernel_sum),
)?;
self.verify_rangeproofs()?;
self.verify_kernel_signatures()?;
Ok(sums)
} }
fn verify_weight(&self) -> Result<(), Error> { fn verify_weight(&self) -> Result<(), Error> {
@ -707,37 +744,22 @@ impl Block {
Ok(()) Ok(())
} }
/// Verify sums /// Verify the kernel signatures.
pub fn verify_sums( /// Note: this is expensive.
&self, fn verify_kernel_signatures(&self) -> Result<(), Error> {
prev_output_sum: &Commitment,
prev_kernel_sum: &Commitment,
) -> Result<((Commitment, Commitment)), Error> {
// Verify the output rangeproofs.
// Note: this is expensive.
for x in &self.outputs {
x.verify_proof()?;
}
// Verify the kernel signatures.
// Note: this is expensive.
for x in &self.kernels { for x in &self.kernels {
x.verify()?; x.verify()?;
} }
Ok(())
// Sum all input|output|overage commitments.
let overage = (REWARD as i64).checked_neg().unwrap_or(0);
let io_sum = self.sum_commitments(overage, Some(prev_output_sum))?;
// Sum the kernel excesses accounting for the kernel offset.
let (kernel_sum, kernel_sum_plus_offset) =
self.sum_kernel_excesses(&self.header.total_kernel_offset, Some(prev_kernel_sum))?;
if io_sum != kernel_sum_plus_offset {
return Err(Error::KernelSumMismatch);
} }
Ok((io_sum, kernel_sum)) /// Verify all the output rangeproofs.
/// Note: this is expensive.
fn verify_rangeproofs(&self) -> Result<(), Error> {
for x in &self.outputs {
x.verify_proof()?;
}
Ok(())
} }
/// Validate the coinbase outputs generated by miners. Entails 2 main /// Validate the coinbase outputs generated by miners. Entails 2 main

169
core/src/core/committed.rs Normal file
View file

@ -0,0 +1,169 @@
// Copyright 2018 The Grin Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! The Committed trait and associated errors.
use keychain;
use keychain::BlindingFactor;
use util::secp::pedersen::*;
use util::{secp, secp_static, static_secp_instance};
/// Errors from summing and verifying kernel excesses via committed trait.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Error {
/// Keychain related error.
Keychain(keychain::Error),
/// Secp related error.
Secp(secp::Error),
/// Kernel sums do not equal output sums.
KernelSumMismatch,
}
impl From<secp::Error> for Error {
fn from(e: secp::Error) -> Error {
Error::Secp(e)
}
}
impl From<keychain::Error> for Error {
fn from(e: keychain::Error) -> Error {
Error::Keychain(e)
}
}
/// Implemented by types that hold inputs and outputs (and kernels)
/// containing Pedersen commitments.
/// Handles the collection of the commitments as well as their
/// summing, taking potential explicit overages of fees into account.
pub trait Committed {
/// Gather the kernel excesses and sum them.
fn sum_kernel_excesses(
&self,
offset: &BlindingFactor,
extra_excess: Option<&Commitment>,
) -> Result<(Commitment, Commitment), Error> {
let zero_commit = secp_static::commit_to_zero_value();
// then gather the kernel excess commitments
let mut kernel_commits = self.kernels_committed();
if let Some(extra) = extra_excess {
kernel_commits.push(*extra);
}
// handle "zero commit" values by filtering them out here
kernel_commits.retain(|x| *x != zero_commit);
// sum the commitments
let kernel_sum = {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
secp.commit_sum(kernel_commits, vec![])?
};
// sum the commitments along with the
// commit to zero built from the offset
let kernel_sum_plus_offset = {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
let mut commits = vec![kernel_sum];
if *offset != BlindingFactor::zero() {
let key = offset.secret_key(&secp)?;
let offset_commit = secp.commit(0, key)?;
commits.push(offset_commit);
}
secp.commit_sum(commits, vec![])?
};
Ok((kernel_sum, kernel_sum_plus_offset))
}
/// Gathers commitments and sum them.
fn sum_commitments(
&self,
overage: i64,
extra_commit: Option<&Commitment>,
) -> Result<Commitment, Error> {
let zero_commit = secp_static::commit_to_zero_value();
// then gather the commitments
let mut input_commits = self.inputs_committed();
let mut output_commits = self.outputs_committed();
// add the overage as output commitment if positive,
// or as an input commitment if negative
if overage != 0 {
let over_commit = {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
secp.commit_value(overage.abs() as u64).unwrap()
};
if overage < 0 {
input_commits.push(over_commit);
} else {
output_commits.push(over_commit);
}
}
if let Some(extra) = extra_commit {
output_commits.push(*extra);
}
// handle "zero commit" values by filtering them out here
output_commits.retain(|x| *x != zero_commit);
input_commits.retain(|x| *x != zero_commit);
// sum all that stuff
{
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
let res = secp.commit_sum(output_commits, input_commits)?;
Ok(res)
}
}
/// Vector of input commitments to verify.
fn inputs_committed(&self) -> Vec<Commitment>;
/// Vector of output commitments to verify.
fn outputs_committed(&self) -> Vec<Commitment>;
/// Vector of kernel excesses to verify.
fn kernels_committed(&self) -> Vec<Commitment>;
/// Verify the sum of the kernel excesses equals the
/// sum of the outputs, taking into account both
/// the kernel_offset and overage.
fn verify_kernel_sums(
&self,
overage: i64,
kernel_offset: BlindingFactor,
prev_output_sum: Option<&Commitment>,
prev_kernel_sum: Option<&Commitment>,
) -> Result<((Commitment, Commitment)), Error> {
// Sum all input|output|overage commitments.
let utxo_sum = self.sum_commitments(overage, prev_output_sum)?;
// Sum the kernel excesses accounting for the kernel offset.
let (kernel_sum, kernel_sum_plus_offset) =
self.sum_kernel_excesses(&kernel_offset, prev_kernel_sum)?;
if utxo_sum != kernel_sum_plus_offset {
return Err(Error::KernelSumMismatch);
}
Ok((utxo_sum, kernel_sum))
}
}

View file

@ -15,6 +15,7 @@
//! Core types //! Core types
pub mod block; pub mod block;
pub mod committed;
pub mod hash; pub mod hash;
pub mod id; pub mod id;
pub mod pmmr; pub mod pmmr;
@ -23,122 +24,19 @@ pub mod transaction;
use consensus::GRIN_BASE; use consensus::GRIN_BASE;
#[allow(dead_code)] #[allow(dead_code)]
use rand::{thread_rng, Rng}; use rand::{thread_rng, Rng};
use std::cmp::Ordering;
use std::num::ParseFloatError; use std::num::ParseFloatError;
use std::{fmt, iter}; use std::{fmt, iter};
use util::secp::pedersen::*; use util::secp::pedersen::*;
use util::{secp, secp_static, static_secp_instance};
pub use self::block::*; pub use self::block::*;
pub use self::committed::Committed;
pub use self::id::ShortId; pub use self::id::ShortId;
pub use self::transaction::*; pub use self::transaction::*;
use core::hash::Hashed; use core::hash::Hashed;
use global; use global;
use keychain;
use keychain::BlindingFactor;
use ser::{Error, Readable, Reader, Writeable, Writer}; use ser::{Error, Readable, Reader, Writeable, Writer};
/// Implemented by types that hold inputs and outputs (and kernels)
/// containing Pedersen commitments.
/// Handles the collection of the commitments as well as their
/// summing, taking potential explicit overages of fees into account.
pub trait Committed {
/// Gather the kernel excesses and sum them.
fn sum_kernel_excesses(
&self,
offset: &BlindingFactor,
extra_excess: Option<&Commitment>,
) -> Result<(Commitment, Commitment), keychain::Error> {
let zero_commit = secp_static::commit_to_zero_value();
// then gather the kernel excess commitments
let mut kernel_commits = self.kernels_committed();
if let Some(extra) = extra_excess {
kernel_commits.push(*extra);
}
// handle "zero commit" values by filtering them out here
kernel_commits.retain(|x| *x != zero_commit);
// sum the commitments
let kernel_sum = {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
secp.commit_sum(kernel_commits, vec![])?
};
// sum the commitments along with the
// commit to zero built from the offset
let kernel_sum_plus_offset = {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
let mut commits = vec![kernel_sum];
if *offset != BlindingFactor::zero() {
let key = offset.secret_key(&secp)?;
let offset_commit = secp.commit(0, key)?;
commits.push(offset_commit);
}
secp.commit_sum(commits, vec![])?
};
Ok((kernel_sum, kernel_sum_plus_offset))
}
/// Gathers commitments and sum them.
fn sum_commitments(
&self,
overage: i64,
extra_commit: Option<&Commitment>,
) -> Result<Commitment, secp::Error> {
let zero_commit = secp_static::commit_to_zero_value();
// then gather the commitments
let mut input_commits = self.inputs_committed();
let mut output_commits = self.outputs_committed();
// add the overage as output commitment if positive,
// or as an input commitment if negative
if overage != 0 {
let over_commit = {
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
secp.commit_value(overage.abs() as u64).unwrap()
};
if overage < 0 {
input_commits.push(over_commit);
} else {
output_commits.push(over_commit);
}
}
if let Some(extra) = extra_commit {
output_commits.push(*extra);
}
// handle "zero commit" values by filtering them out here
output_commits.retain(|x| *x != zero_commit);
input_commits.retain(|x| *x != zero_commit);
// sum all that stuff
{
let secp = static_secp_instance();
let secp = secp.lock().unwrap();
secp.commit_sum(output_commits, input_commits)
}
}
/// Vector of input commitments to verify.
fn inputs_committed(&self) -> Vec<Commitment>;
/// Vector of output commitments to verify.
fn outputs_committed(&self) -> Vec<Commitment>;
/// Vector of kernel excesses to verify.
fn kernels_committed(&self) -> Vec<Commitment>;
}
/// Proof of work /// Proof of work
#[derive(Clone, PartialOrd, PartialEq)] #[derive(Clone, PartialOrd, PartialEq)]
pub struct Proof { pub struct Proof {

View file

@ -14,8 +14,8 @@
//! Transactions //! Transactions
use std::cmp::Ordering;
use std::cmp::max; use std::cmp::max;
use std::cmp::Ordering;
use std::collections::HashSet; use std::collections::HashSet;
use std::io::Cursor; use std::io::Cursor;
use std::{error, fmt}; use std::{error, fmt};
@ -26,11 +26,12 @@ use util::{kernel_sig_msg, static_secp_instance};
use consensus; use consensus;
use consensus::VerifySortOrder; use consensus::VerifySortOrder;
use core::BlockHeader; use core::committed;
use core::Committed; use core::committed::Committed;
use core::global; use core::global;
use core::hash::{Hash, Hashed, ZERO_HASH}; use core::hash::{Hash, Hashed, ZERO_HASH};
use core::pmmr::MerkleProof; use core::pmmr::MerkleProof;
use core::BlockHeader;
use keychain; use keychain;
use keychain::BlindingFactor; use keychain::BlindingFactor;
use ser::{self, read_and_verify_sorted, ser_vec, PMMRable, Readable, Reader, Writeable, use ser::{self, read_and_verify_sorted, ser_vec, PMMRable, Readable, Reader, Writeable,
@ -75,9 +76,8 @@ pub enum Error {
/// Returns if the value hidden within the a RangeProof message isn't /// Returns if the value hidden within the a RangeProof message isn't
/// repeated 3 times, indicating it's incorrect /// repeated 3 times, indicating it's incorrect
InvalidProofMessage, InvalidProofMessage,
/// Error when sums do not verify correctly during tx aggregation. /// Error when verifying kernel sums via committed trait.
/// Likely a "double spend" across two unconfirmed txs. Committed(committed::Error),
AggregationError,
} }
impl error::Error for Error { impl error::Error for Error {
@ -114,6 +114,12 @@ impl From<keychain::Error> for Error {
} }
} }
impl From<committed::Error> for Error {
fn from(e: committed::Error) -> Error {
Error::Committed(e)
}
}
/// A proof that a transaction sums to zero. Includes both the transaction's /// A proof that a transaction sums to zero. Includes both the transaction's
/// Pedersen commitment and the signature, that guarantees that the commitments /// Pedersen commitment and the signature, that guarantees that the commitments
/// amount to zero. /// amount to zero.
@ -387,6 +393,10 @@ impl Transaction {
self.kernels.iter().fold(0, |acc, ref x| acc + x.fee) self.kernels.iter().fold(0, |acc, ref x| acc + x.fee)
} }
fn overage(&self) -> i64 {
self.fee() as i64
}
/// Lock height of a transaction is the max lock height of the kernels. /// Lock height of a transaction is the max lock height of the kernels.
pub fn lock_height(&self) -> u64 { pub fn lock_height(&self) -> u64 {
self.kernels self.kernels
@ -394,46 +404,24 @@ impl Transaction {
.fold(0, |acc, ref x| max(acc, x.lock_height)) .fold(0, |acc, ref x| max(acc, x.lock_height))
} }
/// Verify the kernel signatures.
/// Note: this is expensive.
fn verify_kernel_signatures(&self) -> Result<(), Error> { fn verify_kernel_signatures(&self) -> Result<(), Error> {
// Verify the kernel signatures.
// Note: this is expensive.
for x in &self.kernels { for x in &self.kernels {
x.verify()?; x.verify()?;
} }
Ok(()) Ok(())
} }
/// Verify all the output rangeproofs.
/// Note: this is expensive.
fn verify_rangeproofs(&self) -> Result<(), Error> { fn verify_rangeproofs(&self) -> Result<(), Error> {
// Verify all the output rangeproofs.
// Note: this is expensive.
for x in &self.outputs { for x in &self.outputs {
x.verify_proof()?; x.verify_proof()?;
} }
Ok(()) Ok(())
} }
/// To verify transaction kernels we check that -
/// * all kernels have an even fee
/// * sum of input/output commitments matches sum of kernel commitments
/// after applying offset * each kernel sig is valid (i.e. tx commitments
/// sum to zero, given above is true)
fn verify_kernel_sums(&self) -> Result<(), Error> {
// Sum all input|output|overage commitments.
let overage = self.fee() as i64;
let io_sum = self.sum_commitments(overage, None)?;
// Sum the kernel excesses accounting for the kernel offset.
let (_, kernel_sum) = self.sum_kernel_excesses(&self.offset, None)?;
// sum of kernel commitments (including the offset) must match
// the sum of input/output commitments (minus fee)
if io_sum != kernel_sum {
return Err(Error::KernelSumMismatch);
}
Ok(())
}
/// Validates all relevant parts of a fully built transaction. Checks the /// Validates all relevant parts of a fully built transaction. Checks the
/// excess value against the signature as well as range proofs for each /// excess value against the signature as well as range proofs for each
/// output. /// output.
@ -442,7 +430,7 @@ impl Transaction {
return Err(Error::TooManyInputs); return Err(Error::TooManyInputs);
} }
self.verify_sorted()?; self.verify_sorted()?;
self.verify_kernel_sums()?; self.verify_kernel_sums(self.overage(), self.offset, None, None)?;
self.verify_rangeproofs()?; self.verify_rangeproofs()?;
self.verify_kernel_signatures()?; self.verify_kernel_signatures()?;
@ -553,10 +541,9 @@ pub fn aggregate(transactions: Vec<Transaction>) -> Result<Transaction, Error> {
let tx = Transaction::new(new_inputs, new_outputs, kernels).with_offset(total_kernel_offset); let tx = Transaction::new(new_inputs, new_outputs, kernels).with_offset(total_kernel_offset);
// We need to check sums here as aggregation/cut-through may have created an // We need to check sums here as aggregation/cut-through
// invalid tx. // may have created an invalid tx.
tx.verify_kernel_sums() tx.verify_kernel_sums(tx.overage(), tx.offset, None, None)?;
.map_err(|_| Error::AggregationError)?;
Ok(tx) Ok(tx)
} }

View file

@ -24,6 +24,7 @@ use grin_core::consensus::{BLOCK_OUTPUT_WEIGHT, MAX_BLOCK_WEIGHT};
use grin_core::core::block::Error; use grin_core::core::block::Error;
use grin_core::core::hash::Hashed; use grin_core::core::hash::Hashed;
use grin_core::core::id::{ShortId, ShortIdentifiable}; use grin_core::core::id::{ShortId, ShortIdentifiable};
use grin_core::core::Committed;
use grin_core::core::{Block, BlockHeader, CompactBlock, KernelFeatures, OutputFeatures}; use grin_core::core::{Block, BlockHeader, CompactBlock, KernelFeatures, OutputFeatures};
use grin_core::global; use grin_core::global;
use grin_core::ser; use grin_core::ser;
@ -167,7 +168,12 @@ fn remove_coinbase_output_flag() {
.remove(OutputFeatures::COINBASE_OUTPUT); .remove(OutputFeatures::COINBASE_OUTPUT);
assert_eq!(b.verify_coinbase(), Err(Error::CoinbaseSumMismatch)); assert_eq!(b.verify_coinbase(), Err(Error::CoinbaseSumMismatch));
assert!(b.verify_sums(&zero_commit, &zero_commit).is_ok()); assert!(b.verify_kernel_sums(
b.header.overage(),
b.header.total_kernel_offset(),
None,
None
).is_ok());
assert_eq!( assert_eq!(
b.validate(&zero_commit, &zero_commit), b.validate(&zero_commit, &zero_commit),
Err(Error::CoinbaseSumMismatch) Err(Error::CoinbaseSumMismatch)

View file

@ -16,6 +16,7 @@
use failure::{Backtrace, Context, Fail}; use failure::{Backtrace, Context, Fail};
use std::fmt::{self, Display}; use std::fmt::{self, Display};
use core::core::committed;
use core::core::transaction; use core::core::transaction;
use keychain::{self, extkey}; use keychain::{self, extkey};
use util::secp; use util::secp;
@ -50,6 +51,9 @@ pub enum ErrorKind {
/// Fee error /// Fee error
#[fail(display = "Fee Error")] #[fail(display = "Fee Error")]
Fee(String), Fee(String),
/// Error from summing commitments via committed trait.
#[fail(display = "Committed Error")]
Committed(committed::Error),
} }
impl Fail for Error { impl Fail for Error {
@ -97,6 +101,14 @@ impl From<secp::Error> for Error {
} }
} }
impl From<committed::Error> for Error {
fn from(error: committed::Error) -> Error {
Error {
inner: Context::new(ErrorKind::Committed(error)),
}
}
}
impl From<keychain::Error> for Error { impl From<keychain::Error> for Error {
fn from(error: keychain::Error) -> Error { fn from(error: keychain::Error) -> Error {
Error { Error {

View file

@ -17,13 +17,15 @@
use rand::thread_rng; use rand::thread_rng;
use uuid::Uuid; use uuid::Uuid;
use core::core::{amount_to_hr_string, Committed, Transaction}; use core::core::committed;
use core::core::committed::Committed;
use core::core::{amount_to_hr_string, Transaction};
use keychain::{BlindSum, BlindingFactor, Keychain}; use keychain::{BlindSum, BlindingFactor, Keychain};
use libtx::error::{Error, ErrorKind}; use libtx::error::{Error, ErrorKind};
use libtx::{aggsig, build, tx_fee}; use libtx::{aggsig, build, tx_fee};
use util::secp::Signature;
use util::secp::key::{PublicKey, SecretKey}; use util::secp::key::{PublicKey, SecretKey};
use util::secp::Signature;
use util::{secp, LOGGER}; use util::{secp, LOGGER};
/// Public data for each participant in the slate /// Public data for each participant in the slate