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:
@@ -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
@@ -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)
|
||||
|
||||
+70
-31
@@ -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 {
|
||||
|
||||
+19
-11
@@ -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);
|
||||
|
||||
+44
-24
@@ -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
@@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user