Modify get_stored_tx functions + tests (#454)

This commit is contained in:
Yeastplume 2020-06-25 10:06:04 +01:00 committed by GitHub
parent 99c2505bf5
commit f8ea76732b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 135 additions and 60 deletions

View file

@ -19,7 +19,6 @@ use ed25519_dalek::SecretKey as DalekSecretKey;
use uuid::Uuid; use uuid::Uuid;
use crate::config::{TorConfig, WalletConfig}; use crate::config::{TorConfig, WalletConfig};
use crate::core::core::Transaction;
use crate::core::global; use crate::core::global;
use crate::impls::HttpSlateSender; use crate::impls::HttpSlateSender;
use crate::impls::SlateSender as _; use crate::impls::SlateSender as _;
@ -1129,18 +1128,24 @@ where
} }
/// Retrieves the stored transaction associated with a TxLogEntry. Can be used even after the /// Retrieves the stored transaction associated with a TxLogEntry. Can be used even after the
/// transaction has completed. /// transaction has completed. Either the Transaction Log ID or the Slate UUID must be supplied.
/// If both are supplied, the Transaction Log ID is preferred.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if /// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
/// being used. /// being used.
/// * `tx_log_entry` - A [`TxLogEntry`](../grin_wallet_libwallet/types/struct.TxLogEntry.html) /// * `tx_id` - The id of the transaction in the wallet's Transaction Log. Either this or
/// `slate_id` must be provided.
/// * `slate_id` - The UUID of the Transaction Slate to find. Either this or `tx_id` must be
/// provided
/// ///
/// # Returns /// # Returns
/// * Ok with the stored [`Transaction`](../grin_core/core/transaction/struct.Transaction.html) /// * Ok(Some([Slate](../grin_wallet_libwallet/slate/struct.Slate.html)) containing the stored
/// if successful /// transaction, if successful. Note that this Slate will not contain all of the fields used by
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered. /// the original Slate that resulted in the transaction.
/// * Ok(None) if the stored Transaction isn't found.
/// * [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
/// ///
/// # Example /// # Example
/// Set up as in [`new`](struct.Owner.html#method.new) method above. /// Set up as in [`new`](struct.Owner.html#method.new) method above.
@ -1156,7 +1161,7 @@ where
/// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id); /// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id);
/// ///
/// if let Ok((was_updated, tx_log_entries)) = result { /// if let Ok((was_updated, tx_log_entries)) = result {
/// let stored_tx = api_owner.get_stored_tx(None, tx_log_entries[0].tx_slate_id.unwrap()).unwrap(); /// let stored_tx = api_owner.get_stored_tx(None, Some(tx_log_entries[0].id), None).unwrap();
/// //... /// //...
/// } /// }
/// ``` /// ```
@ -1164,13 +1169,14 @@ where
pub fn get_stored_tx( pub fn get_stored_tx(
&self, &self,
keychain_mask: Option<&SecretKey>, keychain_mask: Option<&SecretKey>,
tx_id: Uuid, tx_id: Option<u32>,
) -> Result<Option<Transaction>, Error> { slate_id: Option<&Uuid>,
) -> Result<Option<Slate>, Error> {
let mut w_lock = self.wallet_inst.lock(); let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?; let w = w_lock.lc_provider()?.wallet_inst()?;
// Test keychain mask, to keep API consistent // Test keychain mask, to keep API consistent
let _ = w.keychain(keychain_mask)?; let _ = w.keychain(keychain_mask)?;
owner::get_stored_tx(&**w, &tx_id) owner::get_stored_tx(&**w, tx_id, slate_id)
} }
/// Scans the entire UTXO set from the node, identify which outputs belong to the given wallet /// Scans the entire UTXO set from the node, identify which outputs belong to the given wallet

View file

