From af45206fde1abbe08645d957984f153a7b9ea693 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Wed, 6 Jan 2021 16:31:47 +1100 Subject: [PATCH] Remember the block-height before XMR lock for generated monero wallet restore height Speeds up wallet creation, because only the blocks after the recorded height will be scanned. --- monero-harness/src/rpc/wallet.rs | 11 +++++++++-- swap/src/monero.rs | 1 + swap/src/monero/wallet.rs | 2 ++ swap/src/protocol/alice/state.rs | 3 ++- swap/src/protocol/alice/swap.rs | 2 +- swap/src/protocol/bob/state.rs | 18 ++++++++++++++++-- swap/src/protocol/bob/swap.rs | 10 +++++++++- 7 files changed, 40 insertions(+), 7 deletions(-) diff --git a/monero-harness/src/rpc/wallet.rs b/monero-harness/src/rpc/wallet.rs index 97c2804d..c3063e80 100644 --- a/monero-harness/src/rpc/wallet.rs +++ b/monero-harness/src/rpc/wallet.rs @@ -186,7 +186,7 @@ impl Client { } /// Get wallet block height, this might be behind monerod height. - pub(crate) async fn block_height(&self) -> Result { + pub async fn block_height(&self) -> Result { let request = Request::new("get_height", ""); let response = self @@ -238,9 +238,16 @@ impl Client { address: &str, spend_key: &str, view_key: &str, + restore_height: Option, ) -> Result { + let restore_height = if let Some(restore_height) = restore_height { + restore_height + } else { + 0 + }; + let params = GenerateFromKeysParams { - restore_height: 0, + restore_height, filename: view_key.into(), address: address.into(), spendkey: spend_key.into(), diff --git a/swap/src/monero.rs b/swap/src/monero.rs index c7fc719d..3c177884 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -210,6 +210,7 @@ pub trait CreateWalletForOutput { &self, private_spend_key: PrivateKey, private_view_key: PrivateViewKey, + restore_height: Option, ) -> anyhow::Result<()>; } diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index 6ac33871..00a53238 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -68,6 +68,7 @@ impl CreateWalletForOutput for Wallet { &self, private_spend_key: PrivateKey, private_view_key: PrivateViewKey, + restore_height: Option, ) -> Result<()> { let public_spend_key = PublicKey::from_private_key(&private_spend_key); let public_view_key = PublicKey::from_private_key(&private_view_key.into()); @@ -80,6 +81,7 @@ impl CreateWalletForOutput for Wallet { &address.to_string(), &private_spend_key.to_string(), &PrivateKey::from(private_view_key).to_string(), + restore_height, ) .await?; diff --git a/swap/src/protocol/alice/state.rs b/swap/src/protocol/alice/state.rs index 40512799..29670a82 100644 --- a/swap/src/protocol/alice/state.rs +++ b/swap/src/protocol/alice/state.rs @@ -538,10 +538,11 @@ impl State5 { let s = s_b.scalar + self.s_a.into_ed25519(); + // TODO: Optimized rescan height should be passed for refund as well. // NOTE: This actually generates and opens a new wallet, closing the currently // open one. monero_wallet - .create_and_load_wallet_for_output(monero::PrivateKey::from_scalar(s), self.v) + .create_and_load_wallet_for_output(monero::PrivateKey::from_scalar(s), self.v, None) .await?; Ok(()) diff --git a/swap/src/protocol/alice/swap.rs b/swap/src/protocol/alice/swap.rs index 78ab1a72..dd16d506 100644 --- a/swap/src/protocol/alice/swap.rs +++ b/swap/src/protocol/alice/swap.rs @@ -405,7 +405,7 @@ pub async fn run_until( let view_key = state3.v; monero_wallet - .create_and_load_wallet_for_output(spend_key, view_key) + .create_and_load_wallet_for_output(spend_key, view_key, None) .await?; let state = AliceState::XmrRefunded; diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index 0ab75c40..e3ab0cfa 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -304,7 +304,12 @@ pub struct State3 { } impl State3 { - pub async fn watch_for_lock_xmr(self, xmr_wallet: &W, msg: alice::Message2) -> Result + pub async fn watch_for_lock_xmr( + self, + xmr_wallet: &W, + msg: alice::Message2, + monero_wallet_restore_blockheight: u32, + ) -> Result where W: monero::WatchForTransfer, { @@ -340,6 +345,7 @@ impl State3 { tx_lock: self.tx_lock, tx_cancel_sig_a: self.tx_cancel_sig_a, tx_refund_encsig: self.tx_refund_encsig, + monero_wallet_restore_blockheight, }) } @@ -373,6 +379,7 @@ impl State3 { tx_lock: self.tx_lock.clone(), tx_cancel_sig_a: self.tx_cancel_sig_a.clone(), tx_refund_encsig: self.tx_refund_encsig.clone(), + monero_wallet_restore_blockheight: 0u32, } } @@ -413,6 +420,7 @@ pub struct State4 { pub tx_lock: bitcoin::TxLock, pub tx_cancel_sig_a: Signature, pub tx_refund_encsig: EncryptedSignature, + pub monero_wallet_restore_blockheight: u32, } impl State4 { @@ -509,6 +517,7 @@ impl State4 { tx_lock: self.tx_lock.clone(), tx_refund_encsig: self.tx_refund_encsig.clone(), tx_cancel_sig: self.tx_cancel_sig_a.clone(), + monero_wallet_restore_blockheight: self.monero_wallet_restore_blockheight, }) } @@ -606,6 +615,7 @@ pub struct State5 { pub tx_lock: bitcoin::TxLock, tx_refund_encsig: EncryptedSignature, tx_cancel_sig: Signature, + pub monero_wallet_restore_blockheight: u32, } impl State5 { @@ -622,7 +632,11 @@ impl State5 { // NOTE: This actually generates and opens a new wallet, closing the currently // open one. monero_wallet - .create_and_load_wallet_for_output(s, self.v) + .create_and_load_wallet_for_output( + s, + self.v, + Some(self.monero_wallet_restore_blockheight), + ) .await?; Ok(()) diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index d17cc2e3..022511d6 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -142,11 +142,19 @@ where let cancel_timelock_expires = state3.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref()); + // Record the current monero wallet block height so we don't have to scan from + // block 0 once we create the redeem wallet. + // TODO: This can be optimized further by extracting the block height when + // tx-lock was included. However, scanning a few more blocks won't do any harm + // and is simpler. + let monero_wallet_restore_blockheight = + monero_wallet.inner.block_height().await?; + select! { msg2 = msg2_watcher => { let xmr_lock_watcher = state3.clone() - .watch_for_lock_xmr(monero_wallet.as_ref(), msg2?); + .watch_for_lock_xmr(monero_wallet.as_ref(), msg2?, monero_wallet_restore_blockheight.height); let cancel_timelock_expires = state3.wait_for_cancel_timelock_to_expire(bitcoin_wallet.as_ref()); select! {