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:
Ignotus Peverell
2018-06-08 06:21:54 +01:00
committed by GitHub
parent a6590ea0ae
commit af178f82f8
43 changed files with 840 additions and 678 deletions
+1
View File
@@ -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;
+18 -11
View File
@@ -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 {
+7 -6
View File
@@ -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)
+70 -31
View File
@@ -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();
+1 -12
View File
@@ -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 {
+19 -11
View File
@@ -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()
+8 -5
View File
@@ -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);
+44 -24
View File
@@ -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()?;
+27 -12
View File
@@ -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
+70 -38
View File
@@ -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,
+10 -7
View File
@@ -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();
+15 -6
View File
@@ -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))
+21 -16
View File
@@ -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![];
+1 -1
View File
@@ -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};
+29 -10
View File
@@ -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();
+42 -30
View File
@@ -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,
+5 -2
View File
@@ -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>;