@ -16,7 +16,6 @@
use uuid::Uuid; use uuid::Uuid;
use crate::config::{TorConfig, WalletConfig}; use crate::config::{TorConfig, WalletConfig};
use crate::core::core::Transaction;
use crate::core::global; use crate::core::global;
use crate::keychain::{Identifier, Keychain}; use crate::keychain::{Identifier, Keychain};
use crate::libwallet::{ use crate::libwallet::{
@ -805,7 +804,8 @@ pub trait OwnerRpc {
"id": 1, "id": 1,
"params": { "params": {
"token": "d202964900000000d302964900000000d402964900000000d502964900000000", "token": "d202964900000000d302964900000000d402964900000000d502964900000000",
"id": "0436430c-2b02-624c-2032-570501212b00" "id": null,
"slate_id": "0436430c-2b02-624c-2032-570501212b00"
} }
} }
# "# # "#
@ -816,28 +816,17 @@ pub trait OwnerRpc {
"id": 1, "id": 1,
"result": { "result": {
"Ok": { "Ok": {
"body": { "coms": [
"inputs": [],
"kernels": [
{ {
"excess": "000000000000000000000000000000000000000000000000000000000000000000", "c": "CZtIz7H4CiNH3ImBhEnmjnajxoF6UyqOnvK0pcz0NjhQ",
"excess_sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "p": "KXAc6uJiysd7ebhoyIOikuYebegZK4aO3NEwCwlz2ROWsVas5r1nNAKjA94Q3dil5rfxe6ZVeldKZyvQTMJzqwTtjiyoC6xIM0XA7IQ/UhgUzhMB7JrcOJVqErTZSKzOcSlaT1K83rihyfLWstpdcxJipenAJ275BN+e+NSAAUIM1Z91ovGuXHocfGufFA52E+Uu+eJJ8p+TQLfvuAaZ5GAWQyRhb5j9TN49tSSXyRnpUiL//qy35l3sp+NoqAznE8Gd59pTaXJiKO4zb1vUlFOMEsy//rG5v9X8iQbRxkJFtRbxA/qW2cVpdYN2UsHg+lgD18zxFH2Pkn422nF/eteUcdvhkvX1D4enn8P+Aw26VptjS5LSzzB5k8zlRWM68mOJfNfm6/Tcr7F20HNYvcONA+RaSd+pyMZRfNaNFn/79sO03g4t0hkJy61MRnuE5XAL5HOjmsWcZp18FVxLyrm4Am7qNDHHec0nfkki0rl0Lh9meMvoaew7W370Ey3bbN0Gzyfb6yi+crlJ+ol2EOSOOg14n9Lup1q8l7PcfgDlyLPSTkDG8kESrbcjUriaK+8FmTRTOOnnYgKjxG76Y3CVKyrKQarbrg6jJTGsr82rbdBm12nr9Qz088ClnS1fp5YAoge5QXxiP3atBejMz81AOPlEi8QPEnynwNNy5GB04zT+SfWpVuwAVvTaYB5q+A6xpsSVEFSGnmZbKW2MFPNEyi3F/dXfSjZSU2NloWFa2bQiFlx3v4/mWoNcjgxB4HABTrZu+MUlIE6ZCzo9ZjweQiIbSWiVw3ovDBvwXpEjVAnD/j2JqaedbHhgmrGKRjMRkR9x+je7c7FfzTgUPRQE/SzoEATcf/ic8RFdzAw1zhwb+ZQVhvuVl3DyYYzLcRin"
"features": {
"Plain": {
"fee": 7000000
}
}
} }
], ],
"outputs": [ "fee": "7000000",
{ "id": "0436430c-2b02-624c-2032-570501212b00",
"commit": "099b48cfb1f80a2347dc89818449e68e76a3c6817a532a8e9ef2b4a5ccf4363850", "sigs": [],
"features": "Plain", "sta": "S3",
"proof": "29701ceae262cac77b79b868c883a292e61e6de8192b868edcd1300b0973d91396b156ace6bd673402a303de10ddd8a5e6b7f17ba6557a574a672bd04cc273ab04ed8e2ca80bac483345c0ec843f521814ce1301ec9adc38956a12b4d948acce71295a4f52bcdeb8a1c9f2d6b2da5d731262a5e9c0276ef904df9ef8d48001420cd59f75a2f1ae5c7a1c7c6b9f140e7613e52ef9e249f29f9340b7efb80699e460164324616f98fd4cde3db52497c919e95222fffeacb7e65deca7e368a80ce713c19de7da5369726228ee336f5bd494538c12ccbffeb1b9bfd5fc8906d1c64245b516f103fa96d9c56975837652c1e0fa5803d7ccf1147d8f927e36da717f7ad79471dbe192f5f50f87a79fc3fe030dba569b634b92d2cf307993cce545633af263897cd7e6ebf4dcafb176d07358bdc38d03e45a49dfa9c8c6517cd68d167ffbf6c3b4de0e2dd21909cbad4c467b84e5700be473a39ac59c669d7c155c4bcab9b8026eea3431c779cd277e4922d2b9742e1f6678cbe869ec3b5b7ef4132ddb6cdd06cf27dbeb28be72b949fa897610e48e3a0d789fd2eea75abc97b3dc7e00e5c8b3d24e40c6f24112adb72352b89a2bef0599345338e9e76202a3c46efa6370952b2aca41aadbae0ea32531acafcdab6dd066d769ebf50cf4f3c0a59d2d5fa79600a207b9417c623f76ad05e8cccfcd4038f9448bc40f127ca7c0d372e46074e334fe49f5a956ec0056f4da601e6af80eb1a6c4951054869e665b296d8c14f344ca2dc5fdd5df4a3652536365a1615ad9b422165c77bf8fe65a835c8e0c41e070014eb66ef8c525204e990b3a3d663c1e42221b496895c37a2f0c1bf05e91235409c3fe3d89a9a79d6c78609ab18a463311911f71fa37bb73b15fcd38143d1404fd2ce81004dc7ff89cf1115dcc0c35ce1c1bf9941586fb959770f2618ccb7118a7" "ver": "4:3"
}
]
},
"offset": "0000000000000000000000000000000000000000000000000000000000000000"
} }
} }
} }
@ -845,7 +834,12 @@ pub trait OwnerRpc {
# , 5, true, true, false, false); # , 5, true, true, false, false);
``` ```
*/ */
fn get_stored_tx(&self, token: Token, id: Uuid) -> Result<Option<Transaction>, ErrorKind>; fn get_stored_tx(
&self,
token: Token,
id: Option<u32>,
slate_id: Option<Uuid>,
) -> Result<Option<VersionedSlate>, ErrorKind>;
/** /**
Networked version of [Owner::scan](struct.Owner.html#method.scan). Networked version of [Owner::scan](struct.Owner.html#method.scan).
@ -1873,8 +1867,28 @@ where
.map_err(|e| e.kind()) .map_err(|e| e.kind())
} }
fn get_stored_tx(&self, token: Token, uuid: Uuid) -> Result<Option<Transaction>, ErrorKind> { fn get_stored_tx(
Owner::get_stored_tx(self, (&token.keychain_mask).as_ref(), uuid).map_err(|e| e.kind()) &self,
token: Token,
id: Option<u32>,
slate_id: Option<Uuid>,
) -> Result<Option<VersionedSlate>, ErrorKind> {
let out_slate = Owner::get_stored_tx(
self,
(&token.keychain_mask).as_ref(),
id,
(&slate_id).as_ref(),
)
.map_err(|e| e.kind())?;
match out_slate {
Some(s) => {
let version = SlateVersion::V4;
Ok(Some(
VersionedSlate::into_version(s, version).map_err(|e| e.kind())?,
))
}
None => Ok(None),
}
} }
fn post_tx(&self, token: Token, slate: VersionedSlate, fluff: bool) -> Result<(), ErrorKind> { fn post_tx(&self, token: Token, slate: VersionedSlate, fluff: bool) -> Result<(), ErrorKind> {

View file

@ -1269,15 +1269,17 @@ where
K: keychain::Keychain + 'static, K: keychain::Keychain + 'static,
{ {
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| { controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let (_, txs) = api.retrieve_txs(m, true, Some(args.id), None)?; let stored_tx_slate = match api.get_stored_tx(m, Some(args.id), None)? {
let stored_tx = api.get_stored_tx(m, txs[0].tx_slate_id.unwrap())?; None => {
if stored_tx.is_none() {
error!( error!(
"Transaction with id {} does not have transaction data. Not reposting.", "Transaction with id {} does not have transaction data. Not reposting.",
args.id args.id
); );
return Ok(()); return Ok(());
} }
Some(s) => s,
};
let (_, txs) = api.retrieve_txs(m, true, Some(args.id), None)?;
match args.dump_file { match args.dump_file {
None => { None => {
if txs[0].confirmed { if txs[0].confirmed {
@ -1287,15 +1289,26 @@ where
); );
return Ok(()); return Ok(());
} }
let mut slate = Slate::blank(2, false); if libwallet::sig_is_blank(
slate.tx = Some(stored_tx.unwrap()); &stored_tx_slate.tx.as_ref().unwrap().kernels()[0].excess_sig,
api.post_tx(m, &slate, args.fluff)?; ) {
info!("Reposted transaction at {}", args.id); error!("Transaction at {} has not been finalized.", args.id);
return Ok(());
}
match api.post_tx(m, &stored_tx_slate, args.fluff) {
Ok(_) => info!("Reposted transaction at {}", args.id),
Err(e) => error!("Could not repost transaction at {}. Reason: {}", args.id, e),
}
return Ok(()); return Ok(());
} }
Some(f) => { Some(f) => {
let mut tx_file = File::create(f.clone())?; let mut tx_file = File::create(f.clone())?;
tx_file.write_all(json::to_string(&stored_tx).unwrap().as_bytes())?; tx_file.write_all(
json::to_string(&stored_tx_slate.tx.unwrap())
.unwrap()
.as_bytes(),
)?;
tx_file.sync_all()?; tx_file.sync_all()?;
info!("Dumped transaction data for tx {} to {}", args.id, f); info!("Dumped transaction data for tx {} to {}", args.id, f);
return Ok(()); return Ok(());

View file

@ -156,7 +156,7 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| { wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?; let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
println!("TXS[0]: {:?}", txs[0]); println!("TXS[0]: {:?}", txs[0]);
let stored_tx = api.get_stored_tx(m, txs[0].tx_slate_id.unwrap())?; let stored_tx = api.get_stored_tx(m, None, Some(&txs[0].tx_slate_id.unwrap()))?;
println!("Stored tx: {:?}", stored_tx); println!("Stored tx: {:?}", stored_tx);
api.post_tx(m, &slate, false)?; api.post_tx(m, &slate, false)?;
bh += 1; bh += 1;
@ -225,9 +225,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
// Now repost from cached // Now repost from cached
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| { wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?; let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
let stored_tx = api.get_stored_tx(m, txs[0].tx_slate_id.unwrap())?; let stored_tx_slate = api.get_stored_tx(m, Some(txs[0].id), None)?.unwrap();
slate.tx = stored_tx; api.post_tx(m, &stored_tx_slate, false)?;
api.post_tx(m, &slate, false)?;
bh += 1; bh += 1;
Ok(()) Ok(())
})?; })?;

View file

@ -317,9 +317,10 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
.iter() .iter()
.find(|t| t.tx_slate_id == Some(slate.id)) .find(|t| t.tx_slate_id == Some(slate.id))
.unwrap(); .unwrap();
let stored_tx = sender_api.get_stored_tx(m, tx.tx_slate_id.unwrap())?; let stored_tx_slate = sender_api
slate.tx = stored_tx; .get_stored_tx(m, None, Some(&tx.tx_slate_id.unwrap()))?
sender_api.post_tx(m, &slate, false)?; .unwrap();
sender_api.post_tx(m, &stored_tx_slate, false)?;
let (_, wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?; let (_, wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?;
// should be mined now // should be mined now
assert_eq!( assert_eq!(

View file

@ -823,13 +823,50 @@ where
} }
/// get stored tx /// get stored tx
pub fn get_stored_tx<'a, T: ?Sized, C, K>(w: &T, id: &Uuid) -> Result<Option<Transaction>, Error> pub fn get_stored_tx<'a, T: ?Sized, C, K>(
w: &T,
tx_id: Option<u32>,
slate_id: Option<&Uuid>,
) -> Result<Option<Slate>, Error>
where where
T: WalletBackend<'a, C, K>, T: WalletBackend<'a, C, K>,
C: NodeClient + 'a, C: NodeClient + 'a,
K: Keychain + 'a, K: Keychain + 'a,
{ {
w.get_stored_tx(&format!("{}", id)) let mut uuid = None;
if let Some(i) = tx_id {
let tx = w.tx_log_iter().find(|t| t.id == i);
if let Some(t) = tx {
uuid = t.tx_slate_id;
}
}
if uuid.is_none() {
if let Some(sid) = slate_id {
uuid = Some(sid.to_owned());
}
}
let id = match uuid {
Some(u) => u,
None => {
return Err(ErrorKind::StoredTx(
"Both the provided Transaction Id and Slate UUID are invalid.".to_owned(),
)
.into());
}
};
let tx_res = w.get_stored_tx(&format!("{}", id))?;
match tx_res {
Some(tx) => {
let mut slate = Slate::blank(2, false);
slate.tx = Some(tx.clone());
slate.fee = tx.fee();
slate.id = id.clone();
slate.offset = tx.offset;
slate.state = SlateState::Standard3;
Ok(Some(slate))
}
None => Ok(None),
}
} }
/// Posts a transaction to the chain /// Posts a transaction to the chain

View file

@ -302,6 +302,10 @@ pub enum ErrorKind {
#[fail(display = "SlatepackAddress error: {}", _0)] #[fail(display = "SlatepackAddress error: {}", _0)]
SlatepackAddress(String), SlatepackAddress(String),
/// Retrieving Stored Tx
#[fail(display = "Stored Tx error: {}", _0)]
StoredTx(String),
/// Other /// Other
#[fail(display = "Generic error: {}", _0)] #[fail(display = "Generic error: {}", _0)]
GenericError(String), GenericError(String),

View file

@ -57,6 +57,7 @@ mod types;
pub use crate::error::{Error, ErrorKind}; pub use crate::error::{Error, ErrorKind};
pub use crate::slate::{ParticipantData, Slate, SlateState}; pub use crate::slate::{ParticipantData, Slate, SlateState};
pub use crate::slate_versions::v4::sig_is_blank;
pub use crate::slate_versions::{ pub use crate::slate_versions::{
SlateVersion, VersionedBinSlate, VersionedCoinbase, VersionedSlate, CURRENT_SLATE_VERSION, SlateVersion, VersionedBinSlate, VersionedCoinbase, VersionedSlate, CURRENT_SLATE_VERSION,
GRIN_BLOCK_HEADER_VERSION, GRIN_BLOCK_HEADER_VERSION,

View file

@ -436,7 +436,7 @@ fn default_sig() -> secp::Signature {
Signature::from_raw_data(&[0; 64]).unwrap() Signature::from_raw_data(&[0; 64]).unwrap()
} }
fn sig_is_blank(s: &secp::Signature) -> bool { pub fn sig_is_blank(s: &secp::Signature) -> bool {
for b in s.to_raw_data().iter() { for b in s.to_raw_data().iter() {
if *b != 0 { if *b != 0 {
return false; return false;