mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-21 03:21:08 +03:00
move verify_kernel_sums into committed trait (#1131)
This commit is contained in:
parent
6fd2afccb4
commit
0ecadd3486
10 changed files with 302 additions and 210 deletions
|
@ -23,6 +23,7 @@ use std::time::{Duration, Instant};
|
|||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::pmmr::MerkleProof;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::Committed;
|
||||
use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel};
|
||||
use core::global;
|
||||
use grin_store::Error::NotFoundErr;
|
||||
|
@ -200,7 +201,14 @@ impl Chain {
|
|||
header.height,
|
||||
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(
|
||||
&header.hash(),
|
||||
&BlockSums {
|
||||
|
|
|
@ -24,11 +24,11 @@ use std::time::Instant;
|
|||
|
||||
use util::secp::pedersen::{Commitment, RangeProof};
|
||||
|
||||
use core::consensus::REWARD;
|
||||
use core::core::committed::Committed;
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::pmmr::{self, MerkleProof, PMMR};
|
||||
use core::core::{Block, BlockHeader, Committed, Input, Output, OutputFeatures, OutputIdentifier,
|
||||
Transaction, TxKernel};
|
||||
use core::core::{Block, BlockHeader, Input, Output, OutputFeatures, OutputIdentifier, Transaction,
|
||||
TxKernel};
|
||||
use core::global;
|
||||
use core::ser::{PMMRIndexHashable, PMMRable};
|
||||
|
||||
|
@ -773,35 +773,6 @@ impl<'a> Extension<'a> {
|
|||
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.
|
||||
pub fn validate(
|
||||
&mut self,
|
||||
|
@ -816,13 +787,21 @@ impl<'a> Extension<'a> {
|
|||
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()?;
|
||||
|
||||
// verify the rangeproof for each output in the sum above
|
||||
// this is an expensive operation (only verified if requested)
|
||||
// Verify the rangeproof for each output in the sum above.
|
||||
// This is an expensive verification step (skip for faster verification).
|
||||
if !skip_rproofs {
|
||||
self.verify_rangeproofs()?;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ use util::secp;
|
|||
use util::secp::pedersen::Commitment;
|
||||
use util::secp_static;
|
||||
|
||||
use core::core::committed;
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::{block, transaction, Block, BlockHeader};
|
||||
|
@ -107,6 +108,8 @@ pub enum Error {
|
|||
Transaction(transaction::Error),
|
||||
/// Anything else
|
||||
Other(String),
|
||||
/// Error from summing and verifying kernel sums via committed trait.
|
||||
Committed(committed::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 {
|
||||
/// Whether the error is due to a block that was intrinsically wrong
|
||||
pub fn is_bad_data(&self) -> bool {
|
||||
|
|
|
@ -21,12 +21,14 @@ use time;
|
|||
|
||||
use consensus;
|
||||
use consensus::{exceeds_weight, reward, VerifySortOrder, REWARD};
|
||||
use core::committed;
|
||||
use core::committed::Committed;
|
||||
use core::hash::{Hash, HashWriter, Hashed, ZERO_HASH};
|
||||
use core::id::ShortIdentifiable;
|
||||
use core::target::Difficulty;
|
||||
use core::transaction;
|
||||
use core::{Commitment, Committed, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId,
|
||||
Transaction, TxKernel};
|
||||
use core::{Commitment, Input, KernelFeatures, Output, OutputFeatures, Proof, ShortId, Transaction,
|
||||
TxKernel};
|
||||
use global;
|
||||
use keychain;
|
||||
use keychain::BlindingFactor;
|
||||
|
@ -66,10 +68,18 @@ pub enum Error {
|
|||
},
|
||||
/// Underlying Merkle proof error
|
||||
MerkleProof,
|
||||
/// Error when verifying kernel sums via committed trait.
|
||||
Committed(committed::Error),
|
||||
/// Other unspecified error condition
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<committed::Error> for Error {
|
||||
fn from(e: committed::Error) -> Error {
|
||||
Error::Committed(e)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<transaction::Error> for Error {
|
||||
fn from(e: transaction::Error) -> Error {
|
||||
Error::Transaction(e)
|
||||
|
@ -219,6 +229,23 @@ impl BlockHeader {
|
|||
hasher.finalize(&mut 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.
|
||||
|
@ -658,7 +685,17 @@ impl Block {
|
|||
self.verify_coinbase()?;
|
||||
self.verify_inputs()?;
|
||||
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> {
|
||||
|
@ -707,37 +744,22 @@ impl Block {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify sums
|
||||
pub fn verify_sums(
|
||||
&self,
|
||||
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.
|
||||
/// Verify the kernel signatures.
|
||||
/// Note: this is expensive.
|
||||
fn verify_kernel_signatures(&self) -> Result<(), Error> {
|
||||
for x in &self.kernels {
|
||||
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);
|
||||
/// Verify all the output rangeproofs.
|
||||
/// Note: this is expensive.
|
||||
fn verify_rangeproofs(&self) -> Result<(), Error> {
|
||||
for x in &self.outputs {
|
||||
x.verify_proof()?;
|
||||
}
|
||||
|
||||
Ok((io_sum, kernel_sum))
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate the coinbase outputs generated by miners. Entails 2 main
|
||||
|
|
169
core/src/core/committed.rs
Normal file
169
core/src/core/committed.rs
Normal 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))
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
//! Core types
|
||||
|
||||
pub mod block;
|
||||
pub mod committed;
|
||||
pub mod hash;
|
||||
pub mod id;
|
||||
pub mod pmmr;
|
||||
|
@ -23,122 +24,19 @@ pub mod transaction;
|
|||
use consensus::GRIN_BASE;
|
||||
#[allow(dead_code)]
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::cmp::Ordering;
|
||||
use std::num::ParseFloatError;
|
||||
use std::{fmt, iter};
|
||||
|
||||
use util::secp::pedersen::*;
|
||||
use util::{secp, secp_static, static_secp_instance};
|
||||
|
||||
pub use self::block::*;
|
||||
pub use self::committed::Committed;
|
||||
pub use self::id::ShortId;
|
||||
pub use self::transaction::*;
|
||||
use core::hash::Hashed;
|
||||
use global;
|
||||
use keychain;
|
||||
use keychain::BlindingFactor;
|
||||
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
|
||||
#[derive(Clone, PartialOrd, PartialEq)]
|
||||
pub struct Proof {
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
//! Transactions
|
||||
|
||||
use std::cmp::Ordering;
|
||||
use std::cmp::max;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::HashSet;
|
||||
use std::io::Cursor;
|
||||
use std::{error, fmt};
|
||||
|
@ -26,11 +26,12 @@ use util::{kernel_sig_msg, static_secp_instance};
|
|||
|
||||
use consensus;
|
||||
use consensus::VerifySortOrder;
|
||||
use core::BlockHeader;
|
||||
use core::Committed;
|
||||
use core::committed;
|
||||
use core::committed::Committed;
|
||||
use core::global;
|
||||
use core::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use core::pmmr::MerkleProof;
|
||||
use core::BlockHeader;
|
||||
use keychain;
|
||||
use keychain::BlindingFactor;
|
||||
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
|
||||
/// repeated 3 times, indicating it's incorrect
|
||||
InvalidProofMessage,
|
||||
/// Error when sums do not verify correctly during tx aggregation.
|
||||
/// Likely a "double spend" across two unconfirmed txs.
|
||||
AggregationError,
|
||||
/// Error when verifying kernel sums via committed trait.
|
||||
Committed(committed::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
|
||||
/// Pedersen commitment and the signature, that guarantees that the commitments
|
||||
/// amount to zero.
|
||||
|
@ -387,6 +393,10 @@ impl Transaction {
|
|||
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.
|
||||
pub fn lock_height(&self) -> u64 {
|
||||
self.kernels
|
||||
|
@ -394,46 +404,24 @@ impl Transaction {
|
|||
.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> {
|
||||
// Verify the kernel signatures.
|
||||
// Note: this is expensive.
|
||||
for x in &self.kernels {
|
||||
x.verify()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify all the output rangeproofs.
|
||||
/// Note: this is expensive.
|
||||
fn verify_rangeproofs(&self) -> Result<(), Error> {
|
||||
// Verify all the output rangeproofs.
|
||||
// Note: this is expensive.
|
||||
for x in &self.outputs {
|
||||
x.verify_proof()?;
|
||||
}
|
||||
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
|
||||
/// excess value against the signature as well as range proofs for each
|
||||
/// output.
|
||||
|
@ -442,7 +430,7 @@ impl Transaction {
|
|||
return Err(Error::TooManyInputs);
|
||||
}
|
||||
self.verify_sorted()?;
|
||||
self.verify_kernel_sums()?;
|
||||
self.verify_kernel_sums(self.overage(), self.offset, None, None)?;
|
||||
self.verify_rangeproofs()?;
|
||||
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);
|
||||
|
||||
// We need to check sums here as aggregation/cut-through may have created an
|
||||
// invalid tx.
|
||||
tx.verify_kernel_sums()
|
||||
.map_err(|_| Error::AggregationError)?;
|
||||
// We need to check sums here as aggregation/cut-through
|
||||
// may have created an invalid tx.
|
||||
tx.verify_kernel_sums(tx.overage(), tx.offset, None, None)?;
|
||||
|
||||
Ok(tx)
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ use grin_core::consensus::{BLOCK_OUTPUT_WEIGHT, MAX_BLOCK_WEIGHT};
|
|||
use grin_core::core::block::Error;
|
||||
use grin_core::core::hash::Hashed;
|
||||
use grin_core::core::id::{ShortId, ShortIdentifiable};
|
||||
use grin_core::core::Committed;
|
||||
use grin_core::core::{Block, BlockHeader, CompactBlock, KernelFeatures, OutputFeatures};
|
||||
use grin_core::global;
|
||||
use grin_core::ser;
|
||||
|
@ -167,7 +168,12 @@ fn remove_coinbase_output_flag() {
|
|||
.remove(OutputFeatures::COINBASE_OUTPUT);
|
||||
|
||||
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!(
|
||||
b.validate(&zero_commit, &zero_commit),
|
||||
Err(Error::CoinbaseSumMismatch)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
use failure::{Backtrace, Context, Fail};
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use core::core::committed;
|
||||
use core::core::transaction;
|
||||
use keychain::{self, extkey};
|
||||
use util::secp;
|
||||
|
@ -50,6 +51,9 @@ pub enum ErrorKind {
|
|||
/// Fee error
|
||||
#[fail(display = "Fee Error")]
|
||||
Fee(String),
|
||||
/// Error from summing commitments via committed trait.
|
||||
#[fail(display = "Committed Error")]
|
||||
Committed(committed::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 {
|
||||
fn from(error: keychain::Error) -> Error {
|
||||
Error {
|
||||
|
|
|
@ -17,13 +17,15 @@
|
|||
use rand::thread_rng;
|
||||
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 libtx::error::{Error, ErrorKind};
|
||||
use libtx::{aggsig, build, tx_fee};
|
||||
|
||||
use util::secp::Signature;
|
||||
use util::secp::key::{PublicKey, SecretKey};
|
||||
use util::secp::Signature;
|
||||
use util::{secp, LOGGER};
|
||||
|
||||
/// Public data for each participant in the slate
|
||||
|
|
Loading…
Reference in a new issue