mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +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::time::{Duration, Instant};
|
||||
|
||||
use core::core::Committed;
|
||||
use core::core::hash::{Hash, Hashed};
|
||||
use core::core::pmmr::MerkleProof;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::Committed;
|
||||
use core::core::{Block, BlockHeader, Output, OutputIdentifier, Transaction, TxKernel};
|
||||
use core::global;
|
||||
use grin_store::Error::NotFoundErr;
|
||||
|
@ -31,8 +31,8 @@ use pipe;
|
|||
use store;
|
||||
use txhashset;
|
||||
use types::*;
|
||||
use util::secp::pedersen::{Commitment, RangeProof};
|
||||
use util::LOGGER;
|
||||
use util::secp::pedersen::{Commitment, RangeProof};
|
||||
|
||||
/// Orphan pool size is limited by MAX_ORPHAN_SIZE
|
||||
pub const MAX_ORPHAN_SIZE: usize = 200;
|
||||
|
|
|
@ -24,15 +24,15 @@ extern crate time;
|
|||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
|
||||
use chain::types::*;
|
||||
use chain::Chain;
|
||||
use chain::types::*;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::{Block, BlockHeader, Transaction};
|
||||
use core::global;
|
||||
use core::global::ChainTypes;
|
||||
use core::{consensus, genesis};
|
||||
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use wallet::libtx;
|
||||
|
||||
use core::pow;
|
||||
|
@ -69,7 +69,7 @@ fn data_files() {
|
|||
//new block so chain references should be freed
|
||||
{
|
||||
let chain = setup(chain_dir);
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
|
||||
for n in 1..4 {
|
||||
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![]);
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
fn _prepare_block_tx(
|
||||
kc: &Keychain,
|
||||
kc: &ExtKeychain,
|
||||
prev: &BlockHeader,
|
||||
chain: &Chain,
|
||||
diff: u64,
|
||||
|
@ -132,14 +132,14 @@ fn _prepare_block_tx(
|
|||
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![]);
|
||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
fn _prepare_fork_block_tx(
|
||||
kc: &Keychain,
|
||||
kc: &ExtKeychain,
|
||||
prev: &BlockHeader,
|
||||
chain: &Chain,
|
||||
diff: u64,
|
||||
|
@ -151,7 +151,7 @@ fn _prepare_fork_block_tx(
|
|||
}
|
||||
|
||||
fn _prepare_block_nosum(
|
||||
kc: &Keychain,
|
||||
kc: &ExtKeychain,
|
||||
prev: &BlockHeader,
|
||||
diff: u64,
|
||||
txs: Vec<&Transaction>,
|
||||
|
@ -159,7 +159,7 @@ fn _prepare_block_nosum(
|
|||
let key_id = kc.derive_key_id(diff as u32).unwrap();
|
||||
|
||||
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(
|
||||
prev,
|
||||
txs.into_iter().cloned().collect(),
|
||||
|
|
|
@ -34,7 +34,7 @@ use core::global;
|
|||
use core::global::ChainTypes;
|
||||
use wallet::libtx::{self, build};
|
||||
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
|
||||
use core::pow;
|
||||
|
||||
|
@ -58,7 +58,7 @@ fn setup(dir_name: &str) -> Chain {
|
|||
#[test]
|
||||
fn mine_empty_chain() {
|
||||
let chain = setup(".grin");
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
|
||||
for n in 1..4 {
|
||||
let prev = chain.head_header().unwrap();
|
||||
|
@ -107,7 +107,7 @@ fn mine_empty_chain() {
|
|||
#[test]
|
||||
fn mine_forks() {
|
||||
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
|
||||
let prev = chain.head_header().unwrap();
|
||||
|
@ -148,7 +148,7 @@ fn mine_forks() {
|
|||
|
||||
#[test]
|
||||
fn mine_losing_fork() {
|
||||
let kc = Keychain::from_random_seed().unwrap();
|
||||
let kc = ExtKeychain::from_random_seed().unwrap();
|
||||
let chain = setup(".grin3");
|
||||
|
||||
// add a first block we'll be forking from
|
||||
|
@ -179,7 +179,7 @@ fn mine_losing_fork() {
|
|||
|
||||
#[test]
|
||||
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
|
||||
// prepare 2 chains, the 2nd will be have the forked blocks we can
|
||||
// then send back on the 1st
|
||||
|
@ -231,7 +231,7 @@ fn spend_in_fork_and_compact() {
|
|||
util::init_test_logger();
|
||||
let chain = setup(".grin6");
|
||||
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;
|
||||
|
||||
|
@ -359,53 +359,63 @@ fn spend_in_fork_and_compact() {
|
|||
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![]);
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
fn prepare_block_tx(
|
||||
kc: &Keychain,
|
||||
fn prepare_block_tx<K>(
|
||||
kc: &K,
|
||||
prev: &BlockHeader,
|
||||
chain: &Chain,
|
||||
diff: u64,
|
||||
txs: Vec<&Transaction>,
|
||||
) -> Block {
|
||||
) -> Block
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||
chain.set_txhashset_roots(&mut b, false).unwrap();
|
||||
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![]);
|
||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
fn prepare_fork_block_tx(
|
||||
kc: &Keychain,
|
||||
fn prepare_fork_block_tx<K>(
|
||||
kc: &K,
|
||||
prev: &BlockHeader,
|
||||
chain: &Chain,
|
||||
diff: u64,
|
||||
txs: Vec<&Transaction>,
|
||||
) -> Block {
|
||||
) -> Block
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let mut b = prepare_block_nosum(kc, prev, diff, txs);
|
||||
chain.set_txhashset_roots(&mut b, true).unwrap();
|
||||
b
|
||||
}
|
||||
|
||||
fn prepare_block_nosum(
|
||||
kc: &Keychain,
|
||||
prev: &BlockHeader,
|
||||
diff: u64,
|
||||
txs: Vec<&Transaction>,
|
||||
) -> Block {
|
||||
fn prepare_block_nosum<K>(kc: &K, prev: &BlockHeader, diff: u64, txs: Vec<&Transaction>) -> Block
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let proof_size = global::proofsize();
|
||||
let key_id = kc.derive_key_id(diff as u32).unwrap();
|
||||
|
||||
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(
|
||||
prev,
|
||||
txs.into_iter().cloned().collect(),
|
||||
|
|
|
@ -22,14 +22,14 @@ extern crate rand;
|
|||
use std::fs;
|
||||
|
||||
use chain::{ChainStore, Tip};
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::Block;
|
||||
use core::core::BlockHeader;
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::target::Difficulty;
|
||||
use core::global;
|
||||
use core::global::ChainTypes;
|
||||
use core::pow;
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
|
||||
use wallet::libtx;
|
||||
|
||||
|
@ -43,7 +43,7 @@ fn test_various_store_indices() {
|
|||
let chain_dir = ".grin_idx_1";
|
||||
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 chain_store =
|
||||
|
|
|
@ -25,14 +25,14 @@ use std::sync::Arc;
|
|||
|
||||
use chain::types::*;
|
||||
use core::consensus;
|
||||
use core::core::OutputIdentifier;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::transaction;
|
||||
use core::core::OutputIdentifier;
|
||||
use core::global;
|
||||
use core::global::ChainTypes;
|
||||
use wallet::libtx::build;
|
||||
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use wallet::libtx;
|
||||
|
||||
use core::pow;
|
||||
|
@ -58,7 +58,7 @@ fn test_coinbase_maturity() {
|
|||
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
@ -145,7 +145,7 @@ fn test_coinbase_maturity() {
|
|||
for _ in 0..3 {
|
||||
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 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::sync::Arc;
|
||||
|
||||
use chain::ChainStore;
|
||||
use chain::store::ChainKVStore;
|
||||
use chain::txhashset;
|
||||
use chain::txhashset::TxHashSet;
|
||||
use chain::types::Tip;
|
||||
use chain::ChainStore;
|
||||
use core::core::pmmr::MerkleProof;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::{Block, BlockHeader};
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use wallet::libtx::{build, reward};
|
||||
|
||||
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 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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
//! Transactions
|
||||
|
||||
use std::cmp::max;
|
||||
use std::cmp::Ordering;
|
||||
use std::cmp::max;
|
||||
use std::collections::HashSet;
|
||||
use std::io::Cursor;
|
||||
use std::{error, fmt};
|
||||
|
@ -26,12 +26,12 @@ use util::{kernel_sig_msg, static_secp_instance};
|
|||
|
||||
use consensus;
|
||||
use consensus::VerifySortOrder;
|
||||
use core::BlockHeader;
|
||||
use core::committed;
|
||||
use core::committed::Committed;
|
||||
use core::global;
|
||||
use core::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use core::pmmr::MerkleProof;
|
||||
use core::BlockHeader;
|
||||
use keychain;
|
||||
use keychain::BlindingFactor;
|
||||
use ser::{self, read_and_verify_sorted, ser_vec, PMMRable, Readable, Reader, Writeable,
|
||||
|
@ -1074,12 +1074,12 @@ impl ProofMessageElements {
|
|||
mod test {
|
||||
use super::*;
|
||||
use core::id::{ShortId, ShortIdentifiable};
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use util::secp;
|
||||
|
||||
#[test]
|
||||
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 commit = keychain.commit(5, &key_id).unwrap();
|
||||
|
||||
|
@ -1124,7 +1124,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
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 commit = keychain.commit(1003, &key_id).unwrap();
|
||||
|
@ -1137,7 +1137,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
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 commit = keychain.commit(5, &key_id).unwrap();
|
||||
|
||||
|
|
|
@ -21,14 +21,14 @@ pub mod common;
|
|||
|
||||
use common::{new_block, tx1i2o, tx2i1o, txspend1i1o};
|
||||
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::hash::Hashed;
|
||||
use grin_core::core::id::{ShortId, ShortIdentifiable};
|
||||
use grin_core::core::Committed;
|
||||
use grin_core::core::{Block, BlockHeader, CompactBlock, KernelFeatures, OutputFeatures};
|
||||
use grin_core::global;
|
||||
use grin_core::ser;
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use std::time::Instant;
|
||||
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?
|
||||
#[allow(dead_code)]
|
||||
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 zero_commit = secp_static::commit_to_zero_value();
|
||||
|
@ -84,7 +84,7 @@ fn very_empty_block() {
|
|||
#[test]
|
||||
// builds a block with a tx spending another and check that cut_through occurred
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
@ -118,7 +118,7 @@ fn block_with_cut_through() {
|
|||
|
||||
#[test]
|
||||
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 prev = BlockHeader::default();
|
||||
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
|
||||
// additionally verifying the merkle_inputs_outputs also fails
|
||||
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 prev = BlockHeader::default();
|
||||
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
|
||||
// invalidates the block and specifically it causes verify_coinbase to fail
|
||||
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 prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
|
@ -212,7 +212,7 @@ fn remove_coinbase_kernel_flag() {
|
|||
|
||||
#[test]
|
||||
fn serialize_deserialize_block() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||
|
@ -229,7 +229,7 @@ fn serialize_deserialize_block() {
|
|||
|
||||
#[test]
|
||||
fn empty_block_serialized_size() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||
|
@ -241,7 +241,7 @@ fn empty_block_serialized_size() {
|
|||
|
||||
#[test]
|
||||
fn block_single_tx_serialized_size() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let tx1 = tx1i2o();
|
||||
let prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
|
@ -254,7 +254,7 @@ fn block_single_tx_serialized_size() {
|
|||
|
||||
#[test]
|
||||
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 key_id = keychain.derive_key_id(1).unwrap();
|
||||
let b = new_block(vec![], &keychain, &prev, &key_id);
|
||||
|
@ -266,7 +266,7 @@ fn empty_compact_block_serialized_size() {
|
|||
|
||||
#[test]
|
||||
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 prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
|
@ -279,7 +279,7 @@ fn compact_block_single_tx_serialized_size() {
|
|||
|
||||
#[test]
|
||||
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);
|
||||
|
||||
let mut txs = vec![];
|
||||
|
@ -298,7 +298,7 @@ fn block_10_tx_serialized_size() {
|
|||
|
||||
#[test]
|
||||
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![];
|
||||
for _ in 0..10 {
|
||||
|
@ -316,7 +316,7 @@ fn compact_block_10_tx_serialized_size() {
|
|||
|
||||
#[test]
|
||||
fn compact_block_hash_with_nonce() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let tx = tx1i2o();
|
||||
let prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
|
@ -346,7 +346,7 @@ fn compact_block_hash_with_nonce() {
|
|||
|
||||
#[test]
|
||||
fn convert_block_to_compact_block() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let tx1 = tx1i2o();
|
||||
let prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
|
@ -369,7 +369,7 @@ fn convert_block_to_compact_block() {
|
|||
|
||||
#[test]
|
||||
fn hydrate_empty_compact_block() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let prev = BlockHeader::default();
|
||||
let key_id = keychain.derive_key_id(1).unwrap();
|
||||
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_wallet as wallet;
|
||||
|
||||
use grin_core::core::Transaction;
|
||||
use grin_core::core::block::{Block, BlockHeader};
|
||||
use grin_core::core::target::Difficulty;
|
||||
use grin_core::core::Transaction;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use wallet::libtx::build::{self, input, output, with_fee};
|
||||
use wallet::libtx::reward;
|
||||
|
||||
// utility producing a transaction with 2 inputs and a single outputs
|
||||
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_id2 = keychain.derive_key_id(2).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
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
|
||||
|
@ -60,7 +60,7 @@ pub fn tx1i1o() -> Transaction {
|
|||
// and two outputs (one change output)
|
||||
// Note: this tx has an "offset" kernel
|
||||
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_id2 = keychain.derive_key_id(2).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
|
||||
// header
|
||||
pub fn new_block(
|
||||
pub fn new_block<K>(
|
||||
txs: Vec<&Transaction>,
|
||||
keychain: &Keychain,
|
||||
keychain: &K,
|
||||
previous_header: &BlockHeader,
|
||||
key_id: &Identifier,
|
||||
) -> Block {
|
||||
) -> Block
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let fees = txs.iter().map(|tx| tx.fee()).sum();
|
||||
let reward_output = reward::output(keychain, &key_id, fees, previous_header.height).unwrap();
|
||||
Block::new(
|
||||
|
@ -96,14 +99,12 @@ pub fn new_block(
|
|||
|
||||
// utility producing a transaction that spends an output with the provided
|
||||
// value and blinding key
|
||||
pub fn txspend1i1o(
|
||||
v: u64,
|
||||
keychain: &Keychain,
|
||||
key_id1: Identifier,
|
||||
key_id2: Identifier,
|
||||
) -> Transaction {
|
||||
pub fn txspend1i1o<K>(v: u64, keychain: &K, key_id1: Identifier, key_id2: Identifier) -> Transaction
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
build::transaction(
|
||||
vec![input(v, key_id1), output(3, key_id2), with_fee(2)],
|
||||
&keychain,
|
||||
keychain,
|
||||
).unwrap()
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ use grin_core::core::block::Error::KernelLockHeight;
|
|||
use grin_core::core::hash::{Hashed, ZERO_HASH};
|
||||
use grin_core::core::{aggregate, deaggregate, KernelFeatures, Output, Transaction};
|
||||
use grin_core::ser;
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use util::{secp_static, static_secp_instance};
|
||||
use wallet::libtx::build::{self, initial_tx, input, output, with_excess, with_fee,
|
||||
with_lock_height};
|
||||
|
@ -72,7 +72,7 @@ fn tx_double_ser_deser() {
|
|||
#[test]
|
||||
#[should_panic(expected = "InvalidSecretKey")]
|
||||
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();
|
||||
|
||||
// blinding should fail as signing with a zero r*G shouldn't work
|
||||
|
@ -88,7 +88,7 @@ fn test_zero_commit_fails() {
|
|||
|
||||
#[test]
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
@ -295,7 +295,7 @@ fn basic_transaction_deaggregation() {
|
|||
|
||||
#[test]
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
@ -349,7 +349,7 @@ fn tx_hash_diff() {
|
|||
/// 2 inputs, 2 outputs transaction.
|
||||
#[test]
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
@ -386,7 +386,7 @@ fn tx_build_exchange() {
|
|||
|
||||
#[test]
|
||||
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 zero_commit = secp_static::commit_to_zero_value();
|
||||
|
@ -402,7 +402,7 @@ fn reward_empty_block() {
|
|||
|
||||
#[test]
|
||||
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 zero_commit = secp_static::commit_to_zero_value();
|
||||
|
@ -421,7 +421,7 @@ fn reward_with_tx_block() {
|
|||
|
||||
#[test]
|
||||
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 zero_commit = secp_static::commit_to_zero_value();
|
||||
|
@ -442,7 +442,7 @@ fn simple_block() {
|
|||
|
||||
#[test]
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
|
|
|
@ -22,13 +22,13 @@ pub mod common;
|
|||
|
||||
use grin_core::core::{Output, OutputFeatures};
|
||||
use grin_core::ser;
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use util::secp;
|
||||
use wallet::libtx::proof;
|
||||
|
||||
#[test]
|
||||
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 commit = keychain.commit(5, &key_id).unwrap();
|
||||
let msg = secp::pedersen::ProofMessage::empty();
|
||||
|
|
|
@ -12,167 +12,11 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::cmp::min;
|
||||
use std::{error, fmt, num};
|
||||
|
||||
use serde::{de, ser};
|
||||
|
||||
use blake2::blake2b::blake2b;
|
||||
use byteorder::{BigEndian, ByteOrder};
|
||||
use util;
|
||||
use util::secp;
|
||||
use types::{Error, Identifier};
|
||||
use util::secp::Secp256k1;
|
||||
use util::secp::key::{PublicKey, 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())
|
||||
}
|
||||
}
|
||||
use util::secp::key::SecretKey;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ChildKey {
|
||||
|
@ -210,7 +54,11 @@ impl ExtendedKey {
|
|||
pub fn from_seed(secp: &Secp256k1, seed: &[u8]) -> Result<ExtendedKey, Error> {
|
||||
match seed.len() {
|
||||
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);
|
||||
|
|
|
@ -12,87 +12,34 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// Implementation of the Keychain trait based on an extended key derivation
|
||||
/// scheme.
|
||||
use rand::{thread_rng, Rng};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, RwLock};
|
||||
use std::{error, fmt};
|
||||
|
||||
use util::secp;
|
||||
use util::secp::{Message, Secp256k1, Signature};
|
||||
use blake2;
|
||||
|
||||
use extkey;
|
||||
use types::{BlindSum, BlindingFactor, Error, Identifier, Keychain};
|
||||
use util::logger::LOGGER;
|
||||
use util::secp::key::SecretKey;
|
||||
use util::secp::pedersen::Commitment;
|
||||
use util::logger::LOGGER;
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
use util::secp::{self, Message, Secp256k1, Signature};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Keychain {
|
||||
pub struct ExtKeychain {
|
||||
secp: Secp256k1,
|
||||
extkey: extkey::ExtendedKey,
|
||||
key_overrides: HashMap<Identifier, SecretKey>,
|
||||
key_derivation_cache: Arc<RwLock<HashMap<Identifier, u32>>>,
|
||||
}
|
||||
|
||||
impl Keychain {
|
||||
pub fn root_key_id(&self) -> Identifier {
|
||||
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> {
|
||||
impl Keychain for ExtKeychain {
|
||||
fn from_seed(seed: &[u8]) -> Result<ExtKeychain, Error> {
|
||||
let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||
let extkey = extkey::ExtendedKey::from_seed(&secp, seed)?;
|
||||
let keychain = Keychain {
|
||||
let keychain = ExtKeychain {
|
||||
secp: secp,
|
||||
extkey: extkey,
|
||||
key_overrides: HashMap::new(),
|
||||
|
@ -102,18 +49,22 @@ impl Keychain {
|
|||
}
|
||||
|
||||
/// 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 = 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)?;
|
||||
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
|
||||
if let Some(key) = self.key_overrides.get(key_id) {
|
||||
trace!(
|
||||
|
@ -128,6 +79,82 @@ impl Keychain {
|
|||
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> {
|
||||
trace!(LOGGER, "Derived Key by key_id: {}", key_id);
|
||||
|
||||
|
@ -184,78 +211,18 @@ impl Keychain {
|
|||
let child_key = self.extkey.derive(&self.secp, derivation)?;
|
||||
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)]
|
||||
mod test {
|
||||
use keychain::{BlindSum, BlindingFactor, Keychain};
|
||||
use keychain::ExtKeychain;
|
||||
use types::{BlindSum, BlindingFactor, Keychain};
|
||||
use util::secp;
|
||||
use util::secp::key::SecretKey;
|
||||
|
||||
#[test]
|
||||
fn test_key_derivation() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let secp = keychain.secp();
|
||||
|
||||
// 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.
|
||||
#[test]
|
||||
fn secret_key_addition() {
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
|
||||
let skey1 = SecretKey::from_slice(
|
||||
&keychain.secp,
|
||||
|
|
|
@ -26,10 +26,9 @@ extern crate serde_json;
|
|||
extern crate slog;
|
||||
extern crate uuid;
|
||||
|
||||
pub mod blind;
|
||||
pub mod extkey;
|
||||
mod types;
|
||||
|
||||
pub use blind::{BlindSum, BlindingFactor};
|
||||
pub use extkey::{ExtendedKey, Identifier, IDENTIFIER_SIZE};
|
||||
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.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
/// Encapsulate a secret key for the blind_sum operation
|
||||
|
||||
use std::cmp::min;
|
||||
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::secp::{self, Secp256k1};
|
||||
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)]
|
||||
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.
|
||||
/// We use one of these (k1) to sign the tx_kernel (k1G)
|
||||
/// Split a blinding_factor (aka secret_key) into a pair of
|
||||
/// 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".
|
||||
/// This prevents an actor from being able to sum a set of inputs, outputs and kernels
|
||||
/// from a block to identify and reconstruct a particular tx from a block.
|
||||
/// You would need both k1, k2 to do this.
|
||||
/// This prevents an actor from being able to sum a set of inputs, outputs
|
||||
/// and kernels from a block to identify and reconstruct a particular tx
|
||||
/// from a block. You would need both k1, k2 to do this.
|
||||
pub fn split(&self, secp: &Secp256k1) -> Result<SplitBlindingFactor, Error> {
|
||||
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)]
|
||||
mod test {
|
||||
use rand::thread_rng;
|
||||
|
||||
use blind::BlindingFactor;
|
||||
use types::BlindingFactor;
|
||||
use util::secp::Secp256k1;
|
||||
use util::secp::key::{SecretKey, ZERO_KEY};
|
||||
|
|
@ -17,8 +17,8 @@ extern crate grin_p2p as p2p;
|
|||
extern crate grin_util as util;
|
||||
|
||||
use std::net::{SocketAddr, TcpListener, TcpStream};
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
use std::thread;
|
||||
use std::time;
|
||||
|
||||
|
|
|
@ -29,19 +29,19 @@ use std::sync::{Arc, RwLock};
|
|||
|
||||
use core::core::{Block, BlockHeader};
|
||||
|
||||
use chain::ChainStore;
|
||||
use chain::txhashset;
|
||||
use chain::types::Tip;
|
||||
use chain::ChainStore;
|
||||
use core::core::target::Difficulty;
|
||||
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use wallet::libtx;
|
||||
|
||||
use common::*;
|
||||
|
||||
#[test]
|
||||
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();
|
||||
clean_output_dir(db_root.clone());
|
||||
|
|
|
@ -29,19 +29,19 @@ use std::sync::{Arc, RwLock};
|
|||
|
||||
use core::core::{Block, BlockHeader};
|
||||
|
||||
use chain::ChainStore;
|
||||
use chain::txhashset;
|
||||
use chain::types::Tip;
|
||||
use chain::ChainStore;
|
||||
use core::core::target::Difficulty;
|
||||
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use wallet::libtx;
|
||||
|
||||
use common::*;
|
||||
|
||||
#[test]
|
||||
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();
|
||||
clean_output_dir(db_root.clone());
|
||||
|
|
|
@ -29,7 +29,7 @@ use std::sync::{Arc, RwLock};
|
|||
|
||||
use core::core::Transaction;
|
||||
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use pool::TransactionPool;
|
||||
use pool::types::*;
|
||||
|
||||
|
@ -82,7 +82,7 @@ impl BlockChain for CoinbaseMaturityErrorChainAdapter {
|
|||
/// Test we correctly verify coinbase maturity when adding txs to the pool.
|
||||
#[test]
|
||||
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
|
||||
// maturity.
|
||||
|
|
|
@ -30,10 +30,10 @@ use std::sync::{Arc, RwLock};
|
|||
|
||||
use core::core::{BlockHeader, Transaction};
|
||||
|
||||
use chain::ChainStore;
|
||||
use chain::store::ChainKVStore;
|
||||
use chain::txhashset;
|
||||
use chain::txhashset::TxHashSet;
|
||||
use chain::ChainStore;
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::pmmr::MerkleProof;
|
||||
use pool::*;
|
||||
|
@ -41,8 +41,8 @@ use pool::*;
|
|||
use keychain::Keychain;
|
||||
use wallet::libtx;
|
||||
|
||||
use pool::types::*;
|
||||
use pool::TransactionPool;
|
||||
use pool::types::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ChainAdapter {
|
||||
|
@ -105,11 +105,14 @@ pub fn test_setup(chain: &Arc<ChainAdapter>) -> TransactionPool<ChainAdapter> {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn test_transaction_spending_coinbase(
|
||||
keychain: &Keychain,
|
||||
pub fn test_transaction_spending_coinbase<K>(
|
||||
keychain: &K,
|
||||
header: &BlockHeader,
|
||||
output_values: Vec<u64>,
|
||||
) -> Transaction {
|
||||
) -> Transaction
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let output_sum = output_values.iter().sum::<u64>() as i64;
|
||||
|
||||
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));
|
||||
|
||||
libtx::build::transaction(tx_elements, &keychain).unwrap()
|
||||
libtx::build::transaction(tx_elements, keychain).unwrap()
|
||||
}
|
||||
|
||||
pub fn test_transaction(
|
||||
keychain: &Keychain,
|
||||
pub fn test_transaction<K>(
|
||||
keychain: &K,
|
||||
input_values: Vec<u64>,
|
||||
output_values: Vec<u64>,
|
||||
) -> Transaction {
|
||||
) -> Transaction
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let input_sum = input_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));
|
||||
|
||||
libtx::build::transaction(tx_elements, &keychain).unwrap()
|
||||
libtx::build::transaction(tx_elements, keychain).unwrap()
|
||||
}
|
||||
|
||||
pub fn test_source() -> TxSource {
|
||||
|
|
|
@ -29,13 +29,13 @@ use std::sync::{Arc, RwLock};
|
|||
|
||||
use core::core::{Block, BlockHeader};
|
||||
|
||||
use chain::ChainStore;
|
||||
use chain::txhashset;
|
||||
use chain::types::Tip;
|
||||
use chain::ChainStore;
|
||||
use core::core::target::Difficulty;
|
||||
use core::core::transaction;
|
||||
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use wallet::libtx;
|
||||
|
||||
use common::*;
|
||||
|
@ -43,7 +43,7 @@ use common::*;
|
|||
/// Test we can add some txs to the pool (both stempool and txpool).
|
||||
#[test]
|
||||
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();
|
||||
clean_output_dir(db_root.clone());
|
||||
|
|
|
@ -31,7 +31,7 @@ use core::core;
|
|||
use core::core::hash::Hashed;
|
||||
use core::ser;
|
||||
use core::ser::AsFixedBytes;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use keychain::{ExtKeychain, Identifier, Keychain};
|
||||
use pool;
|
||||
use util;
|
||||
use util::LOGGER;
|
||||
|
@ -219,7 +219,7 @@ fn build_block(
|
|||
///
|
||||
fn burn_reward(block_fees: BlockFees) -> Result<(core::Output, core::TxKernel, BlockFees), Error> {
|
||||
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 (out, kernel) =
|
||||
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);
|
||||
}
|
||||
|
||||
let wallet = FileWallet::new(self.wallet_config.clone(), "").unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"Error creating wallet: {:?} Config: {:?}",
|
||||
e, self.wallet_config
|
||||
)
|
||||
});
|
||||
let wallet: FileWallet<keychain::ExtKeychain> =
|
||||
FileWallet::new(self.wallet_config.clone(), "").unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"Error creating wallet: {:?} Config: {:?}",
|
||||
e, self.wallet_config
|
||||
)
|
||||
});
|
||||
|
||||
wallet::controller::foreign_listener(wallet, &self.wallet_config.api_listen_addr())
|
||||
.unwrap_or_else(|e| {
|
||||
|
@ -298,7 +299,7 @@ impl LocalServerContainer {
|
|||
config: &WalletConfig,
|
||||
wallet_seed: &wallet::WalletSeed,
|
||||
) -> wallet::WalletInfo {
|
||||
let keychain = wallet_seed
|
||||
let keychain: keychain::ExtKeychain = wallet_seed
|
||||
.derive_keychain("")
|
||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||
let mut wallet = FileWallet::new(config.clone(), "")
|
||||
|
@ -321,7 +322,7 @@ impl LocalServerContainer {
|
|||
let wallet_seed =
|
||||
wallet::WalletSeed::from_file(config).expect("Failed to read wallet seed file.");
|
||||
|
||||
let keychain = wallet_seed
|
||||
let keychain: keychain::ExtKeychain = wallet_seed
|
||||
.derive_keychain("")
|
||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||
let max_outputs = 500;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
use core::core;
|
||||
use core::core::amount_to_hr_string;
|
||||
use keychain::Keychain;
|
||||
use libwallet::Error;
|
||||
use libwallet::types::{OutputData, WalletInfo};
|
||||
use prettytable;
|
||||
|
|
|
@ -103,9 +103,9 @@ impl WalletSeed {
|
|||
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 result = keychain::Keychain::from_seed(seed.as_bytes())?;
|
||||
let result = K::from_seed(seed.as_bytes())?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
|
@ -168,9 +168,9 @@ impl WalletSeed {
|
|||
/// Wallet information tracking all our outputs. Based on HD derivation and
|
||||
/// avoids storing any key data, only storing output amounts and child index.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileWallet {
|
||||
pub struct FileWallet<K> {
|
||||
/// Keychain
|
||||
pub keychain: Option<Keychain>,
|
||||
pub keychain: Option<K>,
|
||||
/// Configuration
|
||||
pub config: WalletConfig,
|
||||
/// passphrase: TODO better ways of dealing with this other than storing
|
||||
|
@ -185,14 +185,18 @@ pub struct FileWallet {
|
|||
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
|
||||
fn open_with_credentials(&mut self) -> Result<(), libwallet::Error> {
|
||||
let wallet_seed = WalletSeed::from_file(&self.config)
|
||||
.context(libwallet::ErrorKind::CallbackImpl("Error opening wallet"))?;
|
||||
self.keychain = Some(wallet_seed.derive_keychain(&self.passphrase).context(
|
||||
libwallet::ErrorKind::CallbackImpl("Error deriving keychain"),
|
||||
)?);
|
||||
let keychain = wallet_seed.derive_keychain(&self.passphrase);
|
||||
self.keychain = Some(keychain.context(libwallet::ErrorKind::CallbackImpl(
|
||||
"Error deriving keychain",
|
||||
))?);
|
||||
// Just blow up password for now after it's been used
|
||||
self.passphrase = String::from("");
|
||||
Ok(())
|
||||
|
@ -205,7 +209,7 @@ impl WalletBackend for FileWallet {
|
|||
}
|
||||
|
||||
/// Return the keychain being used
|
||||
fn keychain(&mut self) -> &mut Keychain {
|
||||
fn keychain(&mut self) -> &mut K {
|
||||
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
|
||||
fn node_url(&self) -> &str {
|
||||
&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
|
||||
pub fn new(config: WalletConfig, passphrase: &str) -> Result<Self, Error> {
|
||||
let mut retval = FileWallet {
|
||||
|
|
|
@ -13,9 +13,7 @@
|
|||
// limitations under the License.
|
||||
//! Aggsig helper functions used in transaction creation.. should be only
|
||||
//! interface into the underlying secp library
|
||||
use keychain::Keychain;
|
||||
use keychain::blind::BlindingFactor;
|
||||
use keychain::extkey::Identifier;
|
||||
use keychain::{BlindingFactor, Identifier, Keychain};
|
||||
use libtx::error::{Error, ErrorKind};
|
||||
use util::kernel_sig_msg;
|
||||
use util::secp::key::{PublicKey, SecretKey};
|
||||
|
@ -72,12 +70,15 @@ pub fn verify_partial_sig(
|
|||
}
|
||||
|
||||
/// Just a simple sig, creates its own nonce, etc
|
||||
pub fn sign_from_key_id(
|
||||
pub fn sign_from_key_id<K>(
|
||||
secp: &Secp256k1,
|
||||
k: &Keychain,
|
||||
k: &K,
|
||||
msg: &Message,
|
||||
key_id: &Identifier,
|
||||
) -> Result<Signature, Error> {
|
||||
) -> Result<Signature, Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let skey = k.derived_key(key_id)?;
|
||||
let sig = aggsig::sign_single(secp, &msg, &skey, None, None, None)?;
|
||||
Ok(sig)
|
||||
|
|
|
@ -30,30 +30,35 @@ use util::{kernel_sig_msg, secp};
|
|||
use core::core::hash::Hash;
|
||||
use core::core::pmmr::MerkleProof;
|
||||
use core::core::{Input, Output, OutputFeatures, ProofMessageElements, Transaction, TxKernel};
|
||||
use keychain;
|
||||
use keychain::{BlindSum, BlindingFactor, Identifier, Keychain};
|
||||
use keychain::{self, BlindSum, BlindingFactor, Identifier, Keychain};
|
||||
use libtx::{aggsig, proof};
|
||||
use util::LOGGER;
|
||||
|
||||
/// Context information available to transaction combinators.
|
||||
pub struct Context<'a> {
|
||||
keychain: &'a Keychain,
|
||||
pub struct Context<'a, K: 'a>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
keychain: &'a K,
|
||||
}
|
||||
|
||||
/// Function type returned by the transaction combinators. Transforms a
|
||||
/// (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);
|
||||
|
||||
/// Adds an input with the provided value and blinding key to the transaction
|
||||
/// being built.
|
||||
fn build_input(
|
||||
fn build_input<K>(
|
||||
value: u64,
|
||||
features: OutputFeatures,
|
||||
block_hash: Option<Hash>,
|
||||
merkle_proof: Option<MerkleProof>,
|
||||
key_id: Identifier,
|
||||
) -> Box<Append> {
|
||||
) -> Box<Append<K>>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
Box::new(
|
||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||
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
|
||||
/// 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!(
|
||||
LOGGER,
|
||||
"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.
|
||||
/// We will use the block hash to verify coinbase maturity.
|
||||
pub fn coinbase_input(
|
||||
pub fn coinbase_input<K>(
|
||||
value: u64,
|
||||
block_hash: Hash,
|
||||
merkle_proof: MerkleProof,
|
||||
key_id: Identifier,
|
||||
) -> Box<Append> {
|
||||
) -> Box<Append<K>>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
debug!(
|
||||
LOGGER,
|
||||
"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
|
||||
/// 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(
|
||||
move |build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||
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.
|
||||
pub fn with_fee(fee: u64) -> Box<Append> {
|
||||
pub fn with_fee<K>(fee: u64) -> Box<Append<K>>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
Box::new(
|
||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||
(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.
|
||||
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(
|
||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||
(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
|
||||
/// combination with the initial_tx function when a new transaction is built
|
||||
/// 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(
|
||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||
(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.
|
||||
pub fn with_offset(offset: BlindingFactor) -> Box<Append> {
|
||||
pub fn with_offset<K>(offset: BlindingFactor) -> Box<Append<K>>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
Box::new(
|
||||
move |_build, (tx, kern, sum)| -> (Transaction, TxKernel, BlindSum) {
|
||||
(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.
|
||||
/// We currently only support building a tx with a single kernel with
|
||||
/// 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);
|
||||
let kern = tx.kernels.remove(0);
|
||||
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),
|
||||
/// output_rand(2)], keychain).unwrap();
|
||||
///
|
||||
pub fn partial_transaction(
|
||||
elems: Vec<Box<Append>>,
|
||||
keychain: &keychain::Keychain,
|
||||
) -> Result<(Transaction, BlindingFactor), keychain::Error> {
|
||||
pub fn partial_transaction<K>(
|
||||
elems: Vec<Box<Append<K>>>,
|
||||
keychain: &K,
|
||||
) -> Result<(Transaction, BlindingFactor), keychain::Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let mut ctx = Context { keychain };
|
||||
let (mut tx, kern, sum) = elems.iter().fold(
|
||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
||||
|
@ -208,10 +240,13 @@ pub fn partial_transaction(
|
|||
}
|
||||
|
||||
/// Builds a complete transaction.
|
||||
pub fn transaction(
|
||||
elems: Vec<Box<Append>>,
|
||||
keychain: &keychain::Keychain,
|
||||
) -> Result<Transaction, keychain::Error> {
|
||||
pub fn transaction<K>(
|
||||
elems: Vec<Box<Append<K>>>,
|
||||
keychain: &K,
|
||||
) -> Result<Transaction, keychain::Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let (mut tx, blind_sum) = partial_transaction(elems, keychain)?;
|
||||
assert_eq!(tx.kernels.len(), 1);
|
||||
|
||||
|
@ -229,10 +264,13 @@ pub fn transaction(
|
|||
|
||||
/// Builds a complete transaction, splitting the key and
|
||||
/// setting the excess, excess_sig and tx offset as necessary.
|
||||
pub fn transaction_with_offset(
|
||||
elems: Vec<Box<Append>>,
|
||||
keychain: &keychain::Keychain,
|
||||
) -> Result<Transaction, keychain::Error> {
|
||||
pub fn transaction_with_offset<K>(
|
||||
elems: Vec<Box<Append<K>>>,
|
||||
keychain: &K,
|
||||
) -> Result<Transaction, keychain::Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let mut ctx = Context { keychain };
|
||||
let (mut tx, mut kern, sum) = elems.iter().fold(
|
||||
(Transaction::empty(), TxKernel::empty(), BlindSum::new()),
|
||||
|
@ -265,10 +303,11 @@ pub fn transaction_with_offset(
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use keychain::ExtKeychain;
|
||||
|
||||
#[test]
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
@ -288,7 +327,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
let key_id3 = keychain.derive_key_id(3).unwrap();
|
||||
|
@ -308,7 +347,7 @@ mod test {
|
|||
|
||||
#[test]
|
||||
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_id2 = keychain.derive_key_id(2).unwrap();
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ use std::fmt::{self, Display};
|
|||
|
||||
use core::core::committed;
|
||||
use core::core::transaction;
|
||||
use keychain::{self, extkey};
|
||||
use keychain;
|
||||
use util::secp;
|
||||
|
||||
/// Lib tx error definition
|
||||
|
@ -36,9 +36,6 @@ pub enum ErrorKind {
|
|||
/// Keychain error
|
||||
#[fail(display = "Keychain Error")]
|
||||
Keychain(keychain::Error),
|
||||
/// Extended key error
|
||||
#[fail(display = "Extended Key Error")]
|
||||
ExtendedKey(extkey::Error),
|
||||
/// Transaction error
|
||||
#[fail(display = "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 {
|
||||
fn from(error: transaction::Error) -> Error {
|
||||
Error {
|
||||
|
|
|
@ -15,18 +15,20 @@
|
|||
//! Rangeproof library functions
|
||||
|
||||
use blake2;
|
||||
use keychain::Keychain;
|
||||
use keychain::extkey::Identifier;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use libtx::error::{Error, ErrorKind};
|
||||
use util::logger::LOGGER;
|
||||
use util::secp::key::SecretKey;
|
||||
use util::secp::pedersen::{Commitment, ProofInfo, ProofMessage, RangeProof};
|
||||
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
|
||||
let root_key = k.root_key_id().to_bytes();
|
||||
let res = blake2::blake2b::blake2b(32, &commit.0, &root_key);
|
||||
let root_key = k.root_key_id();
|
||||
let res = blake2::blake2b::blake2b(32, &commit.0, &root_key.to_bytes()[..]);
|
||||
let res = res.as_bytes();
|
||||
let mut ret_val = [0; 32];
|
||||
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
|
||||
/// back to get the sensitive data
|
||||
|
||||
pub fn create(
|
||||
k: &Keychain,
|
||||
pub fn create<K>(
|
||||
k: &K,
|
||||
amount: u64,
|
||||
key_id: &Identifier,
|
||||
_commit: Commitment,
|
||||
extra_data: Option<Vec<u8>>,
|
||||
msg: ProofMessage,
|
||||
) -> Result<RangeProof, Error> {
|
||||
) -> Result<RangeProof, Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let commit = k.commit(amount, key_id)?;
|
||||
let skey = k.derived_key(key_id)?;
|
||||
let nonce = create_nonce(k, &commit)?;
|
||||
|
@ -83,13 +88,16 @@ pub fn verify(
|
|||
}
|
||||
|
||||
/// Rewind a rangeproof to retrieve the amount
|
||||
pub fn rewind(
|
||||
k: &Keychain,
|
||||
pub fn rewind<K>(
|
||||
k: &K,
|
||||
key_id: &Identifier,
|
||||
commit: Commitment,
|
||||
extra_data: Option<Vec<u8>>,
|
||||
proof: RangeProof,
|
||||
) -> Result<ProofInfo, Error> {
|
||||
) -> Result<ProofInfo, Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let skey = k.derived_key(key_id)?;
|
||||
let nonce = create_nonce(k, &commit)?;
|
||||
let proof_message = k.secp()
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
//! Builds the blinded output and related signature proof for the block
|
||||
//! reward.
|
||||
use keychain;
|
||||
use keychain::{Identifier, Keychain};
|
||||
|
||||
use core::consensus::reward;
|
||||
use core::core::KernelFeatures;
|
||||
|
@ -24,12 +24,15 @@ use libtx::{aggsig, proof};
|
|||
use util::{kernel_sig_msg, secp, static_secp_instance, LOGGER};
|
||||
|
||||
/// output a reward output
|
||||
pub fn output(
|
||||
keychain: &keychain::Keychain,
|
||||
key_id: &keychain::Identifier,
|
||||
pub fn output<K>(
|
||||
keychain: &K,
|
||||
key_id: &Identifier,
|
||||
fees: u64,
|
||||
height: u64,
|
||||
) -> Result<(Output, TxKernel), Error> {
|
||||
) -> Result<(Output, TxKernel), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let value = reward(fees);
|
||||
let commit = keychain.commit(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
|
||||
/// Returns blinding factor
|
||||
pub fn add_transaction_elements(
|
||||
pub fn add_transaction_elements<K>(
|
||||
&mut self,
|
||||
keychain: &Keychain,
|
||||
mut elems: Vec<Box<build::Append>>,
|
||||
) -> Result<BlindingFactor, Error> {
|
||||
keychain: &K,
|
||||
mut elems: Vec<Box<build::Append<K>>>,
|
||||
) -> Result<BlindingFactor, Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
// Append to the exiting transaction
|
||||
if self.tx.kernels.len() != 0 {
|
||||
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;
|
||||
Ok(blind)
|
||||
}
|
||||
|
||||
/// Completes callers part of round 1, adding public key info
|
||||
/// to the slate
|
||||
pub fn fill_round_1(
|
||||
pub fn fill_round_1<K>(
|
||||
&mut self,
|
||||
keychain: &Keychain,
|
||||
keychain: &K,
|
||||
sec_key: &mut SecretKey,
|
||||
sec_nonce: &SecretKey,
|
||||
participant_id: usize,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
// Whoever does this first generates the offset
|
||||
if self.tx.offset == BlindingFactor::zero() {
|
||||
self.generate_offset(keychain, sec_key)?;
|
||||
|
@ -136,13 +142,16 @@ impl Slate {
|
|||
}
|
||||
|
||||
/// Completes caller's part of round 2, completing signatures
|
||||
pub fn fill_round_2(
|
||||
pub fn fill_round_2<K>(
|
||||
&mut self,
|
||||
keychain: &Keychain,
|
||||
keychain: &K,
|
||||
sec_key: &SecretKey,
|
||||
sec_nonce: &SecretKey,
|
||||
participant_id: usize,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
self.check_fees()?;
|
||||
self.verify_part_sigs(keychain.secp())?;
|
||||
let sig_part = aggsig::calculate_partial_sig(
|
||||
|
@ -160,7 +169,10 @@ impl Slate {
|
|||
/// Creates the final signature, callable by either the sender or recipient
|
||||
/// (after phase 3: sender confirmation)
|
||||
/// 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)?;
|
||||
self.finalize_transaction(keychain, &final_sig)
|
||||
}
|
||||
|
@ -201,14 +213,17 @@ impl Slate {
|
|||
/// and saves participant's transaction context
|
||||
/// sec_key can be overriden to replace the blinding
|
||||
/// factor (by whoever split the offset)
|
||||
fn add_participant_info(
|
||||
fn add_participant_info<K>(
|
||||
&mut self,
|
||||
keychain: &Keychain,
|
||||
keychain: &K,
|
||||
sec_key: &SecretKey,
|
||||
sec_nonce: &SecretKey,
|
||||
id: usize,
|
||||
part_sig: Option<Signature>,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
// Add our public key and nonce to the slate
|
||||
let pub_key = PublicKey::from_secret_key(keychain.secp(), &sec_key)?;
|
||||
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
|
||||
/// Return offset private key for the participant to use later in the
|
||||
/// transaction
|
||||
fn generate_offset(
|
||||
&mut self,
|
||||
keychain: &Keychain,
|
||||
sec_key: &mut SecretKey,
|
||||
) -> Result<(), Error> {
|
||||
fn generate_offset<K>(&mut self, keychain: &K, sec_key: &mut SecretKey) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
// Generate a random kernel offset here
|
||||
// and subtract it from the blind_sum so we create
|
||||
// the aggsig context with the "split" key
|
||||
|
@ -308,7 +322,10 @@ impl Slate {
|
|||
///
|
||||
/// 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())?;
|
||||
|
||||
let part_sigs = self.part_sigs();
|
||||
|
@ -332,11 +349,14 @@ impl Slate {
|
|||
}
|
||||
|
||||
/// builds a final transaction after the aggregated sig exchange
|
||||
fn finalize_transaction(
|
||||
fn finalize_transaction<K>(
|
||||
&mut self,
|
||||
keychain: &Keychain,
|
||||
keychain: &K,
|
||||
final_sig: &secp::Signature,
|
||||
) -> Result<(), Error> {
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
let kernel_offset = self.tx.offset;
|
||||
|
||||
self.check_fees()?;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
//! vs. functions to interact with someone else)
|
||||
//! Still experimental, not sure this is the best way to do this
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use libtx::slate::Slate;
|
||||
use libwallet::Error;
|
||||
use libwallet::internal::{tx, updater};
|
||||
|
@ -24,26 +26,33 @@ use libwallet::types::{BlockFees, CbData, OutputData, TxWrapper, WalletBackend,
|
|||
WalletInfo};
|
||||
|
||||
use core::ser;
|
||||
use keychain::Keychain;
|
||||
use util::{self, LOGGER};
|
||||
|
||||
/// Wrapper around internal API functions, containing a reference to
|
||||
/// the wallet/keychain that they're acting upon
|
||||
pub struct APIOwner<'a, W>
|
||||
pub struct APIOwner<'a, W, K>
|
||||
where
|
||||
W: 'a + WalletBackend + WalletClient,
|
||||
W: 'a + WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||
/// perhaps)
|
||||
pub wallet: &'a mut W,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<'a, W> APIOwner<'a, W>
|
||||
impl<'a, W, K> APIOwner<'a, W, K>
|
||||
where
|
||||
W: 'a + WalletBackend + WalletClient,
|
||||
W: 'a + WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Create new API instance
|
||||
pub fn new(wallet_in: &'a mut W) -> APIOwner<'a, W> {
|
||||
APIOwner { wallet: wallet_in }
|
||||
pub fn new(wallet_in: &'a mut W) -> APIOwner<'a, W, K> {
|
||||
APIOwner {
|
||||
wallet: wallet_in,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to update and retrieve outputs
|
||||
|
@ -151,22 +160,28 @@ where
|
|||
|
||||
/// Wrapper around external API functions, intended to communicate
|
||||
/// with other parties
|
||||
pub struct APIForeign<'a, W>
|
||||
pub struct APIForeign<'a, W, K>
|
||||
where
|
||||
W: 'a + WalletBackend + WalletClient,
|
||||
W: 'a + WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||
/// perhaps)
|
||||
pub wallet: &'a mut W,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<'a, W> APIForeign<'a, W>
|
||||
impl<'a, W, K> APIForeign<'a, W, K>
|
||||
where
|
||||
W: 'a + WalletBackend + WalletClient,
|
||||
W: 'a + WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Create new API instance
|
||||
pub fn new(wallet_in: &'a mut W) -> APIForeign<'a, W> {
|
||||
APIForeign { wallet: wallet_in }
|
||||
pub fn new(wallet_in: &'a mut W) -> APIForeign<'a, W, K> {
|
||||
APIForeign {
|
||||
wallet: wallet_in,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Build a new (potential) coinbase transaction in the wallet
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
//! invocations) as needed.
|
||||
//! Still experimental
|
||||
use api::ApiServer;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use bodyparser;
|
||||
|
@ -27,6 +28,7 @@ use serde_json;
|
|||
|
||||
use failure::Fail;
|
||||
|
||||
use keychain::Keychain;
|
||||
use libtx::slate::Slate;
|
||||
use libwallet::api::{APIForeign, APIOwner};
|
||||
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
|
||||
/// 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
|
||||
T: WalletBackend + WalletClient,
|
||||
F: FnOnce(&mut APIOwner<T>) -> Result<(), Error>,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
F: FnOnce(&mut APIOwner<T, K>) -> Result<(), Error>,
|
||||
K: Keychain,
|
||||
{
|
||||
wallet.open_with_credentials()?;
|
||||
f(&mut APIOwner::new(wallet))?;
|
||||
|
@ -49,10 +52,11 @@ where
|
|||
|
||||
/// Instantiate wallet Foreign API for a single-use (command line) 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
|
||||
T: WalletBackend + WalletClient,
|
||||
F: FnOnce(&mut APIForeign<T>) -> Result<(), Error>,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
F: FnOnce(&mut APIForeign<T, K>) -> Result<(), Error>,
|
||||
K: Keychain,
|
||||
{
|
||||
wallet.open_with_credentials()?;
|
||||
f(&mut APIForeign::new(wallet))?;
|
||||
|
@ -62,14 +66,13 @@ where
|
|||
|
||||
/// Listener version, providing same API but listening for requests on a
|
||||
/// 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
|
||||
T: WalletBackend,
|
||||
OwnerAPIHandler<T>: Handler,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
OwnerAPIHandler<T, K>: Handler,
|
||||
K: Keychain,
|
||||
{
|
||||
let api_handler = OwnerAPIHandler {
|
||||
wallet: Arc::new(Mutex::new(wallet)),
|
||||
};
|
||||
let api_handler = OwnerAPIHandler::new(Arc::new(Mutex::new(wallet)));
|
||||
|
||||
let router = router!(
|
||||
receive_tx: get "/wallet/owner/*" => api_handler,
|
||||
|
@ -89,14 +92,13 @@ where
|
|||
|
||||
/// Listener version, providing same API but listening for requests on a
|
||||
/// 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
|
||||
T: WalletBackend + WalletClient,
|
||||
ForeignAPIHandler<T>: Handler,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
ForeignAPIHandler<T, K>: Handler,
|
||||
K: Keychain,
|
||||
{
|
||||
let api_handler = ForeignAPIHandler {
|
||||
wallet: Arc::new(Mutex::new(wallet)),
|
||||
};
|
||||
let api_handler = ForeignAPIHandler::new(Arc::new(Mutex::new(wallet)));
|
||||
|
||||
let router = router!(
|
||||
receive_tx: post "/wallet/foreign/*" => api_handler,
|
||||
|
@ -115,22 +117,32 @@ where
|
|||
}
|
||||
/// API Handler/Wrapper for owner functions
|
||||
|
||||
pub struct OwnerAPIHandler<T>
|
||||
pub struct OwnerAPIHandler<T, K>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Wallet instance
|
||||
pub wallet: Arc<Mutex<T>>,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<T> OwnerAPIHandler<T>
|
||||
impl<T, K> OwnerAPIHandler<T, K>
|
||||
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(
|
||||
&self,
|
||||
req: &mut Request,
|
||||
api: &mut APIOwner<T>,
|
||||
api: &mut APIOwner<T, K>,
|
||||
) -> Result<Vec<OutputData>, Error> {
|
||||
let res = api.retrieve_outputs(false)?;
|
||||
Ok(res.1)
|
||||
|
@ -139,23 +151,23 @@ where
|
|||
fn retrieve_summary_info(
|
||||
&self,
|
||||
req: &mut Request,
|
||||
api: &mut APIOwner<T>,
|
||||
api: &mut APIOwner<T, K>,
|
||||
) -> Result<WalletInfo, Error> {
|
||||
let res = api.retrieve_summary_info()?;
|
||||
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
|
||||
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
|
||||
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 path_elems = url.path();
|
||||
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
|
||||
T: WalletBackend + WalletClient + Send + Sync + 'static,
|
||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||
// every request should open with stored credentials,
|
||||
|
@ -199,19 +212,33 @@ where
|
|||
|
||||
/// API Handler/Wrapper for foreign functions
|
||||
|
||||
pub struct ForeignAPIHandler<T>
|
||||
pub struct ForeignAPIHandler<T, K>
|
||||
where
|
||||
T: WalletBackend + WalletClient,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Wallet instance
|
||||
pub wallet: Arc<Mutex<T>>,
|
||||
phantom: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<T> ForeignAPIHandler<T>
|
||||
impl<T, K> ForeignAPIHandler<T, K>
|
||||
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>>();
|
||||
match struct_body {
|
||||
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>>();
|
||||
if let Ok(Some(mut slate)) = struct_body {
|
||||
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 path_elems = url.path();
|
||||
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
|
||||
T: WalletBackend + WalletClient + Send + Sync + 'static,
|
||||
T: WalletBackend<K> + WalletClient + Send + Sync + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
fn handle(&self, req: &mut Request) -> IronResult<Response> {
|
||||
// every request should open with stored credentials,
|
||||
|
|
|
@ -13,22 +13,24 @@
|
|||
// limitations under the License.
|
||||
|
||||
//! Wallet key management functions
|
||||
use keychain::Identifier;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use libwallet::error::Error;
|
||||
use libwallet::types::WalletBackend;
|
||||
|
||||
/// 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
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
wallet.with_wallet(|wallet_data| next_available_key(wallet_data))
|
||||
}
|
||||
|
||||
/// 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
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
let root_key_id = wallet.keychain().root_key_id();
|
||||
let derivation = wallet.next_child(root_key_id.clone());
|
||||
|
@ -37,9 +39,10 @@ where
|
|||
}
|
||||
|
||||
/// 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
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
if let Some(existing) = wallet.get_output(&key_id) {
|
||||
let key_id = existing.key_id.clone();
|
||||
|
|
|
@ -20,7 +20,7 @@ use core::core::transaction::ProofMessageElements;
|
|||
use core::global;
|
||||
use error::{Error, ErrorKind};
|
||||
use failure::{Fail, ResultExt};
|
||||
use keychain::Identifier;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use libtx::proof;
|
||||
use libwallet::types::*;
|
||||
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
|
||||
T: WalletBackend + WalletClient,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
let query_param = format!("start_index={}&max={}", start_height, max);
|
||||
|
||||
|
@ -75,7 +76,7 @@ where
|
|||
}
|
||||
|
||||
// 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,
|
||||
outputs: Vec<api::OutputPrintable>,
|
||||
found_key_index: &mut Vec<u32>,
|
||||
|
@ -88,7 +89,11 @@ fn find_outputs_with_key<T: WalletBackend + WalletClient>(
|
|||
u64,
|
||||
bool,
|
||||
Option<MerkleProofWrapper>,
|
||||
)> {
|
||||
)>
|
||||
where
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
let mut wallet_outputs: Vec<(
|
||||
pedersen::Commitment,
|
||||
Identifier,
|
||||
|
@ -225,7 +230,11 @@ fn find_outputs_with_key<T: WalletBackend + WalletClient>(
|
|||
}
|
||||
|
||||
/// 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
|
||||
let is_empty = wallet
|
||||
.read_wallet(|wallet_data| Ok(wallet_data.outputs().len() == 0))
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
//! Selection of inputs for building transactions
|
||||
|
||||
use keychain::Identifier;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use libtx::{build, tx_fee, slate::Slate};
|
||||
use libwallet::error::{Error, ErrorKind};
|
||||
use libwallet::internal::{keys, sigcontext};
|
||||
|
@ -25,7 +25,7 @@ use libwallet::types::*;
|
|||
/// and saves the private wallet identifiers of our selected outputs
|
||||
/// into our transaction context
|
||||
|
||||
pub fn build_send_tx_slate<T>(
|
||||
pub fn build_send_tx_slate<T, K>(
|
||||
wallet: &mut T,
|
||||
num_participants: usize,
|
||||
amount: u64,
|
||||
|
@ -43,7 +43,8 @@ pub fn build_send_tx_slate<T>(
|
|||
Error,
|
||||
>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
let (elems, inputs, change_id, amount, fee) = select_send_tx(
|
||||
wallet,
|
||||
|
@ -107,7 +108,7 @@ where
|
|||
/// returning the key of the fresh output and a closure
|
||||
/// that actually performs the addition of the output to the
|
||||
/// wallet
|
||||
pub fn build_recipient_output_with_slate<T>(
|
||||
pub fn build_recipient_output_with_slate<T, K>(
|
||||
wallet: &mut T,
|
||||
slate: &mut Slate,
|
||||
) -> Result<
|
||||
|
@ -119,25 +120,27 @@ pub fn build_recipient_output_with_slate<T>(
|
|||
Error,
|
||||
>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
// Create a potential output for this transaction
|
||||
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 amount = slate.amount;
|
||||
let height = slate.height;
|
||||
|
||||
let keychain = wallet.keychain().clone();
|
||||
|
||||
let blinding =
|
||||
slate.add_transaction_elements(&keychain, vec![build::output(amount, key_id.clone())])?;
|
||||
|
||||
// Add blinding sum to our context
|
||||
let mut context = sigcontext::Context::new(
|
||||
keychain.secp(),
|
||||
blinding.secret_key(wallet.keychain().secp()).unwrap(),
|
||||
blinding
|
||||
.secret_key(wallet.keychain().clone().secp())
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
context.add_output(&key_id);
|
||||
|
@ -166,7 +169,7 @@ where
|
|||
/// 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,
|
||||
/// selecting outputs to spend and building the change.
|
||||
pub fn select_send_tx<T>(
|
||||
pub fn select_send_tx<T, K>(
|
||||
wallet: &mut T,
|
||||
amount: u64,
|
||||
current_height: u64,
|
||||
|
@ -176,7 +179,7 @@ pub fn select_send_tx<T>(
|
|||
selection_strategy_is_use_all: bool,
|
||||
) -> Result<
|
||||
(
|
||||
Vec<Box<build::Append>>,
|
||||
Vec<Box<build::Append<K>>>,
|
||||
Vec<OutputData>,
|
||||
Option<Identifier>,
|
||||
u64, // amount
|
||||
|
@ -185,9 +188,10 @@ pub fn select_send_tx<T>(
|
|||
Error,
|
||||
>
|
||||
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
|
||||
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
|
||||
pub fn inputs_and_change<T>(
|
||||
pub fn inputs_and_change<T, K>(
|
||||
coins: &Vec<OutputData>,
|
||||
wallet: &mut T,
|
||||
height: u64,
|
||||
amount: u64,
|
||||
fee: u64,
|
||||
) -> Result<(Vec<Box<build::Append>>, Option<Identifier>), Error>
|
||||
) -> Result<(Vec<Box<build::Append<K>>>, Option<Identifier>), Error>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
let mut parts = vec![];
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//! Signature context holder helper (may be removed or replaced eventually)
|
||||
use keychain::extkey::Identifier;
|
||||
use keychain::Identifier;
|
||||
use libtx::aggsig;
|
||||
use util::secp::key::{PublicKey, SecretKey};
|
||||
use util::secp::{self, Secp256k1};
|
||||
|
|
|
@ -25,7 +25,11 @@ use util::LOGGER;
|
|||
|
||||
/// Receive a tranaction, modifying the slate accordingly (which can then be
|
||||
/// 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
|
||||
let (_, mut context, receiver_create_fn) =
|
||||
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
|
||||
/// wallet
|
||||
pub fn create_send_tx<T: WalletBackend + WalletClient>(
|
||||
pub fn create_send_tx<T, K>(
|
||||
wallet: &mut T,
|
||||
amount: u64,
|
||||
minimum_confirmations: u64,
|
||||
|
@ -62,7 +66,11 @@ pub fn create_send_tx<T: WalletBackend + WalletClient>(
|
|||
impl FnOnce(&mut T) -> Result<(), Error>,
|
||||
),
|
||||
Error,
|
||||
> {
|
||||
>
|
||||
where
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
// Get lock height
|
||||
let current_height = wallet.get_chain_height(wallet.node_url())?;
|
||||
// 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
|
||||
pub fn complete_tx<T: WalletBackend>(
|
||||
pub fn complete_tx<T, K>(
|
||||
wallet: &mut T,
|
||||
slate: &mut Slate,
|
||||
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)?;
|
||||
// Final transaction can be built by anyone at this stage
|
||||
let res = slate.finalize(wallet.keychain());
|
||||
|
@ -117,13 +129,20 @@ pub fn complete_tx<T: WalletBackend>(
|
|||
}
|
||||
|
||||
/// Issue a burn tx
|
||||
pub fn issue_burn_tx<T: WalletBackend + WalletClient>(
|
||||
pub fn issue_burn_tx<T, K>(
|
||||
wallet: &mut T,
|
||||
amount: u64,
|
||||
minimum_confirmations: u64,
|
||||
max_outputs: usize,
|
||||
) -> Result<Transaction, Error> {
|
||||
let keychain = &Keychain::burn_enabled(wallet.keychain(), &Identifier::zero());
|
||||
) -> Result<Transaction, Error>
|
||||
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())?;
|
||||
|
||||
|
@ -159,14 +178,14 @@ pub fn issue_burn_tx<T: WalletBackend + WalletClient>(
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use keychain::Keychain;
|
||||
use keychain::{ExtKeychain, Keychain};
|
||||
use libtx::build;
|
||||
|
||||
#[test]
|
||||
// demonstrate that input.commitment == referenced output.commitment
|
||||
// based on the public key and amount begin spent
|
||||
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 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::global;
|
||||
use core::ser;
|
||||
use keychain::Identifier;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use libtx::reward;
|
||||
use libwallet::error::{Error, ErrorKind};
|
||||
use libwallet::internal::keys;
|
||||
|
@ -33,10 +33,11 @@ use util::LOGGER;
|
|||
use util::secp::pedersen;
|
||||
|
||||
/// Retrieve all of the outputs (doesn't attempt to update from node)
|
||||
pub fn retrieve_outputs<T: WalletBackend>(
|
||||
wallet: &mut T,
|
||||
show_spent: bool,
|
||||
) -> Result<Vec<OutputData>, Error> {
|
||||
pub fn retrieve_outputs<T, K>(wallet: &mut T, show_spent: bool) -> Result<Vec<OutputData>, Error>
|
||||
where
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
let root_key_id = wallet.keychain().clone().root_key_id();
|
||||
|
||||
let mut outputs = vec![];
|
||||
|
@ -66,9 +67,10 @@ pub fn retrieve_outputs<T: WalletBackend>(
|
|||
|
||||
/// Refreshes the outputs in a wallet with the latest information
|
||||
/// 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
|
||||
T: WalletBackend + WalletClient,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
let height = wallet.get_chain_height(wallet.node_url())?;
|
||||
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
|
||||
// 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
|
||||
T: WalletBackend + WalletClient,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
// build a local map of wallet outputs keyed by commit
|
||||
// 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
|
||||
/// 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,
|
||||
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
||||
let _ = wallet.read_wallet(|wallet_data| {
|
||||
|
@ -150,19 +154,21 @@ where
|
|||
|
||||
/// As above, but only return unspent outputs with missing block hashes
|
||||
/// 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,
|
||||
) -> Result<HashMap<pedersen::Commitment, Identifier>, Error>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
let mut wallet_outputs: HashMap<pedersen::Commitment, Identifier> = HashMap::new();
|
||||
let _ = wallet.read_wallet(|wallet_data| {
|
||||
let keychain = wallet_data.keychain().clone();
|
||||
for out in wallet_data.outputs().clone().values().filter(|x| {
|
||||
x.root_key_id == wallet_data.keychain().root_key_id() && x.block.is_none()
|
||||
let unspents = wallet_data.outputs().values().filter(|x| {
|
||||
x.root_key_id == keychain.root_key_id() && x.block.is_none()
|
||||
&& x.status == OutputStatus::Unspent
|
||||
}) {
|
||||
});
|
||||
for out in unspents {
|
||||
let commit = keychain.commit_with_key_index(out.value, out.n_child)?;
|
||||
wallet_outputs.insert(commit, out.key_id.clone());
|
||||
}
|
||||
|
@ -172,13 +178,14 @@ where
|
|||
}
|
||||
|
||||
/// 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_outputs: &HashMap<pedersen::Commitment, Identifier>,
|
||||
api_outputs: &HashMap<pedersen::Commitment, String>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
// 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.
|
||||
|
@ -198,9 +205,10 @@ where
|
|||
|
||||
/// Builds a single api query to retrieve the latest output data from the node.
|
||||
/// 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
|
||||
T: WalletBackend + WalletClient,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
debug!(LOGGER, "Refreshing wallet outputs");
|
||||
|
||||
|
@ -216,9 +224,10 @@ where
|
|||
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
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
if height < 500 {
|
||||
return Ok(());
|
||||
|
@ -231,10 +240,11 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
/// Retrieve summary info about the wallet
|
||||
pub fn retrieve_info<T>(wallet: &mut T) -> Result<WalletInfo, Error>
|
||||
/// Retrieve summar info about the wallet
|
||||
pub fn retrieve_info<T, K>(wallet: &mut T) -> Result<WalletInfo, Error>
|
||||
where
|
||||
T: WalletBackend + WalletClient,
|
||||
T: WalletBackend<K> + WalletClient,
|
||||
K: Keychain,
|
||||
{
|
||||
let result = refresh_outputs(wallet);
|
||||
|
||||
|
@ -291,9 +301,10 @@ where
|
|||
}
|
||||
|
||||
/// 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
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
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
|
||||
/// Build a coinbase output and the corresponding kernel
|
||||
pub fn receive_coinbase<T>(
|
||||
pub fn receive_coinbase<T, K>(
|
||||
wallet: &mut T,
|
||||
block_fees: &BlockFees,
|
||||
) -> Result<(Output, TxKernel, BlockFees), Error>
|
||||
where
|
||||
T: WalletBackend,
|
||||
T: WalletBackend<K>,
|
||||
K: Keychain,
|
||||
{
|
||||
let root_key_id = wallet.keychain().root_key_id();
|
||||
|
||||
|
@ -365,7 +377,7 @@ where
|
|||
debug!(LOGGER, "receive_coinbase: {:?}", block_fees);
|
||||
|
||||
let (out, kern) = reward::output(
|
||||
&wallet.keychain(),
|
||||
wallet.keychain(),
|
||||
&key_id,
|
||||
block_fees.fees,
|
||||
block_fees.height,
|
||||
|
|
|
@ -36,7 +36,10 @@ use util::secp::pedersen;
|
|||
/// Wallets should implement this backend for their storage. All functions
|
||||
/// here expect that the wallet instance has instantiated itself or stored
|
||||
/// whatever credentials it needs
|
||||
pub trait WalletBackend {
|
||||
pub trait WalletBackend<K>
|
||||
where
|
||||
K: Keychain,
|
||||
{
|
||||
/// Initialise with whatever stored credentials we have
|
||||
fn open_with_credentials(&mut self) -> Result<(), Error>;
|
||||
|
||||
|
@ -44,7 +47,7 @@ pub trait WalletBackend {
|
|||
fn close(&mut self) -> Result<(), Error>;
|
||||
|
||||
/// Return the keychain being used
|
||||
fn keychain(&mut self) -> &mut Keychain;
|
||||
fn keychain(&mut self) -> &mut K;
|
||||
|
||||
/// Return the outputs directly
|
||||
fn outputs(&mut self) -> &mut HashMap<String, OutputData>;
|
||||
|
|
|
@ -27,6 +27,7 @@ use chain::Chain;
|
|||
use core::core::hash::Hashed;
|
||||
use core::core::{Output, OutputFeatures, OutputIdentifier, Transaction, TxKernel};
|
||||
use core::{consensus, global, pow};
|
||||
use keychain::ExtKeychain;
|
||||
use wallet::file_wallet::*;
|
||||
use wallet::libwallet::internal::updater;
|
||||
use wallet::libwallet::types::*;
|
||||
|
@ -37,10 +38,11 @@ use util::secp::pedersen;
|
|||
|
||||
/// Mostly for testing, refreshes output state against a local chain instance
|
||||
/// instead of via an http API call
|
||||
pub fn refresh_output_state_local<T: WalletBackend>(
|
||||
wallet: &mut T,
|
||||
chain: &chain::Chain,
|
||||
) -> Result<(), Error> {
|
||||
pub fn refresh_output_state_local<T, K>(wallet: &mut T, chain: &chain::Chain) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<K>,
|
||||
K: keychain::Keychain,
|
||||
{
|
||||
let wallet_outputs = updater::map_wallet_outputs(wallet)?;
|
||||
let chain_outputs: Vec<Option<api::Output>> = wallet_outputs
|
||||
.keys()
|
||||
|
@ -66,10 +68,14 @@ pub fn refresh_output_state_local<T: WalletBackend>(
|
|||
/// (0:total, 1:amount_awaiting_confirmation, 2:confirmed but locked,
|
||||
/// 3:currently_spendable, 4:locked total) TODO: Should be a wallet lib
|
||||
/// function with nicer return values
|
||||
pub fn get_wallet_balances<T: WalletBackend>(
|
||||
pub fn get_wallet_balances<T, K>(
|
||||
wallet: &mut T,
|
||||
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 mut unspent_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
|
||||
/// the block and adds it to the chain, with option transactions included.
|
||||
/// Helpful for building up precise wallet balances for testing.
|
||||
pub fn award_block_to_wallet<T: WalletBackend>(
|
||||
chain: &Chain,
|
||||
txs: Vec<&Transaction>,
|
||||
wallet: &mut T,
|
||||
) {
|
||||
pub fn award_block_to_wallet<T, K>(chain: &Chain, txs: Vec<&Transaction>, wallet: &mut T)
|
||||
where
|
||||
T: WalletBackend<K>,
|
||||
K: keychain::Keychain,
|
||||
{
|
||||
let prev = chain.head_header().unwrap();
|
||||
let fee_amt = txs.iter().map(|tx| tx.fee()).sum();
|
||||
let fees = BlockFees {
|
||||
|
@ -188,14 +194,18 @@ pub fn award_block_to_wallet<T: WalletBackend>(
|
|||
}
|
||||
|
||||
/// 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 {
|
||||
award_block_to_wallet(chain, vec![], wallet);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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();
|
||||
wallet_config.data_file_dir = String::from(dir);
|
||||
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 uuid;
|
||||
|
||||
use keychain::{BlindSum, BlindingFactor, Keychain};
|
||||
use keychain::{BlindSum, BlindingFactor, ExtKeychain, Keychain};
|
||||
use util::secp::key::{PublicKey, SecretKey};
|
||||
use util::secp::pedersen::ProofMessage;
|
||||
use util::{kernel_sig_msg, secp};
|
||||
|
@ -31,8 +31,8 @@ use rand::thread_rng;
|
|||
|
||||
#[test]
|
||||
fn aggsig_sender_receiver_interaction() {
|
||||
let sender_keychain = Keychain::from_random_seed().unwrap();
|
||||
let receiver_keychain = Keychain::from_random_seed().unwrap();
|
||||
let sender_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let receiver_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
|
||||
// Calculate the kernel excess here for convenience.
|
||||
// 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())
|
||||
.unwrap();
|
||||
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let blinding_factor = keychain
|
||||
.blind_sum(&BlindSum::new()
|
||||
.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
|
||||
{
|
||||
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();
|
||||
|
||||
|
@ -214,8 +214,8 @@ fn aggsig_sender_receiver_interaction() {
|
|||
|
||||
#[test]
|
||||
fn aggsig_sender_receiver_interaction_offset() {
|
||||
let sender_keychain = Keychain::from_random_seed().unwrap();
|
||||
let receiver_keychain = Keychain::from_random_seed().unwrap();
|
||||
let sender_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let receiver_keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
|
||||
// This is the kernel offset that we use to split the key
|
||||
// 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())
|
||||
.unwrap();
|
||||
|
||||
let keychain = Keychain::from_random_seed().unwrap();
|
||||
let keychain = ExtKeychain::from_random_seed().unwrap();
|
||||
let blinding_factor = keychain
|
||||
.blind_sum(&BlindSum::new()
|
||||
.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
|
||||
{
|
||||
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();
|
||||
|
||||
|
@ -406,7 +406,7 @@ fn aggsig_sender_receiver_interaction_offset() {
|
|||
|
||||
#[test]
|
||||
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 commit = keychain.commit(5, &key_id).unwrap();
|
||||
let msg = ProofMessage::from_bytes(&[0u8; 64]);
|
||||
|
|
|
@ -132,7 +132,7 @@ fn build_transaction() {
|
|||
|
||||
let _ = slate
|
||||
.fill_round_2(
|
||||
&wallet1.keychain.as_ref().unwrap(),
|
||||
wallet1.keychain.as_ref().unwrap(),
|
||||
&recp_context.sec_key,
|
||||
&recp_context.sec_nonce,
|
||||
1,
|
||||
|
@ -149,7 +149,7 @@ fn build_transaction() {
|
|||
// SENDER Part 3: Sender confirmation
|
||||
let _ = slate
|
||||
.fill_round_2(
|
||||
&wallet1.keychain.as_ref().unwrap(),
|
||||
wallet1.keychain.as_ref().unwrap(),
|
||||
&sender_context.sec_key,
|
||||
&sender_context.sec_nonce,
|
||||
0,
|
||||
|
@ -161,7 +161,7 @@ fn build_transaction() {
|
|||
debug!(LOGGER, "{:?}", slate);
|
||||
|
||||
// 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 {
|
||||
panic!("Error creating final tx: {:?}", e);
|
||||
|
|
Loading…
Reference in a new issue