TTL Implementation ()

* 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
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 653 additions and 327 deletions

603
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -133,7 +133,7 @@ pub trait ForeignRpc {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "4",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [
@ -253,7 +253,7 @@ pub trait ForeignRpc {
"fee": "7000000",
"height": "5",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"participant_data": [
{
@ -283,7 +283,7 @@ pub trait ForeignRpc {
"height": "5",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [
@ -420,7 +420,7 @@ pub trait ForeignRpc {
"fee": "7000000",
"height": "5",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"participant_data": [
{
@ -455,7 +455,7 @@ pub trait ForeignRpc {
"height": "5",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [

View file

@ -30,8 +30,9 @@ use crate::libwallet::{
NodeHeightResult, OutputCommitMapping, Slate, TxLogEntry, WalletInfo, WalletInst,
WalletLCProvider,
};
use crate::util::logger::LoggingConfig;
use crate::util::secp::key::SecretKey;
use crate::util::{from_hex, static_secp_instance, LoggingConfig, Mutex, ZeroingString};
use crate::util::{from_hex, static_secp_instance, Mutex, ZeroingString};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::{channel, Sender};
use std::sync::Arc;

View file

@ -239,6 +239,7 @@ pub trait OwnerRpc: Sync + Send {
"num_outputs": 1,
"parent_key_id": "0200000000000000000000000000000000",
"stored_tx": null,
"ttl_cutoff_height": null,
"tx_slate_id": null,
"payment_proof": null,
"tx_type": "ConfirmedCoinbase"
@ -258,6 +259,7 @@ pub trait OwnerRpc: Sync + Send {
"num_outputs": 1,
"parent_key_id": "0200000000000000000000000000000000",
"stored_tx": null,
"ttl_cutoff_height": null,
"tx_slate_id": null,
"payment_proof": null,
"tx_type": "ConfirmedCoinbase"
@ -343,6 +345,7 @@ pub trait OwnerRpc: Sync + Send {
"message": "my message",
"target_slate_version": null,
"payment_proof_recipient_address": null,
"ttl_blocks": null,
"send_args": null
}
},
@ -361,7 +364,7 @@ pub trait OwnerRpc: Sync + Send {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [
@ -448,7 +451,7 @@ pub trait OwnerRpc: Sync + Send {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [
@ -514,7 +517,7 @@ pub trait OwnerRpc: Sync + Send {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [
@ -565,6 +568,7 @@ pub trait OwnerRpc: Sync + Send {
"message": "Ok, here are your grins",
"target_slate_version": null,
"payment_proof_recipient_address": null,
"ttl_blocks": null,
"send_args": null
}
],
@ -583,7 +587,7 @@ pub trait OwnerRpc: Sync + Send {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [
@ -671,7 +675,7 @@ pub trait OwnerRpc: Sync + Send {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "4",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [
@ -760,7 +764,7 @@ pub trait OwnerRpc: Sync + Send {
},
"num_participants": 2,
"id": "0436430c-2b02-624c-2032-570501212b00",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"tx": {
"offset": "d202964900000000d302964900000000d402964900000000d502964900000000",
@ -835,7 +839,7 @@ pub trait OwnerRpc: Sync + Send {
"fee": "7000000",
"height": "5",
"id": "0436430c-2b02-624c-2032-570501212b00",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"lock_height": "0",
"num_participants": 2,
@ -1116,7 +1120,7 @@ pub trait OwnerRpc: Sync + Send {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "4",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"payment_proof": null,
"num_participants": 2,
"participant_data": [

View file

@ -25,8 +25,9 @@ use crate::libwallet::{
OutputCommitMapping, Slate, SlateVersion, StatusMessage, TxLogEntry, VersionedSlate,
WalletInfo, WalletLCProvider,
};
use crate::util::logger::LoggingConfig;
use crate::util::secp::key::{PublicKey, SecretKey};
use crate::util::{static_secp_instance, LoggingConfig, ZeroingString};
use crate::util::{static_secp_instance, ZeroingString};
use crate::{ECDHPubkey, Owner, PubAddress, Token};
use easy_jsonrpc_mw;
use rand::thread_rng;
@ -263,6 +264,7 @@ pub trait OwnerRpcS {
"num_outputs": 1,
"parent_key_id": "0200000000000000000000000000000000",
"stored_tx": null,
"ttl_cutoff_height": null,
"tx_slate_id": null,
"payment_proof": null,
"tx_type": "ConfirmedCoinbase"
@ -282,6 +284,7 @@ pub trait OwnerRpcS {
"num_outputs": 1,
"parent_key_id": "0200000000000000000000000000000000",
"stored_tx": null,
"ttl_cutoff_height": null,
"payment_proof": null,
"tx_slate_id": null,
"tx_type": "ConfirmedCoinbase"
@ -374,6 +377,7 @@ pub trait OwnerRpcS {
"message": "my message",
"target_slate_version": null,
"payment_proof_recipient_address": "d03c09e9c19bb74aa9ea44e0fe5ae237a9bf40bddf0941064a80913a4459c8bb",
"ttl_blocks": null,
"send_args": null
}
},
@ -392,7 +396,7 @@ pub trait OwnerRpcS {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"num_participants": 2,
"payment_proof": {
"receiver_address": "d03c09e9c19bb74aa9ea44e0fe5ae237a9bf40bddf0941064a80913a4459c8bb",
@ -484,7 +488,7 @@ pub trait OwnerRpcS {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"num_participants": 2,
"payment_proof": null,
"participant_data": [
@ -555,7 +559,7 @@ pub trait OwnerRpcS {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"num_participants": 2,
"payment_proof": null,
"participant_data": [
@ -606,6 +610,7 @@ pub trait OwnerRpcS {
"message": "Ok, here are your grins",
"target_slate_version": null,
"payment_proof_recipient_address": null,
"ttl_blocks": null,
"send_args": null
}
},
@ -624,7 +629,7 @@ pub trait OwnerRpcS {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"num_participants": 2,
"payment_proof": null,
"participant_data": [
@ -715,7 +720,7 @@ pub trait OwnerRpcS {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "4",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"num_participants": 2,
"payment_proof": null,
"participant_data": [
@ -847,7 +852,7 @@ pub trait OwnerRpcS {
"fee": "7000000",
"height": "5",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"participant_data": [
{
"id": "0",
@ -882,7 +887,7 @@ pub trait OwnerRpcS {
"height": "5",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "0",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"num_participants": 2,
"payment_proof": null,
"participant_data": [
@ -1180,7 +1185,7 @@ pub trait OwnerRpcS {
"height": "4",
"id": "0436430c-2b02-624c-2032-570501212b00",
"lock_height": "4",
"ttl_cutoff_height": "0",
"ttl_cutoff_height": null,
"num_participants": 2,
"participant_data": [
{

View file

@ -29,7 +29,7 @@ use crate::comments::insert_comments;
use crate::core::global;
use crate::types::{ConfigError, GlobalWalletConfig, GlobalWalletConfigMembers};
use crate::types::{TorConfig, WalletConfig};
use crate::util::LoggingConfig;
use crate::util::logger::LoggingConfig;
/// Wallet configuration file name
pub const WALLET_CONFIG_FILE_NAME: &'static str = "grin-wallet.toml";

View file

@ -19,7 +19,7 @@ use std::io;
use std::path::PathBuf;
use crate::core::global::ChainTypes;
use crate::util::LoggingConfig;
use crate::util::logger::LoggingConfig;
/// Command-line wallet configuration
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]

View file

@ -58,14 +58,14 @@ fn check_middleware(
// allow coinbases to be built regardless
ForeignCheckMiddlewareFn::BuildCoinbase => Ok(()),
_ => {
let mut bhv = 1;
let mut bhv = 2;
if let Some(n) = node_version_info {
bhv = n.block_header_version;
}
if let Some(s) = slate {
if s.version_info.version < CURRENT_SLATE_VERSION
|| (bhv == 1 && s.version_info.block_header_version != 1)
|| (bhv > 1 && s.version_info.block_header_version < GRIN_BLOCK_HEADER_VERSION)
// || (bhv == 3 && s.version_info.block_header_version != 3)
|| (bhv > 3 && s.version_info.block_header_version < GRIN_BLOCK_HEADER_VERSION)
{
Err(ErrorKind::Compatibility(
"Incoming Slate is not compatible with this wallet. \

View file

@ -152,6 +152,7 @@ pub fn txs(
bMG->"Type",
bMG->"Shared Transaction Id",
bMG->"Creation Time",
bMG->"TTL Cutoff Height",
bMG->"Confirmed?",
bMG->"Confirmation Time",
bMG->"Num. \nInputs",
@ -173,6 +174,10 @@ pub fn txs(
};
let entry_type = format!("{}", t.tx_type);
let creation_ts = format!("{}", t.creation_ts.format("%Y-%m-%d %H:%M:%S"));
let ttl_cutoff_height = match t.ttl_cutoff_height {
Some(b) => format!("{}", b),
None => "None".to_owned(),
};
let confirmation_ts = match t.confirmation_ts {
Some(m) => format!("{}", m.format("%Y-%m-%d %H:%M:%S")),
None => "None".to_owned(),
@ -212,6 +217,7 @@ pub fn txs(
bFC->entry_type,
bFC->slate_id,
bFB->creation_ts,
bFB->ttl_cutoff_height,
bFC->confirmed,
bFB->confirmation_ts,
bFC->num_inputs,

View file

@ -0,0 +1,182 @@
// Copyright 2019 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.
//! tests ttl_cutoff blocks
#[macro_use]
extern crate log;
extern crate grin_wallet_controller as wallet;
extern crate grin_wallet_impls as impls;
extern crate grin_wallet_util;
use grin_wallet_libwallet as libwallet;
use impls::test_framework::{self, LocalWalletClient};
use libwallet::{InitTxArgs, Slate, TxLogEntryType};
use std::thread;
use std::time::Duration;
#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
/// Test cutoff block times
fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
create_wallet_and_add!(
client1,
wallet1,
mask1_i,
test_dir,
"wallet1",
None,
&mut wallet_proxy,
false
);
let mask1 = (&mask1_i).as_ref();
create_wallet_and_add!(
client2,
wallet2,
mask2_i,
test_dir,
"wallet2",
None,
&mut wallet_proxy,
false
);
let mask2 = (&mask2_i).as_ref();
// Set the wallet proxy listener running
thread::spawn(move || {
if let Err(e) = wallet_proxy.run() {
error!("Wallet Proxy error: {}", e);
}
});
// few values to keep things shorter
// Do some mining
let bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let amount = 60_000_000_000;
let mut slate = Slate::blank(1);
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
// note this will increment the block count as part of the transaction "Posting"
let args = InitTxArgs {
src_acct_name: None,
amount: amount,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
ttl_blocks: Some(2),
..Default::default()
};
let slate_i = sender_api.init_send_tx(m, args)?;
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(m, &slate, 0)?;
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
let tx = txs[0].clone();
assert_eq!(tx.ttl_cutoff_height, Some(12));
Ok(())
})?;
// Now mine past the block, and check again. Transaction should be gone.
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false);
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
let tx = txs[0].clone();
assert_eq!(tx.ttl_cutoff_height, Some(12));
assert!(tx.tx_type == TxLogEntryType::TxSentCancelled);
Ok(())
})?;
// Should also be gone in wallet 2, and output gone
wallet::controller::owner_single_use(wallet2.clone(), mask2, |sender_api, m| {
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
let tx = txs[0].clone();
let outputs = sender_api.retrieve_outputs(m, false, true, None)?.1;
assert_eq!(outputs.len(), 0);
assert_eq!(tx.ttl_cutoff_height, Some(12));
assert!(tx.tx_type == TxLogEntryType::TxReceivedCancelled);
Ok(())
})?;
// try again, except try and send off the transaction for completion beyond the expiry
let mut slate = Slate::blank(1);
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
// note this will increment the block count as part of the transaction "Posting"
let args = InitTxArgs {
src_acct_name: None,
amount: amount,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
ttl_blocks: Some(2),
..Default::default()
};
let slate_i = sender_api.init_send_tx(m, args)?;
sender_api.tx_lock_outputs(m, &slate_i, 0)?;
slate = slate_i;
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
let tx = txs[0].clone();
assert_eq!(tx.ttl_cutoff_height, Some(14));
Ok(())
})?;
// Mine past the ttl block and try to send
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false);
// Wallet 2 will need to have updated past the TTL
wallet::controller::owner_single_use(wallet2.clone(), mask2, |sender_api, m| {
let (_, _) = sender_api.retrieve_txs(m, true, None, Some(slate.id))?;
Ok(())
})?;
// And when wallet 1 sends, should be rejected
wallet::controller::owner_single_use(wallet1.clone(), mask1, |_sender_api, _m| {
let res = client1.send_tx_slate_direct("wallet2", &slate);
println!("Send after TTL result is: {:?}", res);
assert!(res.is_err());
Ok(())
})?;
// let logging finish
thread::sleep(Duration::from_millis(200));
Ok(())
}
#[test]
fn ttl_cutoff() {
let test_dir = "test_output/ttl_cutoff";
setup(test_dir);
if let Err(e) = ttl_cutoff_test_impl(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}

View file

@ -27,7 +27,7 @@ use crate::util::secp::key::SecretKey;
use crate::util::ZeroingString;
use crate::LMDBBackend;
use failure::ResultExt;
use grin_wallet_util::grin_util::LoggingConfig;
use grin_wallet_util::grin_util::logger::LoggingConfig;
use std::fs;
use std::path::PathBuf;

View file

@ -225,14 +225,24 @@ where
let w = w_lock.lc_provider()?.wallet_inst()?;
let mask = wallet.2.clone();
// receive tx
foreign::receive_tx(
match foreign::receive_tx(
&mut **w,
(&mask).as_ref(),
&Slate::from(slate),
None,
None,
false,
)?
) {
Err(e) => {
return Ok(WalletProxyMessage {
sender_id: m.dest,
dest: m.sender_id,
method: m.method,
body: serde_json::to_string(&format!("Error: {}", e)).unwrap(),
})
}
Ok(s) => s,
}
};
Ok(WalletProxyMessage {

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)?;

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>>>>,

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,

View file

@ -233,6 +233,10 @@ pub enum ErrorKind {
#[fail(display = "Proof Address decoding: {}", _0)]
AddressDecoding(String),
/// Transaction has expired it's TTL
#[fail(display = "Transaction Expired")]
TransactionExpired,
/// Other
#[fail(display = "Generic error: {}", _0)]
GenericError(String),

View file

@ -142,6 +142,7 @@ where
let filename = format!("{}.grintx", slate_id);
t.stored_tx = Some(filename);
t.fee = Some(slate.fee);
t.ttl_cutoff_height = slate.ttl_cutoff_height;
match slate.calc_excess(&keychain) {
Ok(e) => t.kernel_excess = Some(e),
@ -263,6 +264,7 @@ where
t.amount_credited = amount;
t.num_outputs = 1;
t.messages = messages;
t.ttl_cutoff_height = slate.ttl_cutoff_height;
// when invoicing, this will be invalid
match slate.calc_excess(&keychain) {
Ok(e) => t.kernel_excess = Some(e),

View file

@ -45,6 +45,7 @@ pub fn new_tx_slate<'a, T: ?Sized, C, K>(
amount: u64,
num_participants: usize,
use_test_rng: bool,
ttl_blocks: Option<u64>,
) -> Result<Slate, Error>
where
T: WalletBackend<'a, C, K>,
@ -53,6 +54,9 @@ where
{
let current_height = wallet.w2n_client().get_chain_tip()?.0;
let mut slate = Slate::blank(num_participants);
if let Some(b) = ttl_blocks {
slate.ttl_cutoff_height = Some(current_height + b);
}
if use_test_rng {
{
let sc = SLATE_COUNTER.lock();
@ -68,6 +72,14 @@ where
slate.version_info.block_header_version = 1;
}
if valid_header_version(current_height, HeaderVersion(2)) {
slate.version_info.block_header_version = 2;
}
if valid_header_version(current_height, HeaderVersion(3)) {
slate.version_info.block_header_version = 3;
}
// Set the lock_height explicitly to 0 here.
// This will generate a Plain kernel (rather than a HeightLocked kernel).
slate.lock_height = 0;

View file

@ -184,11 +184,10 @@ pub struct Slate {
/// Lock height
#[serde(with = "secp_ser::string_or_u64")]
pub lock_height: u64,
/// Participant data, each participant in the transaction will
/// insert their public data here. For now, 0 is sender and 1
/// is receiver, though this will change for multi-party
#[serde(with = "secp_ser::string_or_u64")]
pub ttl_cutoff_height: u64,
/// TTL cutoff height, after which point the transaction should be
/// cancelled and no further transactions accepted
#[serde(with = "secp_ser::opt_string_or_u64")]
pub ttl_cutoff_height: Option<u64>,
/// Participant data, each participant in the transaction will
/// insert their public data here. For now, 0 is sender and 1
/// is receiver, though this will change for multi-party
@ -254,7 +253,7 @@ impl Slate {
fee: 0,
height: 0,
lock_height: 0,
ttl_cutoff_height: 0,
ttl_cutoff_height: None,
participant_data: vec![],
version_info: VersionCompatInfo {
version: CURRENT_SLATE_VERSION,

View file

@ -30,7 +30,7 @@ pub mod v3;
pub const CURRENT_SLATE_VERSION: u16 = 3;
/// The grin block header this slate is intended to be compatible with
pub const GRIN_BLOCK_HEADER_VERSION: u16 = 2;
pub const GRIN_BLOCK_HEADER_VERSION: u16 = 3;
/// Existing versions of the slate
#[derive(EnumIter, Serialize, Deserialize, Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]

View file

@ -56,8 +56,8 @@ pub struct SlateV3 {
/// TTL, the block height at which wallets
/// should refuse to process the transaction and unlock all
/// associated outputs
#[serde(with = "secp_ser::string_or_u64")]
pub ttl_cutoff_height: u64,
#[serde(with = "secp_ser::opt_string_or_u64")]
pub ttl_cutoff_height: Option<u64>,
/// Participant data, each participant in the transaction will
/// insert their public data here. For now, 0 is sender and 1
/// is receiver, though this will change for multi-party

View file

@ -22,9 +22,10 @@ use crate::grin_core::core::{Output, Transaction, TxKernel};
use crate::grin_core::libtx::{aggsig, secp_ser};
use crate::grin_core::{global, ser};
use crate::grin_keychain::{Identifier, Keychain};
use crate::grin_util::logger::LoggingConfig;
use crate::grin_util::secp::key::{PublicKey, SecretKey};
use crate::grin_util::secp::{self, pedersen, Secp256k1};
use crate::grin_util::{LoggingConfig, ZeroingString};
use crate::grin_util::ZeroingString;
use crate::slate::ParticipantMessages;
use crate::slate_versions::ser as dalek_ser;
use chrono::prelude::*;
@ -778,6 +779,10 @@ pub struct TxLogEntry {
/// Fee
#[serde(with = "secp_ser::opt_string_or_u64")]
pub fee: Option<u64>,
/// Cutoff block height
#[serde(with = "secp_ser::opt_string_or_u64")]
#[serde(default)]
pub ttl_cutoff_height: Option<u64>,
/// Message data, stored as json
pub messages: Option<ParticipantMessages>,
/// Location of the store transaction, (reference or resending)
@ -824,6 +829,7 @@ impl TxLogEntry {
num_inputs: 0,
num_outputs: 0,
fee: None,
ttl_cutoff_height: None,
messages: None,
stored_tx: None,
kernel_excess: None,

View file

@ -104,7 +104,7 @@ fn real_main() -> i32 {
// Load logging config
let l = config.members.as_mut().unwrap().logging.clone().unwrap();
init_logger(Some(l));
init_logger(Some(l), None);
info!(
"Using wallet configuration file at {}",
config.config_file_path.as_ref().unwrap().to_str().unwrap()

View file

@ -12,6 +12,7 @@
"message": "my message",
"target_slate_version": null,
"payment_proof_recipient_address": null,
"ttl_blocks": null,
"send_args": null
}
},

View file

@ -13,6 +13,7 @@
"message": "my message",
"target_slate_version": null,
"payment_proof_recipient_address": null,
"ttl_blocks": null,
"send_args": null
}
},