TTL Implementation (#261)

* refactor address generation code into libwallet, bool to flag whether to include proof, add sender address in init_send_tx

* rustfmt

* require payment proof addr as part of init_tx

* rustfmt

* store payment proof on sender transaction side

* rustfmt

* change sig to ed25519 sig

* rustfmt

* add message creation and signature

* rustfmt

* add payment proof verification function

* rustfmt

* validate proof on sender side, store proof

* rustfmt

* fix json tests

* fixes and updates to tests

* added API functions for converting and retrieving proof addresses

* rustfmt

* add payment proof to init_send_tx example

* rustfmt

* incorrect comment

* add commands for requesting payment proofs

* rustfmt

* wire up payment proofs into command line

* rustfmt

* add address command

* rustfmt

* added tor sending from owner api

* rustfmt

* add TTL to slate, transaction log

* ttl cutoff tests

* add ttl check to recieve functions, add tests, modify doctests

* rustfmt

* fixes from upstream changes and test fixes

* rustfmt

* remove unnecessary block header version check
This commit is contained in:
Yeastplume
2019-12-02 13:54:57 +00:00
committed by GitHub
parent 9fd1d49dda
commit 45480392da
25 changed files with 653 additions and 327 deletions
+3
View File
@@ -15,6 +15,7 @@
//! Generic implementation of owner API functions
use strum::IntoEnumIterator;
use crate::api_impl::owner::check_ttl;
use crate::grin_keychain::Keychain;
use crate::grin_util::secp::key::SecretKey;
use crate::internal::{tx, updater};
@@ -70,6 +71,7 @@ where
K: Keychain + 'a,
{
let mut ret_slate = slate.clone();
check_ttl(w, &ret_slate)?;
let parent_key_id = match dest_acct_name {
Some(d) => {
let pm = w.get_acct_path(d.to_owned())?;
@@ -143,6 +145,7 @@ where
K: Keychain + 'a,
{
let mut sl = slate.clone();
check_ttl(w, &sl)?;
let context = w.get_private_context(keychain_mask, sl.id.as_bytes(), 1)?;
tx::complete_tx(&mut *w, keychain_mask, &mut sl, 1, &context)?;
tx::update_stored_tx(&mut *w, keychain_mask, &context, &mut sl, true)?;
+45 -8
View File
@@ -224,7 +224,7 @@ where
None => None,
};
let mut slate = tx::new_tx_slate(&mut *w, args.amount, 2, use_test_rng)?;
let mut slate = tx::new_tx_slate(&mut *w, args.amount, 2, use_test_rng, args.ttl_blocks)?;
// if we just want to estimate, don't save a context, just send the results
// back
@@ -324,7 +324,7 @@ where
None => None,
};
let mut slate = tx::new_tx_slate(&mut *w, args.amount, 2, use_test_rng)?;
let mut slate = tx::new_tx_slate(&mut *w, args.amount, 2, use_test_rng, None)?;
let context = tx::add_output_to_slate(
&mut *w,
keychain_mask,
@@ -366,6 +366,7 @@ where
K: Keychain + 'a,
{
let mut ret_slate = slate.clone();
check_ttl(w, &ret_slate)?;
let parent_key_id = match args.src_acct_name {
Some(d) => {
let pm = w.get_acct_path(d.to_owned())?;
@@ -401,6 +402,11 @@ where
// update slate current height
ret_slate.height = w.w2n_client().get_chain_tip()?.0;
// update ttl if desired
if let Some(b) = args.ttl_blocks {
ret_slate.ttl_cutoff_height = Some(ret_slate.height + b);
}
let context = tx::add_inputs_to_slate(
&mut *w,
keychain_mask,
@@ -459,6 +465,7 @@ where
K: Keychain + 'a,
{
let mut sl = slate.clone();
check_ttl(w, &sl)?;
let context = w.get_private_context(keychain_mask, sl.id.as_bytes(), 0)?;
let parent_key_id = w.parent_key_id();
tx::complete_tx(&mut *w, keychain_mask, &mut sl, 0, &context)?;
@@ -733,16 +740,46 @@ where
info.hash = tip.1;
wallet_lock!(wallet_inst, w);
let mut batch = w.batch(keychain_mask)?;
batch.save_last_scanned_block(info)?;
// init considered complete after first successful update
batch.save_init_status(WalletInitStatus::InitComplete)?;
batch.commit()?;
{
wallet_lock!(wallet_inst, w);
let mut batch = w.batch(keychain_mask)?;
batch.save_last_scanned_block(info)?;
// init considered complete after first successful update
batch.save_init_status(WalletInitStatus::InitComplete)?;
batch.commit()?;
}
// Step 5: Cancel any transactions with an expired TTL
for tx in txs {
if let Some(e) = tx.ttl_cutoff_height {
if e >= tip.0 {
wallet_lock!(wallet_inst, w);
let parent_key_id = w.parent_key_id();
tx::cancel_tx(&mut **w, keychain_mask, &parent_key_id, Some(tx.id), None)?;
}
}
}
Ok(result)
}
/// Check TTL
pub fn check_ttl<'a, T: ?Sized, C, K>(w: &mut T, slate: &Slate) -> Result<(), Error>
where
T: WalletBackend<'a, C, K>,
C: NodeClient + 'a,
K: Keychain + 'a,
{
// Refuse if TTL is expired
let last_confirmed_height = w.last_confirmed_height()?;
if let Some(e) = slate.ttl_cutoff_height {
if last_confirmed_height >= e {
return Err(ErrorKind::TransactionExpired)?;
}
}
Ok(())
}
/// Attempt to update outputs in wallet, return whether it was successful
fn update_outputs<'a, L, C, K>(
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
+4
View File
@@ -89,6 +89,9 @@ pub struct InitTxArgs {
/// down to the minimum slate version compatible with the current. If `None` the slate
/// is generated with the latest version.
pub target_slate_version: Option<u16>,
/// Number of blocks from current after which TX should be ignored
#[serde(with = "secp_ser::opt_string_or_u64")]
pub ttl_blocks: Option<u64>,
/// If set, require a payment proof for the particular recipient
#[serde(with = "dalek_ser::option_dalek_pubkey_serde")]
pub payment_proof_recipient_address: Option<DalekPublicKey>,
@@ -129,6 +132,7 @@ impl Default for InitTxArgs {
selection_strategy_is_use_all: true,
message: None,
target_slate_version: None,
ttl_blocks: None,
estimate_only: Some(false),
payment_proof_recipient_address: None,
send_args: None,