mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
Refactor transaction building combinators (#3057)
* tx combinators now take operate on Result to allow for more robust errors handling replace with_fee() and with_lock_height() with a more flexible with_features() * pass kernel features in as arg to build::transaction() * fix chain tests * fix pool tests * do not pass kernel around in the combinators just set it once on the tx when building * build::partial_transaction now takes a existing tx to build on
This commit is contained in:
parent
eadf66339d
commit
50ce7ba043
9 changed files with 155 additions and 225 deletions
|
@ -16,7 +16,7 @@ use self::chain::types::{NoopAdapter, Tip};
|
||||||
use self::chain::Chain;
|
use self::chain::Chain;
|
||||||
use self::core::core::hash::Hashed;
|
use self::core::core::hash::Hashed;
|
||||||
use self::core::core::verifier_cache::LruVerifierCache;
|
use self::core::core::verifier_cache::LruVerifierCache;
|
||||||
use self::core::core::{Block, BlockHeader, OutputIdentifier, Transaction};
|
use self::core::core::{Block, BlockHeader, KernelFeatures, OutputIdentifier, Transaction};
|
||||||
use self::core::global::ChainTypes;
|
use self::core::global::ChainTypes;
|
||||||
use self::core::libtx::{self, build, ProofBuilder};
|
use self::core::libtx::{self, build, ProofBuilder};
|
||||||
use self::core::pow::Difficulty;
|
use self::core::pow::Difficulty;
|
||||||
|
@ -562,10 +562,10 @@ fn spend_in_fork_and_compact() {
|
||||||
let key_id31 = ExtKeychainPath::new(1, 31, 0, 0, 0).to_identifier();
|
let key_id31 = ExtKeychainPath::new(1, 31, 0, 0, 0).to_identifier();
|
||||||
|
|
||||||
let tx1 = build::transaction(
|
let tx1 = build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: 20000 },
|
||||||
vec![
|
vec![
|
||||||
build::coinbase_input(consensus::REWARD, key_id2.clone()),
|
build::coinbase_input(consensus::REWARD, key_id2.clone()),
|
||||||
build::output(consensus::REWARD - 20000, key_id30.clone()),
|
build::output(consensus::REWARD - 20000, key_id30.clone()),
|
||||||
build::with_fee(20000),
|
|
||||||
],
|
],
|
||||||
&kc,
|
&kc,
|
||||||
&pb,
|
&pb,
|
||||||
|
@ -580,10 +580,10 @@ fn spend_in_fork_and_compact() {
|
||||||
chain.validate(false).unwrap();
|
chain.validate(false).unwrap();
|
||||||
|
|
||||||
let tx2 = build::transaction(
|
let tx2 = build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: 20000 },
|
||||||
vec![
|
vec![
|
||||||
build::input(consensus::REWARD - 20000, key_id30.clone()),
|
build::input(consensus::REWARD - 20000, key_id30.clone()),
|
||||||
build::output(consensus::REWARD - 40000, key_id31.clone()),
|
build::output(consensus::REWARD - 40000, key_id31.clone()),
|
||||||
build::with_fee(20000),
|
|
||||||
],
|
],
|
||||||
&kc,
|
&kc,
|
||||||
&pb,
|
&pb,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
use self::chain::types::NoopAdapter;
|
use self::chain::types::NoopAdapter;
|
||||||
use self::chain::ErrorKind;
|
use self::chain::ErrorKind;
|
||||||
use self::core::core::verifier_cache::LruVerifierCache;
|
use self::core::core::verifier_cache::LruVerifierCache;
|
||||||
|
use self::core::core::KernelFeatures;
|
||||||
use self::core::global::{self, ChainTypes};
|
use self::core::global::{self, ChainTypes};
|
||||||
use self::core::libtx::{self, build, ProofBuilder};
|
use self::core::libtx::{self, build, ProofBuilder};
|
||||||
use self::core::pow::Difficulty;
|
use self::core::pow::Difficulty;
|
||||||
|
@ -99,10 +100,10 @@ fn test_coinbase_maturity() {
|
||||||
// here we build a tx that attempts to spend the earlier coinbase output
|
// here we build a tx that attempts to spend the earlier coinbase output
|
||||||
// this is not a valid tx as the coinbase output cannot be spent yet
|
// this is not a valid tx as the coinbase output cannot be spent yet
|
||||||
let coinbase_txn = build::transaction(
|
let coinbase_txn = build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: 2 },
|
||||||
vec![
|
vec![
|
||||||
build::coinbase_input(amount, key_id1.clone()),
|
build::coinbase_input(amount, key_id1.clone()),
|
||||||
build::output(amount - 2, key_id2.clone()),
|
build::output(amount - 2, key_id2.clone()),
|
||||||
build::with_fee(2),
|
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
|
@ -182,10 +183,10 @@ fn test_coinbase_maturity() {
|
||||||
// here we build a tx that attempts to spend the earlier coinbase output
|
// here we build a tx that attempts to spend the earlier coinbase output
|
||||||
// this is not a valid tx as the coinbase output cannot be spent yet
|
// this is not a valid tx as the coinbase output cannot be spent yet
|
||||||
let coinbase_txn = build::transaction(
|
let coinbase_txn = build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: 2 },
|
||||||
vec![
|
vec![
|
||||||
build::coinbase_input(amount, key_id1.clone()),
|
build::coinbase_input(amount, key_id1.clone()),
|
||||||
build::output(amount - 2, key_id2.clone()),
|
build::output(amount - 2, key_id2.clone()),
|
||||||
build::with_fee(2),
|
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
|
|
|
@ -463,42 +463,17 @@ impl TxKernel {
|
||||||
|
|
||||||
/// Build an empty tx kernel with zero values.
|
/// Build an empty tx kernel with zero values.
|
||||||
pub fn empty() -> TxKernel {
|
pub fn empty() -> TxKernel {
|
||||||
|
TxKernel::with_features(KernelFeatures::Plain { fee: 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build an empty tx kernel with the provided kernel features.
|
||||||
|
pub fn with_features(features: KernelFeatures) -> TxKernel {
|
||||||
TxKernel {
|
TxKernel {
|
||||||
features: KernelFeatures::Plain { fee: 0 },
|
features,
|
||||||
excess: Commitment::from_vec(vec![0; 33]),
|
excess: Commitment::from_vec(vec![0; 33]),
|
||||||
excess_sig: secp::Signature::from_raw_data(&[0; 64]).unwrap(),
|
excess_sig: secp::Signature::from_raw_data(&[0; 64]).unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new tx kernel with the provided fee.
|
|
||||||
/// Will panic if we cannot safely do this on the existing kernel.
|
|
||||||
/// i.e. Do not try and set a fee on a coinbase kernel.
|
|
||||||
pub fn with_fee(self, fee: u64) -> TxKernel {
|
|
||||||
match self.features {
|
|
||||||
KernelFeatures::Plain { .. } => {
|
|
||||||
let features = KernelFeatures::Plain { fee };
|
|
||||||
TxKernel { features, ..self }
|
|
||||||
}
|
|
||||||
KernelFeatures::HeightLocked { lock_height, .. } => {
|
|
||||||
let features = KernelFeatures::HeightLocked { fee, lock_height };
|
|
||||||
TxKernel { features, ..self }
|
|
||||||
}
|
|
||||||
KernelFeatures::Coinbase => panic!("fee not supported on coinbase kernel"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Builds a new tx kernel with the provided lock_height.
|
|
||||||
/// Will panic if we cannot safely do this on the existing kernel.
|
|
||||||
/// i.e. Do not try and set a lock_height on a coinbase kernel.
|
|
||||||
pub fn with_lock_height(self, lock_height: u64) -> TxKernel {
|
|
||||||
match self.features {
|
|
||||||
KernelFeatures::Plain { fee } | KernelFeatures::HeightLocked { fee, .. } => {
|
|
||||||
let features = KernelFeatures::HeightLocked { fee, lock_height };
|
|
||||||
TxKernel { features, ..self }
|
|
||||||
}
|
|
||||||
KernelFeatures::Coinbase => panic!("lock_height not supported on coinbase kernel"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enum of possible tx weight verification options -
|
/// Enum of possible tx weight verification options -
|
||||||
|
@ -684,6 +659,13 @@ impl TransactionBody {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a new TransactionBody replacing any existing kernels with the provided kernel.
|
||||||
|
pub fn replace_kernel(mut self, kernel: TxKernel) -> TransactionBody {
|
||||||
|
self.kernels.clear();
|
||||||
|
self.kernels.push(kernel);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Total fee for a TransactionBody is the sum of fees of all fee carrying kernels.
|
/// Total fee for a TransactionBody is the sum of fees of all fee carrying kernels.
|
||||||
pub fn fee(&self) -> u64 {
|
pub fn fee(&self) -> u64 {
|
||||||
self.kernels
|
self.kernels
|
||||||
|
@ -1012,8 +994,8 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new transaction with the provided output added. Existing
|
/// Builds a new transaction with the provided kernel added. Existing
|
||||||
/// outputs, if any, are kept intact.
|
/// kernels, if any, are kept intact.
|
||||||
/// Sort order is maintained.
|
/// Sort order is maintained.
|
||||||
pub fn with_kernel(self, kernel: TxKernel) -> Transaction {
|
pub fn with_kernel(self, kernel: TxKernel) -> Transaction {
|
||||||
Transaction {
|
Transaction {
|
||||||
|
@ -1022,6 +1004,14 @@ impl Transaction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Builds a new transaction replacing any existing kernels with the provided kernel.
|
||||||
|
pub fn replace_kernel(self, kernel: TxKernel) -> Transaction {
|
||||||
|
Transaction {
|
||||||
|
body: self.body.replace_kernel(kernel),
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get inputs
|
/// Get inputs
|
||||||
pub fn inputs(&self) -> &Vec<Input> {
|
pub fn inputs(&self) -> &Vec<Input> {
|
||||||
&self.body.inputs
|
&self.body.inputs
|
||||||
|
|
|
@ -22,10 +22,16 @@
|
||||||
//! _transaction_ function.
|
//! _transaction_ function.
|
||||||
//!
|
//!
|
||||||
//! Example:
|
//! Example:
|
||||||
//! build::transaction(vec![input_rand(75), output_rand(42), output_rand(32),
|
//! build::transaction(
|
||||||
//! with_fee(1)])
|
//! KernelFeatures::Plain{ fee: 2 },
|
||||||
|
//! vec![
|
||||||
|
//! input_rand(75),
|
||||||
|
//! output_rand(42),
|
||||||
|
//! output_rand(32),
|
||||||
|
//! ]
|
||||||
|
//! )
|
||||||
|
|
||||||
use crate::core::{Input, Output, OutputFeatures, Transaction, TxKernel};
|
use crate::core::{Input, KernelFeatures, Output, OutputFeatures, Transaction, TxKernel};
|
||||||
use crate::keychain::{BlindSum, BlindingFactor, Identifier, Keychain};
|
use crate::keychain::{BlindSum, BlindingFactor, Identifier, Keychain};
|
||||||
use crate::libtx::proof::{self, ProofBuild};
|
use crate::libtx::proof::{self, ProofBuild};
|
||||||
use crate::libtx::{aggsig, Error};
|
use crate::libtx::{aggsig, Error};
|
||||||
|
@ -44,11 +50,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Function type returned by the transaction combinators. Transforms a
|
/// Function type returned by the transaction combinators. Transforms a
|
||||||
/// (Transaction, BlindSum) pair into another, provided some context.
|
/// (Transaction, BlindSum) tuple into another, given the provided context.
|
||||||
|
/// Will return an Err if seomthing went wrong at any point during transaction building.
|
||||||
pub type Append<K, B> = dyn for<'a> Fn(
|
pub type Append<K, B> = dyn for<'a> Fn(
|
||||||
&'a mut Context<'_, K, B>,
|
&'a mut Context<'_, K, B>,
|
||||||
(Transaction, TxKernel, BlindSum),
|
Result<(Transaction, BlindSum), Error>,
|
||||||
) -> (Transaction, TxKernel, BlindSum);
|
) -> Result<(Transaction, BlindSum), Error>;
|
||||||
|
|
||||||
/// Adds an input with the provided value and blinding key to the transaction
|
/// Adds an input with the provided value and blinding key to the transaction
|
||||||
/// being built.
|
/// being built.
|
||||||
|
@ -58,17 +65,21 @@ where
|
||||||
B: ProofBuild,
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |build, acc| -> Result<(Transaction, BlindSum), Error> {
|
||||||
let commit = build
|
if let Ok((tx, sum)) = acc {
|
||||||
.keychain
|
let commit =
|
||||||
.commit(value, &key_id, &SwitchCommitmentType::Regular)
|
build
|
||||||
.unwrap(); // TODO: proper support for different switch commitment schemes
|
.keychain
|
||||||
let input = Input::new(features, commit);
|
.commit(value, &key_id, &SwitchCommitmentType::Regular)?;
|
||||||
(
|
// TODO: proper support for different switch commitment schemes
|
||||||
tx.with_input(input),
|
let input = Input::new(features, commit);
|
||||||
kern,
|
Ok((
|
||||||
sum.sub_key_id(key_id.to_value_path(value)),
|
tx.with_input(input),
|
||||||
)
|
sum.sub_key_id(key_id.to_value_path(value)),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
acc
|
||||||
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -105,11 +116,13 @@ where
|
||||||
B: ProofBuild,
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |build, acc| -> Result<(Transaction, BlindSum), Error> {
|
||||||
|
let (tx, sum) = acc?;
|
||||||
|
|
||||||
// TODO: proper support for different switch commitment schemes
|
// TODO: proper support for different switch commitment schemes
|
||||||
let switch = &SwitchCommitmentType::Regular;
|
let switch = &SwitchCommitmentType::Regular;
|
||||||
|
|
||||||
let commit = build.keychain.commit(value, &key_id, switch).unwrap();
|
let commit = build.keychain.commit(value, &key_id, switch)?;
|
||||||
|
|
||||||
debug!("Building output: {}, {:?}", value, commit);
|
debug!("Building output: {}, {:?}", value, commit);
|
||||||
|
|
||||||
|
@ -121,44 +134,16 @@ where
|
||||||
switch,
|
switch,
|
||||||
commit,
|
commit,
|
||||||
None,
|
None,
|
||||||
)
|
)?;
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
(
|
Ok((
|
||||||
tx.with_output(Output {
|
tx.with_output(Output {
|
||||||
features: OutputFeatures::Plain,
|
features: OutputFeatures::Plain,
|
||||||
commit,
|
commit,
|
||||||
proof: rproof,
|
proof: rproof,
|
||||||
}),
|
}),
|
||||||
kern,
|
|
||||||
sum.add_key_id(key_id.to_value_path(value)),
|
sum.add_key_id(key_id.to_value_path(value)),
|
||||||
)
|
))
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the fee on the transaction being built.
|
|
||||||
pub fn with_fee<K, B>(fee: u64) -> Box<Append<K, B>>
|
|
||||||
where
|
|
||||||
K: Keychain,
|
|
||||||
B: ProofBuild,
|
|
||||||
{
|
|
||||||
Box::new(
|
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
|
||||||
(tx, kern.with_fee(fee), sum)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the lock_height on the transaction being built.
|
|
||||||
pub fn with_lock_height<K, B>(lock_height: u64) -> Box<Append<K, B>>
|
|
||||||
where
|
|
||||||
K: Keychain,
|
|
||||||
B: ProofBuild,
|
|
||||||
{
|
|
||||||
Box::new(
|
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
|
||||||
(tx, kern.with_lock_height(lock_height), sum)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -172,53 +157,32 @@ where
|
||||||
B: ProofBuild,
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, acc| -> Result<(Transaction, BlindSum), Error> {
|
||||||
(tx, kern, sum.add_blinding_factor(excess.clone()))
|
acc.map(|(tx, sum)| (tx, sum.add_blinding_factor(excess.clone())))
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets a known tx "offset". Used in final step of tx construction.
|
|
||||||
pub fn with_offset<K, B>(offset: BlindingFactor) -> Box<Append<K, B>>
|
|
||||||
where
|
|
||||||
K: Keychain,
|
|
||||||
B: ProofBuild,
|
|
||||||
{
|
|
||||||
Box::new(
|
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
|
||||||
(tx.with_offset(offset.clone()), kern, sum)
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets an initial transaction to add to when building a new transaction.
|
/// Sets an initial transaction to add to when building a new transaction.
|
||||||
/// We currently only support building a tx with a single kernel with
|
pub fn initial_tx<K, B>(tx: Transaction) -> Box<Append<K, B>>
|
||||||
/// build::transaction()
|
|
||||||
pub fn initial_tx<K, B>(mut tx: Transaction) -> Box<Append<K, B>>
|
|
||||||
where
|
where
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
B: ProofBuild,
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
assert_eq!(tx.kernels().len(), 1);
|
|
||||||
let kern = tx.kernels_mut().remove(0);
|
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (_, _, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, acc| -> Result<(Transaction, BlindSum), Error> {
|
||||||
(tx.clone(), kern.clone(), sum)
|
acc.map(|(_, sum)| (tx.clone(), sum))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a new transaction by combining all the combinators provided in a
|
/// Takes an existing transaction and partially builds on it.
|
||||||
/// Vector. Transactions can either be built "from scratch" with a list of
|
|
||||||
/// inputs or outputs or from a pre-existing transaction that gets added to.
|
|
||||||
///
|
///
|
||||||
/// Example:
|
/// Example:
|
||||||
/// let (tx1, sum) = build::transaction(vec![input_rand(4), output_rand(1),
|
/// let (tx, sum) = build::transaction(tx, vec![input_rand(4), output_rand(1))], keychain)?;
|
||||||
/// with_fee(1)], keychain).unwrap();
|
|
||||||
/// let (tx2, _) = build::transaction(vec![initial_tx(tx1), with_excess(sum),
|
|
||||||
/// output_rand(2)], keychain).unwrap();
|
|
||||||
///
|
///
|
||||||
pub fn partial_transaction<K, B>(
|
pub fn partial_transaction<K, B>(
|
||||||
|
tx: Transaction,
|
||||||
elems: Vec<Box<Append<K, B>>>,
|
elems: Vec<Box<Append<K, B>>>,
|
||||||
keychain: &K,
|
keychain: &K,
|
||||||
builder: &B,
|
builder: &B,
|
||||||
|
@ -228,22 +192,16 @@ where
|
||||||
B: ProofBuild,
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
let mut ctx = Context { keychain, builder };
|
let mut ctx = Context { keychain, builder };
|
||||||
let (tx, kern, sum) = elems.iter().fold(
|
let (tx, sum) = elems
|
||||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
.iter()
|
||||||
|acc, elem| elem(&mut ctx, acc),
|
.fold(Ok((tx, BlindSum::new())), |acc, elem| elem(&mut ctx, acc))?;
|
||||||
);
|
|
||||||
let blind_sum = ctx.keychain.blind_sum(&sum)?;
|
let blind_sum = ctx.keychain.blind_sum(&sum)?;
|
||||||
|
|
||||||
// we only support building a tx with a single kernel via build::transaction()
|
|
||||||
assert!(tx.kernels().is_empty());
|
|
||||||
|
|
||||||
let tx = tx.with_kernel(kern);
|
|
||||||
|
|
||||||
Ok((tx, blind_sum))
|
Ok((tx, blind_sum))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a complete transaction.
|
/// Builds a complete transaction.
|
||||||
pub fn transaction<K, B>(
|
pub fn transaction<K, B>(
|
||||||
|
features: KernelFeatures,
|
||||||
elems: Vec<Box<Append<K, B>>>,
|
elems: Vec<Box<Append<K, B>>>,
|
||||||
keychain: &K,
|
keychain: &K,
|
||||||
builder: &B,
|
builder: &B,
|
||||||
|
@ -253,10 +211,11 @@ where
|
||||||
B: ProofBuild,
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
let mut ctx = Context { keychain, builder };
|
let mut ctx = Context { keychain, builder };
|
||||||
let (mut tx, mut kern, sum) = elems.iter().fold(
|
let (mut tx, sum) = elems
|
||||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
.iter()
|
||||||
|acc, elem| elem(&mut ctx, acc),
|
.fold(Ok((Transaction::empty(), BlindSum::new())), |acc, elem| {
|
||||||
);
|
elem(&mut ctx, acc)
|
||||||
|
})?;
|
||||||
let blind_sum = ctx.keychain.blind_sum(&sum)?;
|
let blind_sum = ctx.keychain.blind_sum(&sum)?;
|
||||||
|
|
||||||
// Split the key so we can generate an offset for the tx.
|
// Split the key so we can generate an offset for the tx.
|
||||||
|
@ -264,6 +223,8 @@ where
|
||||||
let k1 = split.blind_1;
|
let k1 = split.blind_1;
|
||||||
let k2 = split.blind_2;
|
let k2 = split.blind_2;
|
||||||
|
|
||||||
|
let mut kern = TxKernel::with_features(features);
|
||||||
|
|
||||||
// Construct the message to be signed.
|
// Construct the message to be signed.
|
||||||
let msg = kern.msg_to_sign()?;
|
let msg = kern.msg_to_sign()?;
|
||||||
|
|
||||||
|
@ -271,17 +232,14 @@ where
|
||||||
let skey = k1.secret_key(&keychain.secp())?;
|
let skey = k1.secret_key(&keychain.secp())?;
|
||||||
kern.excess = ctx.keychain.secp().commit(0, skey)?;
|
kern.excess = ctx.keychain.secp().commit(0, skey)?;
|
||||||
let pubkey = &kern.excess.to_pubkey(&keychain.secp())?;
|
let pubkey = &kern.excess.to_pubkey(&keychain.secp())?;
|
||||||
kern.excess_sig =
|
kern.excess_sig = aggsig::sign_with_blinding(&keychain.secp(), &msg, &k1, Some(&pubkey))?;
|
||||||
aggsig::sign_with_blinding(&keychain.secp(), &msg, &k1, Some(&pubkey)).unwrap();
|
|
||||||
|
|
||||||
// Store the kernel offset (k2) on the tx.
|
// Store the kernel offset (k2) on the tx.
|
||||||
// Commitments will sum correctly when accounting for the offset.
|
// Commitments will sum correctly when accounting for the offset.
|
||||||
tx.offset = k2.clone();
|
tx.offset = k2.clone();
|
||||||
|
|
||||||
// Set the kernel on the tx (assert this is now a single-kernel tx).
|
// Set the kernel on the tx.
|
||||||
assert!(tx.kernels().is_empty());
|
let tx = tx.replace_kernel(kern);
|
||||||
let tx = tx.with_kernel(kern);
|
|
||||||
assert_eq!(tx.kernels().len(), 1);
|
|
||||||
|
|
||||||
Ok(tx)
|
Ok(tx)
|
||||||
}
|
}
|
||||||
|
@ -313,12 +271,8 @@ mod test {
|
||||||
let vc = verifier_cache();
|
let vc = verifier_cache();
|
||||||
|
|
||||||
let tx = transaction(
|
let tx = transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 2 },
|
||||||
input(10, key_id1),
|
vec![input(10, key_id1), input(12, key_id2), output(20, key_id3)],
|
||||||
input(12, key_id2),
|
|
||||||
output(20, key_id3),
|
|
||||||
with_fee(2),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -338,12 +292,8 @@ mod test {
|
||||||
let vc = verifier_cache();
|
let vc = verifier_cache();
|
||||||
|
|
||||||
let tx = transaction(
|
let tx = transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 2 },
|
||||||
input(10, key_id1),
|
vec![input(10, key_id1), input(12, key_id2), output(20, key_id3)],
|
||||||
input(12, key_id2),
|
|
||||||
output(20, key_id3),
|
|
||||||
with_fee(2),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -362,7 +312,8 @@ mod test {
|
||||||
let vc = verifier_cache();
|
let vc = verifier_cache();
|
||||||
|
|
||||||
let tx = transaction(
|
let tx = transaction(
|
||||||
vec![input(6, key_id1), output(2, key_id2), with_fee(4)],
|
KernelFeatures::Plain { fee: 4 },
|
||||||
|
vec![input(6, key_id1), output(2, key_id2)],
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
|
|
@ -44,6 +44,9 @@ pub enum ErrorKind {
|
||||||
/// Rangeproof error
|
/// Rangeproof error
|
||||||
#[fail(display = "Rangeproof Error")]
|
#[fail(display = "Rangeproof Error")]
|
||||||
RangeProof(String),
|
RangeProof(String),
|
||||||
|
/// Other error
|
||||||
|
#[fail(display = "Other Error")]
|
||||||
|
Other(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Fail for Error {
|
impl Fail for Error {
|
||||||
|
|
|
@ -24,7 +24,7 @@ use crate::core::core::Committed;
|
||||||
use crate::core::core::{
|
use crate::core::core::{
|
||||||
Block, BlockHeader, CompactBlock, HeaderVersion, KernelFeatures, OutputFeatures,
|
Block, BlockHeader, CompactBlock, HeaderVersion, KernelFeatures, OutputFeatures,
|
||||||
};
|
};
|
||||||
use crate::core::libtx::build::{self, input, output, with_fee};
|
use crate::core::libtx::build::{self, input, output};
|
||||||
use crate::core::libtx::ProofBuilder;
|
use crate::core::libtx::ProofBuilder;
|
||||||
use crate::core::{global, ser};
|
use crate::core::{global, ser};
|
||||||
use crate::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
use crate::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
||||||
|
@ -58,8 +58,9 @@ fn too_large_block() {
|
||||||
parts.push(output(5, pks.pop().unwrap()));
|
parts.push(output(5, pks.pop().unwrap()));
|
||||||
}
|
}
|
||||||
|
|
||||||
parts.append(&mut vec![input(500000, pks.pop().unwrap()), with_fee(2)]);
|
parts.append(&mut vec![input(500000, pks.pop().unwrap())]);
|
||||||
let tx = build::transaction(parts, &keychain, &builder).unwrap();
|
let tx =
|
||||||
|
build::transaction(KernelFeatures::Plain { fee: 2 }, parts, &keychain, &builder).unwrap();
|
||||||
|
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, 1, 0, 0, 0);
|
||||||
|
@ -92,7 +93,8 @@ fn block_with_cut_through() {
|
||||||
|
|
||||||
let mut btx1 = tx2i1o();
|
let mut btx1 = tx2i1o();
|
||||||
let mut btx2 = build::transaction(
|
let mut btx2 = build::transaction(
|
||||||
vec![input(7, key_id1), output(5, key_id2.clone()), with_fee(2)],
|
KernelFeatures::Plain { fee: 2 },
|
||||||
|
vec![input(7, key_id1), output(5, key_id2.clone())],
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -477,12 +479,8 @@ fn same_amount_outputs_copy_range_proof() {
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
|
||||||
let tx = build::transaction(
|
let tx = build::transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 1 },
|
||||||
input(7, key_id1),
|
vec![input(7, key_id1), output(3, key_id2), output(3, key_id3)],
|
||||||
output(3, key_id2),
|
|
||||||
output(3, key_id3),
|
|
||||||
with_fee(1),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -527,23 +525,19 @@ fn wrong_amount_range_proof() {
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
|
||||||
let tx1 = build::transaction(
|
let tx1 = build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: 1 },
|
||||||
vec![
|
vec![
|
||||||
input(7, key_id1.clone()),
|
input(7, key_id1.clone()),
|
||||||
output(3, key_id2.clone()),
|
output(3, key_id2.clone()),
|
||||||
output(3, key_id3.clone()),
|
output(3, key_id3.clone()),
|
||||||
with_fee(1),
|
|
||||||
],
|
],
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let tx2 = build::transaction(
|
let tx2 = build::transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 1 },
|
||||||
input(7, key_id1),
|
vec![input(7, key_id1), output(2, key_id2), output(4, key_id3)],
|
||||||
output(2, key_id2),
|
|
||||||
output(4, key_id3),
|
|
||||||
with_fee(1),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
|
|
@ -15,12 +15,9 @@
|
||||||
//! Common test functions
|
//! Common test functions
|
||||||
|
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use grin_core::core::{
|
use grin_core::core::{Block, BlockHeader, KernelFeatures, Transaction};
|
||||||
block::{Block, BlockHeader},
|
|
||||||
Transaction,
|
|
||||||
};
|
|
||||||
use grin_core::libtx::{
|
use grin_core::libtx::{
|
||||||
build::{self, input, output, with_fee},
|
build::{self, input, output},
|
||||||
proof::{ProofBuild, ProofBuilder},
|
proof::{ProofBuild, ProofBuilder},
|
||||||
reward,
|
reward,
|
||||||
};
|
};
|
||||||
|
@ -36,12 +33,8 @@ pub fn tx2i1o() -> Transaction {
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 2 },
|
||||||
input(10, key_id1),
|
vec![input(10, key_id1), input(11, key_id2), output(19, key_id3)],
|
||||||
input(11, key_id2),
|
|
||||||
output(19, key_id3),
|
|
||||||
with_fee(2),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -56,7 +49,8 @@ pub fn tx1i1o() -> Transaction {
|
||||||
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
let key_id2 = keychain::ExtKeychain::derive_key_id(1, 2, 0, 0, 0);
|
||||||
|
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![input(5, key_id1), output(3, key_id2), with_fee(2)],
|
KernelFeatures::Plain { fee: 2 },
|
||||||
|
vec![input(5, key_id1), output(3, key_id2)],
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -74,12 +68,8 @@ pub fn tx1i2o() -> Transaction {
|
||||||
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = keychain::ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 2 },
|
||||||
input(6, key_id1),
|
vec![input(6, key_id1), output(3, key_id2), output(1, key_id3)],
|
||||||
output(3, key_id2),
|
|
||||||
output(1, key_id3),
|
|
||||||
with_fee(2),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -124,7 +114,8 @@ where
|
||||||
B: ProofBuild,
|
B: ProofBuild,
|
||||||
{
|
{
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![input(v, key_id1), output(3, key_id2), with_fee(2)],
|
KernelFeatures::Plain { fee: 2 },
|
||||||
|
vec![input(v, key_id1), output(3, key_id2)],
|
||||||
keychain,
|
keychain,
|
||||||
builder,
|
builder,
|
||||||
)
|
)
|
||||||
|
|
|
@ -20,10 +20,10 @@ use self::core::core::block::BlockHeader;
|
||||||
use self::core::core::block::Error::KernelLockHeight;
|
use self::core::core::block::Error::KernelLockHeight;
|
||||||
use self::core::core::hash::{Hashed, ZERO_HASH};
|
use self::core::core::hash::{Hashed, ZERO_HASH};
|
||||||
use self::core::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
use self::core::core::verifier_cache::{LruVerifierCache, VerifierCache};
|
||||||
use self::core::core::{aggregate, deaggregate, KernelFeatures, Output, Transaction, Weighting};
|
use self::core::core::{
|
||||||
use self::core::libtx::build::{
|
aggregate, deaggregate, KernelFeatures, Output, Transaction, TxKernel, Weighting,
|
||||||
self, initial_tx, input, output, with_excess, with_fee, with_lock_height,
|
|
||||||
};
|
};
|
||||||
|
use self::core::libtx::build::{self, initial_tx, input, output, with_excess};
|
||||||
use self::core::libtx::ProofBuilder;
|
use self::core::libtx::ProofBuilder;
|
||||||
use self::core::ser;
|
use self::core::ser;
|
||||||
use self::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
use self::keychain::{BlindingFactor, ExtKeychain, Keychain};
|
||||||
|
@ -99,6 +99,7 @@ fn test_zero_commit_fails() {
|
||||||
|
|
||||||
// blinding should fail as signing with a zero r*G shouldn't work
|
// blinding should fail as signing with a zero r*G shouldn't work
|
||||||
build::transaction(
|
build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: 0 },
|
||||||
vec![input(10, key_id1.clone()), output(10, key_id1.clone())],
|
vec![input(10, key_id1.clone()), output(10, key_id1.clone())],
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
|
@ -120,12 +121,8 @@ fn build_tx_kernel() {
|
||||||
|
|
||||||
// first build a valid tx with corresponding blinding factor
|
// first build a valid tx with corresponding blinding factor
|
||||||
let tx = build::transaction(
|
let tx = build::transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 2 },
|
||||||
input(10, key_id1),
|
vec![input(10, key_id1), output(5, key_id2), output(3, key_id3)],
|
||||||
output(5, key_id2),
|
|
||||||
output(3, key_id3),
|
|
||||||
with_fee(2),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -373,12 +370,8 @@ fn hash_output() {
|
||||||
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
let key_id3 = ExtKeychain::derive_key_id(1, 3, 0, 0, 0);
|
||||||
|
|
||||||
let tx = build::transaction(
|
let tx = build::transaction(
|
||||||
vec![
|
KernelFeatures::Plain { fee: 1 },
|
||||||
input(75, key_id1),
|
vec![input(75, key_id1), output(42, key_id2), output(32, key_id3)],
|
||||||
output(42, key_id2),
|
|
||||||
output(32, key_id3),
|
|
||||||
with_fee(1),
|
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -439,12 +432,11 @@ fn tx_build_exchange() {
|
||||||
|
|
||||||
// Alice builds her transaction, with change, which also produces the sum
|
// Alice builds her transaction, with change, which also produces the sum
|
||||||
// of blinding factors before they're obscured.
|
// of blinding factors before they're obscured.
|
||||||
let (tx, sum) = build::partial_transaction(
|
let tx = Transaction::empty()
|
||||||
vec![in1, in2, output(1, key_id3), with_fee(2)],
|
.with_kernel(TxKernel::with_features(KernelFeatures::Plain { fee: 2 }));
|
||||||
&keychain,
|
let (tx, sum) =
|
||||||
&builder,
|
build::partial_transaction(tx, vec![in1, in2, output(1, key_id3)], &keychain, &builder)
|
||||||
)
|
.unwrap();
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
(tx, sum)
|
(tx, sum)
|
||||||
};
|
};
|
||||||
|
@ -453,6 +445,7 @@ fn tx_build_exchange() {
|
||||||
// blinding factors. He adds his output, finalizes the transaction so it's
|
// blinding factors. He adds his output, finalizes the transaction so it's
|
||||||
// ready for broadcast.
|
// ready for broadcast.
|
||||||
let tx_final = build::transaction(
|
let tx_final = build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: 2 },
|
||||||
vec![
|
vec![
|
||||||
initial_tx(tx_alice),
|
initial_tx(tx_alice),
|
||||||
with_excess(blind_sum),
|
with_excess(blind_sum),
|
||||||
|
@ -547,12 +540,11 @@ fn test_block_with_timelocked_tx() {
|
||||||
// first check we can add a timelocked tx where lock height matches current
|
// first check we can add a timelocked tx where lock height matches current
|
||||||
// block height and that the resulting block is valid
|
// block height and that the resulting block is valid
|
||||||
let tx1 = build::transaction(
|
let tx1 = build::transaction(
|
||||||
vec![
|
KernelFeatures::HeightLocked {
|
||||||
input(5, key_id1.clone()),
|
fee: 2,
|
||||||
output(3, key_id2.clone()),
|
lock_height: 1,
|
||||||
with_fee(2),
|
},
|
||||||
with_lock_height(1),
|
vec![input(5, key_id1.clone()), output(3, key_id2.clone())],
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
@ -572,12 +564,11 @@ fn test_block_with_timelocked_tx() {
|
||||||
// now try adding a timelocked tx where lock height is greater than current
|
// now try adding a timelocked tx where lock height is greater than current
|
||||||
// block height
|
// block height
|
||||||
let tx1 = build::transaction(
|
let tx1 = build::transaction(
|
||||||
vec![
|
KernelFeatures::HeightLocked {
|
||||||
input(5, key_id1.clone()),
|
fee: 2,
|
||||||
output(3, key_id2.clone()),
|
lock_height: 2,
|
||||||
with_fee(2),
|
},
|
||||||
with_lock_height(2),
|
vec![input(5, key_id1.clone()), output(3, key_id2.clone())],
|
||||||
],
|
|
||||||
&keychain,
|
&keychain,
|
||||||
&builder,
|
&builder,
|
||||||
)
|
)
|
||||||
|
|
|
@ -18,7 +18,7 @@ use self::chain::store::ChainStore;
|
||||||
use self::chain::types::Tip;
|
use self::chain::types::Tip;
|
||||||
use self::core::core::hash::{Hash, Hashed};
|
use self::core::core::hash::{Hash, Hashed};
|
||||||
use self::core::core::verifier_cache::VerifierCache;
|
use self::core::core::verifier_cache::VerifierCache;
|
||||||
use self::core::core::{Block, BlockHeader, BlockSums, Committed, Transaction};
|
use self::core::core::{Block, BlockHeader, BlockSums, Committed, KernelFeatures, Transaction};
|
||||||
use self::core::libtx;
|
use self::core::libtx;
|
||||||
use self::keychain::{ExtKeychain, Keychain};
|
use self::keychain::{ExtKeychain, Keychain};
|
||||||
use self::pool::types::*;
|
use self::pool::types::*;
|
||||||
|
@ -193,9 +193,13 @@ where
|
||||||
tx_elements.push(libtx::build::output(output_value, key_id));
|
tx_elements.push(libtx::build::output(output_value, key_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_elements.push(libtx::build::with_fee(fees as u64));
|
libtx::build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: fees as u64 },
|
||||||
libtx::build::transaction(tx_elements, keychain, &libtx::ProofBuilder::new(keychain)).unwrap()
|
tx_elements,
|
||||||
|
keychain,
|
||||||
|
&libtx::ProofBuilder::new(keychain),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_transaction<K>(
|
pub fn test_transaction<K>(
|
||||||
|
@ -223,9 +227,14 @@ where
|
||||||
let key_id = ExtKeychain::derive_key_id(1, output_value as u32, 0, 0, 0);
|
let key_id = ExtKeychain::derive_key_id(1, output_value as u32, 0, 0, 0);
|
||||||
tx_elements.push(libtx::build::output(output_value, key_id));
|
tx_elements.push(libtx::build::output(output_value, key_id));
|
||||||
}
|
}
|
||||||
tx_elements.push(libtx::build::with_fee(fees as u64));
|
|
||||||
|
|
||||||
libtx::build::transaction(tx_elements, keychain, &libtx::ProofBuilder::new(keychain)).unwrap()
|
libtx::build::transaction(
|
||||||
|
KernelFeatures::Plain { fee: fees as u64 },
|
||||||
|
tx_elements,
|
||||||
|
keychain,
|
||||||
|
&libtx::ProofBuilder::new(keychain),
|
||||||
|
)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_source() -> TxSource {
|
pub fn test_source() -> TxSource {
|
||||||
|
|
Loading…
Reference in a new issue