diff --git a/src/bin/cmd/client.rs b/src/bin/cmd/client.rs index 78a20ef2c..714c9521d 100644 --- a/src/bin/cmd/client.rs +++ b/src/bin/cmd/client.rs @@ -13,7 +13,6 @@ // limitations under the License. /// Grin client commands processing - use std::net::SocketAddr; use clap::ArgMatches; diff --git a/src/bin/cmd/wallet.rs b/src/bin/cmd/wallet.rs index 6e6a4bba6..27f093714 100644 --- a/src/bin/cmd/wallet.rs +++ b/src/bin/cmd/wallet.rs @@ -247,12 +247,7 @@ pub fn wallet_command(wallet_args: &ArgMatches, global_config: GlobalConfig) { let tx_file = send_args .value_of("input") .expect("Receiver's transaction file required"); - let priv_file = send_args - .value_of("private") - .expect("Private transaction file required"); - let slate = api - .file_finalize_tx(priv_file, tx_file) - .expect("Finalize failed"); + let slate = api.file_finalize_tx(tx_file).expect("Finalize failed"); let result = api.post_tx(&slate, fluff); match result { diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 7539451a7..e653e4855 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -208,7 +208,7 @@ fn main() { .default_value("1") .takes_value(true)) .arg(Arg::with_name("dest") - .help("Send the transaction to the provided server") + .help("Send the transaction to the provided server (start with http://) or save as file.") .short("d") .long("dest") .takes_value(true)) @@ -232,11 +232,6 @@ fn main() { .short("i") .long("input") .takes_value(true)) - .arg(Arg::with_name("private") - .help("Private transaction file previously generated by send.") - .short("p") - .long("private") - .takes_value(true)) .arg(Arg::with_name("fluff") .help("Fluff the transaction (ignore Dandelion relay protocol)") .short("f") diff --git a/src/bin/tui/peers.rs b/src/bin/tui/peers.rs index 40a2f11d1..a53036a04 100644 --- a/src/bin/tui/peers.rs +++ b/src/bin/tui/peers.rs @@ -80,15 +80,14 @@ pub struct TUIPeerView; impl TUIStatusListener for TUIPeerView { fn create() -> Box { - let table_view = - TableView::::new() - .column(PeerColumn::Address, "Address", |c| c.width_percent(20)) - .column(PeerColumn::State, "State", |c| c.width_percent(20)) - .column(PeerColumn::Direction, "Direction", |c| c.width_percent(20)) - .column(PeerColumn::TotalDifficulty, "Total Difficulty", |c| { - c.width_percent(20) - }) - .column(PeerColumn::Version, "Version", |c| c.width_percent(20)); + let table_view = TableView::::new() + .column(PeerColumn::Address, "Address", |c| c.width_percent(20)) + .column(PeerColumn::State, "State", |c| c.width_percent(20)) + .column(PeerColumn::Direction, "Direction", |c| c.width_percent(20)) + .column(PeerColumn::TotalDifficulty, "Total Difficulty", |c| { + c.width_percent(20) + }) + .column(PeerColumn::Version, "Version", |c| c.width_percent(20)); let peer_status_view = BoxView::with_full_screen( LinearLayout::new(Orientation::Vertical) .child( diff --git a/src/bin/tui/table.rs b/src/bin/tui/table.rs index 76e9d6f1e..43977207b 100644 --- a/src/bin/tui/table.rs +++ b/src/bin/tui/table.rs @@ -664,7 +664,8 @@ impl, H: Eq + Hash + Copy + Clone + 'static> TableView fn column_select(&mut self) { let next = self.active_column(); let column = self.columns[next].column; - let current = self.columns + let current = self + .columns .iter() .position(|c| c.order != Ordering::Equal) .unwrap_or(0); @@ -736,10 +737,10 @@ impl + 'static, H: Eq + Hash + Copy + Clone + 'static> View let column_count = self.columns.len(); // Split up all columns into sized / unsized groups - let (mut sized, mut usized): (Vec<&mut TableColumn>, Vec<&mut TableColumn>) = - self.columns - .iter_mut() - .partition(|c| c.requested_width.is_some()); + let (mut sized, mut usized): (Vec<&mut TableColumn>, Vec<&mut TableColumn>) = self + .columns + .iter_mut() + .partition(|c| c.requested_width.is_some()); // Subtract one for the separators between our columns (that's column_count - 1) let mut available_width = size.x.saturating_sub(column_count.saturating_sub(1) * 3); diff --git a/wallet/src/file_wallet.rs b/wallet/src/file_wallet.rs index 6d9153f8d..ddecb153a 100644 --- a/wallet/src/file_wallet.rs +++ b/wallet/src/file_wallet.rs @@ -35,7 +35,7 @@ use error::{Error, ErrorKind}; use libwallet; use libwallet::types::{ - OutputData, TxLogEntry, WalletBackend, WalletClient, WalletDetails, WalletOutputBatch, + Context, OutputData, TxLogEntry, WalletBackend, WalletClient, WalletDetails, WalletOutputBatch, }; use types::{WalletConfig, WalletSeed}; @@ -121,6 +121,18 @@ where unimplemented!() } + fn save_private_context( + &mut self, + _slate_id: &[u8], + _ctx: &Context, + ) -> Result<(), libwallet::Error> { + unimplemented!() + } + + fn delete_private_context(&mut self, _slate_id: &[u8]) -> Result<(), libwallet::Error> { + unimplemented!() + } + fn commit(&self) -> Result<(), libwallet::Error> { let mut data_file = File::create(self.data_file_path.clone()) .context(libwallet::ErrorKind::CallbackImpl("Could not create"))?; @@ -239,6 +251,10 @@ where Box::new(self.tx_log.iter().cloned()) } + fn get_private_context(&mut self, _slate_id: &[u8]) -> Result { + unimplemented!() + } + fn get(&self, id: &Identifier) -> Result { self.outputs .get(&id.to_hex()) diff --git a/wallet/src/libwallet/api.rs b/wallet/src/libwallet/api.rs index 889f9e99d..361ae3392 100644 --- a/wallet/src/libwallet/api.rs +++ b/wallet/src/libwallet/api.rs @@ -28,7 +28,7 @@ use core::core::hash::Hashed; use core::ser; use keychain::Keychain; use libtx::slate::Slate; -use libwallet::internal::{selection, sigcontext, tx, updater}; +use libwallet::internal::{selection, tx, updater}; use libwallet::types::{ BlockFees, CbData, OutputData, TxLogEntry, TxWrapper, WalletBackend, WalletClient, WalletInfo, }; @@ -207,9 +207,12 @@ where let mut pub_tx = File::create(dest)?; pub_tx.write_all(json::to_string(&slate).unwrap().as_bytes())?; pub_tx.sync_all()?; - let mut priv_tx = File::create(dest.to_owned() + ".private")?; - priv_tx.write_all(json::to_string(&context).unwrap().as_bytes())?; - priv_tx.sync_all()?; + + { + let mut batch = w.batch()?; + batch.save_private_context(slate.id.as_bytes(), &context)?; + batch.commit()?; + } // lock our inputs lock_fn(&mut **w)?; @@ -259,23 +262,24 @@ where /// propagation. pub fn file_finalize_tx( &mut self, - private_tx_file: &str, receiver_file: &str, ) -> Result { + let mut pub_tx_f = File::open(receiver_file)?; let mut content = String::new(); pub_tx_f.read_to_string(&mut content)?; let mut slate: Slate = json::from_str(&content).map_err(|_| ErrorKind::Format)?; - let mut priv_tx_f = File::open(private_tx_file)?; - let mut content = String::new(); - priv_tx_f.read_to_string(&mut content)?; - let context: sigcontext::Context = json::from_str(&content).map_err(|_| ErrorKind::Format)?; - let mut w = self.wallet.lock().unwrap(); w.open_with_credentials()?; + let context = w.get_private_context(slate.id.as_bytes())?; tx::complete_tx(&mut **w, &mut slate, &context)?; + { + let mut batch = w.batch()?; + batch.delete_private_context(slate.id.as_bytes())?; + batch.commit()?; + } w.close()?; Ok(slate) diff --git a/wallet/src/libwallet/internal/mod.rs b/wallet/src/libwallet/internal/mod.rs index 46c20f834..46c9bd432 100644 --- a/wallet/src/libwallet/internal/mod.rs +++ b/wallet/src/libwallet/internal/mod.rs @@ -24,6 +24,5 @@ pub mod keys; pub mod restore; pub mod selection; -pub mod sigcontext; pub mod tx; pub mod updater; diff --git a/wallet/src/libwallet/internal/selection.rs b/wallet/src/libwallet/internal/selection.rs index 4198fdd57..f073d6b37 100644 --- a/wallet/src/libwallet/internal/selection.rs +++ b/wallet/src/libwallet/internal/selection.rs @@ -17,7 +17,7 @@ use keychain::{Identifier, Keychain}; use libtx::{build, slate::Slate, tx_fee}; use libwallet::error::{Error, ErrorKind}; -use libwallet::internal::{keys, sigcontext}; +use libwallet::internal::keys; use libwallet::types::*; use util::LOGGER; @@ -37,14 +37,7 @@ pub fn build_send_tx_slate( max_outputs: usize, change_outputs: usize, selection_strategy_is_use_all: bool, -) -> Result< - ( - Slate, - sigcontext::Context, - impl FnOnce(&mut T) -> Result<(), Error>, - ), - Error, -> +) -> Result<(Slate, Context, impl FnOnce(&mut T) -> Result<(), Error>), Error> where T: WalletBackend, C: WalletClient, @@ -74,7 +67,7 @@ where let blinding = slate.add_transaction_elements(&keychain, elems)?; // Create our own private context - let mut context = sigcontext::Context::new( + let mut context = Context::new( wallet.keychain().secp(), blinding.secret_key(&keychain.secp()).unwrap(), ); @@ -149,7 +142,7 @@ pub fn build_recipient_output_with_slate( ) -> Result< ( Identifier, - sigcontext::Context, + Context, impl FnOnce(&mut T) -> Result<(), Error>, ), Error, @@ -173,7 +166,7 @@ where slate.add_transaction_elements(&keychain, vec![build::output(amount, key_id.clone())])?; // Add blinding sum to our context - let mut context = sigcontext::Context::new( + let mut context = Context::new( keychain.secp(), blinding .secret_key(wallet.keychain().clone().secp()) diff --git a/wallet/src/libwallet/internal/sigcontext.rs b/wallet/src/libwallet/internal/sigcontext.rs deleted file mode 100644 index 2ee07f04d..000000000 --- a/wallet/src/libwallet/internal/sigcontext.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2018 The Grin Developers -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//! Signature context holder helper (may be removed or replaced eventually) -use keychain::Identifier; -use libtx::aggsig; -use util::secp::key::{PublicKey, SecretKey}; -use util::secp::{self, Secp256k1}; - -#[derive(Serialize, Deserialize, Clone, Debug)] -/// Holds the context for a single aggsig transaction -pub struct Context { - /// Secret key (of which public is shared) - pub sec_key: SecretKey, - /// Secret nonce (of which public is shared) - /// (basically a SecretKey) - pub sec_nonce: SecretKey, - /// store my outputs between invocations - pub output_ids: Vec, - /// store my inputs - pub input_ids: Vec, - /// store the calculated fee - pub fee: u64, -} - -impl Context { - /// Create a new context with defaults - pub fn new(secp: &secp::Secp256k1, sec_key: SecretKey) -> Context { - Context { - sec_key: sec_key, - sec_nonce: aggsig::create_secnonce(secp).unwrap(), - input_ids: vec![], - output_ids: vec![], - fee: 0, - } - } -} - -impl Context { - /// Tracks an output contributing to my excess value (if it needs to - /// be kept between invocations - pub fn add_output(&mut self, output_id: &Identifier) { - self.output_ids.push(output_id.clone()); - } - - /// Returns all stored outputs - pub fn get_outputs(&self) -> Vec { - self.output_ids.clone() - } - - /// Tracks IDs of my inputs into the transaction - /// be kept between invocations - pub fn add_input(&mut self, input_id: &Identifier) { - self.input_ids.push(input_id.clone()); - } - - /// Returns all stored input identifiers - pub fn get_inputs(&self) -> Vec { - self.input_ids.clone() - } - - /// Returns private key, private nonce - pub fn get_private_keys(&self) -> (SecretKey, SecretKey) { - (self.sec_key.clone(), self.sec_nonce.clone()) - } - - /// Returns public key, public nonce - pub fn get_public_keys(&self, secp: &Secp256k1) -> (PublicKey, PublicKey) { - ( - PublicKey::from_secret_key(secp, &self.sec_key).unwrap(), - PublicKey::from_secret_key(secp, &self.sec_nonce).unwrap(), - ) - } -} diff --git a/wallet/src/libwallet/internal/tx.rs b/wallet/src/libwallet/internal/tx.rs index 4b070c378..9f612bd6e 100644 --- a/wallet/src/libwallet/internal/tx.rs +++ b/wallet/src/libwallet/internal/tx.rs @@ -18,8 +18,8 @@ use core::core::Transaction; use keychain::{Identifier, Keychain}; use libtx::slate::Slate; use libtx::{build, tx_fee}; -use libwallet::internal::{selection, sigcontext, updater}; -use libwallet::types::{TxLogEntryType, WalletBackend, WalletClient}; +use libwallet::internal::{selection, updater}; +use libwallet::types::{Context, TxLogEntryType, WalletBackend, WalletClient}; use libwallet::{Error, ErrorKind}; use util::LOGGER; @@ -61,14 +61,7 @@ pub fn create_send_tx( max_outputs: usize, num_change_outputs: usize, selection_strategy_is_use_all: bool, -) -> Result< - ( - Slate, - sigcontext::Context, - impl FnOnce(&mut T) -> Result<(), Error>, - ), - Error, -> +) -> Result<(Slate, Context, impl FnOnce(&mut T) -> Result<(), Error>), Error> where T: WalletBackend, C: WalletClient, @@ -117,7 +110,7 @@ where pub fn complete_tx( wallet: &mut T, slate: &mut Slate, - context: &sigcontext::Context, + context: &Context, ) -> Result<(), Error> where T: WalletBackend, diff --git a/wallet/src/libwallet/types.rs b/wallet/src/libwallet/types.rs index 1f3a7f7d7..6d1023869 100644 --- a/wallet/src/libwallet/types.rs +++ b/wallet/src/libwallet/types.rs @@ -30,10 +30,12 @@ use core::ser; use keychain::{Identifier, Keychain}; +use libtx::aggsig; use libtx::slate::Slate; use libwallet::error::{Error, ErrorKind}; -use util::secp::pedersen; +use util::secp::key::{PublicKey, SecretKey}; +use util::secp::{self, pedersen, Secp256k1}; /// Combined trait to allow dynamic wallet dispatch pub trait WalletInst: WalletBackend + Send + Sync + 'static @@ -82,6 +84,9 @@ where /// Get an (Optional) tx log entry by uuid fn get_tx_log_entry(&self, uuid: &Uuid) -> Result, Error>; + /// Retrieves the private context associated with a given slate id + fn get_private_context(&mut self, slate_id: &[u8]) -> Result; + /// Iterate over all output data stored by the backend fn tx_log_iter<'a>(&'a self) -> Box + 'a>; @@ -137,6 +142,12 @@ where /// Save an output as locked in the backend fn lock_output(&mut self, out: &mut OutputData) -> Result<(), Error>; + /// Saves the private context associated with a slate id + fn save_private_context(&mut self, slate_id: &[u8], ctx: &Context) -> Result<(), Error>; + + /// Delete the private context associated with the slate id + fn delete_private_context(&mut self, slate_id: &[u8]) -> Result<(), Error>; + /// Write the wallet data to backend file fn commit(&self) -> Result<(), Error>; } @@ -315,6 +326,85 @@ impl fmt::Display for OutputStatus { } } +#[derive(Serialize, Deserialize, Clone, Debug)] +/// Holds the context for a single aggsig transaction +pub struct Context { + /// Secret key (of which public is shared) + pub sec_key: SecretKey, + /// Secret nonce (of which public is shared) + /// (basically a SecretKey) + pub sec_nonce: SecretKey, + /// store my outputs between invocations + pub output_ids: Vec, + /// store my inputs + pub input_ids: Vec, + /// store the calculated fee + pub fee: u64, +} + +impl Context { + /// Create a new context with defaults + pub fn new(secp: &secp::Secp256k1, sec_key: SecretKey) -> Context { + Context { + sec_key: sec_key, + sec_nonce: aggsig::create_secnonce(secp).unwrap(), + input_ids: vec![], + output_ids: vec![], + fee: 0, + } + } +} + +impl Context { + /// Tracks an output contributing to my excess value (if it needs to + /// be kept between invocations + pub fn add_output(&mut self, output_id: &Identifier) { + self.output_ids.push(output_id.clone()); + } + + /// Returns all stored outputs + pub fn get_outputs(&self) -> Vec { + self.output_ids.clone() + } + + /// Tracks IDs of my inputs into the transaction + /// be kept between invocations + pub fn add_input(&mut self, input_id: &Identifier) { + self.input_ids.push(input_id.clone()); + } + + /// Returns all stored input identifiers + pub fn get_inputs(&self) -> Vec { + self.input_ids.clone() + } + + /// Returns private key, private nonce + pub fn get_private_keys(&self) -> (SecretKey, SecretKey) { + (self.sec_key.clone(), self.sec_nonce.clone()) + } + + /// Returns public key, public nonce + pub fn get_public_keys(&self, secp: &Secp256k1) -> (PublicKey, PublicKey) { + ( + PublicKey::from_secret_key(secp, &self.sec_key).unwrap(), + PublicKey::from_secret_key(secp, &self.sec_nonce).unwrap(), + ) + } +} + +impl ser::Writeable for Context { + fn write(&self, writer: &mut W) -> Result<(), ser::Error> { + writer.write_bytes(&serde_json::to_vec(self).map_err(|_| ser::Error::CorruptedData)?) + } +} + +impl ser::Readable for Context { + fn read(reader: &mut ser::Reader) -> Result { + let data = reader.read_vec()?; + serde_json::from_slice(&data[..]).map_err(|_| ser::Error::CorruptedData) + } +} + /// Block Identifier #[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)] pub struct BlockIdentifier(pub Hash); diff --git a/wallet/src/lmdb_wallet.rs b/wallet/src/lmdb_wallet.rs index 94c6eeccc..4287e96da 100644 --- a/wallet/src/lmdb_wallet.rs +++ b/wallet/src/lmdb_wallet.rs @@ -33,6 +33,7 @@ const COMMITMENT_PREFIX: u8 = 'C' as u8; const OUTPUT_PREFIX: u8 = 'o' as u8; const DERIV_PREFIX: u8 = 'd' as u8; const CONFIRMED_HEIGHT_PREFIX: u8 = 'c' as u8; +const PRIVATE_TX_CONTEXT_PREFIX: u8 = 'p' as u8; const TX_LOG_ENTRY_PREFIX: u8 = 't' as u8; const TX_LOG_ID_PREFIX: u8 = 'i' as u8; @@ -161,6 +162,14 @@ where Box::new(self.db.iter(&[TX_LOG_ENTRY_PREFIX]).unwrap()) } + fn get_private_context(&mut self, slate_id: &[u8]) -> Result { + let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec()); + option_to_not_found( + self.db.get_ser(&ctx_key), + &format!("Slate id: {:x?}", slate_id.to_vec()), + ).map_err(|e| e.into()) + } + fn batch<'a>(&'a mut self) -> Result + 'a>, Error> { Ok(Box::new(Batch { _store: self, @@ -336,6 +345,22 @@ where self.save(out.clone()) } + fn save_private_context(&mut self, slate_id: &[u8], ctx: &Context) -> Result<(), Error> { + let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec()); + self.db.borrow().as_ref().unwrap().put_ser(&ctx_key, &ctx)?; + Ok(()) + } + + fn delete_private_context(&mut self, slate_id: &[u8]) -> Result<(), Error> { + let ctx_key = to_key(PRIVATE_TX_CONTEXT_PREFIX, &mut slate_id.to_vec()); + self.db + .borrow() + .as_ref() + .unwrap() + .delete(&ctx_key) + .map_err(|e| e.into()) + } + fn commit(&self) -> Result<(), Error> { let db = self.db.replace(None); db.unwrap().commit()?; diff --git a/wallet/tests/libwallet.rs b/wallet/tests/libwallet.rs index 81db7eae6..82cb37349 100644 --- a/wallet/tests/libwallet.rs +++ b/wallet/tests/libwallet.rs @@ -24,7 +24,7 @@ use keychain::{BlindSum, BlindingFactor, ExtKeychain, Keychain}; use util::secp::key::{PublicKey, SecretKey}; use util::{kernel_sig_msg, secp}; use wallet::libtx::{aggsig, proof}; -use wallet::libwallet::internal::sigcontext; +use wallet::libwallet::types::Context; use rand::thread_rng; @@ -46,9 +46,11 @@ fn aggsig_sender_receiver_interaction() { let keychain = ExtKeychain::from_random_seed().unwrap(); let blinding_factor = keychain - .blind_sum(&BlindSum::new() - .sub_blinding_factor(BlindingFactor::from_secret_key(skey1)) - .add_blinding_factor(BlindingFactor::from_secret_key(skey2))) + .blind_sum( + &BlindSum::new() + .sub_blinding_factor(BlindingFactor::from_secret_key(skey1)) + .add_blinding_factor(BlindingFactor::from_secret_key(skey2)), + ) .unwrap(); keychain @@ -76,7 +78,7 @@ fn aggsig_sender_receiver_interaction() { let blind = blinding_factor.secret_key(&keychain.secp()).unwrap(); - s_cx = sigcontext::Context::new(&keychain.secp(), blind); + s_cx = Context::new(&keychain.secp(), blind); s_cx.get_public_keys(&keychain.secp()) }; @@ -89,7 +91,7 @@ fn aggsig_sender_receiver_interaction() { // let blind = blind_sum.secret_key(&keychain.secp())?; let blind = keychain.derived_key(&key_id).unwrap(); - rx_cx = sigcontext::Context::new(&keychain.secp(), blind); + rx_cx = Context::new(&keychain.secp(), blind); let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp()); rx_cx.add_output(&key_id); @@ -234,12 +236,14 @@ fn aggsig_sender_receiver_interaction_offset() { let keychain = ExtKeychain::from_random_seed().unwrap(); let blinding_factor = keychain - .blind_sum(&BlindSum::new() + .blind_sum( + &BlindSum::new() .sub_blinding_factor(BlindingFactor::from_secret_key(skey1)) .add_blinding_factor(BlindingFactor::from_secret_key(skey2)) // subtract the kernel offset here like as would when // verifying a kernel signature - .sub_blinding_factor(BlindingFactor::from_secret_key(kernel_offset))) + .sub_blinding_factor(BlindingFactor::from_secret_key(kernel_offset)), + ) .unwrap(); keychain @@ -261,16 +265,18 @@ fn aggsig_sender_receiver_interaction_offset() { // dealing with an input here so we need to negate the blinding_factor // rather than use it as is let blinding_factor = keychain - .blind_sum(&BlindSum::new() + .blind_sum( + &BlindSum::new() .sub_blinding_factor(BlindingFactor::from_secret_key(skey)) // subtract the kernel offset to create an aggsig context // with our "split" key - .sub_blinding_factor(BlindingFactor::from_secret_key(kernel_offset))) + .sub_blinding_factor(BlindingFactor::from_secret_key(kernel_offset)), + ) .unwrap(); let blind = blinding_factor.secret_key(&keychain.secp()).unwrap(); - s_cx = sigcontext::Context::new(&keychain.secp(), blind); + s_cx = Context::new(&keychain.secp(), blind); s_cx.get_public_keys(&keychain.secp()) }; @@ -282,7 +288,7 @@ fn aggsig_sender_receiver_interaction_offset() { let blind = keychain.derived_key(&key_id).unwrap(); - rx_cx = sigcontext::Context::new(&keychain.secp(), blind); + rx_cx = Context::new(&keychain.secp(), blind); let (pub_excess, pub_nonce) = rx_cx.get_public_keys(&keychain.secp()); rx_cx.add_output(&key_id);