From f8ea76732b14304963ca91b0e9eb9dde0ab216a5 Mon Sep 17 00:00:00 2001 From: Yeastplume Date: Thu, 25 Jun 2020 10:06:04 +0100 Subject: [PATCH] Modify get_stored_tx functions + tests (#454) --- api/src/owner.rs | 26 +++++++----- api/src/owner_rpc.rs | 68 ++++++++++++++++++------------ controller/src/command.rs | 39 +++++++++++------ controller/tests/repost.rs | 7 ++- controller/tests/transaction.rs | 7 +-- libwallet/src/api_impl/owner.rs | 41 +++++++++++++++++- libwallet/src/error.rs | 4 ++ libwallet/src/lib.rs | 1 + libwallet/src/slate_versions/v4.rs | 2 +- 9 files changed, 135 insertions(+), 60 deletions(-) diff --git a/api/src/owner.rs b/api/src/owner.rs index d3c49bb8..cc0c5c76 100644 --- a/api/src/owner.rs +++ b/api/src/owner.rs @@ -19,7 +19,6 @@ use ed25519_dalek::SecretKey as DalekSecretKey; use uuid::Uuid; use crate::config::{TorConfig, WalletConfig}; -use crate::core::core::Transaction; use crate::core::global; use crate::impls::HttpSlateSender; use crate::impls::SlateSender as _; @@ -1129,18 +1128,24 @@ where } /// 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 /// /// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if /// 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 - /// * Ok with the stored [`Transaction`](../grin_core/core/transaction/struct.Transaction.html) - /// if successful - /// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered. + /// * Ok(Some([Slate](../grin_wallet_libwallet/slate/struct.Slate.html)) containing the stored + /// transaction, if successful. Note that this Slate will not contain all of the fields used by + /// 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 /// 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); /// /// 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( &self, keychain_mask: Option<&SecretKey>, - tx_id: Uuid, - ) -> Result, Error> { + tx_id: Option, + slate_id: Option<&Uuid>, + ) -> Result, Error> { let mut w_lock = self.wallet_inst.lock(); let w = w_lock.lc_provider()?.wallet_inst()?; // Test keychain mask, to keep API consistent 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 diff --git a/api/src/owner_rpc.rs b/api/src/owner_rpc.rs index dbcb3829..219aef8e 100644 --- a/api/src/owner_rpc.rs +++ b/api/src/owner_rpc.rs @@ -16,7 +16,6 @@ use uuid::Uuid; use crate::config::{TorConfig, WalletConfig}; -use crate::core::core::Transaction; use crate::core::global; use crate::keychain::{Identifier, Keychain}; use crate::libwallet::{ @@ -805,7 +804,8 @@ pub trait OwnerRpc { "id": 1, "params": { "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, "result": { "Ok": { - "body": { - "inputs": [], - "kernels": [ - { - "excess": "000000000000000000000000000000000000000000000000000000000000000000", - "excess_sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "features": { - "Plain": { - "fee": 7000000 - } - } - } - ], - "outputs": [ - { - "commit": "099b48cfb1f80a2347dc89818449e68e76a3c6817a532a8e9ef2b4a5ccf4363850", - "features": "Plain", - "proof": "29701ceae262cac77b79b868c883a292e61e6de8192b868edcd1300b0973d91396b156ace6bd673402a303de10ddd8a5e6b7f17ba6557a574a672bd04cc273ab04ed8e2ca80bac483345c0ec843f521814ce1301ec9adc38956a12b4d948acce71295a4f52bcdeb8a1c9f2d6b2da5d731262a5e9c0276ef904df9ef8d48001420cd59f75a2f1ae5c7a1c7c6b9f140e7613e52ef9e249f29f9340b7efb80699e460164324616f98fd4cde3db52497c919e95222fffeacb7e65deca7e368a80ce713c19de7da5369726228ee336f5bd494538c12ccbffeb1b9bfd5fc8906d1c64245b516f103fa96d9c56975837652c1e0fa5803d7ccf1147d8f927e36da717f7ad79471dbe192f5f50f87a79fc3fe030dba569b634b92d2cf307993cce545633af263897cd7e6ebf4dcafb176d07358bdc38d03e45a49dfa9c8c6517cd68d167ffbf6c3b4de0e2dd21909cbad4c467b84e5700be473a39ac59c669d7c155c4bcab9b8026eea3431c779cd277e4922d2b9742e1f6678cbe869ec3b5b7ef4132ddb6cdd06cf27dbeb28be72b949fa897610e48e3a0d789fd2eea75abc97b3dc7e00e5c8b3d24e40c6f24112adb72352b89a2bef0599345338e9e76202a3c46efa6370952b2aca41aadbae0ea32531acafcdab6dd066d769ebf50cf4f3c0a59d2d5fa79600a207b9417c623f76ad05e8cccfcd4038f9448bc40f127ca7c0d372e46074e334fe49f5a956ec0056f4da601e6af80eb1a6c4951054869e665b296d8c14f344ca2dc5fdd5df4a3652536365a1615ad9b422165c77bf8fe65a835c8e0c41e070014eb66ef8c525204e990b3a3d663c1e42221b496895c37a2f0c1bf05e91235409c3fe3d89a9a79d6c78609ab18a463311911f71fa37bb73b15fcd38143d1404fd2ce81004dc7ff89cf1115dcc0c35ce1c1bf9941586fb959770f2618ccb7118a7" - } - ] - }, - "offset": "0000000000000000000000000000000000000000000000000000000000000000" + "coms": [ + { + "c": "CZtIz7H4CiNH3ImBhEnmjnajxoF6UyqOnvK0pcz0NjhQ", + "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" + } + ], + "fee": "7000000", + "id": "0436430c-2b02-624c-2032-570501212b00", + "sigs": [], + "sta": "S3", + "ver": "4:3" } } } @@ -845,7 +834,12 @@ pub trait OwnerRpc { # , 5, true, true, false, false); ``` */ - fn get_stored_tx(&self, token: Token, id: Uuid) -> Result, ErrorKind>; + fn get_stored_tx( + &self, + token: Token, + id: Option, + slate_id: Option, + ) -> Result, ErrorKind>; /** Networked version of [Owner::scan](struct.Owner.html#method.scan). @@ -1873,8 +1867,28 @@ where .map_err(|e| e.kind()) } - fn get_stored_tx(&self, token: Token, uuid: Uuid) -> Result, ErrorKind> { - Owner::get_stored_tx(self, (&token.keychain_mask).as_ref(), uuid).map_err(|e| e.kind()) + fn get_stored_tx( + &self, + token: Token, + id: Option, + slate_id: Option, + ) -> Result, 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> { diff --git a/controller/src/command.rs b/controller/src/command.rs index 58a70151..dba46ae2 100644 --- a/controller/src/command.rs +++ b/controller/src/command.rs @@ -1269,15 +1269,17 @@ where K: keychain::Keychain + 'static, { controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| { + let stored_tx_slate = match api.get_stored_tx(m, Some(args.id), None)? { + None => { + error!( + "Transaction with id {} does not have transaction data. Not reposting.", + args.id + ); + return Ok(()); + } + Some(s) => s, + }; let (_, txs) = api.retrieve_txs(m, true, Some(args.id), None)?; - let stored_tx = api.get_stored_tx(m, txs[0].tx_slate_id.unwrap())?; - if stored_tx.is_none() { - error!( - "Transaction with id {} does not have transaction data. Not reposting.", - args.id - ); - return Ok(()); - } match args.dump_file { None => { if txs[0].confirmed { @@ -1287,15 +1289,26 @@ where ); return Ok(()); } - let mut slate = Slate::blank(2, false); - slate.tx = Some(stored_tx.unwrap()); - api.post_tx(m, &slate, args.fluff)?; - info!("Reposted transaction at {}", args.id); + if libwallet::sig_is_blank( + &stored_tx_slate.tx.as_ref().unwrap().kernels()[0].excess_sig, + ) { + 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(()); } Some(f) => { 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()?; info!("Dumped transaction data for tx {} to {}", args.id, f); return Ok(()); diff --git a/controller/tests/repost.rs b/controller/tests/repost.rs index 5f7dcaca..4ca01771 100644 --- a/controller/tests/repost.rs +++ b/controller/tests/repost.rs @@ -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| { let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?; 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); api.post_tx(m, &slate, false)?; bh += 1; @@ -225,9 +225,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> // Now repost from cached wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| { 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())?; - slate.tx = stored_tx; - api.post_tx(m, &slate, false)?; + let stored_tx_slate = api.get_stored_tx(m, Some(txs[0].id), None)?.unwrap(); + api.post_tx(m, &stored_tx_slate, false)?; bh += 1; Ok(()) })?; diff --git a/controller/tests/transaction.rs b/controller/tests/transaction.rs index 4d79207b..2f19ffef 100644 --- a/controller/tests/transaction.rs +++ b/controller/tests/transaction.rs @@ -317,9 +317,10 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error> .iter() .find(|t| t.tx_slate_id == Some(slate.id)) .unwrap(); - let stored_tx = sender_api.get_stored_tx(m, tx.tx_slate_id.unwrap())?; - slate.tx = stored_tx; - sender_api.post_tx(m, &slate, false)?; + let stored_tx_slate = sender_api + .get_stored_tx(m, None, Some(&tx.tx_slate_id.unwrap()))? + .unwrap(); + sender_api.post_tx(m, &stored_tx_slate, false)?; let (_, wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?; // should be mined now assert_eq!( diff --git a/libwallet/src/api_impl/owner.rs b/libwallet/src/api_impl/owner.rs index b327c051..001e1ee6 100644 --- a/libwallet/src/api_impl/owner.rs +++ b/libwallet/src/api_impl/owner.rs @@ -823,13 +823,50 @@ where } /// get stored tx -pub fn get_stored_tx<'a, T: ?Sized, C, K>(w: &T, id: &Uuid) -> Result, Error> +pub fn get_stored_tx<'a, T: ?Sized, C, K>( + w: &T, + tx_id: Option, + slate_id: Option<&Uuid>, +) -> Result, Error> where T: WalletBackend<'a, C, K>, C: NodeClient + '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 diff --git a/libwallet/src/error.rs b/libwallet/src/error.rs index 81e3f67a..673ff846 100644 --- a/libwallet/src/error.rs +++ b/libwallet/src/error.rs @@ -302,6 +302,10 @@ pub enum ErrorKind { #[fail(display = "SlatepackAddress error: {}", _0)] SlatepackAddress(String), + /// Retrieving Stored Tx + #[fail(display = "Stored Tx error: {}", _0)] + StoredTx(String), + /// Other #[fail(display = "Generic error: {}", _0)] GenericError(String), diff --git a/libwallet/src/lib.rs b/libwallet/src/lib.rs index 506f96a8..5121c52c 100644 --- a/libwallet/src/lib.rs +++ b/libwallet/src/lib.rs @@ -57,6 +57,7 @@ mod types; pub use crate::error::{Error, ErrorKind}; pub use crate::slate::{ParticipantData, Slate, SlateState}; +pub use crate::slate_versions::v4::sig_is_blank; pub use crate::slate_versions::{ SlateVersion, VersionedBinSlate, VersionedCoinbase, VersionedSlate, CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION, diff --git a/libwallet/src/slate_versions/v4.rs b/libwallet/src/slate_versions/v4.rs index e0e020b0..3e3fef40 100644 --- a/libwallet/src/slate_versions/v4.rs +++ b/libwallet/src/slate_versions/v4.rs @@ -436,7 +436,7 @@ fn default_sig() -> secp::Signature { 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() { if *b != 0 { return false;