mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 17:01:09 +03:00
Refactor the Keychain to be based on a trait (#1146)
* First pass at restructuring the keychain crate and introducing a Keychain trait * Parameterized everything that had to. Stuff compiles. * More stuff compiles, fix most tests * Big merge, pushing down opening the keychain forced adding factory methods on trait * Test fixes for pool and servers crate
This commit is contained in:
parent
a6590ea0ae
commit
af178f82f8
43 changed files with 840 additions and 678 deletions
|
@ -20,10 +20,10 @@ use std::fs::File;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
|
use core::core::Committed;
|
||||||
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;
|
||||||
|
@ -31,8 +31,8 @@ use pipe;
|
||||||
use store;
|
use store;
|
||||||
use txhashset;
|
use txhashset;
|
||||||
use types::*;
|
use types::*;
|
||||||
use util::secp::pedersen::{Commitment, RangeProof};
|
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
use util::secp::pedersen::{Commitment, RangeProof};
|
||||||
|
|
||||||
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
||||||
pub const MAX_ORPHAN_SIZE: usize = 200;
|
pub const MAX_ORPHAN_SIZE: usize = 200;
|
||||||
|
|
|
@ -24,15 +24,15 @@ extern crate time;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use chain::types::*;
|
|
||||||
use chain::Chain;
|
use chain::Chain;
|
||||||
|
use chain::types::*;
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
use core::core::{Block, BlockHeader, Transaction};
|
use core::core::{Block, BlockHeader, Transaction};
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
use core::{consensus, genesis};
|
use core::{consensus, genesis};
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use wallet::libtx;
|
use wallet::libtx;
|
||||||
|
|
||||||
use core::pow;
|
use core::pow;
|
||||||
|
@ -69,7 +69,7 @@ fn data_files() {
|
||||||
//new block so chain references should be freed
|
//new block so chain references should be freed
|
||||||
{
|
{
|
||||||
let chain = setup(chain_dir);
|
let chain = setup(chain_dir);
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
for n in 1..4 {
|
for n in 1..4 {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
@ -114,14 +114,14 @@ fn data_files() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _prepare_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
fn _prepare_block(kc: &ExtKeychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
||||||
let mut b = _prepare_block_nosum(kc, prev, diff, vec![]);
|
let mut b = _prepare_block_nosum(kc, prev, diff, vec![]);
|
||||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _prepare_block_tx(
|
fn _prepare_block_tx(
|
||||||
kc: &Keychain,
|
kc: &ExtKeychain,
|
||||||
prev: &BlockHeader,
|
prev: &BlockHeader,
|
||||||
chain: &Chain,
|
chain: &Chain,
|
||||||
diff: u64,
|
diff: u64,
|
||||||
|
@ -132,14 +132,14 @@ fn _prepare_block_tx(
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _prepare_fork_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
fn _prepare_fork_block(kc: &ExtKeychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
||||||
let mut b = _prepare_block_nosum(kc, prev, diff, vec![]);
|
let mut b = _prepare_block_nosum(kc, prev, diff, vec![]);
|
||||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _prepare_fork_block_tx(
|
fn _prepare_fork_block_tx(
|
||||||
kc: &Keychain,
|
kc: &ExtKeychain,
|
||||||
prev: &BlockHeader,
|
prev: &BlockHeader,
|
||||||
chain: &Chain,
|
chain: &Chain,
|
||||||
diff: u64,
|
diff: u64,
|
||||||
|
@ -151,7 +151,7 @@ fn _prepare_fork_block_tx(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _prepare_block_nosum(
|
fn _prepare_block_nosum(
|
||||||
kc: &Keychain,
|
kc: &ExtKeychain,
|
||||||
prev: &BlockHeader,
|
prev: &BlockHeader,
|
||||||
diff: u64,
|
diff: u64,
|
||||||
txs: Vec<&Transaction>,
|
txs: Vec<&Transaction>,
|
||||||
|
@ -159,7 +159,7 @@ fn _prepare_block_nosum(
|
||||||
let key_id = kc.derive_key_id(diff as u32).unwrap();
|
let key_id = kc.derive_key_id(diff as u32).unwrap();
|
||||||
|
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward = libtx::reward::output(&kc, &key_id, fees, prev.height).unwrap();
|
let reward = libtx::reward::output(kc, &key_id, fees, prev.height).unwrap();
|
||||||
let mut b = match core::core::Block::new(
|
let mut b = match core::core::Block::new(
|
||||||
prev,
|
prev,
|
||||||
txs.into_iter().cloned().collect(),
|
txs.into_iter().cloned().collect(),
|
||||||
|
|
|
@ -34,7 +34,7 @@ use core::global;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
use wallet::libtx::{self, build};
|
use wallet::libtx::{self, build};
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
|
|
||||||
use core::pow;
|
use core::pow;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ fn setup(dir_name: &str) -> Chain {
|
||||||
#[test]
|
#[test]
|
||||||
fn mine_empty_chain() {
|
fn mine_empty_chain() {
|
||||||
let chain = setup(".grin");
|
let chain = setup(".grin");
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
for n in 1..4 {
|
for n in 1..4 {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
@ -107,7 +107,7 @@ fn mine_empty_chain() {
|
||||||
#[test]
|
#[test]
|
||||||
fn mine_forks() {
|
fn mine_forks() {
|
||||||
let chain = setup(".grin2");
|
let chain = setup(".grin2");
|
||||||
let kc = Keychain::from_random_seed().unwrap();
|
let kc = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
// add a first block to not fork genesis
|
// add a first block to not fork genesis
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
@ -148,7 +148,7 @@ fn mine_forks() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn mine_losing_fork() {
|
fn mine_losing_fork() {
|
||||||
let kc = Keychain::from_random_seed().unwrap();
|
let kc = ExtKeychain::from_random_seed().unwrap();
|
||||||
let chain = setup(".grin3");
|
let chain = setup(".grin3");
|
||||||
|
|
||||||
// add a first block we'll be forking from
|
// add a first block we'll be forking from
|
||||||
|
@ -179,7 +179,7 @@ fn mine_losing_fork() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn longer_fork() {
|
fn longer_fork() {
|
||||||
let kc = Keychain::from_random_seed().unwrap();
|
let kc = ExtKeychain::from_random_seed().unwrap();
|
||||||
// to make it easier to compute the txhashset roots in the test, we
|
// to make it easier to compute the txhashset roots in the test, we
|
||||||
// prepare 2 chains, the 2nd will be have the forked blocks we can
|
// prepare 2 chains, the 2nd will be have the forked blocks we can
|
||||||
// then send back on the 1st
|
// then send back on the 1st
|
||||||
|
@ -231,7 +231,7 @@ fn spend_in_fork_and_compact() {
|
||||||
util::init_test_logger();
|
util::init_test_logger();
|
||||||
let chain = setup(".grin6");
|
let chain = setup(".grin6");
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let kc = Keychain::from_random_seed().unwrap();
|
let kc = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let mut fork_head = prev;
|
let mut fork_head = prev;
|
||||||
|
|
||||||
|
@ -359,53 +359,63 @@ fn spend_in_fork_and_compact() {
|
||||||
chain.validate(false).unwrap();
|
chain.validate(false).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
fn prepare_block<K>(kc: &K, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
||||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_block_tx(
|
fn prepare_block_tx<K>(
|
||||||
kc: &Keychain,
|
kc: &K,
|
||||||
prev: &BlockHeader,
|
prev: &BlockHeader,
|
||||||
chain: &Chain,
|
chain: &Chain,
|
||||||
diff: u64,
|
diff: u64,
|
||||||
txs: Vec<&Transaction>,
|
txs: Vec<&Transaction>,
|
||||||
) -> Block {
|
) -> Block
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_fork_block(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block {
|
fn prepare_fork_block<K>(kc: &K, prev: &BlockHeader, chain: &Chain, diff: u64) -> Block
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
let mut b = prepare_block_nosum(kc, prev, diff, vec![]);
|
||||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_fork_block_tx(
|
fn prepare_fork_block_tx<K>(
|
||||||
kc: &Keychain,
|
kc: &K,
|
||||||
prev: &BlockHeader,
|
prev: &BlockHeader,
|
||||||
chain: &Chain,
|
chain: &Chain,
|
||||||
diff: u64,
|
diff: u64,
|
||||||
txs: Vec<&Transaction>,
|
txs: Vec<&Transaction>,
|
||||||
) -> Block {
|
) -> Block
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||||
b
|
b
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prepare_block_nosum(
|
fn prepare_block_nosum<K>(kc: &K, prev: &BlockHeader, diff: u64, txs: Vec<&Transaction>) -> Block
|
||||||
kc: &Keychain,
|
where
|
||||||
prev: &BlockHeader,
|
K: Keychain,
|
||||||
diff: u64,
|
{
|
||||||
txs: Vec<&Transaction>,
|
|
||||||
) -> Block {
|
|
||||||
let proof_size = global::proofsize();
|
let proof_size = global::proofsize();
|
||||||
let key_id = kc.derive_key_id(diff as u32).unwrap();
|
let key_id = kc.derive_key_id(diff as u32).unwrap();
|
||||||
|
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward = libtx::reward::output(&kc, &key_id, fees, prev.height).unwrap();
|
let reward = libtx::reward::output(kc, &key_id, fees, prev.height).unwrap();
|
||||||
let mut b = match core::core::Block::new(
|
let mut b = match core::core::Block::new(
|
||||||
prev,
|
prev,
|
||||||
txs.into_iter().cloned().collect(),
|
txs.into_iter().cloned().collect(),
|
||||||
|
|
|
@ -22,14 +22,14 @@ extern crate rand;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
use chain::{ChainStore, Tip};
|
use chain::{ChainStore, Tip};
|
||||||
use core::core::hash::Hashed;
|
|
||||||
use core::core::target::Difficulty;
|
|
||||||
use core::core::Block;
|
use core::core::Block;
|
||||||
use core::core::BlockHeader;
|
use core::core::BlockHeader;
|
||||||
|
use core::core::hash::Hashed;
|
||||||
|
use core::core::target::Difficulty;
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
use core::pow;
|
use core::pow;
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
|
|
||||||
use wallet::libtx;
|
use wallet::libtx;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ fn test_various_store_indices() {
|
||||||
let chain_dir = ".grin_idx_1";
|
let chain_dir = ".grin_idx_1";
|
||||||
clean_output_dir(chain_dir);
|
clean_output_dir(chain_dir);
|
||||||
|
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
let chain_store =
|
let chain_store =
|
||||||
|
|
|
@ -25,14 +25,14 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use chain::types::*;
|
use chain::types::*;
|
||||||
use core::consensus;
|
use core::consensus;
|
||||||
|
use core::core::OutputIdentifier;
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
use core::core::transaction;
|
use core::core::transaction;
|
||||||
use core::core::OutputIdentifier;
|
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::global::ChainTypes;
|
use core::global::ChainTypes;
|
||||||
use wallet::libtx::build;
|
use wallet::libtx::build;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use wallet::libtx;
|
use wallet::libtx;
|
||||||
|
|
||||||
use core::pow;
|
use core::pow;
|
||||||
|
@ -58,7 +58,7 @@ fn test_coinbase_maturity() {
|
||||||
|
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -145,7 +145,7 @@ fn test_coinbase_maturity() {
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
|
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let pk = keychain.derive_key_id(1).unwrap();
|
let pk = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap();
|
let reward = libtx::reward::output(&keychain, &pk, 0, prev.height).unwrap();
|
||||||
|
|
|
@ -20,15 +20,15 @@ extern crate grin_wallet as wallet;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use chain::ChainStore;
|
||||||
use chain::store::ChainKVStore;
|
use chain::store::ChainKVStore;
|
||||||
use chain::txhashset;
|
use chain::txhashset;
|
||||||
use chain::txhashset::TxHashSet;
|
use chain::txhashset::TxHashSet;
|
||||||
use chain::types::Tip;
|
use chain::types::Tip;
|
||||||
use chain::ChainStore;
|
|
||||||
use core::core::pmmr::MerkleProof;
|
use core::core::pmmr::MerkleProof;
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
use core::core::{Block, BlockHeader};
|
use core::core::{Block, BlockHeader};
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use wallet::libtx::{build, reward};
|
use wallet::libtx::{build, reward};
|
||||||
|
|
||||||
fn clean_output_dir(dir_name: &str) {
|
fn clean_output_dir(dir_name: &str) {
|
||||||
|
@ -43,7 +43,7 @@ fn test_some_raw_txs() {
|
||||||
let store = Arc::new(ChainKVStore::new(db_root.clone()).unwrap());
|
let store = Arc::new(ChainKVStore::new(db_root.clone()).unwrap());
|
||||||
let mut txhashset = TxHashSet::open(db_root.clone(), store.clone()).unwrap();
|
let mut txhashset = TxHashSet::open(db_root.clone(), store.clone()).unwrap();
|
||||||
|
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
|
|
||||||
//! Transactions
|
//! Transactions
|
||||||
|
|
||||||
use std::cmp::max;
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::cmp::max;
|
||||||
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,12 +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::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,
|
||||||
|
@ -1074,12 +1074,12 @@ impl ProofMessageElements {
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::id::{ShortId, ShortIdentifiable};
|
use core::id::{ShortId, ShortIdentifiable};
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use util::secp;
|
use util::secp;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_kernel_ser_deser() {
|
fn test_kernel_ser_deser() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let commit = keychain.commit(5, &key_id).unwrap();
|
||||||
|
|
||||||
|
@ -1124,7 +1124,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn commit_consistency() {
|
fn commit_consistency() {
|
||||||
let keychain = Keychain::from_seed(&[0; 32]).unwrap();
|
let keychain = ExtKeychain::from_seed(&[0; 32]).unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
let commit = keychain.commit(1003, &key_id).unwrap();
|
let commit = keychain.commit(1003, &key_id).unwrap();
|
||||||
|
@ -1137,7 +1137,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn input_short_id() {
|
fn input_short_id() {
|
||||||
let keychain = Keychain::from_seed(&[0; 32]).unwrap();
|
let keychain = ExtKeychain::from_seed(&[0; 32]).unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let commit = keychain.commit(5, &key_id).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -21,14 +21,14 @@ pub mod common;
|
||||||
|
|
||||||
use common::{new_block, tx1i2o, tx2i1o, txspend1i1o};
|
use common::{new_block, tx1i2o, tx2i1o, txspend1i1o};
|
||||||
use grin_core::consensus::{BLOCK_OUTPUT_WEIGHT, MAX_BLOCK_WEIGHT};
|
use grin_core::consensus::{BLOCK_OUTPUT_WEIGHT, MAX_BLOCK_WEIGHT};
|
||||||
|
use grin_core::core::Committed;
|
||||||
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;
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
use wallet::libtx::build::{self, input, output, with_fee};
|
use wallet::libtx::build::{self, input, output, with_fee};
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ use util::{secp, secp_static};
|
||||||
// TODO: make this fast enough or add similar but faster test?
|
// TODO: make this fast enough or add similar but faster test?
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn too_large_block() {
|
fn too_large_block() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let max_out = MAX_BLOCK_WEIGHT / BLOCK_OUTPUT_WEIGHT;
|
let max_out = MAX_BLOCK_WEIGHT / BLOCK_OUTPUT_WEIGHT;
|
||||||
|
|
||||||
let zero_commit = secp_static::commit_to_zero_value();
|
let zero_commit = secp_static::commit_to_zero_value();
|
||||||
|
@ -84,7 +84,7 @@ fn very_empty_block() {
|
||||||
#[test]
|
#[test]
|
||||||
// builds a block with a tx spending another and check that cut_through occurred
|
// builds a block with a tx spending another and check that cut_through occurred
|
||||||
fn block_with_cut_through() {
|
fn block_with_cut_through() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -118,7 +118,7 @@ fn block_with_cut_through() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_block_with_coinbase_is_valid() {
|
fn empty_block_with_coinbase_is_valid() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let zero_commit = secp_static::commit_to_zero_value();
|
let zero_commit = secp_static::commit_to_zero_value();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -152,7 +152,7 @@ fn empty_block_with_coinbase_is_valid() {
|
||||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||||
// additionally verifying the merkle_inputs_outputs also fails
|
// additionally verifying the merkle_inputs_outputs also fails
|
||||||
fn remove_coinbase_output_flag() {
|
fn remove_coinbase_output_flag() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let zero_commit = secp_static::commit_to_zero_value();
|
let zero_commit = secp_static::commit_to_zero_value();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -184,7 +184,7 @@ fn remove_coinbase_output_flag() {
|
||||||
// test that flipping the COINBASE_KERNEL flag on the kernel features
|
// test that flipping the COINBASE_KERNEL flag on the kernel features
|
||||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||||
fn remove_coinbase_kernel_flag() {
|
fn remove_coinbase_kernel_flag() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let zero_commit = secp_static::commit_to_zero_value();
|
let zero_commit = secp_static::commit_to_zero_value();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -212,7 +212,7 @@ fn remove_coinbase_kernel_flag() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn serialize_deserialize_block() {
|
fn serialize_deserialize_block() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||||
|
@ -229,7 +229,7 @@ fn serialize_deserialize_block() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_block_serialized_size() {
|
fn empty_block_serialized_size() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||||
|
@ -241,7 +241,7 @@ fn empty_block_serialized_size() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_single_tx_serialized_size() {
|
fn block_single_tx_serialized_size() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -254,7 +254,7 @@ fn block_single_tx_serialized_size() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn empty_compact_block_serialized_size() {
|
fn empty_compact_block_serialized_size() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||||
|
@ -266,7 +266,7 @@ fn empty_compact_block_serialized_size() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_block_single_tx_serialized_size() {
|
fn compact_block_single_tx_serialized_size() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -279,7 +279,7 @@ fn compact_block_single_tx_serialized_size() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_10_tx_serialized_size() {
|
fn block_10_tx_serialized_size() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
global::set_mining_mode(global::ChainTypes::Mainnet);
|
global::set_mining_mode(global::ChainTypes::Mainnet);
|
||||||
|
|
||||||
let mut txs = vec![];
|
let mut txs = vec![];
|
||||||
|
@ -298,7 +298,7 @@ fn block_10_tx_serialized_size() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_block_10_tx_serialized_size() {
|
fn compact_block_10_tx_serialized_size() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let mut txs = vec![];
|
let mut txs = vec![];
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
|
@ -316,7 +316,7 @@ fn compact_block_10_tx_serialized_size() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compact_block_hash_with_nonce() {
|
fn compact_block_hash_with_nonce() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let tx = tx1i2o();
|
let tx = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -346,7 +346,7 @@ fn compact_block_hash_with_nonce() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn convert_block_to_compact_block() {
|
fn convert_block_to_compact_block() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let tx1 = tx1i2o();
|
let tx1 = tx1i2o();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
@ -369,7 +369,7 @@ fn convert_block_to_compact_block() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hydrate_empty_compact_block() {
|
fn hydrate_empty_compact_block() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let prev = BlockHeader::default();
|
let prev = BlockHeader::default();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||||
|
|
|
@ -19,16 +19,16 @@ extern crate grin_keychain as keychain;
|
||||||
extern crate grin_util as util;
|
extern crate grin_util as util;
|
||||||
extern crate grin_wallet as wallet;
|
extern crate grin_wallet as wallet;
|
||||||
|
|
||||||
|
use grin_core::core::Transaction;
|
||||||
use grin_core::core::block::{Block, BlockHeader};
|
use grin_core::core::block::{Block, BlockHeader};
|
||||||
use grin_core::core::target::Difficulty;
|
use grin_core::core::target::Difficulty;
|
||||||
use grin_core::core::Transaction;
|
|
||||||
use keychain::{Identifier, Keychain};
|
use keychain::{Identifier, Keychain};
|
||||||
use wallet::libtx::build::{self, input, output, with_fee};
|
use wallet::libtx::build::{self, input, output, with_fee};
|
||||||
use wallet::libtx::reward;
|
use wallet::libtx::reward;
|
||||||
|
|
||||||
// utility producing a transaction with 2 inputs and a single outputs
|
// utility producing a transaction with 2 inputs and a single outputs
|
||||||
pub fn tx2i1o() -> Transaction {
|
pub fn tx2i1o() -> Transaction {
|
||||||
let keychain = keychain::Keychain::from_random_seed().unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -46,7 +46,7 @@ pub fn tx2i1o() -> Transaction {
|
||||||
|
|
||||||
// utility producing a transaction with a single input and output
|
// utility producing a transaction with a single input and output
|
||||||
pub fn tx1i1o() -> Transaction {
|
pub fn tx1i1o() -> Transaction {
|
||||||
let keychain = keychain::Keychain::from_random_seed().unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ pub fn tx1i1o() -> Transaction {
|
||||||
// and two outputs (one change output)
|
// and two outputs (one change output)
|
||||||
// Note: this tx has an "offset" kernel
|
// Note: this tx has an "offset" kernel
|
||||||
pub fn tx1i2o() -> Transaction {
|
pub fn tx1i2o() -> Transaction {
|
||||||
let keychain = keychain::Keychain::from_random_seed().unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -78,12 +78,15 @@ pub fn tx1i2o() -> Transaction {
|
||||||
|
|
||||||
// utility to create a block without worrying about the key or previous
|
// utility to create a block without worrying about the key or previous
|
||||||
// header
|
// header
|
||||||
pub fn new_block(
|
pub fn new_block<K>(
|
||||||
txs: Vec<&Transaction>,
|
txs: Vec<&Transaction>,
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
previous_header: &BlockHeader,
|
previous_header: &BlockHeader,
|
||||||
key_id: &Identifier,
|
key_id: &Identifier,
|
||||||
) -> Block {
|
) -> Block
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let reward_output = reward::output(keychain, &key_id, fees, previous_header.height).unwrap();
|
let reward_output = reward::output(keychain, &key_id, fees, previous_header.height).unwrap();
|
||||||
Block::new(
|
Block::new(
|
||||||
|
@ -96,14 +99,12 @@ pub fn new_block(
|
||||||
|
|
||||||
// utility producing a transaction that spends an output with the provided
|
// utility producing a transaction that spends an output with the provided
|
||||||
// value and blinding key
|
// value and blinding key
|
||||||
pub fn txspend1i1o(
|
pub fn txspend1i1o<K>(v: u64, keychain: &K, key_id1: Identifier, key_id2: Identifier) -> Transaction
|
||||||
v: u64,
|
where
|
||||||
keychain: &Keychain,
|
K: Keychain,
|
||||||
key_id1: Identifier,
|
{
|
||||||
key_id2: Identifier,
|
|
||||||
) -> Transaction {
|
|
||||||
build::transaction(
|
build::transaction(
|
||||||
vec![input(v, key_id1), output(3, key_id2), with_fee(2)],
|
vec![input(v, key_id1), output(3, key_id2), with_fee(2)],
|
||||||
&keychain,
|
keychain,
|
||||||
).unwrap()
|
).unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ use grin_core::core::block::Error::KernelLockHeight;
|
||||||
use grin_core::core::hash::{Hashed, ZERO_HASH};
|
use grin_core::core::hash::{Hashed, ZERO_HASH};
|
||||||
use grin_core::core::{aggregate, deaggregate, KernelFeatures, Output, Transaction};
|
use grin_core::core::{aggregate, deaggregate, KernelFeatures, Output, Transaction};
|
||||||
use grin_core::ser;
|
use grin_core::ser;
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use util::{secp_static, static_secp_instance};
|
use util::{secp_static, static_secp_instance};
|
||||||
use wallet::libtx::build::{self, initial_tx, input, output, with_excess, with_fee,
|
use wallet::libtx::build::{self, initial_tx, input, output, with_excess, with_fee,
|
||||||
with_lock_height};
|
with_lock_height};
|
||||||
|
@ -72,7 +72,7 @@ fn tx_double_ser_deser() {
|
||||||
#[test]
|
#[test]
|
||||||
#[should_panic(expected = "InvalidSecretKey")]
|
#[should_panic(expected = "InvalidSecretKey")]
|
||||||
fn test_zero_commit_fails() {
|
fn test_zero_commit_fails() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -88,7 +88,7 @@ fn test_zero_commit_fails() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn build_tx_kernel() {
|
fn build_tx_kernel() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -295,7 +295,7 @@ fn basic_transaction_deaggregation() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hash_output() {
|
fn hash_output() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -349,7 +349,7 @@ fn tx_hash_diff() {
|
||||||
/// 2 inputs, 2 outputs transaction.
|
/// 2 inputs, 2 outputs transaction.
|
||||||
#[test]
|
#[test]
|
||||||
fn tx_build_exchange() {
|
fn tx_build_exchange() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -386,7 +386,7 @@ fn tx_build_exchange() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reward_empty_block() {
|
fn reward_empty_block() {
|
||||||
let keychain = keychain::Keychain::from_random_seed().unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
let zero_commit = secp_static::commit_to_zero_value();
|
let zero_commit = secp_static::commit_to_zero_value();
|
||||||
|
@ -402,7 +402,7 @@ fn reward_empty_block() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn reward_with_tx_block() {
|
fn reward_with_tx_block() {
|
||||||
let keychain = keychain::Keychain::from_random_seed().unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
let zero_commit = secp_static::commit_to_zero_value();
|
let zero_commit = secp_static::commit_to_zero_value();
|
||||||
|
@ -421,7 +421,7 @@ fn reward_with_tx_block() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn simple_block() {
|
fn simple_block() {
|
||||||
let keychain = keychain::Keychain::from_random_seed().unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
let zero_commit = secp_static::commit_to_zero_value();
|
let zero_commit = secp_static::commit_to_zero_value();
|
||||||
|
@ -442,7 +442,7 @@ fn simple_block() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_block_with_timelocked_tx() {
|
fn test_block_with_timelocked_tx() {
|
||||||
let keychain = keychain::Keychain::from_random_seed().unwrap();
|
let keychain = keychain::ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
|
|
|
@ -22,13 +22,13 @@ pub mod common;
|
||||||
|
|
||||||
use grin_core::core::{Output, OutputFeatures};
|
use grin_core::core::{Output, OutputFeatures};
|
||||||
use grin_core::ser;
|
use grin_core::ser;
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use util::secp;
|
use util::secp;
|
||||||
use wallet::libtx::proof;
|
use wallet::libtx::proof;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_output_ser_deser() {
|
fn test_output_ser_deser() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let commit = keychain.commit(5, &key_id).unwrap();
|
||||||
let msg = secp::pedersen::ProofMessage::empty();
|
let msg = secp::pedersen::ProofMessage::empty();
|
||||||
|
|
|
@ -12,167 +12,11 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::cmp::min;
|
|
||||||
use std::{error, fmt, num};
|
|
||||||
|
|
||||||
use serde::{de, ser};
|
|
||||||
|
|
||||||
use blake2::blake2b::blake2b;
|
use blake2::blake2b::blake2b;
|
||||||
use byteorder::{BigEndian, ByteOrder};
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
use util;
|
use types::{Error, Identifier};
|
||||||
use util::secp;
|
|
||||||
use util::secp::Secp256k1;
|
use util::secp::Secp256k1;
|
||||||
use util::secp::key::{PublicKey, SecretKey};
|
use util::secp::key::SecretKey;
|
||||||
|
|
||||||
// Size of an identifier in bytes
|
|
||||||
pub const IDENTIFIER_SIZE: usize = 10;
|
|
||||||
|
|
||||||
/// An ExtKey error
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
/// The size of the seed is invalid
|
|
||||||
InvalidSeedSize,
|
|
||||||
InvalidSliceSize,
|
|
||||||
InvalidExtendedKey,
|
|
||||||
Secp(secp::Error),
|
|
||||||
ParseIntError(num::ParseIntError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<secp::Error> for Error {
|
|
||||||
fn from(e: secp::Error) -> Error {
|
|
||||||
Error::Secp(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<num::ParseIntError> for Error {
|
|
||||||
fn from(e: num::ParseIntError) -> Error {
|
|
||||||
Error::ParseIntError(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Passthrough Debug to Display, since errors should be user-visible
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
|
||||||
f.write_str(error::Error::description(self))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn cause(&self) -> Option<&error::Error> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
Error::InvalidSeedSize => "keychain: seed isn't of size 128, 256 or 512",
|
|
||||||
// TODO change when ser. ext. size is fixed
|
|
||||||
Error::InvalidSliceSize => "keychain: serialized extended key must be of size 73",
|
|
||||||
Error::InvalidExtendedKey => "keychain: the given serialized extended key is invalid",
|
|
||||||
Error::Secp(_) => "keychain: secp error",
|
|
||||||
Error::ParseIntError(_) => "keychain: error parsing int",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Ord, Hash, PartialOrd)]
|
|
||||||
pub struct Identifier([u8; IDENTIFIER_SIZE]);
|
|
||||||
|
|
||||||
impl ser::Serialize for Identifier {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: ser::Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_str(&self.to_hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de> de::Deserialize<'de> for Identifier {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Identifier, D::Error>
|
|
||||||
where
|
|
||||||
D: de::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
deserializer.deserialize_str(IdentifierVisitor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct IdentifierVisitor;
|
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for IdentifierVisitor {
|
|
||||||
type Value = Identifier;
|
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
formatter.write_str("an identifier")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
|
||||||
where
|
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
let identifier = Identifier::from_hex(s).unwrap();
|
|
||||||
Ok(identifier)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Identifier {
|
|
||||||
pub fn zero() -> Identifier {
|
|
||||||
Identifier::from_bytes(&[0; IDENTIFIER_SIZE])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_bytes(bytes: &[u8]) -> Identifier {
|
|
||||||
let mut identifier = [0; IDENTIFIER_SIZE];
|
|
||||||
for i in 0..min(IDENTIFIER_SIZE, bytes.len()) {
|
|
||||||
identifier[i] = bytes[i];
|
|
||||||
}
|
|
||||||
Identifier(identifier)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> [u8; IDENTIFIER_SIZE] {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_pubkey(secp: &Secp256k1, pubkey: &PublicKey) -> Identifier {
|
|
||||||
let bytes = pubkey.serialize_vec(secp, true);
|
|
||||||
let identifier = blake2b(IDENTIFIER_SIZE, &[], &bytes[..]);
|
|
||||||
Identifier::from_bytes(&identifier.as_bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the identifier of the secret key
|
|
||||||
/// which is the blake2b (10 byte) digest of the PublicKey
|
|
||||||
/// corresponding to the secret key provided.
|
|
||||||
fn from_secret_key(secp: &Secp256k1, key: &SecretKey) -> Result<Identifier, Error> {
|
|
||||||
let key_id = PublicKey::from_secret_key(secp, key)?;
|
|
||||||
Ok(Identifier::from_pubkey(secp, &key_id))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn from_hex(hex: &str) -> Result<Identifier, Error> {
|
|
||||||
let bytes = util::from_hex(hex.to_string()).unwrap();
|
|
||||||
Ok(Identifier::from_bytes(&bytes))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_hex(&self) -> String {
|
|
||||||
util::to_hex(self.0.to_vec())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRef<[u8]> for Identifier {
|
|
||||||
fn as_ref(&self) -> &[u8] {
|
|
||||||
&self.0.as_ref()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::fmt::Debug for Identifier {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
|
||||||
write!(f, "{}(", stringify!(Identifier))?;
|
|
||||||
write!(f, "{}", self.to_hex())?;
|
|
||||||
write!(f, ")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Identifier {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}", self.to_hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ChildKey {
|
pub struct ChildKey {
|
||||||
|
@ -210,7 +54,11 @@ impl ExtendedKey {
|
||||||
pub fn from_seed(secp: &Secp256k1, seed: &[u8]) -> Result<ExtendedKey, Error> {
|
pub fn from_seed(secp: &Secp256k1, seed: &[u8]) -> Result<ExtendedKey, Error> {
|
||||||
match seed.len() {
|
match seed.len() {
|
||||||
16 | 32 | 64 => (),
|
16 | 32 | 64 => (),
|
||||||
_ => return Err(Error::InvalidSeedSize),
|
_ => {
|
||||||
|
return Err(Error::KeyDerivation(
|
||||||
|
"seed size must be 128, 256 or 512".to_owned(),
|
||||||
|
))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let derived = blake2b(64, b"Grin/MW Seed", seed);
|
let derived = blake2b(64, b"Grin/MW Seed", seed);
|
||||||
|
|
|
@ -12,87 +12,34 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
/// Implementation of the Keychain trait based on an extended key derivation
|
||||||
|
/// scheme.
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::{error, fmt};
|
|
||||||
|
|
||||||
use util::secp;
|
use blake2;
|
||||||
use util::secp::{Message, Secp256k1, Signature};
|
|
||||||
|
use extkey;
|
||||||
|
use types::{BlindSum, BlindingFactor, Error, Identifier, Keychain};
|
||||||
|
use util::logger::LOGGER;
|
||||||
use util::secp::key::SecretKey;
|
use util::secp::key::SecretKey;
|
||||||
use util::secp::pedersen::Commitment;
|
use util::secp::pedersen::Commitment;
|
||||||
use util::logger::LOGGER;
|
use util::secp::{self, Message, Secp256k1, Signature};
|
||||||
use blake2;
|
|
||||||
use blind::{BlindSum, BlindingFactor};
|
|
||||||
use extkey::{self, Identifier};
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone, Debug)]
|
|
||||||
pub enum Error {
|
|
||||||
ExtendedKey(extkey::Error),
|
|
||||||
Secp(secp::Error),
|
|
||||||
KeyDerivation(String),
|
|
||||||
Transaction(String),
|
|
||||||
RangeProof(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<secp::Error> for Error {
|
|
||||||
fn from(e: secp::Error) -> Error {
|
|
||||||
Error::Secp(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<extkey::Error> for Error {
|
|
||||||
fn from(e: extkey::Error) -> Error {
|
|
||||||
Error::ExtendedKey(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl error::Error for Error {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
match *self {
|
|
||||||
_ => "some kind of keychain error",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
_ => write!(f, "some kind of keychain error"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Keychain {
|
pub struct ExtKeychain {
|
||||||
secp: Secp256k1,
|
secp: Secp256k1,
|
||||||
extkey: extkey::ExtendedKey,
|
extkey: extkey::ExtendedKey,
|
||||||
key_overrides: HashMap<Identifier, SecretKey>,
|
key_overrides: HashMap<Identifier, SecretKey>,
|
||||||
key_derivation_cache: Arc<RwLock<HashMap<Identifier, u32>>>,
|
key_derivation_cache: Arc<RwLock<HashMap<Identifier, u32>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Keychain {
|
impl Keychain for ExtKeychain {
|
||||||
pub fn root_key_id(&self) -> Identifier {
|
fn from_seed(seed: &[u8]) -> Result<ExtKeychain, Error> {
|
||||||
self.extkey.root_key_id.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
// For tests and burn only, associate a key identifier with a known secret key.
|
|
||||||
pub fn burn_enabled(keychain: &Keychain, burn_key_id: &Identifier) -> Keychain {
|
|
||||||
let mut key_overrides = HashMap::new();
|
|
||||||
key_overrides.insert(
|
|
||||||
burn_key_id.clone(),
|
|
||||||
SecretKey::from_slice(&keychain.secp, &[1; 32]).unwrap(),
|
|
||||||
);
|
|
||||||
Keychain {
|
|
||||||
key_overrides: key_overrides,
|
|
||||||
..keychain.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_seed(seed: &[u8]) -> Result<Keychain, Error> {
|
|
||||||
let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||||
let extkey = extkey::ExtendedKey::from_seed(&secp, seed)?;
|
let extkey = extkey::ExtendedKey::from_seed(&secp, seed)?;
|
||||||
let keychain = Keychain {
|
let keychain = ExtKeychain {
|
||||||
secp: secp,
|
secp: secp,
|
||||||
extkey: extkey,
|
extkey: extkey,
|
||||||
key_overrides: HashMap::new(),
|
key_overrides: HashMap::new(),
|
||||||
|
@ -102,18 +49,22 @@ impl Keychain {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For testing - probably not a good idea to use outside of tests.
|
/// For testing - probably not a good idea to use outside of tests.
|
||||||
pub fn from_random_seed() -> Result<Keychain, Error> {
|
fn from_random_seed() -> Result<ExtKeychain, Error> {
|
||||||
let seed: String = thread_rng().gen_ascii_chars().take(16).collect();
|
let seed: String = thread_rng().gen_ascii_chars().take(16).collect();
|
||||||
let seed = blake2::blake2b::blake2b(32, &[], seed.as_bytes());
|
let seed = blake2::blake2b::blake2b(32, &[], seed.as_bytes());
|
||||||
Keychain::from_seed(seed.as_bytes())
|
ExtKeychain::from_seed(seed.as_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_key_id(&self, derivation: u32) -> Result<Identifier, Error> {
|
fn root_key_id(&self) -> Identifier {
|
||||||
|
self.extkey.root_key_id.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn derive_key_id(&self, derivation: u32) -> Result<Identifier, Error> {
|
||||||
let child_key = self.extkey.derive(&self.secp, derivation)?;
|
let child_key = self.extkey.derive(&self.secp, derivation)?;
|
||||||
Ok(child_key.key_id)
|
Ok(child_key.key_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derived_key(&self, key_id: &Identifier) -> Result<SecretKey, Error> {
|
fn derived_key(&self, key_id: &Identifier) -> Result<SecretKey, Error> {
|
||||||
// first check our overrides and just return the key if we have one in there
|
// first check our overrides and just return the key if we have one in there
|
||||||
if let Some(key) = self.key_overrides.get(key_id) {
|
if let Some(key) = self.key_overrides.get(key_id) {
|
||||||
trace!(
|
trace!(
|
||||||
|
@ -128,6 +79,82 @@ impl Keychain {
|
||||||
Ok(child_key.key)
|
Ok(child_key.key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn commit(&self, amount: u64, key_id: &Identifier) -> Result<Commitment, Error> {
|
||||||
|
let skey = self.derived_key(key_id)?;
|
||||||
|
let commit = self.secp.commit(amount, skey)?;
|
||||||
|
Ok(commit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn commit_with_key_index(&self, amount: u64, derivation: u32) -> Result<Commitment, Error> {
|
||||||
|
let child_key = self.derived_key_from_index(derivation)?;
|
||||||
|
let commit = self.secp.commit(amount, child_key.key)?;
|
||||||
|
Ok(commit)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blind_sum(&self, blind_sum: &BlindSum) -> Result<BlindingFactor, Error> {
|
||||||
|
let mut pos_keys: Vec<SecretKey> = blind_sum
|
||||||
|
.positive_key_ids
|
||||||
|
.iter()
|
||||||
|
.filter_map(|k| self.derived_key(&k).ok())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut neg_keys: Vec<SecretKey> = blind_sum
|
||||||
|
.negative_key_ids
|
||||||
|
.iter()
|
||||||
|
.filter_map(|k| self.derived_key(&k).ok())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
pos_keys.extend(&blind_sum
|
||||||
|
.positive_blinding_factors
|
||||||
|
.iter()
|
||||||
|
.filter_map(|b| b.secret_key(&self.secp).ok())
|
||||||
|
.collect::<Vec<SecretKey>>());
|
||||||
|
|
||||||
|
neg_keys.extend(&blind_sum
|
||||||
|
.negative_blinding_factors
|
||||||
|
.iter()
|
||||||
|
.filter_map(|b| b.secret_key(&self.secp).ok())
|
||||||
|
.collect::<Vec<SecretKey>>());
|
||||||
|
|
||||||
|
let sum = self.secp.blind_sum(pos_keys, neg_keys)?;
|
||||||
|
Ok(BlindingFactor::from_secret_key(sum))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign(&self, msg: &Message, key_id: &Identifier) -> Result<Signature, Error> {
|
||||||
|
let skey = self.derived_key(key_id)?;
|
||||||
|
let sig = self.secp.sign(msg, &skey)?;
|
||||||
|
Ok(sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_with_blinding(
|
||||||
|
&self,
|
||||||
|
msg: &Message,
|
||||||
|
blinding: &BlindingFactor,
|
||||||
|
) -> Result<Signature, Error> {
|
||||||
|
let skey = &blinding.secret_key(&self.secp)?;
|
||||||
|
let sig = self.secp.sign(msg, &skey)?;
|
||||||
|
Ok(sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn secp(&self) -> &Secp256k1 {
|
||||||
|
&self.secp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExtKeychain {
|
||||||
|
// For tests and burn only, associate a key identifier with a known secret key.
|
||||||
|
pub fn burn_enabled(keychain: &ExtKeychain, burn_key_id: &Identifier) -> ExtKeychain {
|
||||||
|
let mut key_overrides = HashMap::new();
|
||||||
|
key_overrides.insert(
|
||||||
|
burn_key_id.clone(),
|
||||||
|
SecretKey::from_slice(&keychain.secp, &[1; 32]).unwrap(),
|
||||||
|
);
|
||||||
|
ExtKeychain {
|
||||||
|
key_overrides: key_overrides,
|
||||||
|
..keychain.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn derived_child_key(&self, key_id: &Identifier) -> Result<extkey::ChildKey, Error> {
|
fn derived_child_key(&self, key_id: &Identifier) -> Result<extkey::ChildKey, Error> {
|
||||||
trace!(LOGGER, "Derived Key by key_id: {}", key_id);
|
trace!(LOGGER, "Derived Key by key_id: {}", key_id);
|
||||||
|
|
||||||
|
@ -184,78 +211,18 @@ impl Keychain {
|
||||||
let child_key = self.extkey.derive(&self.secp, derivation)?;
|
let child_key = self.extkey.derive(&self.secp, derivation)?;
|
||||||
return Ok(child_key);
|
return Ok(child_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn commit(&self, amount: u64, key_id: &Identifier) -> Result<Commitment, Error> {
|
|
||||||
let skey = self.derived_key(key_id)?;
|
|
||||||
let commit = self.secp.commit(amount, skey)?;
|
|
||||||
Ok(commit)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn commit_with_key_index(&self, amount: u64, derivation: u32) -> Result<Commitment, Error> {
|
|
||||||
let child_key = self.derived_key_from_index(derivation)?;
|
|
||||||
let commit = self.secp.commit(amount, child_key.key)?;
|
|
||||||
Ok(commit)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn blind_sum(&self, blind_sum: &BlindSum) -> Result<BlindingFactor, Error> {
|
|
||||||
let mut pos_keys: Vec<SecretKey> = blind_sum
|
|
||||||
.positive_key_ids
|
|
||||||
.iter()
|
|
||||||
.filter_map(|k| self.derived_key(&k).ok())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut neg_keys: Vec<SecretKey> = blind_sum
|
|
||||||
.negative_key_ids
|
|
||||||
.iter()
|
|
||||||
.filter_map(|k| self.derived_key(&k).ok())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
pos_keys.extend(&blind_sum
|
|
||||||
.positive_blinding_factors
|
|
||||||
.iter()
|
|
||||||
.filter_map(|b| b.secret_key(&self.secp).ok())
|
|
||||||
.collect::<Vec<SecretKey>>());
|
|
||||||
|
|
||||||
neg_keys.extend(&blind_sum
|
|
||||||
.negative_blinding_factors
|
|
||||||
.iter()
|
|
||||||
.filter_map(|b| b.secret_key(&self.secp).ok())
|
|
||||||
.collect::<Vec<SecretKey>>());
|
|
||||||
|
|
||||||
let sum = self.secp.blind_sum(pos_keys, neg_keys)?;
|
|
||||||
Ok(BlindingFactor::from_secret_key(sum))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sign(&self, msg: &Message, key_id: &Identifier) -> Result<Signature, Error> {
|
|
||||||
let skey = self.derived_key(key_id)?;
|
|
||||||
let sig = self.secp.sign(msg, &skey)?;
|
|
||||||
Ok(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sign_with_blinding(
|
|
||||||
&self,
|
|
||||||
msg: &Message,
|
|
||||||
blinding: &BlindingFactor,
|
|
||||||
) -> Result<Signature, Error> {
|
|
||||||
let skey = &blinding.secret_key(&self.secp)?;
|
|
||||||
let sig = self.secp.sign(msg, &skey)?;
|
|
||||||
Ok(sig)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn secp(&self) -> &Secp256k1 {
|
|
||||||
&self.secp
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use keychain::{BlindSum, BlindingFactor, Keychain};
|
use keychain::ExtKeychain;
|
||||||
|
use types::{BlindSum, BlindingFactor, Keychain};
|
||||||
use util::secp;
|
use util::secp;
|
||||||
use util::secp::key::SecretKey;
|
use util::secp::key::SecretKey;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_derivation() {
|
fn test_key_derivation() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let secp = keychain.secp();
|
let secp = keychain.secp();
|
||||||
|
|
||||||
// use the keychain to derive a "key_id" based on the underlying seed
|
// use the keychain to derive a "key_id" based on the underlying seed
|
||||||
|
@ -279,7 +246,7 @@ mod test {
|
||||||
// and summing the keys used to commit to 0 have the same result.
|
// and summing the keys used to commit to 0 have the same result.
|
||||||
#[test]
|
#[test]
|
||||||
fn secret_key_addition() {
|
fn secret_key_addition() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let skey1 = SecretKey::from_slice(
|
let skey1 = SecretKey::from_slice(
|
||||||
&keychain.secp,
|
&keychain.secp,
|
||||||
|
|
|
@ -26,10 +26,9 @@ extern crate serde_json;
|
||||||
extern crate slog;
|
extern crate slog;
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
|
|
||||||
pub mod blind;
|
|
||||||
pub mod extkey;
|
pub mod extkey;
|
||||||
|
mod types;
|
||||||
|
|
||||||
pub use blind::{BlindSum, BlindingFactor};
|
|
||||||
pub use extkey::{ExtendedKey, Identifier, IDENTIFIER_SIZE};
|
|
||||||
pub mod keychain;
|
pub mod keychain;
|
||||||
pub use keychain::{Error, Keychain};
|
pub use keychain::ExtKeychain;
|
||||||
|
pub use types::{BlindSum, BlindingFactor, Error, Identifier, Keychain, IDENTIFIER_SIZE};
|
||||||
|
|
|
@ -11,16 +11,156 @@
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
/// Encapsulate a secret key for the blind_sum operation
|
|
||||||
|
|
||||||
use std::cmp::min;
|
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
|
use std::cmp::min;
|
||||||
|
/// Keychain trait and its main supporting types. The Identifier is a
|
||||||
|
/// semi-opaque structure (just bytes) to track keys within the Keychain.
|
||||||
|
/// BlindingFactor is a useful wrapper around a private key to help with
|
||||||
|
/// commitment generation.
|
||||||
|
use std::{error, fmt};
|
||||||
|
|
||||||
|
use blake2::blake2b::blake2b;
|
||||||
|
use serde::{de, ser};
|
||||||
|
|
||||||
use extkey::Identifier;
|
|
||||||
use keychain::Error;
|
|
||||||
use util;
|
use util;
|
||||||
use util::secp::{self, Secp256k1};
|
|
||||||
use util::secp::constants::SECRET_KEY_SIZE;
|
use util::secp::constants::SECRET_KEY_SIZE;
|
||||||
|
use util::secp::key::{PublicKey, SecretKey};
|
||||||
|
use util::secp::pedersen::Commitment;
|
||||||
|
use util::secp::{self, Message, Secp256k1, Signature};
|
||||||
|
|
||||||
|
// Size of an identifier in bytes
|
||||||
|
pub const IDENTIFIER_SIZE: usize = 10;
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Secp(secp::Error),
|
||||||
|
KeyDerivation(String),
|
||||||
|
Transaction(String),
|
||||||
|
RangeProof(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<secp::Error> for Error {
|
||||||
|
fn from(e: secp::Error) -> Error {
|
||||||
|
Error::Secp(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl error::Error for Error {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
_ => "some kind of keychain error",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Error {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
_ => write!(f, "some kind of keychain error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Ord, Hash, PartialOrd)]
|
||||||
|
pub struct Identifier([u8; IDENTIFIER_SIZE]);
|
||||||
|
|
||||||
|
impl ser::Serialize for Identifier {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: ser::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&self.to_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> de::Deserialize<'de> for Identifier {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Identifier, D::Error>
|
||||||
|
where
|
||||||
|
D: de::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
deserializer.deserialize_str(IdentifierVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IdentifierVisitor;
|
||||||
|
|
||||||
|
impl<'de> de::Visitor<'de> for IdentifierVisitor {
|
||||||
|
type Value = Identifier;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
formatter.write_str("an identifier")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
let identifier = Identifier::from_hex(s).unwrap();
|
||||||
|
Ok(identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Identifier {
|
||||||
|
pub fn zero() -> Identifier {
|
||||||
|
Identifier::from_bytes(&[0; IDENTIFIER_SIZE])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_bytes(bytes: &[u8]) -> Identifier {
|
||||||
|
let mut identifier = [0; IDENTIFIER_SIZE];
|
||||||
|
for i in 0..min(IDENTIFIER_SIZE, bytes.len()) {
|
||||||
|
identifier[i] = bytes[i];
|
||||||
|
}
|
||||||
|
Identifier(identifier)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> [u8; IDENTIFIER_SIZE] {
|
||||||
|
self.0.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_pubkey(secp: &Secp256k1, pubkey: &PublicKey) -> Identifier {
|
||||||
|
let bytes = pubkey.serialize_vec(secp, true);
|
||||||
|
let identifier = blake2b(IDENTIFIER_SIZE, &[], &bytes[..]);
|
||||||
|
Identifier::from_bytes(&identifier.as_bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the identifier of the secret key
|
||||||
|
/// which is the blake2b (10 byte) digest of the PublicKey
|
||||||
|
/// corresponding to the secret key provided.
|
||||||
|
pub fn from_secret_key(secp: &Secp256k1, key: &SecretKey) -> Result<Identifier, Error> {
|
||||||
|
let key_id = PublicKey::from_secret_key(secp, key)?;
|
||||||
|
Ok(Identifier::from_pubkey(secp, &key_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_hex(hex: &str) -> Result<Identifier, Error> {
|
||||||
|
let bytes = util::from_hex(hex.to_string()).unwrap();
|
||||||
|
Ok(Identifier::from_bytes(&bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_hex(&self) -> String {
|
||||||
|
util::to_hex(self.0.to_vec())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<[u8]> for Identifier {
|
||||||
|
fn as_ref(&self) -> &[u8] {
|
||||||
|
&self.0.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Debug for Identifier {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||||
|
try!(write!(f, "{}(", stringify!(Identifier)));
|
||||||
|
try!(write!(f, "{}", self.to_hex()));
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Identifier {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.to_hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct BlindingFactor([u8; SECRET_KEY_SIZE]);
|
pub struct BlindingFactor([u8; SECRET_KEY_SIZE]);
|
||||||
|
@ -68,12 +208,12 @@ impl BlindingFactor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split a blinding_factor (aka secret_key) into a pair of blinding_factors.
|
/// Split a blinding_factor (aka secret_key) into a pair of
|
||||||
/// We use one of these (k1) to sign the tx_kernel (k1G)
|
/// blinding_factors. We use one of these (k1) to sign the tx_kernel (k1G)
|
||||||
/// and the other gets aggregated in the block_header as the "offset".
|
/// and the other gets aggregated in the block_header as the "offset".
|
||||||
/// This prevents an actor from being able to sum a set of inputs, outputs and kernels
|
/// This prevents an actor from being able to sum a set of inputs, outputs
|
||||||
/// from a block to identify and reconstruct a particular tx from a block.
|
/// and kernels from a block to identify and reconstruct a particular tx
|
||||||
/// You would need both k1, k2 to do this.
|
/// from a block. You would need both k1, k2 to do this.
|
||||||
pub fn split(&self, secp: &Secp256k1) -> Result<SplitBlindingFactor, Error> {
|
pub fn split(&self, secp: &Secp256k1) -> Result<SplitBlindingFactor, Error> {
|
||||||
let skey_1 = secp::key::SecretKey::new(secp, &mut thread_rng());
|
let skey_1 = secp::key::SecretKey::new(secp, &mut thread_rng());
|
||||||
|
|
||||||
|
@ -138,11 +278,25 @@ impl BlindSum {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait Keychain: Sync + Send + Clone {
|
||||||
|
fn from_seed(seed: &[u8]) -> Result<Self, Error>;
|
||||||
|
fn from_random_seed() -> Result<Self, Error>;
|
||||||
|
fn root_key_id(&self) -> Identifier;
|
||||||
|
fn derive_key_id(&self, derivation: u32) -> Result<Identifier, Error>;
|
||||||
|
fn derived_key(&self, key_id: &Identifier) -> Result<SecretKey, Error>;
|
||||||
|
fn commit(&self, amount: u64, key_id: &Identifier) -> Result<Commitment, Error>;
|
||||||
|
fn commit_with_key_index(&self, amount: u64, derivation: u32) -> Result<Commitment, Error>;
|
||||||
|
fn blind_sum(&self, blind_sum: &BlindSum) -> Result<BlindingFactor, Error>;
|
||||||
|
fn sign(&self, msg: &Message, key_id: &Identifier) -> Result<Signature, Error>;
|
||||||
|
fn sign_with_blinding(&self, &Message, &BlindingFactor) -> Result<Signature, Error>;
|
||||||
|
fn secp(&self) -> &Secp256k1;
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use rand::thread_rng;
|
use rand::thread_rng;
|
||||||
|
|
||||||
use blind::BlindingFactor;
|
use types::BlindingFactor;
|
||||||
use util::secp::Secp256k1;
|
use util::secp::Secp256k1;
|
||||||
use util::secp::key::{SecretKey, ZERO_KEY};
|
use util::secp::key::{SecretKey, ZERO_KEY};
|
||||||
|
|
|
@ -17,8 +17,8 @@ extern crate grin_p2p as p2p;
|
||||||
extern crate grin_util as util;
|
extern crate grin_util as util;
|
||||||
|
|
||||||
use std::net::{SocketAddr, TcpListener, TcpStream};
|
use std::net::{SocketAddr, TcpListener, TcpStream};
|
||||||
use std::sync::atomic::AtomicBool;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
|
|
|
@ -29,19 +29,19 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use core::core::{Block, BlockHeader};
|
use core::core::{Block, BlockHeader};
|
||||||
|
|
||||||
|
use chain::ChainStore;
|
||||||
use chain::txhashset;
|
use chain::txhashset;
|
||||||
use chain::types::Tip;
|
use chain::types::Tip;
|
||||||
use chain::ChainStore;
|
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use wallet::libtx;
|
use wallet::libtx;
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transaction_pool_block_building() {
|
fn test_transaction_pool_block_building() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain: ExtKeychain = Keychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let db_root = ".grin_block_building".to_string();
|
let db_root = ".grin_block_building".to_string();
|
||||||
clean_output_dir(db_root.clone());
|
clean_output_dir(db_root.clone());
|
||||||
|
|
|
@ -29,19 +29,19 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use core::core::{Block, BlockHeader};
|
use core::core::{Block, BlockHeader};
|
||||||
|
|
||||||
|
use chain::ChainStore;
|
||||||
use chain::txhashset;
|
use chain::txhashset;
|
||||||
use chain::types::Tip;
|
use chain::types::Tip;
|
||||||
use chain::ChainStore;
|
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use wallet::libtx;
|
use wallet::libtx;
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_transaction_pool_block_reconciliation() {
|
fn test_transaction_pool_block_reconciliation() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain: ExtKeychain = Keychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let db_root = ".grin_block_reconcilliation".to_string();
|
let db_root = ".grin_block_reconcilliation".to_string();
|
||||||
clean_output_dir(db_root.clone());
|
clean_output_dir(db_root.clone());
|
||||||
|
|
|
@ -29,7 +29,7 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use core::core::Transaction;
|
use core::core::Transaction;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use pool::TransactionPool;
|
use pool::TransactionPool;
|
||||||
use pool::types::*;
|
use pool::types::*;
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ impl BlockChain for CoinbaseMaturityErrorChainAdapter {
|
||||||
/// Test we correctly verify coinbase maturity when adding txs to the pool.
|
/// Test we correctly verify coinbase maturity when adding txs to the pool.
|
||||||
#[test]
|
#[test]
|
||||||
fn test_coinbase_maturity() {
|
fn test_coinbase_maturity() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain: ExtKeychain = Keychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
// Mocking this up with an adapter that will raise an error for coinbase
|
// Mocking this up with an adapter that will raise an error for coinbase
|
||||||
// maturity.
|
// maturity.
|
||||||
|
|
|
@ -30,10 +30,10 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use core::core::{BlockHeader, Transaction};
|
use core::core::{BlockHeader, Transaction};
|
||||||
|
|
||||||
|
use chain::ChainStore;
|
||||||
use chain::store::ChainKVStore;
|
use chain::store::ChainKVStore;
|
||||||
use chain::txhashset;
|
use chain::txhashset;
|
||||||
use chain::txhashset::TxHashSet;
|
use chain::txhashset::TxHashSet;
|
||||||
use chain::ChainStore;
|
|
||||||
use core::core::hash::Hashed;
|
use core::core::hash::Hashed;
|
||||||
use core::core::pmmr::MerkleProof;
|
use core::core::pmmr::MerkleProof;
|
||||||
use pool::*;
|
use pool::*;
|
||||||
|
@ -41,8 +41,8 @@ use pool::*;
|
||||||
use keychain::Keychain;
|
use keychain::Keychain;
|
||||||
use wallet::libtx;
|
use wallet::libtx;
|
||||||
|
|
||||||
use pool::types::*;
|
|
||||||
use pool::TransactionPool;
|
use pool::TransactionPool;
|
||||||
|
use pool::types::*;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ChainAdapter {
|
pub struct ChainAdapter {
|
||||||
|
@ -105,11 +105,14 @@ pub fn test_setup(chain: &Arc<ChainAdapter>) -> TransactionPool<ChainAdapter> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_transaction_spending_coinbase(
|
pub fn test_transaction_spending_coinbase<K>(
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
header: &BlockHeader,
|
header: &BlockHeader,
|
||||||
output_values: Vec<u64>,
|
output_values: Vec<u64>,
|
||||||
) -> Transaction {
|
) -> Transaction
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let output_sum = output_values.iter().sum::<u64>() as i64;
|
let output_sum = output_values.iter().sum::<u64>() as i64;
|
||||||
|
|
||||||
let coinbase_reward: u64 = 60_000_000_000;
|
let coinbase_reward: u64 = 60_000_000_000;
|
||||||
|
@ -137,14 +140,17 @@ pub fn test_transaction_spending_coinbase(
|
||||||
|
|
||||||
tx_elements.push(libtx::build::with_fee(fees as u64));
|
tx_elements.push(libtx::build::with_fee(fees as u64));
|
||||||
|
|
||||||
libtx::build::transaction(tx_elements, &keychain).unwrap()
|
libtx::build::transaction(tx_elements, keychain).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_transaction(
|
pub fn test_transaction<K>(
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
input_values: Vec<u64>,
|
input_values: Vec<u64>,
|
||||||
output_values: Vec<u64>,
|
output_values: Vec<u64>,
|
||||||
) -> Transaction {
|
) -> Transaction
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let input_sum = input_values.iter().sum::<u64>() as i64;
|
let input_sum = input_values.iter().sum::<u64>() as i64;
|
||||||
let output_sum = output_values.iter().sum::<u64>() as i64;
|
let output_sum = output_values.iter().sum::<u64>() as i64;
|
||||||
|
|
||||||
|
@ -164,7 +170,7 @@ pub fn test_transaction(
|
||||||
}
|
}
|
||||||
tx_elements.push(libtx::build::with_fee(fees as u64));
|
tx_elements.push(libtx::build::with_fee(fees as u64));
|
||||||
|
|
||||||
libtx::build::transaction(tx_elements, &keychain).unwrap()
|
libtx::build::transaction(tx_elements, keychain).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn test_source() -> TxSource {
|
pub fn test_source() -> TxSource {
|
||||||
|
|
|
@ -29,13 +29,13 @@ use std::sync::{Arc, RwLock};
|
||||||
|
|
||||||
use core::core::{Block, BlockHeader};
|
use core::core::{Block, BlockHeader};
|
||||||
|
|
||||||
|
use chain::ChainStore;
|
||||||
use chain::txhashset;
|
use chain::txhashset;
|
||||||
use chain::types::Tip;
|
use chain::types::Tip;
|
||||||
use chain::ChainStore;
|
|
||||||
use core::core::target::Difficulty;
|
use core::core::target::Difficulty;
|
||||||
use core::core::transaction;
|
use core::core::transaction;
|
||||||
|
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use wallet::libtx;
|
use wallet::libtx;
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
|
@ -43,7 +43,7 @@ use common::*;
|
||||||
/// Test we can add some txs to the pool (both stempool and txpool).
|
/// Test we can add some txs to the pool (both stempool and txpool).
|
||||||
#[test]
|
#[test]
|
||||||
fn test_the_transaction_pool() {
|
fn test_the_transaction_pool() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain: ExtKeychain = Keychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let db_root = ".grin_transaction_pool".to_string();
|
let db_root = ".grin_transaction_pool".to_string();
|
||||||
clean_output_dir(db_root.clone());
|
clean_output_dir(db_root.clone());
|
||||||
|
|
|
@ -31,7 +31,7 @@ use core::core;
|
||||||
use core::core::hash::Hashed;
|
use core::core::hash::Hashed;
|
||||||
use core::ser;
|
use core::ser;
|
||||||
use core::ser::AsFixedBytes;
|
use core::ser::AsFixedBytes;
|
||||||
use keychain::{Identifier, Keychain};
|
use keychain::{ExtKeychain, Identifier, Keychain};
|
||||||
use pool;
|
use pool;
|
||||||
use util;
|
use util;
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
@ -219,7 +219,7 @@ fn build_block(
|
||||||
///
|
///
|
||||||
fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, BlockFees), Error> {
|
fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, BlockFees), Error> {
|
||||||
warn!(LOGGER, "Burning block fees: {:?}", block_fees);
|
warn!(LOGGER, "Burning block fees: {:?}", block_fees);
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let (out, kernel) =
|
let (out, kernel) =
|
||||||
wallet::libtx::reward::output(&keychain, &key_id, block_fees.fees, block_fees.height)
|
wallet::libtx::reward::output(&keychain, &key_id, block_fees.fees, block_fees.height)
|
||||||
|
|
|
@ -268,12 +268,13 @@ impl LocalServerContainer {
|
||||||
//panic!("Error initting wallet seed: {}", e);
|
//panic!("Error initting wallet seed: {}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
let wallet = FileWallet::new(self.wallet_config.clone(), "").unwrap_or_else(|e| {
|
let wallet: FileWallet<keychain::ExtKeychain> =
|
||||||
panic!(
|
FileWallet::new(self.wallet_config.clone(), "").unwrap_or_else(|e| {
|
||||||
"Error creating wallet: {:?} Config: {:?}",
|
panic!(
|
||||||
e, self.wallet_config
|
"Error creating wallet: {:?} Config: {:?}",
|
||||||
)
|
e, self.wallet_config
|
||||||
});
|
)
|
||||||
|
});
|
||||||
|
|
||||||
wallet::controller::foreign_listener(wallet, &self.wallet_config.api_listen_addr())
|
wallet::controller::foreign_listener(wallet, &self.wallet_config.api_listen_addr())
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
|
@ -298,7 +299,7 @@ impl LocalServerContainer {
|
||||||
config: &WalletConfig,
|
config: &WalletConfig,
|
||||||
wallet_seed: &wallet::WalletSeed,
|
wallet_seed: &wallet::WalletSeed,
|
||||||
) -> wallet::WalletInfo {
|
) -> wallet::WalletInfo {
|
||||||
let keychain = wallet_seed
|
let keychain: keychain::ExtKeychain = wallet_seed
|
||||||
.derive_keychain("")
|
.derive_keychain("")
|
||||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||||
let mut wallet = FileWallet::new(config.clone(), "")
|
let mut wallet = FileWallet::new(config.clone(), "")
|
||||||
|
@ -321,7 +322,7 @@ impl LocalServerContainer {
|
||||||
let wallet_seed =
|
let wallet_seed =
|
||||||
wallet::WalletSeed::from_file(config).expect("Failed to read wallet seed file.");
|
wallet::WalletSeed::from_file(config).expect("Failed to read wallet seed file.");
|
||||||
|
|
||||||
let keychain = wallet_seed
|
let keychain: keychain::ExtKeychain = wallet_seed
|
||||||
.derive_keychain("")
|
.derive_keychain("")
|
||||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||||
let max_outputs = 500;
|
let max_outputs = 500;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
use core::core;
|
use core::core;
|
||||||
use core::core::amount_to_hr_string;
|
use core::core::amount_to_hr_string;
|
||||||
|
use keychain::Keychain;
|
||||||
use libwallet::Error;
|
use libwallet::Error;
|
||||||
use libwallet::types::{OutputData, WalletInfo};
|
use libwallet::types::{OutputData, WalletInfo};
|
||||||
use prettytable;
|
use prettytable;
|
||||||
|
|
|
@ -103,9 +103,9 @@ impl WalletSeed {
|
||||||
util::to_hex(self.0.to_vec())
|
util::to_hex(self.0.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn derive_keychain(&self, password: &str) -> Result<keychain::Keychain, Error> {
|
pub fn derive_keychain<K: Keychain>(&self, password: &str) -> Result<K, Error> {
|
||||||
let seed = blake2::blake2b::blake2b(64, &password.as_bytes(), &self.0);
|
let seed = blake2::blake2b::blake2b(64, &password.as_bytes(), &self.0);
|
||||||
let result = keychain::Keychain::from_seed(seed.as_bytes())?;
|
let result = K::from_seed(seed.as_bytes())?;
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,9 +168,9 @@ impl WalletSeed {
|
||||||
/// Wallet information tracking all our outputs. Based on HD derivation and
|
/// Wallet information tracking all our outputs. Based on HD derivation and
|
||||||
/// avoids storing any key data, only storing output amounts and child index.
|
/// avoids storing any key data, only storing output amounts and child index.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct FileWallet {
|
pub struct FileWallet<K> {
|
||||||
/// Keychain
|
/// Keychain
|
||||||
pub keychain: Option<Keychain>,
|
pub keychain: Option<K>,
|
||||||
/// Configuration
|
/// Configuration
|
||||||
pub config: WalletConfig,
|
pub config: WalletConfig,
|
||||||
/// passphrase: TODO better ways of dealing with this other than storing
|
/// passphrase: TODO better ways of dealing with this other than storing
|
||||||
|
@ -185,14 +185,18 @@ pub struct FileWallet {
|
||||||
pub lock_file_path: String,
|
pub lock_file_path: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalletBackend for FileWallet {
|
impl<K> WalletBackend<K> for FileWallet<K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
/// Initialise with whatever stored credentials we have
|
/// Initialise with whatever stored credentials we have
|
||||||
fn open_with_credentials(&mut self) -> Result<(), libwallet::Error> {
|
fn open_with_credentials(&mut self) -> Result<(), libwallet::Error> {
|
||||||
let wallet_seed = WalletSeed::from_file(&self.config)
|
let wallet_seed = WalletSeed::from_file(&self.config)
|
||||||
.context(libwallet::ErrorKind::CallbackImpl("Error opening wallet"))?;
|
.context(libwallet::ErrorKind::CallbackImpl("Error opening wallet"))?;
|
||||||
self.keychain = Some(wallet_seed.derive_keychain(&self.passphrase).context(
|
let keychain = wallet_seed.derive_keychain(&self.passphrase);
|
||||||
libwallet::ErrorKind::CallbackImpl("Error deriving keychain"),
|
self.keychain = Some(keychain.context(libwallet::ErrorKind::CallbackImpl(
|
||||||
)?);
|
"Error deriving keychain",
|
||||||
|
))?);
|
||||||
// Just blow up password for now after it's been used
|
// Just blow up password for now after it's been used
|
||||||
self.passphrase = String::from("");
|
self.passphrase = String::from("");
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -205,7 +209,7 @@ impl WalletBackend for FileWallet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the keychain being used
|
/// Return the keychain being used
|
||||||
fn keychain(&mut self) -> &mut Keychain {
|
fn keychain(&mut self) -> &mut K {
|
||||||
self.keychain.as_mut().unwrap()
|
self.keychain.as_mut().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +402,7 @@ impl WalletBackend for FileWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalletClient for FileWallet {
|
impl<K> WalletClient for FileWallet<K> {
|
||||||
/// Return URL for check node
|
/// Return URL for check node
|
||||||
fn node_url(&self) -> &str {
|
fn node_url(&self) -> &str {
|
||||||
&self.config.check_node_api_http_addr
|
&self.config.check_node_api_http_addr
|
||||||
|
@ -473,7 +477,10 @@ impl WalletClient for FileWallet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileWallet {
|
impl<K> FileWallet<K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
/// Create a new FileWallet instance
|
/// Create a new FileWallet instance
|
||||||
pub fn new(config: WalletConfig, passphrase: &str) -> Result<Self, Error> {
|
pub fn new(config: WalletConfig, passphrase: &str) -> Result<Self, Error> {
|
||||||
let mut retval = FileWallet {
|
let mut retval = FileWallet {
|
||||||
|
|
|
@ -13,9 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//! Aggsig helper functions used in transaction creation.. should be only
|
//! Aggsig helper functions used in transaction creation.. should be only
|
||||||
//! interface into the underlying secp library
|
//! interface into the underlying secp library
|
||||||
use keychain::Keychain;
|
use keychain::{BlindingFactor, Identifier, Keychain};
|
||||||
use keychain::blind::BlindingFactor;
|
|
||||||
use keychain::extkey::Identifier;
|
|
||||||
use libtx::error::{Error, ErrorKind};
|
use libtx::error::{Error, ErrorKind};
|
||||||
use util::kernel_sig_msg;
|
use util::kernel_sig_msg;
|
||||||
use util::secp::key::{PublicKey, SecretKey};
|
use util::secp::key::{PublicKey, SecretKey};
|
||||||
|
@ -72,12 +70,15 @@ pub fn verify_partial_sig(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just a simple sig, creates its own nonce, etc
|
/// Just a simple sig, creates its own nonce, etc
|
||||||
pub fn sign_from_key_id(
|
pub fn sign_from_key_id<K>(
|
||||||
secp: &Secp256k1,
|
secp: &Secp256k1,
|
||||||
k: &Keychain,
|
k: &K,
|
||||||
msg: &Message,
|
msg: &Message,
|
||||||
key_id: &Identifier,
|
key_id: &Identifier,
|
||||||
) -> Result<Signature, Error> {
|
) -> Result<Signature, Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let skey = k.derived_key(key_id)?;
|
let skey = k.derived_key(key_id)?;
|
||||||
let sig = aggsig::sign_single(secp, &msg, &skey, None, None, None)?;
|
let sig = aggsig::sign_single(secp, &msg, &skey, None, None, None)?;
|
||||||
Ok(sig)
|
Ok(sig)
|
||||||
|
|
|
@ -30,30 +30,35 @@ use util::{kernel_sig_msg, secp};
|
||||||
use core::core::hash::Hash;
|
use core::core::hash::Hash;
|
||||||
use core::core::pmmr::MerkleProof;
|
use core::core::pmmr::MerkleProof;
|
||||||
use core::core::{Input, Output, OutputFeatures, ProofMessageElements, Transaction, TxKernel};
|
use core::core::{Input, Output, OutputFeatures, ProofMessageElements, Transaction, TxKernel};
|
||||||
use keychain;
|
use keychain::{self, BlindSum, BlindingFactor, Identifier, Keychain};
|
||||||
use keychain::{BlindSum, BlindingFactor, Identifier, Keychain};
|
|
||||||
use libtx::{aggsig, proof};
|
use libtx::{aggsig, proof};
|
||||||
use util::LOGGER;
|
use util::LOGGER;
|
||||||
|
|
||||||
/// Context information available to transaction combinators.
|
/// Context information available to transaction combinators.
|
||||||
pub struct Context<'a> {
|
pub struct Context<'a, K: 'a>
|
||||||
keychain: &'a Keychain,
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
keychain: &'a K,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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) pair into another, provided some context.
|
||||||
pub type Append = for<'a> Fn(&'a mut Context, (Transaction, TxKernel, BlindSum))
|
pub type Append<K: Keychain> = for<'a> Fn(&'a mut Context<K>, (Transaction, TxKernel, BlindSum))
|
||||||
-> (Transaction, TxKernel, BlindSum);
|
-> (Transaction, TxKernel, BlindSum);
|
||||||
|
|
||||||
/// 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.
|
||||||
fn build_input(
|
fn build_input<K>(
|
||||||
value: u64,
|
value: u64,
|
||||||
features: OutputFeatures,
|
features: OutputFeatures,
|
||||||
block_hash: Option<Hash>,
|
block_hash: Option<Hash>,
|
||||||
merkle_proof: Option<MerkleProof>,
|
merkle_proof: Option<MerkleProof>,
|
||||||
key_id: Identifier,
|
key_id: Identifier,
|
||||||
) -> Box<Append> {
|
) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
let commit = build.keychain.commit(value, &key_id).unwrap();
|
let commit = build.keychain.commit(value, &key_id).unwrap();
|
||||||
|
@ -65,7 +70,10 @@ fn build_input(
|
||||||
|
|
||||||
/// 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.
|
||||||
pub fn input(value: u64, key_id: Identifier) -> Box<Append> {
|
pub fn input<K>(value: u64, key_id: Identifier) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
debug!(
|
debug!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
"Building input (spending regular output): {}, {}", value, key_id
|
"Building input (spending regular output): {}, {}", value, key_id
|
||||||
|
@ -75,12 +83,15 @@ pub fn input(value: u64, key_id: Identifier) -> Box<Append> {
|
||||||
|
|
||||||
/// Adds a coinbase input spending a coinbase output.
|
/// Adds a coinbase input spending a coinbase output.
|
||||||
/// We will use the block hash to verify coinbase maturity.
|
/// We will use the block hash to verify coinbase maturity.
|
||||||
pub fn coinbase_input(
|
pub fn coinbase_input<K>(
|
||||||
value: u64,
|
value: u64,
|
||||||
block_hash: Hash,
|
block_hash: Hash,
|
||||||
merkle_proof: MerkleProof,
|
merkle_proof: MerkleProof,
|
||||||
key_id: Identifier,
|
key_id: Identifier,
|
||||||
) -> Box<Append> {
|
) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
debug!(
|
debug!(
|
||||||
LOGGER,
|
LOGGER,
|
||||||
"Building input (spending coinbase): {}, {}", value, key_id
|
"Building input (spending coinbase): {}, {}", value, key_id
|
||||||
|
@ -96,7 +107,10 @@ pub fn coinbase_input(
|
||||||
|
|
||||||
/// Adds an output with the provided value and key identifier from the
|
/// Adds an output with the provided value and key identifier from the
|
||||||
/// keychain.
|
/// keychain.
|
||||||
pub fn output(value: u64, key_id: Identifier) -> Box<Append> {
|
pub fn output<K>(value: u64, key_id: Identifier) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
debug!(LOGGER, "Building an output: {}, {}", value, key_id,);
|
debug!(LOGGER, "Building an output: {}, {}", value, key_id,);
|
||||||
|
@ -129,7 +143,10 @@ pub fn output(value: u64, key_id: Identifier) -> Box<Append> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the fee on the transaction being built.
|
/// Sets the fee on the transaction being built.
|
||||||
pub fn with_fee(fee: u64) -> Box<Append> {
|
pub fn with_fee<K>(fee: u64) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
(tx, kern.with_fee(fee), sum)
|
(tx, kern.with_fee(fee), sum)
|
||||||
|
@ -138,7 +155,10 @@ pub fn with_fee(fee: u64) -> Box<Append> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the lock_height on the transaction being built.
|
/// Sets the lock_height on the transaction being built.
|
||||||
pub fn with_lock_height(lock_height: u64) -> Box<Append> {
|
pub fn with_lock_height<K>(lock_height: u64) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
(tx, kern.with_lock_height(lock_height), sum)
|
(tx, kern.with_lock_height(lock_height), sum)
|
||||||
|
@ -149,7 +169,10 @@ pub fn with_lock_height(lock_height: u64) -> Box<Append> {
|
||||||
/// Adds a known excess value on the transaction being built. Usually used in
|
/// Adds a known excess value on the transaction being built. Usually used in
|
||||||
/// combination with the initial_tx function when a new transaction is built
|
/// combination with the initial_tx function when a new transaction is built
|
||||||
/// by adding to a pre-existing one.
|
/// by adding to a pre-existing one.
|
||||||
pub fn with_excess(excess: BlindingFactor) -> Box<Append> {
|
pub fn with_excess<K>(excess: BlindingFactor) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
(tx, kern, sum.add_blinding_factor(excess.clone()))
|
(tx, kern, sum.add_blinding_factor(excess.clone()))
|
||||||
|
@ -158,7 +181,10 @@ pub fn with_excess(excess: BlindingFactor) -> Box<Append> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets a known tx "offset". Used in final step of tx construction.
|
/// Sets a known tx "offset". Used in final step of tx construction.
|
||||||
pub fn with_offset(offset: BlindingFactor) -> Box<Append> {
|
pub fn with_offset<K>(offset: BlindingFactor) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
Box::new(
|
Box::new(
|
||||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||||
(tx.with_offset(offset), kern, sum)
|
(tx.with_offset(offset), kern, sum)
|
||||||
|
@ -169,7 +195,10 @@ pub fn with_offset(offset: BlindingFactor) -> Box<Append> {
|
||||||
/// 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
|
/// We currently only support building a tx with a single kernel with
|
||||||
/// build::transaction()
|
/// build::transaction()
|
||||||
pub fn initial_tx(mut tx: Transaction) -> Box<Append> {
|
pub fn initial_tx<K>(mut tx: Transaction) -> Box<Append<K>>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
assert_eq!(tx.kernels.len(), 1);
|
assert_eq!(tx.kernels.len(), 1);
|
||||||
let kern = tx.kernels.remove(0);
|
let kern = tx.kernels.remove(0);
|
||||||
Box::new(
|
Box::new(
|
||||||
|
@ -189,10 +218,13 @@ pub fn initial_tx(mut tx: Transaction) -> Box<Append> {
|
||||||
/// let (tx2, _) = build::transaction(vec![initial_tx(tx1), with_excess(sum),
|
/// let (tx2, _) = build::transaction(vec![initial_tx(tx1), with_excess(sum),
|
||||||
/// output_rand(2)], keychain).unwrap();
|
/// output_rand(2)], keychain).unwrap();
|
||||||
///
|
///
|
||||||
pub fn partial_transaction(
|
pub fn partial_transaction<K>(
|
||||||
elems: Vec<Box<Append>>,
|
elems: Vec<Box<Append<K>>>,
|
||||||
keychain: &keychain::Keychain,
|
keychain: &K,
|
||||||
) -> Result<(Transaction, BlindingFactor), keychain::Error> {
|
) -> Result<(Transaction, BlindingFactor), keychain::Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let mut ctx = Context { keychain };
|
let mut ctx = Context { keychain };
|
||||||
let (mut tx, kern, sum) = elems.iter().fold(
|
let (mut tx, kern, sum) = elems.iter().fold(
|
||||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
||||||
|
@ -208,10 +240,13 @@ pub fn partial_transaction(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a complete transaction.
|
/// Builds a complete transaction.
|
||||||
pub fn transaction(
|
pub fn transaction<K>(
|
||||||
elems: Vec<Box<Append>>,
|
elems: Vec<Box<Append<K>>>,
|
||||||
keychain: &keychain::Keychain,
|
keychain: &K,
|
||||||
) -> Result<Transaction, keychain::Error> {
|
) -> Result<Transaction, keychain::Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let (mut tx, blind_sum) = partial_transaction(elems, keychain)?;
|
let (mut tx, blind_sum) = partial_transaction(elems, keychain)?;
|
||||||
assert_eq!(tx.kernels.len(), 1);
|
assert_eq!(tx.kernels.len(), 1);
|
||||||
|
|
||||||
|
@ -229,10 +264,13 @@ pub fn transaction(
|
||||||
|
|
||||||
/// Builds a complete transaction, splitting the key and
|
/// Builds a complete transaction, splitting the key and
|
||||||
/// setting the excess, excess_sig and tx offset as necessary.
|
/// setting the excess, excess_sig and tx offset as necessary.
|
||||||
pub fn transaction_with_offset(
|
pub fn transaction_with_offset<K>(
|
||||||
elems: Vec<Box<Append>>,
|
elems: Vec<Box<Append<K>>>,
|
||||||
keychain: &keychain::Keychain,
|
keychain: &K,
|
||||||
) -> Result<Transaction, keychain::Error> {
|
) -> Result<Transaction, keychain::Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let mut ctx = Context { keychain };
|
let mut ctx = Context { keychain };
|
||||||
let (mut tx, mut kern, sum) = elems.iter().fold(
|
let (mut tx, mut kern, sum) = elems.iter().fold(
|
||||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
||||||
|
@ -265,10 +303,11 @@ pub fn transaction_with_offset(
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use keychain::ExtKeychain;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blind_simple_tx() {
|
fn blind_simple_tx() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -288,7 +327,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blind_simple_tx_with_offset() {
|
fn blind_simple_tx_with_offset() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||||
|
@ -308,7 +347,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn blind_simpler_tx() {
|
fn blind_simpler_tx() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
let key_id2 = keychain.derive_key_id(2).unwrap();
|
let key_id2 = keychain.derive_key_id(2).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ use std::fmt::{self, Display};
|
||||||
|
|
||||||
use core::core::committed;
|
use core::core::committed;
|
||||||
use core::core::transaction;
|
use core::core::transaction;
|
||||||
use keychain::{self, extkey};
|
use keychain;
|
||||||
use util::secp;
|
use util::secp;
|
||||||
|
|
||||||
/// Lib tx error definition
|
/// Lib tx error definition
|
||||||
|
@ -36,9 +36,6 @@ pub enum ErrorKind {
|
||||||
/// Keychain error
|
/// Keychain error
|
||||||
#[fail(display = "Keychain Error")]
|
#[fail(display = "Keychain Error")]
|
||||||
Keychain(keychain::Error),
|
Keychain(keychain::Error),
|
||||||
/// Extended key error
|
|
||||||
#[fail(display = "Extended Key Error")]
|
|
||||||
ExtendedKey(extkey::Error),
|
|
||||||
/// Transaction error
|
/// Transaction error
|
||||||
#[fail(display = "Transaction Error")]
|
#[fail(display = "Transaction Error")]
|
||||||
Transaction(transaction::Error),
|
Transaction(transaction::Error),
|
||||||
|
@ -117,14 +114,6 @@ impl From<keychain::Error> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<extkey::Error> for Error {
|
|
||||||
fn from(error: extkey::Error) -> Error {
|
|
||||||
Error {
|
|
||||||
inner: Context::new(ErrorKind::ExtendedKey(error)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<transaction::Error> for Error {
|
impl From<transaction::Error> for Error {
|
||||||
fn from(error: transaction::Error) -> Error {
|
fn from(error: transaction::Error) -> Error {
|
||||||
Error {
|
Error {
|
||||||
|
|
|
@ -15,18 +15,20 @@
|
||||||
//! Rangeproof library functions
|
//! Rangeproof library functions
|
||||||
|
|
||||||
use blake2;
|
use blake2;
|
||||||
use keychain::Keychain;
|
use keychain::{Identifier, Keychain};
|
||||||
use keychain::extkey::Identifier;
|
|
||||||
use libtx::error::{Error, ErrorKind};
|
use libtx::error::{Error, ErrorKind};
|
||||||
use util::logger::LOGGER;
|
use util::logger::LOGGER;
|
||||||
use util::secp::key::SecretKey;
|
use util::secp::key::SecretKey;
|
||||||
use util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof};
|
use util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof};
|
||||||
use util::secp::{self, Secp256k1};
|
use util::secp::{self, Secp256k1};
|
||||||
|
|
||||||
fn create_nonce(k: &Keychain, commit: &Commitment) -> Result<SecretKey, Error> {
|
fn create_nonce<K>(k: &K, commit: &Commitment) -> Result<SecretKey, Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
// hash(commit|masterkey) as nonce
|
// hash(commit|masterkey) as nonce
|
||||||
let root_key = k.root_key_id().to_bytes();
|
let root_key = k.root_key_id();
|
||||||
let res = blake2::blake2b::blake2b(32, &commit.0, &root_key);
|
let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.to_bytes()[..]);
|
||||||
let res = res.as_bytes();
|
let res = res.as_bytes();
|
||||||
let mut ret_val = [0; 32];
|
let mut ret_val = [0; 32];
|
||||||
for i in 0..res.len() {
|
for i in 0..res.len() {
|
||||||
|
@ -43,14 +45,17 @@ fn create_nonce(k: &Keychain, commit: &Commitment) -> Result<SecretKey, Error> {
|
||||||
/// So we want this to take an opaque structure that can be called
|
/// So we want this to take an opaque structure that can be called
|
||||||
/// back to get the sensitive data
|
/// back to get the sensitive data
|
||||||
|
|
||||||
pub fn create(
|
pub fn create<K>(
|
||||||
k: &Keychain,
|
k: &K,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
key_id: &Identifier,
|
key_id: &Identifier,
|
||||||
_commit: Commitment,
|
_commit: Commitment,
|
||||||
extra_data: Option<Vec<u8>>,
|
extra_data: Option<Vec<u8>>,
|
||||||
msg: ProofMessage,
|
msg: ProofMessage,
|
||||||
) -> Result<RangeProof, Error> {
|
) -> Result<RangeProof, Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let commit = k.commit(amount, key_id)?;
|
let commit = k.commit(amount, key_id)?;
|
||||||
let skey = k.derived_key(key_id)?;
|
let skey = k.derived_key(key_id)?;
|
||||||
let nonce = create_nonce(k, &commit)?;
|
let nonce = create_nonce(k, &commit)?;
|
||||||
|
@ -83,13 +88,16 @@ pub fn verify(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rewind a rangeproof to retrieve the amount
|
/// Rewind a rangeproof to retrieve the amount
|
||||||
pub fn rewind(
|
pub fn rewind<K>(
|
||||||
k: &Keychain,
|
k: &K,
|
||||||
key_id: &Identifier,
|
key_id: &Identifier,
|
||||||
commit: Commitment,
|
commit: Commitment,
|
||||||
extra_data: Option<Vec<u8>>,
|
extra_data: Option<Vec<u8>>,
|
||||||
proof: RangeProof,
|
proof: RangeProof,
|
||||||
) -> Result<ProofInfo, Error> {
|
) -> Result<ProofInfo, Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let skey = k.derived_key(key_id)?;
|
let skey = k.derived_key(key_id)?;
|
||||||
let nonce = create_nonce(k, &commit)?;
|
let nonce = create_nonce(k, &commit)?;
|
||||||
let proof_message = k.secp()
|
let proof_message = k.secp()
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
//! Builds the blinded output and related signature proof for the block
|
//! Builds the blinded output and related signature proof for the block
|
||||||
//! reward.
|
//! reward.
|
||||||
use keychain;
|
use keychain::{Identifier, Keychain};
|
||||||
|
|
||||||
use core::consensus::reward;
|
use core::consensus::reward;
|
||||||
use core::core::KernelFeatures;
|
use core::core::KernelFeatures;
|
||||||
|
@ -24,12 +24,15 @@ use libtx::{aggsig, proof};
|
||||||
use util::{kernel_sig_msg, secp, static_secp_instance, LOGGER};
|
use util::{kernel_sig_msg, secp, static_secp_instance, LOGGER};
|
||||||
|
|
||||||
/// output a reward output
|
/// output a reward output
|
||||||
pub fn output(
|
pub fn output<K>(
|
||||||
keychain: &keychain::Keychain,
|
keychain: &K,
|
||||||
key_id: &keychain::Identifier,
|
key_id: &Identifier,
|
||||||
fees: u64,
|
fees: u64,
|
||||||
height: u64,
|
height: u64,
|
||||||
) -> Result<(Output, TxKernel), Error> {
|
) -> Result<(Output, TxKernel), Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let value = reward(fees);
|
let value = reward(fees);
|
||||||
let commit = keychain.commit(value, key_id)?;
|
let commit = keychain.commit(value, key_id)?;
|
||||||
let msg = ProofMessageElements::new(value, key_id);
|
let msg = ProofMessageElements::new(value, key_id);
|
||||||
|
|
|
@ -104,29 +104,35 @@ impl Slate {
|
||||||
|
|
||||||
/// Adds selected inputs and outputs to the slate's transaction
|
/// Adds selected inputs and outputs to the slate's transaction
|
||||||
/// Returns blinding factor
|
/// Returns blinding factor
|
||||||
pub fn add_transaction_elements(
|
pub fn add_transaction_elements<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
mut elems: Vec<Box<build::Append>>,
|
mut elems: Vec<Box<build::Append<K>>>,
|
||||||
) -> Result<BlindingFactor, Error> {
|
) -> Result<BlindingFactor, Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
// Append to the exiting transaction
|
// Append to the exiting transaction
|
||||||
if self.tx.kernels.len() != 0 {
|
if self.tx.kernels.len() != 0 {
|
||||||
elems.insert(0, build::initial_tx(self.tx.clone()));
|
elems.insert(0, build::initial_tx(self.tx.clone()));
|
||||||
}
|
}
|
||||||
let (tx, blind) = build::partial_transaction(elems, &keychain)?;
|
let (tx, blind) = build::partial_transaction(elems, keychain)?;
|
||||||
self.tx = tx;
|
self.tx = tx;
|
||||||
Ok(blind)
|
Ok(blind)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Completes callers part of round 1, adding public key info
|
/// Completes callers part of round 1, adding public key info
|
||||||
/// to the slate
|
/// to the slate
|
||||||
pub fn fill_round_1(
|
pub fn fill_round_1<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
sec_key: &mut SecretKey,
|
sec_key: &mut SecretKey,
|
||||||
sec_nonce: &SecretKey,
|
sec_nonce: &SecretKey,
|
||||||
participant_id: usize,
|
participant_id: usize,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
// Whoever does this first generates the offset
|
// Whoever does this first generates the offset
|
||||||
if self.tx.offset == BlindingFactor::zero() {
|
if self.tx.offset == BlindingFactor::zero() {
|
||||||
self.generate_offset(keychain, sec_key)?;
|
self.generate_offset(keychain, sec_key)?;
|
||||||
|
@ -136,13 +142,16 @@ impl Slate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Completes caller's part of round 2, completing signatures
|
/// Completes caller's part of round 2, completing signatures
|
||||||
pub fn fill_round_2(
|
pub fn fill_round_2<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
sec_key: &SecretKey,
|
sec_key: &SecretKey,
|
||||||
sec_nonce: &SecretKey,
|
sec_nonce: &SecretKey,
|
||||||
participant_id: usize,
|
participant_id: usize,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
self.check_fees()?;
|
self.check_fees()?;
|
||||||
self.verify_part_sigs(keychain.secp())?;
|
self.verify_part_sigs(keychain.secp())?;
|
||||||
let sig_part = aggsig::calculate_partial_sig(
|
let sig_part = aggsig::calculate_partial_sig(
|
||||||
|
@ -160,7 +169,10 @@ impl Slate {
|
||||||
/// Creates the final signature, callable by either the sender or recipient
|
/// Creates the final signature, callable by either the sender or recipient
|
||||||
/// (after phase 3: sender confirmation)
|
/// (after phase 3: sender confirmation)
|
||||||
/// TODO: Only callable by receiver at the moment
|
/// TODO: Only callable by receiver at the moment
|
||||||
pub fn finalize(&mut self, keychain: &Keychain) -> Result<(), Error> {
|
pub fn finalize<K>(&mut self, keychain: &K) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let final_sig = self.finalize_signature(keychain)?;
|
let final_sig = self.finalize_signature(keychain)?;
|
||||||
self.finalize_transaction(keychain, &final_sig)
|
self.finalize_transaction(keychain, &final_sig)
|
||||||
}
|
}
|
||||||
|
@ -201,14 +213,17 @@ impl Slate {
|
||||||
/// and saves participant's transaction context
|
/// and saves participant's transaction context
|
||||||
/// sec_key can be overriden to replace the blinding
|
/// sec_key can be overriden to replace the blinding
|
||||||
/// factor (by whoever split the offset)
|
/// factor (by whoever split the offset)
|
||||||
fn add_participant_info(
|
fn add_participant_info<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
sec_key: &SecretKey,
|
sec_key: &SecretKey,
|
||||||
sec_nonce: &SecretKey,
|
sec_nonce: &SecretKey,
|
||||||
id: usize,
|
id: usize,
|
||||||
part_sig: Option<Signature>,
|
part_sig: Option<Signature>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
// Add our public key and nonce to the slate
|
// Add our public key and nonce to the slate
|
||||||
let pub_key = PublicKey::from_secret_key(keychain.secp(), &sec_key)?;
|
let pub_key = PublicKey::from_secret_key(keychain.secp(), &sec_key)?;
|
||||||
let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &sec_nonce)?;
|
let pub_nonce = PublicKey::from_secret_key(keychain.secp(), &sec_nonce)?;
|
||||||
|
@ -226,11 +241,10 @@ impl Slate {
|
||||||
/// For now, we'll have the transaction initiator be responsible for it
|
/// For now, we'll have the transaction initiator be responsible for it
|
||||||
/// Return offset private key for the participant to use later in the
|
/// Return offset private key for the participant to use later in the
|
||||||
/// transaction
|
/// transaction
|
||||||
fn generate_offset(
|
fn generate_offset<K>(&mut self, keychain: &K, sec_key: &mut SecretKey) -> Result<(), Error>
|
||||||
&mut self,
|
where
|
||||||
keychain: &Keychain,
|
K: Keychain,
|
||||||
sec_key: &mut SecretKey,
|
{
|
||||||
) -> Result<(), Error> {
|
|
||||||
// Generate a random kernel offset here
|
// Generate a random kernel offset here
|
||||||
// and subtract it from the blind_sum so we create
|
// and subtract it from the blind_sum so we create
|
||||||
// the aggsig context with the "split" key
|
// the aggsig context with the "split" key
|
||||||
|
@ -308,7 +322,10 @@ impl Slate {
|
||||||
///
|
///
|
||||||
/// Returns completed transaction ready for posting to the chain
|
/// Returns completed transaction ready for posting to the chain
|
||||||
|
|
||||||
fn finalize_signature(&mut self, keychain: &Keychain) -> Result<Signature, Error> {
|
fn finalize_signature<K>(&mut self, keychain: &K) -> Result<Signature, Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
self.verify_part_sigs(keychain.secp())?;
|
self.verify_part_sigs(keychain.secp())?;
|
||||||
|
|
||||||
let part_sigs = self.part_sigs();
|
let part_sigs = self.part_sigs();
|
||||||
|
@ -332,11 +349,14 @@ impl Slate {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// builds a final transaction after the aggregated sig exchange
|
/// builds a final transaction after the aggregated sig exchange
|
||||||
fn finalize_transaction(
|
fn finalize_transaction<K>(
|
||||||
&mut self,
|
&mut self,
|
||||||
keychain: &Keychain,
|
keychain: &K,
|
||||||
final_sig: &secp::Signature,
|
final_sig: &secp::Signature,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let kernel_offset = self.tx.offset;
|
let kernel_offset = self.tx.offset;
|
||||||
|
|
||||||
self.check_fees()?;
|
self.check_fees()?;
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
//! vs. functions to interact with someone else)
|
//! vs. functions to interact with someone else)
|
||||||
//! Still experimental, not sure this is the best way to do this
|
//! Still experimental, not sure this is the best way to do this
|
||||||
|
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use libtx::slate::Slate;
|
use libtx::slate::Slate;
|
||||||
use libwallet::Error;
|
use libwallet::Error;
|
||||||
use libwallet::internal::{tx, updater};
|
use libwallet::internal::{tx, updater};
|
||||||
|
@ -24,26 +26,33 @@ use libwallet::types::{BlockFees, CbData, OutputData, TxWrapper, WalletBackend,
|
||||||
WalletInfo};
|
WalletInfo};
|
||||||
|
|
||||||
use core::ser;
|
use core::ser;
|
||||||
|
use keychain::Keychain;
|
||||||
use util::{self, LOGGER};
|
use util::{self, LOGGER};
|
||||||
|
|
||||||
/// Wrapper around internal API functions, containing a reference to
|
/// Wrapper around internal API functions, containing a reference to
|
||||||
/// the wallet/keychain that they're acting upon
|
/// the wallet/keychain that they're acting upon
|
||||||
pub struct APIOwner<'a, W>
|
pub struct APIOwner<'a, W, K>
|
||||||
where
|
where
|
||||||
W: 'a + WalletBackend + WalletClient,
|
W: 'a + WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||||
/// perhaps)
|
/// perhaps)
|
||||||
pub wallet: &'a mut W,
|
pub wallet: &'a mut W,
|
||||||
|
phantom: PhantomData<K>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W> APIOwner<'a, W>
|
impl<'a, W, K> APIOwner<'a, W, K>
|
||||||
where
|
where
|
||||||
W: 'a + WalletBackend + WalletClient,
|
W: 'a + WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Create new API instance
|
/// Create new API instance
|
||||||
pub fn new(wallet_in: &'a mut W) -> APIOwner<'a, W> {
|
pub fn new(wallet_in: &'a mut W) -> APIOwner<'a, W, K> {
|
||||||
APIOwner { wallet: wallet_in }
|
APIOwner {
|
||||||
|
wallet: wallet_in,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to update and retrieve outputs
|
/// Attempt to update and retrieve outputs
|
||||||
|
@ -151,22 +160,28 @@ where
|
||||||
|
|
||||||
/// Wrapper around external API functions, intended to communicate
|
/// Wrapper around external API functions, intended to communicate
|
||||||
/// with other parties
|
/// with other parties
|
||||||
pub struct APIForeign<'a, W>
|
pub struct APIForeign<'a, W, K>
|
||||||
where
|
where
|
||||||
W: 'a + WalletBackend + WalletClient,
|
W: 'a + WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||||
/// perhaps)
|
/// perhaps)
|
||||||
pub wallet: &'a mut W,
|
pub wallet: &'a mut W,
|
||||||
|
phantom: PhantomData<K>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W> APIForeign<'a, W>
|
impl<'a, W, K> APIForeign<'a, W, K>
|
||||||
where
|
where
|
||||||
W: 'a + WalletBackend + WalletClient,
|
W: 'a + WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Create new API instance
|
/// Create new API instance
|
||||||
pub fn new(wallet_in: &'a mut W) -> APIForeign<'a, W> {
|
pub fn new(wallet_in: &'a mut W) -> APIForeign<'a, W, K> {
|
||||||
APIForeign { wallet: wallet_in }
|
APIForeign {
|
||||||
|
wallet: wallet_in,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a new (potential) coinbase transaction in the wallet
|
/// Build a new (potential) coinbase transaction in the wallet
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
//! invocations) as needed.
|
//! invocations) as needed.
|
||||||
//! Still experimental
|
//! Still experimental
|
||||||
use api::ApiServer;
|
use api::ApiServer;
|
||||||
|
use std::marker::PhantomData;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use bodyparser;
|
use bodyparser;
|
||||||
|
@ -27,6 +28,7 @@ use serde_json;
|
||||||
|
|
||||||
use failure::Fail;
|
use failure::Fail;
|
||||||
|
|
||||||
|
use keychain::Keychain;
|
||||||
use libtx::slate::Slate;
|
use libtx::slate::Slate;
|
||||||
use libwallet::api::{APIForeign, APIOwner};
|
use libwallet::api::{APIForeign, APIOwner};
|
||||||
use libwallet::types::{BlockFees, CbData, OutputData, WalletBackend, WalletClient, WalletInfo};
|
use libwallet::types::{BlockFees, CbData, OutputData, WalletBackend, WalletClient, WalletInfo};
|
||||||
|
@ -36,10 +38,11 @@ use util::LOGGER;
|
||||||
|
|
||||||
/// Instantiate wallet Owner API for a single-use (command line) call
|
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||||
/// Return a function containing a loaded API context to call
|
/// Return a function containing a loaded API context to call
|
||||||
pub fn owner_single_use<F, T>(wallet: &mut T, f: F) -> Result<(), Error>
|
pub fn owner_single_use<F, T, K>(wallet: &mut T, f: F) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
F: FnOnce(&mut APIOwner<T>) -> Result<(), Error>,
|
F: FnOnce(&mut APIOwner<T, K>) -> Result<(), Error>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
wallet.open_with_credentials()?;
|
wallet.open_with_credentials()?;
|
||||||
f(&mut APIOwner::new(wallet))?;
|
f(&mut APIOwner::new(wallet))?;
|
||||||
|
@ -49,10 +52,11 @@ where
|
||||||
|
|
||||||
/// Instantiate wallet Foreign API for a single-use (command line) call
|
/// Instantiate wallet Foreign API for a single-use (command line) call
|
||||||
/// Return a function containing a loaded API context to call
|
/// Return a function containing a loaded API context to call
|
||||||
pub fn foreign_single_use<F, T>(wallet: &mut T, f: F) -> Result<(), Error>
|
pub fn foreign_single_use<F, T, K>(wallet: &mut T, f: F) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
F: FnOnce(&mut APIForeign<T>) -> Result<(), Error>,
|
F: FnOnce(&mut APIForeign<T, K>) -> Result<(), Error>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
wallet.open_with_credentials()?;
|
wallet.open_with_credentials()?;
|
||||||
f(&mut APIForeign::new(wallet))?;
|
f(&mut APIForeign::new(wallet))?;
|
||||||
|
@ -62,14 +66,13 @@ where
|
||||||
|
|
||||||
/// Listener version, providing same API but listening for requests on a
|
/// Listener version, providing same API but listening for requests on a
|
||||||
/// port and wrapping the calls
|
/// port and wrapping the calls
|
||||||
pub fn owner_listener<T>(wallet: T, addr: &str) -> Result<(), Error>
|
pub fn owner_listener<T, K>(wallet: T, addr: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K> + WalletClient,
|
||||||
OwnerAPIHandler<T>: Handler,
|
OwnerAPIHandler<T, K>: Handler,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let api_handler = OwnerAPIHandler {
|
let api_handler = OwnerAPIHandler::new(Arc::new(Mutex::new(wallet)));
|
||||||
wallet: Arc::new(Mutex::new(wallet)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let router = router!(
|
let router = router!(
|
||||||
receive_tx: get "/wallet/owner/*" => api_handler,
|
receive_tx: get "/wallet/owner/*" => api_handler,
|
||||||
|
@ -89,14 +92,13 @@ where
|
||||||
|
|
||||||
/// Listener version, providing same API but listening for requests on a
|
/// Listener version, providing same API but listening for requests on a
|
||||||
/// port and wrapping the calls
|
/// port and wrapping the calls
|
||||||
pub fn foreign_listener<T>(wallet: T, addr: &str) -> Result<(), Error>
|
pub fn foreign_listener<T, K>(wallet: T, addr: &str) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
ForeignAPIHandler<T>: Handler,
|
ForeignAPIHandler<T, K>: Handler,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let api_handler = ForeignAPIHandler {
|
let api_handler = ForeignAPIHandler::new(Arc::new(Mutex::new(wallet)));
|
||||||
wallet: Arc::new(Mutex::new(wallet)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let router = router!(
|
let router = router!(
|
||||||
receive_tx: post "/wallet/foreign/*" => api_handler,
|
receive_tx: post "/wallet/foreign/*" => api_handler,
|
||||||
|
@ -115,22 +117,32 @@ where
|
||||||
}
|
}
|
||||||
/// API Handler/Wrapper for owner functions
|
/// API Handler/Wrapper for owner functions
|
||||||
|
|
||||||
pub struct OwnerAPIHandler<T>
|
pub struct OwnerAPIHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet instance
|
/// Wallet instance
|
||||||
pub wallet: Arc<Mutex<T>>,
|
pub wallet: Arc<Mutex<T>>,
|
||||||
|
phantom: PhantomData<K>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> OwnerAPIHandler<T>
|
impl<T, K> OwnerAPIHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
|
pub fn new(wallet: Arc<Mutex<T>>) -> OwnerAPIHandler<T, K> {
|
||||||
|
OwnerAPIHandler {
|
||||||
|
wallet,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn retrieve_outputs(
|
fn retrieve_outputs(
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIOwner<T>,
|
api: &mut APIOwner<T, K>,
|
||||||
) -> Result<Vec<OutputData>, Error> {
|
) -> Result<Vec<OutputData>, Error> {
|
||||||
let res = api.retrieve_outputs(false)?;
|
let res = api.retrieve_outputs(false)?;
|
||||||
Ok(res.1)
|
Ok(res.1)
|
||||||
|
@ -139,23 +151,23 @@ where
|
||||||
fn retrieve_summary_info(
|
fn retrieve_summary_info(
|
||||||
&self,
|
&self,
|
||||||
req: &mut Request,
|
req: &mut Request,
|
||||||
api: &mut APIOwner<T>,
|
api: &mut APIOwner<T, K>,
|
||||||
) -> Result<WalletInfo, Error> {
|
) -> Result<WalletInfo, Error> {
|
||||||
let res = api.retrieve_summary_info()?;
|
let res = api.retrieve_summary_info()?;
|
||||||
Ok(res.1)
|
Ok(res.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T>) -> Result<(), Error> {
|
fn issue_send_tx(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
||||||
// TODO: Args
|
// TODO: Args
|
||||||
api.issue_send_tx(60, 10, "", 1000, true, true)
|
api.issue_send_tx(60, 10, "", 1000, true, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_burn_tx(&self, req: &mut Request, api: &mut APIOwner<T>) -> Result<(), Error> {
|
fn issue_burn_tx(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> Result<(), Error> {
|
||||||
// TODO: Args
|
// TODO: Args
|
||||||
api.issue_burn_tx(60, 10, 1000)
|
api.issue_burn_tx(60, 10, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T>) -> IronResult<Response> {
|
fn handle_request(&self, req: &mut Request, api: &mut APIOwner<T, K>) -> IronResult<Response> {
|
||||||
let url = req.url.clone();
|
let url = req.url.clone();
|
||||||
let path_elems = url.path();
|
let path_elems = url.path();
|
||||||
match *path_elems.last().unwrap() {
|
match *path_elems.last().unwrap() {
|
||||||
|
@ -175,9 +187,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Handler for OwnerAPIHandler<T>
|
impl<T, K> Handler for OwnerAPIHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
||||||
|
K: Keychain + 'static,
|
||||||
{
|
{
|
||||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||||
// every request should open with stored credentials,
|
// every request should open with stored credentials,
|
||||||
|
@ -199,19 +212,33 @@ where
|
||||||
|
|
||||||
/// API Handler/Wrapper for foreign functions
|
/// API Handler/Wrapper for foreign functions
|
||||||
|
|
||||||
pub struct ForeignAPIHandler<T>
|
pub struct ForeignAPIHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
/// Wallet instance
|
/// Wallet instance
|
||||||
pub wallet: Arc<Mutex<T>>,
|
pub wallet: Arc<Mutex<T>>,
|
||||||
|
phantom: PhantomData<K>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ForeignAPIHandler<T>
|
impl<T, K> ForeignAPIHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
fn build_coinbase(&self, req: &mut Request, api: &mut APIForeign<T>) -> Result<CbData, Error> {
|
pub fn new(wallet: Arc<Mutex<T>>) -> ForeignAPIHandler<T, K> {
|
||||||
|
ForeignAPIHandler {
|
||||||
|
wallet,
|
||||||
|
phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_coinbase(
|
||||||
|
&self,
|
||||||
|
req: &mut Request,
|
||||||
|
api: &mut APIForeign<T, K>,
|
||||||
|
) -> Result<CbData, Error> {
|
||||||
let struct_body = req.get::<bodyparser::Struct<BlockFees>>();
|
let struct_body = req.get::<bodyparser::Struct<BlockFees>>();
|
||||||
match struct_body {
|
match struct_body {
|
||||||
Ok(Some(block_fees)) => api.build_coinbase(&block_fees),
|
Ok(Some(block_fees)) => api.build_coinbase(&block_fees),
|
||||||
|
@ -230,7 +257,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn receive_tx(&self, req: &mut Request, api: &mut APIForeign<T>) -> Result<Slate, Error> {
|
fn receive_tx(&self, req: &mut Request, api: &mut APIForeign<T, K>) -> Result<Slate, Error> {
|
||||||
let struct_body = req.get::<bodyparser::Struct<Slate>>();
|
let struct_body = req.get::<bodyparser::Struct<Slate>>();
|
||||||
if let Ok(Some(mut slate)) = struct_body {
|
if let Ok(Some(mut slate)) = struct_body {
|
||||||
api.receive_tx(&mut slate)?;
|
api.receive_tx(&mut slate)?;
|
||||||
|
@ -240,7 +267,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_request(&self, req: &mut Request, api: &mut APIForeign<T>) -> IronResult<Response> {
|
fn handle_request(
|
||||||
|
&self,
|
||||||
|
req: &mut Request,
|
||||||
|
api: &mut APIForeign<T, K>,
|
||||||
|
) -> IronResult<Response> {
|
||||||
let url = req.url.clone();
|
let url = req.url.clone();
|
||||||
let path_elems = url.path();
|
let path_elems = url.path();
|
||||||
match *path_elems.last().unwrap() {
|
match *path_elems.last().unwrap() {
|
||||||
|
@ -256,9 +287,10 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Handler for ForeignAPIHandler<T>
|
impl<T, K> Handler for ForeignAPIHandler<T, K>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient + Send + Sync + 'static,
|
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
||||||
|
K: Keychain + 'static,
|
||||||
{
|
{
|
||||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||||
// every request should open with stored credentials,
|
// every request should open with stored credentials,
|
||||||
|
|
|
@ -13,22 +13,24 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
//! Wallet key management functions
|
//! Wallet key management functions
|
||||||
use keychain::Identifier;
|
use keychain::{Identifier, Keychain};
|
||||||
use libwallet::error::Error;
|
use libwallet::error::Error;
|
||||||
use libwallet::types::WalletBackend;
|
use libwallet::types::WalletBackend;
|
||||||
|
|
||||||
/// Get our next available key
|
/// Get our next available key
|
||||||
pub fn new_output_key<T>(wallet: &mut T) -> Result<(Identifier, u32), Error>
|
pub fn new_output_key<T, K>(wallet: &mut T) -> Result<(Identifier, u32), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
wallet.with_wallet(|wallet_data| next_available_key(wallet_data))
|
wallet.with_wallet(|wallet_data| next_available_key(wallet_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get next available key in the wallet
|
/// Get next available key in the wallet
|
||||||
pub fn next_available_key<T>(wallet: &mut T) -> (Identifier, u32)
|
pub fn next_available_key<T, K>(wallet: &mut T) -> (Identifier, u32)
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let root_key_id = wallet.keychain().root_key_id();
|
let root_key_id = wallet.keychain().root_key_id();
|
||||||
let derivation = wallet.next_child(root_key_id.clone());
|
let derivation = wallet.next_child(root_key_id.clone());
|
||||||
|
@ -37,9 +39,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve an existing key from a wallet
|
/// Retrieve an existing key from a wallet
|
||||||
pub fn retrieve_existing_key<T>(wallet: &T, key_id: Identifier) -> (Identifier, u32)
|
pub fn retrieve_existing_key<T, K>(wallet: &T, key_id: Identifier) -> (Identifier, u32)
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
if let Some(existing) = wallet.get_output(&key_id) {
|
if let Some(existing) = wallet.get_output(&key_id) {
|
||||||
let key_id = existing.key_id.clone();
|
let key_id = existing.key_id.clone();
|
||||||
|
|
|
@ -20,7 +20,7 @@ use core::core::transaction::ProofMessageElements;
|
||||||
use core::global;
|
use core::global;
|
||||||
use error::{Error, ErrorKind};
|
use error::{Error, ErrorKind};
|
||||||
use failure::{Fail, ResultExt};
|
use failure::{Fail, ResultExt};
|
||||||
use keychain::Identifier;
|
use keychain::{Identifier, Keychain};
|
||||||
use libtx::proof;
|
use libtx::proof;
|
||||||
use libwallet::types::*;
|
use libwallet::types::*;
|
||||||
use util;
|
use util;
|
||||||
|
@ -51,9 +51,10 @@ fn coinbase_status(output: &api::OutputPrintable) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn outputs_batch<T>(wallet: &T, start_height: u64, max: u64) -> Result<api::OutputListing, Error>
|
fn outputs_batch<T, K>(wallet: &T, start_height: u64, max: u64) -> Result<api::OutputListing, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let query_param = format!("start_index={}&max={}", start_height, max);
|
let query_param = format!("start_index={}&max={}", start_height, max);
|
||||||
|
|
||||||
|
@ -75,7 +76,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO - wrap the many return values in a struct
|
// TODO - wrap the many return values in a struct
|
||||||
fn find_outputs_with_key<T: WalletBackend + WalletClient>(
|
fn find_outputs_with_key<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
outputs: Vec<api::OutputPrintable>,
|
outputs: Vec<api::OutputPrintable>,
|
||||||
found_key_index: &mut Vec<u32>,
|
found_key_index: &mut Vec<u32>,
|
||||||
|
@ -88,7 +89,11 @@ fn find_outputs_with_key<T: WalletBackend + WalletClient>(
|
||||||
u64,
|
u64,
|
||||||
bool,
|
bool,
|
||||||
Option<MerkleProofWrapper>,
|
Option<MerkleProofWrapper>,
|
||||||
)> {
|
)>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let mut wallet_outputs: Vec<(
|
let mut wallet_outputs: Vec<(
|
||||||
pedersen::Commitment,
|
pedersen::Commitment,
|
||||||
Identifier,
|
Identifier,
|
||||||
|
@ -225,7 +230,11 @@ fn find_outputs_with_key<T: WalletBackend + WalletClient>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restore a wallet
|
/// Restore a wallet
|
||||||
pub fn restore<T: WalletBackend + WalletClient>(wallet: &mut T) -> Result<(), Error> {
|
pub fn restore<T, K>(wallet: &mut T) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
// Don't proceed if wallet.dat has anything in it
|
// Don't proceed if wallet.dat has anything in it
|
||||||
let is_empty = wallet
|
let is_empty = wallet
|
||||||
.read_wallet(|wallet_data| Ok(wallet_data.outputs().len() == 0))
|
.read_wallet(|wallet_data| Ok(wallet_data.outputs().len() == 0))
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
//! Selection of inputs for building transactions
|
//! Selection of inputs for building transactions
|
||||||
|
|
||||||
use keychain::Identifier;
|
use keychain::{Identifier, Keychain};
|
||||||
use libtx::{build, tx_fee, slate::Slate};
|
use libtx::{build, tx_fee, slate::Slate};
|
||||||
use libwallet::error::{Error, ErrorKind};
|
use libwallet::error::{Error, ErrorKind};
|
||||||
use libwallet::internal::{keys, sigcontext};
|
use libwallet::internal::{keys, sigcontext};
|
||||||
|
@ -25,7 +25,7 @@ use libwallet::types::*;
|
||||||
/// and saves the private wallet identifiers of our selected outputs
|
/// and saves the private wallet identifiers of our selected outputs
|
||||||
/// into our transaction context
|
/// into our transaction context
|
||||||
|
|
||||||
pub fn build_send_tx_slate<T>(
|
pub fn build_send_tx_slate<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
num_participants: usize,
|
num_participants: usize,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
|
@ -43,7 +43,8 @@ pub fn build_send_tx_slate<T>(
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let (elems, inputs, change_id, amount, fee) = select_send_tx(
|
let (elems, inputs, change_id, amount, fee) = select_send_tx(
|
||||||
wallet,
|
wallet,
|
||||||
|
@ -107,7 +108,7 @@ where
|
||||||
/// returning the key of the fresh output and a closure
|
/// returning the key of the fresh output and a closure
|
||||||
/// that actually performs the addition of the output to the
|
/// that actually performs the addition of the output to the
|
||||||
/// wallet
|
/// wallet
|
||||||
pub fn build_recipient_output_with_slate<T>(
|
pub fn build_recipient_output_with_slate<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
slate: &mut Slate,
|
slate: &mut Slate,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
|
@ -119,25 +120,27 @@ pub fn build_recipient_output_with_slate<T>(
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// Create a potential output for this transaction
|
// Create a potential output for this transaction
|
||||||
let (key_id, derivation) = keys::new_output_key(wallet)?;
|
let (key_id, derivation) = keys::new_output_key(wallet)?;
|
||||||
|
|
||||||
let root_key_id = wallet.keychain().root_key_id();
|
let keychain = wallet.keychain().clone();
|
||||||
|
let root_key_id = keychain.root_key_id();
|
||||||
let key_id_inner = key_id.clone();
|
let key_id_inner = key_id.clone();
|
||||||
let amount = slate.amount;
|
let amount = slate.amount;
|
||||||
let height = slate.height;
|
let height = slate.height;
|
||||||
|
|
||||||
let keychain = wallet.keychain().clone();
|
|
||||||
|
|
||||||
let blinding =
|
let blinding =
|
||||||
slate.add_transaction_elements(&keychain, vec![build::output(amount, key_id.clone())])?;
|
slate.add_transaction_elements(&keychain, vec![build::output(amount, key_id.clone())])?;
|
||||||
|
|
||||||
// Add blinding sum to our context
|
// Add blinding sum to our context
|
||||||
let mut context = sigcontext::Context::new(
|
let mut context = sigcontext::Context::new(
|
||||||
keychain.secp(),
|
keychain.secp(),
|
||||||
blinding.secret_key(wallet.keychain().secp()).unwrap(),
|
blinding
|
||||||
|
.secret_key(wallet.keychain().clone().secp())
|
||||||
|
.unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
context.add_output(&key_id);
|
context.add_output(&key_id);
|
||||||
|
@ -166,7 +169,7 @@ where
|
||||||
/// Builds a transaction to send to someone from the HD seed associated with the
|
/// Builds a transaction to send to someone from the HD seed associated with the
|
||||||
/// wallet and the amount to send. Handles reading through the wallet data file,
|
/// wallet and the amount to send. Handles reading through the wallet data file,
|
||||||
/// selecting outputs to spend and building the change.
|
/// selecting outputs to spend and building the change.
|
||||||
pub fn select_send_tx<T>(
|
pub fn select_send_tx<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
current_height: u64,
|
current_height: u64,
|
||||||
|
@ -176,7 +179,7 @@ pub fn select_send_tx<T>(
|
||||||
selection_strategy_is_use_all: bool,
|
selection_strategy_is_use_all: bool,
|
||||||
) -> Result<
|
) -> Result<
|
||||||
(
|
(
|
||||||
Vec<Box<build::Append>>,
|
Vec<Box<build::Append<K>>>,
|
||||||
Vec<OutputData>,
|
Vec<OutputData>,
|
||||||
Option<Identifier>,
|
Option<Identifier>,
|
||||||
u64, // amount
|
u64, // amount
|
||||||
|
@ -185,9 +188,10 @@ pub fn select_send_tx<T>(
|
||||||
Error,
|
Error,
|
||||||
>
|
>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let key_id = wallet.keychain().clone().root_key_id();
|
let key_id = wallet.keychain().root_key_id();
|
||||||
|
|
||||||
// select some spendable coins from the wallet
|
// select some spendable coins from the wallet
|
||||||
let mut coins = wallet.read_wallet(|wallet_data| {
|
let mut coins = wallet.read_wallet(|wallet_data| {
|
||||||
|
@ -280,15 +284,16 @@ pub fn coins_proof_count(coins: &Vec<OutputData>) -> usize {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Selects inputs and change for a transaction
|
/// Selects inputs and change for a transaction
|
||||||
pub fn inputs_and_change<T>(
|
pub fn inputs_and_change<T, K>(
|
||||||
coins: &Vec<OutputData>,
|
coins: &Vec<OutputData>,
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
height: u64,
|
height: u64,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
fee: u64,
|
fee: u64,
|
||||||
) -> Result<(Vec<Box<build::Append>>, Option<Identifier>), Error>
|
) -> Result<(Vec<Box<build::Append<K>>>, Option<Identifier>), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut parts = vec![];
|
let mut parts = vec![];
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//! Signature context holder helper (may be removed or replaced eventually)
|
//! Signature context holder helper (may be removed or replaced eventually)
|
||||||
use keychain::extkey::Identifier;
|
use keychain::Identifier;
|
||||||
use libtx::aggsig;
|
use libtx::aggsig;
|
||||||
use util::secp::key::{PublicKey, SecretKey};
|
use util::secp::key::{PublicKey, SecretKey};
|
||||||
use util::secp::{self, Secp256k1};
|
use util::secp::{self, Secp256k1};
|
||||||
|
|
|
@ -25,7 +25,11 @@ use util::LOGGER;
|
||||||
|
|
||||||
/// Receive a tranaction, modifying the slate accordingly (which can then be
|
/// Receive a tranaction, modifying the slate accordingly (which can then be
|
||||||
/// sent back to sender for posting)
|
/// sent back to sender for posting)
|
||||||
pub fn receive_tx<T: WalletBackend>(wallet: &mut T, slate: &mut Slate) -> Result<(), Error> {
|
pub fn receive_tx<T, K>(wallet: &mut T, slate: &mut Slate) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
// create an output using the amount in the slate
|
// create an output using the amount in the slate
|
||||||
let (_, mut context, receiver_create_fn) =
|
let (_, mut context, receiver_create_fn) =
|
||||||
selection::build_recipient_output_with_slate(wallet, slate).unwrap();
|
selection::build_recipient_output_with_slate(wallet, slate).unwrap();
|
||||||
|
@ -49,7 +53,7 @@ pub fn receive_tx<T: WalletBackend>(wallet: &mut T, slate: &mut Slate) -> Result
|
||||||
|
|
||||||
/// Issue a new transaction to the provided sender by spending some of our
|
/// Issue a new transaction to the provided sender by spending some of our
|
||||||
/// wallet
|
/// wallet
|
||||||
pub fn create_send_tx<T: WalletBackend + WalletClient>(
|
pub fn create_send_tx<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
minimum_confirmations: u64,
|
minimum_confirmations: u64,
|
||||||
|
@ -62,7 +66,11 @@ pub fn create_send_tx<T: WalletBackend + WalletClient>(
|
||||||
impl FnOnce(&mut T) -> Result<(), Error>,
|
impl FnOnce(&mut T) -> Result<(), Error>,
|
||||||
),
|
),
|
||||||
Error,
|
Error,
|
||||||
> {
|
>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
// Get lock height
|
// Get lock height
|
||||||
let current_height = wallet.get_chain_height(wallet.node_url())?;
|
let current_height = wallet.get_chain_height(wallet.node_url())?;
|
||||||
// ensure outputs we're selecting are up to date
|
// ensure outputs we're selecting are up to date
|
||||||
|
@ -102,11 +110,15 @@ pub fn create_send_tx<T: WalletBackend + WalletClient>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Complete a transaction as the sender
|
/// Complete a transaction as the sender
|
||||||
pub fn complete_tx<T: WalletBackend>(
|
pub fn complete_tx<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
slate: &mut Slate,
|
slate: &mut Slate,
|
||||||
context: &sigcontext::Context,
|
context: &sigcontext::Context,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
let _ = slate.fill_round_2(wallet.keychain(), &context.sec_key, &context.sec_nonce, 0)?;
|
let _ = slate.fill_round_2(wallet.keychain(), &context.sec_key, &context.sec_nonce, 0)?;
|
||||||
// Final transaction can be built by anyone at this stage
|
// Final transaction can be built by anyone at this stage
|
||||||
let res = slate.finalize(wallet.keychain());
|
let res = slate.finalize(wallet.keychain());
|
||||||
|
@ -117,13 +129,20 @@ pub fn complete_tx<T: WalletBackend>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Issue a burn tx
|
/// Issue a burn tx
|
||||||
pub fn issue_burn_tx<T: WalletBackend + WalletClient>(
|
pub fn issue_burn_tx<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
amount: u64,
|
amount: u64,
|
||||||
minimum_confirmations: u64,
|
minimum_confirmations: u64,
|
||||||
max_outputs: usize,
|
max_outputs: usize,
|
||||||
) -> Result<Transaction, Error> {
|
) -> Result<Transaction, Error>
|
||||||
let keychain = &Keychain::burn_enabled(wallet.keychain(), &Identifier::zero());
|
where
|
||||||
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
// let keychain = &Keychain::burn_enabled(wallet.keychain(),
|
||||||
|
// &Identifier::zero());
|
||||||
|
let keychain = wallet.keychain().clone();
|
||||||
|
|
||||||
let current_height = wallet.get_chain_height(wallet.node_url())?;
|
let current_height = wallet.get_chain_height(wallet.node_url())?;
|
||||||
|
|
||||||
|
@ -159,14 +178,14 @@ pub fn issue_burn_tx<T: WalletBackend + WalletClient>(
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use keychain::Keychain;
|
use keychain::{ExtKeychain, Keychain};
|
||||||
use libtx::build;
|
use libtx::build;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
// demonstrate that input.commitment == referenced output.commitment
|
// demonstrate that input.commitment == referenced output.commitment
|
||||||
// based on the public key and amount begin spent
|
// based on the public key and amount begin spent
|
||||||
fn output_commitment_equals_input_commitment_on_spend() {
|
fn output_commitment_equals_input_commitment_on_spend() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id1 = keychain.derive_key_id(1).unwrap();
|
let key_id1 = keychain.derive_key_id(1).unwrap();
|
||||||
|
|
||||||
let tx1 = build::transaction(vec![build::output(105, key_id1.clone())], &keychain).unwrap();
|
let tx1 = build::transaction(vec![build::output(105, key_id1.clone())], &keychain).unwrap();
|
||||||
|
|
|
@ -23,7 +23,7 @@ use core::consensus::reward;
|
||||||
use core::core::{Output, TxKernel};
|
use core::core::{Output, TxKernel};
|
||||||
use core::global;
|
use core::global;
|
||||||
use core::ser;
|
use core::ser;
|
||||||
use keychain::Identifier;
|
use keychain::{Identifier, Keychain};
|
||||||
use libtx::reward;
|
use libtx::reward;
|
||||||
use libwallet::error::{Error, ErrorKind};
|
use libwallet::error::{Error, ErrorKind};
|
||||||
use libwallet::internal::keys;
|
use libwallet::internal::keys;
|
||||||
|
@ -33,10 +33,11 @@ use util::LOGGER;
|
||||||
use util::secp::pedersen;
|
use util::secp::pedersen;
|
||||||
|
|
||||||
/// Retrieve all of the outputs (doesn't attempt to update from node)
|
/// Retrieve all of the outputs (doesn't attempt to update from node)
|
||||||
pub fn retrieve_outputs<T: WalletBackend>(
|
pub fn retrieve_outputs<T, K>(wallet: &mut T, show_spent: bool) -> Result<Vec<OutputData>, Error>
|
||||||
wallet: &mut T,
|
where
|
||||||
show_spent: bool,
|
T: WalletBackend<K>,
|
||||||
) -> Result<Vec<OutputData>, Error> {
|
K: Keychain,
|
||||||
|
{
|
||||||
let root_key_id = wallet.keychain().clone().root_key_id();
|
let root_key_id = wallet.keychain().clone().root_key_id();
|
||||||
|
|
||||||
let mut outputs = vec![];
|
let mut outputs = vec![];
|
||||||
|
@ -66,9 +67,10 @@ pub fn retrieve_outputs<T: WalletBackend>(
|
||||||
|
|
||||||
/// Refreshes the outputs in a wallet with the latest information
|
/// Refreshes the outputs in a wallet with the latest information
|
||||||
/// from a node
|
/// from a node
|
||||||
pub fn refresh_outputs<T>(wallet: &mut T) -> Result<(), Error>
|
pub fn refresh_outputs<T, K>(wallet: &mut T) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let height = wallet.get_chain_height(wallet.node_url())?;
|
let height = wallet.get_chain_height(wallet.node_url())?;
|
||||||
refresh_output_state(wallet, height)?;
|
refresh_output_state(wallet, height)?;
|
||||||
|
@ -78,9 +80,10 @@ where
|
||||||
|
|
||||||
// TODO - this might be slow if we have really old outputs that have never been
|
// TODO - this might be slow if we have really old outputs that have never been
|
||||||
// refreshed
|
// refreshed
|
||||||
fn refresh_missing_block_hashes<T>(wallet: &mut T, height: u64) -> Result<(), Error>
|
fn refresh_missing_block_hashes<T, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// build a local map of wallet outputs keyed by commit
|
// build a local map of wallet outputs keyed by commit
|
||||||
// and a list of outputs we want to query the node for
|
// and a list of outputs we want to query the node for
|
||||||
|
@ -125,11 +128,12 @@ where
|
||||||
|
|
||||||
/// build a local map of wallet outputs keyed by commit
|
/// build a local map of wallet outputs keyed by commit
|
||||||
/// and a list of outputs we want to query the node for
|
/// and a list of outputs we want to query the node for
|
||||||
pub fn map_wallet_outputs<T>(
|
pub fn map_wallet_outputs<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
||||||
let _ = wallet.read_wallet(|wallet_data| {
|
let _ = wallet.read_wallet(|wallet_data| {
|
||||||
|
@ -150,19 +154,21 @@ where
|
||||||
|
|
||||||
/// As above, but only return unspent outputs with missing block hashes
|
/// As above, but only return unspent outputs with missing block hashes
|
||||||
/// and a list of outputs we want to query the node for
|
/// and a list of outputs we want to query the node for
|
||||||
pub fn map_wallet_outputs_missing_block<T>(
|
pub fn map_wallet_outputs_missing_block<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
||||||
let _ = wallet.read_wallet(|wallet_data| {
|
let _ = wallet.read_wallet(|wallet_data| {
|
||||||
let keychain = wallet_data.keychain().clone();
|
let keychain = wallet_data.keychain().clone();
|
||||||
for out in wallet_data.outputs().clone().values().filter(|x| {
|
let unspents = wallet_data.outputs().values().filter(|x| {
|
||||||
x.root_key_id == wallet_data.keychain().root_key_id() && x.block.is_none()
|
x.root_key_id == keychain.root_key_id() && x.block.is_none()
|
||||||
&& x.status == OutputStatus::Unspent
|
&& x.status == OutputStatus::Unspent
|
||||||
}) {
|
});
|
||||||
|
for out in unspents {
|
||||||
let commit = keychain.commit_with_key_index(out.value, out.n_child)?;
|
let commit = keychain.commit_with_key_index(out.value, out.n_child)?;
|
||||||
wallet_outputs.insert(commit, out.key_id.clone());
|
wallet_outputs.insert(commit, out.key_id.clone());
|
||||||
}
|
}
|
||||||
|
@ -172,13 +178,14 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply refreshed API output data to the wallet
|
/// Apply refreshed API output data to the wallet
|
||||||
pub fn apply_api_outputs<T>(
|
pub fn apply_api_outputs<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
wallet_outputs: &HashMap<pedersen::Commitment, Identifier>,
|
wallet_outputs: &HashMap<pedersen::Commitment, Identifier>,
|
||||||
api_outputs: &HashMap<pedersen::Commitment, String>,
|
api_outputs: &HashMap<pedersen::Commitment, String>,
|
||||||
) -> Result<(), Error>
|
) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
// now for each commit, find the output in the wallet and the corresponding
|
// now for each commit, find the output in the wallet and the corresponding
|
||||||
// api output (if it exists) and refresh it in-place in the wallet.
|
// api output (if it exists) and refresh it in-place in the wallet.
|
||||||
|
@ -198,9 +205,10 @@ where
|
||||||
|
|
||||||
/// Builds a single api query to retrieve the latest output data from the node.
|
/// Builds a single api query to retrieve the latest output data from the node.
|
||||||
/// So we can refresh the local wallet outputs.
|
/// So we can refresh the local wallet outputs.
|
||||||
fn refresh_output_state<T>(wallet: &mut T, height: u64) -> Result<(), Error>
|
fn refresh_output_state<T, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
debug!(LOGGER, "Refreshing wallet outputs");
|
debug!(LOGGER, "Refreshing wallet outputs");
|
||||||
|
|
||||||
|
@ -216,9 +224,10 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clean_old_unconfirmed<T>(wallet: &mut T, height: u64) -> Result<(), Error>
|
fn clean_old_unconfirmed<T, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
if height < 500 {
|
if height < 500 {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
@ -231,10 +240,11 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve summary info about the wallet
|
/// Retrieve summar info about the wallet
|
||||||
pub fn retrieve_info<T>(wallet: &mut T) -> Result<WalletInfo, Error>
|
pub fn retrieve_info<T, K>(wallet: &mut T) -> Result<WalletInfo, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend + WalletClient,
|
T: WalletBackend<K> + WalletClient,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let result = refresh_outputs(wallet);
|
let result = refresh_outputs(wallet);
|
||||||
|
|
||||||
|
@ -291,9 +301,10 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a coinbase output and insert into wallet
|
/// Build a coinbase output and insert into wallet
|
||||||
pub fn build_coinbase<T>(wallet: &mut T, block_fees: &BlockFees) -> Result<CbData, Error>
|
pub fn build_coinbase<T, K>(wallet: &mut T, block_fees: &BlockFees) -> Result<CbData, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let (out, kern, block_fees) = receive_coinbase(wallet, block_fees).context(ErrorKind::Node)?;
|
let (out, kern, block_fees) = receive_coinbase(wallet, block_fees).context(ErrorKind::Node)?;
|
||||||
|
|
||||||
|
@ -315,12 +326,13 @@ where
|
||||||
|
|
||||||
//TODO: Split up the output creation and the wallet insertion
|
//TODO: Split up the output creation and the wallet insertion
|
||||||
/// Build a coinbase output and the corresponding kernel
|
/// Build a coinbase output and the corresponding kernel
|
||||||
pub fn receive_coinbase<T>(
|
pub fn receive_coinbase<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
block_fees: &BlockFees,
|
block_fees: &BlockFees,
|
||||||
) -> Result<(Output, TxKernel, BlockFees), Error>
|
) -> Result<(Output, TxKernel, BlockFees), Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend,
|
T: WalletBackend<K>,
|
||||||
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let root_key_id = wallet.keychain().root_key_id();
|
let root_key_id = wallet.keychain().root_key_id();
|
||||||
|
|
||||||
|
@ -365,7 +377,7 @@ where
|
||||||
debug!(LOGGER, "receive_coinbase: {:?}", block_fees);
|
debug!(LOGGER, "receive_coinbase: {:?}", block_fees);
|
||||||
|
|
||||||
let (out, kern) = reward::output(
|
let (out, kern) = reward::output(
|
||||||
&wallet.keychain(),
|
wallet.keychain(),
|
||||||
&key_id,
|
&key_id,
|
||||||
block_fees.fees,
|
block_fees.fees,
|
||||||
block_fees.height,
|
block_fees.height,
|
||||||
|
|
|
@ -36,7 +36,10 @@ use util::secp::pedersen;
|
||||||
/// Wallets should implement this backend for their storage. All functions
|
/// Wallets should implement this backend for their storage. All functions
|
||||||
/// here expect that the wallet instance has instantiated itself or stored
|
/// here expect that the wallet instance has instantiated itself or stored
|
||||||
/// whatever credentials it needs
|
/// whatever credentials it needs
|
||||||
pub trait WalletBackend {
|
pub trait WalletBackend<K>
|
||||||
|
where
|
||||||
|
K: Keychain,
|
||||||
|
{
|
||||||
/// Initialise with whatever stored credentials we have
|
/// Initialise with whatever stored credentials we have
|
||||||
fn open_with_credentials(&mut self) -> Result<(), Error>;
|
fn open_with_credentials(&mut self) -> Result<(), Error>;
|
||||||
|
|
||||||
|
@ -44,7 +47,7 @@ pub trait WalletBackend {
|
||||||
fn close(&mut self) -> Result<(), Error>;
|
fn close(&mut self) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Return the keychain being used
|
/// Return the keychain being used
|
||||||
fn keychain(&mut self) -> &mut Keychain;
|
fn keychain(&mut self) -> &mut K;
|
||||||
|
|
||||||
/// Return the outputs directly
|
/// Return the outputs directly
|
||||||
fn outputs(&mut self) -> &mut HashMap<String, OutputData>;
|
fn outputs(&mut self) -> &mut HashMap<String, OutputData>;
|
||||||
|
|
|
@ -27,6 +27,7 @@ use chain::Chain;
|
||||||
use core::core::hash::Hashed;
|
use core::core::hash::Hashed;
|
||||||
use core::core::{Output, OutputFeatures, OutputIdentifier, Transaction, TxKernel};
|
use core::core::{Output, OutputFeatures, OutputIdentifier, Transaction, TxKernel};
|
||||||
use core::{consensus, global, pow};
|
use core::{consensus, global, pow};
|
||||||
|
use keychain::ExtKeychain;
|
||||||
use wallet::file_wallet::*;
|
use wallet::file_wallet::*;
|
||||||
use wallet::libwallet::internal::updater;
|
use wallet::libwallet::internal::updater;
|
||||||
use wallet::libwallet::types::*;
|
use wallet::libwallet::types::*;
|
||||||
|
@ -37,10 +38,11 @@ use util::secp::pedersen;
|
||||||
|
|
||||||
/// Mostly for testing, refreshes output state against a local chain instance
|
/// Mostly for testing, refreshes output state against a local chain instance
|
||||||
/// instead of via an http API call
|
/// instead of via an http API call
|
||||||
pub fn refresh_output_state_local<T: WalletBackend>(
|
pub fn refresh_output_state_local<T, K>(wallet: &mut T, chain: &chain::Chain) -> Result<(), Error>
|
||||||
wallet: &mut T,
|
where
|
||||||
chain: &chain::Chain,
|
T: WalletBackend<K>,
|
||||||
) -> Result<(), Error> {
|
K: keychain::Keychain,
|
||||||
|
{
|
||||||
let wallet_outputs = updater::map_wallet_outputs(wallet)?;
|
let wallet_outputs = updater::map_wallet_outputs(wallet)?;
|
||||||
let chain_outputs: Vec<Option<api::Output>> = wallet_outputs
|
let chain_outputs: Vec<Option<api::Output>> = wallet_outputs
|
||||||
.keys()
|
.keys()
|
||||||
|
@ -66,10 +68,14 @@ pub fn refresh_output_state_local<T: WalletBackend>(
|
||||||
/// (0:total, 1:amount_awaiting_confirmation, 2:confirmed but locked,
|
/// (0:total, 1:amount_awaiting_confirmation, 2:confirmed but locked,
|
||||||
/// 3:currently_spendable, 4:locked total) TODO: Should be a wallet lib
|
/// 3:currently_spendable, 4:locked total) TODO: Should be a wallet lib
|
||||||
/// function with nicer return values
|
/// function with nicer return values
|
||||||
pub fn get_wallet_balances<T: WalletBackend>(
|
pub fn get_wallet_balances<T, K>(
|
||||||
wallet: &mut T,
|
wallet: &mut T,
|
||||||
height: u64,
|
height: u64,
|
||||||
) -> Result<(u64, u64, u64, u64, u64), Error> {
|
) -> Result<(u64, u64, u64, u64, u64), Error>
|
||||||
|
where
|
||||||
|
T: WalletBackend<K>,
|
||||||
|
K: keychain::Keychain,
|
||||||
|
{
|
||||||
let ret_val = wallet.read_wallet(|wallet_data| {
|
let ret_val = wallet.read_wallet(|wallet_data| {
|
||||||
let mut unspent_total = 0;
|
let mut unspent_total = 0;
|
||||||
let mut unspent_but_locked_total = 0;
|
let mut unspent_but_locked_total = 0;
|
||||||
|
@ -151,11 +157,11 @@ pub fn add_block_with_reward(chain: &Chain, txs: Vec<&Transaction>, reward: (Out
|
||||||
/// adds a reward output to a wallet, includes that reward in a block, mines
|
/// adds a reward output to a wallet, includes that reward in a block, mines
|
||||||
/// the block and adds it to the chain, with option transactions included.
|
/// the block and adds it to the chain, with option transactions included.
|
||||||
/// Helpful for building up precise wallet balances for testing.
|
/// Helpful for building up precise wallet balances for testing.
|
||||||
pub fn award_block_to_wallet<T: WalletBackend>(
|
pub fn award_block_to_wallet<T, K>(chain: &Chain, txs: Vec<&Transaction>, wallet: &mut T)
|
||||||
chain: &Chain,
|
where
|
||||||
txs: Vec<&Transaction>,
|
T: WalletBackend<K>,
|
||||||
wallet: &mut T,
|
K: keychain::Keychain,
|
||||||
) {
|
{
|
||||||
let prev = chain.head_header().unwrap();
|
let prev = chain.head_header().unwrap();
|
||||||
let fee_amt = txs.iter().map(|tx| tx.fee()).sum();
|
let fee_amt = txs.iter().map(|tx| tx.fee()).sum();
|
||||||
let fees = BlockFees {
|
let fees = BlockFees {
|
||||||
|
@ -188,14 +194,18 @@ pub fn award_block_to_wallet<T: WalletBackend>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// adds many block rewards to a wallet, no transactions
|
/// adds many block rewards to a wallet, no transactions
|
||||||
pub fn award_blocks_to_wallet<T: WalletBackend>(chain: &Chain, wallet: &mut T, num_rewards: usize) {
|
pub fn award_blocks_to_wallet<T, K>(chain: &Chain, wallet: &mut T, num_rewards: usize)
|
||||||
|
where
|
||||||
|
T: WalletBackend<K>,
|
||||||
|
K: keychain::Keychain,
|
||||||
|
{
|
||||||
for _ in 0..num_rewards {
|
for _ in 0..num_rewards {
|
||||||
award_block_to_wallet(chain, vec![], wallet);
|
award_block_to_wallet(chain, vec![], wallet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new wallet in a particular directory
|
/// Create a new wallet in a particular directory
|
||||||
pub fn create_wallet(dir: &str) -> FileWallet {
|
pub fn create_wallet(dir: &str) -> FileWallet<ExtKeychain> {
|
||||||
let mut wallet_config = WalletConfig::default();
|
let mut wallet_config = WalletConfig::default();
|
||||||
wallet_config.data_file_dir = String::from(dir);
|
wallet_config.data_file_dir = String::from(dir);
|
||||||
wallet::WalletSeed::init_file(&wallet_config).expect("Failed to create wallet seed file.");
|
wallet::WalletSeed::init_file(&wallet_config).expect("Failed to create wallet seed file.");
|
||||||
|
|
|
@ -20,7 +20,7 @@ extern crate grin_wallet as wallet;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate uuid;
|
extern crate uuid;
|
||||||
|
|
||||||
use keychain::{BlindSum, BlindingFactor, Keychain};
|
use keychain::{BlindSum, BlindingFactor, ExtKeychain, Keychain};
|
||||||
use util::secp::key::{PublicKey, SecretKey};
|
use util::secp::key::{PublicKey, SecretKey};
|
||||||
use util::secp::pedersen::ProofMessage;
|
use util::secp::pedersen::ProofMessage;
|
||||||
use util::{kernel_sig_msg, secp};
|
use util::{kernel_sig_msg, secp};
|
||||||
|
@ -31,8 +31,8 @@ use rand::thread_rng;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn aggsig_sender_receiver_interaction() {
|
fn aggsig_sender_receiver_interaction() {
|
||||||
let sender_keychain = Keychain::from_random_seed().unwrap();
|
let sender_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let receiver_keychain = Keychain::from_random_seed().unwrap();
|
let receiver_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
// Calculate the kernel excess here for convenience.
|
// Calculate the kernel excess here for convenience.
|
||||||
// Normally this would happen during transaction building.
|
// Normally this would happen during transaction building.
|
||||||
|
@ -45,7 +45,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||||
.derived_key(&receiver_keychain.derive_key_id(1).unwrap())
|
.derived_key(&receiver_keychain.derive_key_id(1).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let blinding_factor = keychain
|
let blinding_factor = keychain
|
||||||
.blind_sum(&BlindSum::new()
|
.blind_sum(&BlindSum::new()
|
||||||
.sub_blinding_factor(BlindingFactor::from_secret_key(skey1))
|
.sub_blinding_factor(BlindingFactor::from_secret_key(skey1))
|
||||||
|
@ -201,7 +201,7 @@ fn aggsig_sender_receiver_interaction() {
|
||||||
|
|
||||||
// Check we can verify the sig using the kernel excess
|
// Check we can verify the sig using the kernel excess
|
||||||
{
|
{
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let msg = secp::Message::from_slice(&kernel_sig_msg(0, 0)).unwrap();
|
let msg = secp::Message::from_slice(&kernel_sig_msg(0, 0)).unwrap();
|
||||||
|
|
||||||
|
@ -214,8 +214,8 @@ fn aggsig_sender_receiver_interaction() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn aggsig_sender_receiver_interaction_offset() {
|
fn aggsig_sender_receiver_interaction_offset() {
|
||||||
let sender_keychain = Keychain::from_random_seed().unwrap();
|
let sender_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let receiver_keychain = Keychain::from_random_seed().unwrap();
|
let receiver_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
// This is the kernel offset that we use to split the key
|
// This is the kernel offset that we use to split the key
|
||||||
// Summing these at the block level prevents the
|
// Summing these at the block level prevents the
|
||||||
|
@ -233,7 +233,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||||
.derived_key(&receiver_keychain.derive_key_id(1).unwrap())
|
.derived_key(&receiver_keychain.derive_key_id(1).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let blinding_factor = keychain
|
let blinding_factor = keychain
|
||||||
.blind_sum(&BlindSum::new()
|
.blind_sum(&BlindSum::new()
|
||||||
.sub_blinding_factor(BlindingFactor::from_secret_key(skey1))
|
.sub_blinding_factor(BlindingFactor::from_secret_key(skey1))
|
||||||
|
@ -393,7 +393,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||||
|
|
||||||
// Check we can verify the sig using the kernel excess
|
// Check we can verify the sig using the kernel excess
|
||||||
{
|
{
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
|
|
||||||
let msg = secp::Message::from_slice(&kernel_sig_msg(0, 0)).unwrap();
|
let msg = secp::Message::from_slice(&kernel_sig_msg(0, 0)).unwrap();
|
||||||
|
|
||||||
|
@ -406,7 +406,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rewind_range_proof() {
|
fn test_rewind_range_proof() {
|
||||||
let keychain = Keychain::from_random_seed().unwrap();
|
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||||
let key_id = keychain.derive_key_id(1).unwrap();
|
let key_id = keychain.derive_key_id(1).unwrap();
|
||||||
let commit = keychain.commit(5, &key_id).unwrap();
|
let commit = keychain.commit(5, &key_id).unwrap();
|
||||||
let msg = ProofMessage::from_bytes(&[0u8; 64]);
|
let msg = ProofMessage::from_bytes(&[0u8; 64]);
|
||||||
|
|
|
@ -132,7 +132,7 @@ fn build_transaction() {
|
||||||
|
|
||||||
let _ = slate
|
let _ = slate
|
||||||
.fill_round_2(
|
.fill_round_2(
|
||||||
&wallet1.keychain.as_ref().unwrap(),
|
wallet1.keychain.as_ref().unwrap(),
|
||||||
&recp_context.sec_key,
|
&recp_context.sec_key,
|
||||||
&recp_context.sec_nonce,
|
&recp_context.sec_nonce,
|
||||||
1,
|
1,
|
||||||
|
@ -149,7 +149,7 @@ fn build_transaction() {
|
||||||
// SENDER Part 3: Sender confirmation
|
// SENDER Part 3: Sender confirmation
|
||||||
let _ = slate
|
let _ = slate
|
||||||
.fill_round_2(
|
.fill_round_2(
|
||||||
&wallet1.keychain.as_ref().unwrap(),
|
wallet1.keychain.as_ref().unwrap(),
|
||||||
&sender_context.sec_key,
|
&sender_context.sec_key,
|
||||||
&sender_context.sec_nonce,
|
&sender_context.sec_nonce,
|
||||||
0,
|
0,
|
||||||
|
@ -161,7 +161,7 @@ fn build_transaction() {
|
||||||
debug!(LOGGER, "{:?}", slate);
|
debug!(LOGGER, "{:?}", slate);
|
||||||
|
|
||||||
// Final transaction can be built by anyone at this stage
|
// Final transaction can be built by anyone at this stage
|
||||||
let res = slate.finalize(&wallet1.keychain.as_ref().unwrap());
|
let res = slate.finalize(wallet1.keychain.as_ref().unwrap());
|
||||||
|
|
||||||
if let Err(e) = res {
|
if let Err(e) = res {
|
||||||
panic!("Error creating final tx: {:?}", e);
|
panic!("Error creating final tx: {:?}", e);
|
||||||
|
|
Loading…
Reference in a new issue