Repository: farcaster-project/farcaster-node
Pull request #784 (2022-11-18 09:08:59)

Feat: Use creation height when sweeping Monero
This allows us to use the recorded creation height of a Monero address when sweeping from that address.


Patch:
diff --git a/src/cli/command.rs b/src/cli/command.rs
index 27eb2815..c36ebb92 100644
--- a/src/cli/command.rs
+++ b/src/cli/command.rs
@@ -603,6 +603,7 @@ impl Exec for Command {
                             source_view_key: secret_key_info.view,
                             destination_address,
                             minimum_balance: monero::Amount::from_pico(0),
+                            from_height: secret_key_info.creation_height,
                         })),
                     )?;
                     runtime.report_response_or_fail()?;
diff --git a/src/farcasterd/syncer_state_machine.rs b/src/farcasterd/syncer_state_machine.rs
index 0bb5db20..60566e7e 100644
--- a/src/farcasterd/syncer_state_machine.rs
+++ b/src/farcasterd/syncer_state_machine.rs
@@ -151,7 +151,6 @@ fn attempt_transition_to_awaiting_syncer_or_awaiting_syncer_request(
                 retry: false,
                 lifetime: u64::MAX,
                 addendum: sweep_address,
-                from_height: None,
             });
             runtime.syncer_task_counter += 1;
 
diff --git a/src/grpcd/runtime.rs b/src/grpcd/runtime.rs
index 3e238600..1d8d1ac8 100644
--- a/src/grpcd/runtime.rs
+++ b/src/grpcd/runtime.rs
@@ -1302,6 +1302,7 @@ impl Farcaster for FarcasterService {
                                     source_view_key: secret_key_info.view,
                                     destination_address,
                                     minimum_balance: monero::Amount::from_pico(0),
+                                    from_height: secret_key_info.creation_height,
                                 },
                             )),
                             service_id: ServiceId::Farcasterd,
diff --git a/src/swapd/runtime.rs b/src/swapd/runtime.rs
index 997b7c17..b7a5e500 100644
--- a/src/swapd/runtime.rs
+++ b/src/swapd/runtime.rs
@@ -1566,13 +1566,10 @@ impl Runtime {
                             .pop()
                             .unwrap();
                         if let (
-                            BusMsg::Sync(SyncMsg::Task(Task::SweepAddress(mut task))),
+                            BusMsg::Sync(SyncMsg::Task(Task::SweepAddress(task))),
                             ServiceBus::Sync,
                         ) = (request.clone(), bus_id)
                         {
-                            // safe cast
-                            task.from_height =
-                                Some(self.syncer_state.monero_height - *confirmations as u64);
                             let request = BusMsg::Sync(SyncMsg::Task(Task::SweepAddress(task)));
 
                             info!(
@@ -1934,7 +1931,7 @@ impl Runtime {
                                     tx.clone(),
                                     endpoints,
                                     self.swap_id.clone(),
-                                    self.syncer_state.monero_height,
+                                    self.monero_address_creation_height,
                                 )?;
                                 let task = self.syncer_state.sweep_xmr(sweep_xmr.clone(), true);
                                 let acc_confs_needs = self
@@ -1984,7 +1981,7 @@ impl Runtime {
                                     tx.clone(),
                                     endpoints,
                                     self.swap_id.clone(),
-                                    self.syncer_state.monero_height,
+                                    self.monero_address_creation_height,
                                 )?;
                                 let task = self.syncer_state.sweep_xmr(sweep_xmr.clone(), true);
                                 let acc_confs_needs = self
@@ -2054,7 +2051,7 @@ impl Runtime {
                                     endpoints,
                                     tx.clone(),
                                     self.swap_id.clone(),
-                                    self.syncer_state.monero_height,
+                                    self.monero_address_creation_height,
                                 )?;
                                 let task = self.syncer_state.sweep_xmr(sweep_xmr.clone(), true);
                                 let acc_confs_needs = self
diff --git a/src/swapd/syncer_client.rs b/src/swapd/syncer_client.rs
index ebe41d0f..6f93eef6 100644
--- a/src/swapd/syncer_client.rs
+++ b/src/swapd/syncer_client.rs
@@ -265,7 +265,6 @@ impl SyncerState {
             lifetime,
             addendum: SweepAddressAddendum::Bitcoin(addendum),
             retry,
-            from_height: None,
         };
         let task = Task::SweepAddress(sweep_task);
         self.tasks.tasks.insert(id, task.clone());
@@ -281,7 +280,6 @@ impl SyncerState {
             lifetime,
             addendum: SweepAddressAddendum::Monero(addendum),
             retry,
-            from_height: None,
         };
         let task = Task::SweepAddress(sweep_task);
         self.tasks.tasks.insert(id, task.clone());
diff --git a/src/swapd/wallet.rs b/src/swapd/wallet.rs
index e91a1ada..a6f65de9 100644
--- a/src/swapd/wallet.rs
+++ b/src/swapd/wallet.rs
@@ -483,7 +483,7 @@ impl Wallet {
         buy_tx: bitcoin::Transaction,
         endpoints: &mut Endpoints,
         swap_id: SwapId,
-        current_monero_block_height: u64,
+        monero_address_creation_height: Option<u64>,
     ) -> Result<SweepMoneroAddress, Error> {
         if let Wallet::Bob(BobState {
             bob,
@@ -558,7 +558,7 @@ impl Wallet {
                         swap_id: Some(swap_id),
                         view: keypair.view.as_bytes().try_into().unwrap(),
                         spend: keypair.spend.as_bytes().try_into().unwrap(),
-                        creation_height: Some(current_monero_block_height),
+                        creation_height: monero_address_creation_height,
                     },
                 })),
             )?;
@@ -568,6 +568,7 @@ impl Wallet {
                 source_spend_key: spend,
                 destination_address: target_monero_address.clone(),
                 minimum_balance: pub_offer.offer.accordant_amount,
+                from_height: monero_address_creation_height,
             };
             Ok(sweep_keys)
         } else {
@@ -580,7 +581,7 @@ impl Wallet {
         endpoints: &mut Endpoints,
         refund_tx: bitcoin::Transaction,
         swap_id: SwapId,
-        current_monero_block_height: u64,
+        monero_address_creation_height: Option<u64>,
     ) -> Result<SweepMoneroAddress, Error> {
         if let Wallet::Alice(AliceState {
             alice,
@@ -657,7 +658,7 @@ impl Wallet {
                         swap_id: Some(swap_id),
                         view: keypair.view.as_bytes().try_into().unwrap(),
                         spend: keypair.spend.as_bytes().try_into().unwrap(),
-                        creation_height: Some(current_monero_block_height),
+                        creation_height: monero_address_creation_height,
                     },
                 })),
             )?;
@@ -667,6 +668,7 @@ impl Wallet {
                 source_spend_key: spend,
                 destination_address: target_monero_address.clone(),
                 minimum_balance: pub_offer.offer.accordant_amount,
+                from_height: monero_address_creation_height,
             };
             Ok(sweep_keys)
         } else {
diff --git a/src/syncerd/monero_syncer.rs b/src/syncerd/monero_syncer.rs
index 8c0a3b02..5fb0b57e 100644
--- a/src/syncerd/monero_syncer.rs
+++ b/src/syncerd/monero_syncer.rs
@@ -703,7 +703,7 @@ fn sweep_polling(
                         addendum.minimum_balance,
                         &network,
                         Arc::clone(&wallet),
-                        sweep_address_task.from_height,
+                        addendum.from_height,
                         wallet_dir_path.clone(),
                     )
                     .await
diff --git a/src/syncerd/syncer_state.rs b/src/syncerd/syncer_state.rs
index a21cbb3f..d5607f2c 100644
--- a/src/syncerd/syncer_state.rs
+++ b/src/syncerd/syncer_state.rs
@@ -1088,7 +1088,6 @@ async fn syncer_state_sweep_addresses() {
         id: TaskId(0),
         lifetime: 11,
         retry: true,
-        from_height: None,
         addendum: SweepAddressAddendum::Monero(SweepMoneroAddress {
             source_view_key: monero::PrivateKey::from_str(
                 "77916d0cd56ed1920aef6ca56d8a41bac915b68e4c46a589e0956e27a7b77404",
@@ -1103,6 +1102,7 @@ async fn syncer_state_sweep_addresses() {
             )
             .unwrap(),
             minimum_balance: monero::Amount::from_pico(1),
+            from_height: None,
         }),
     };
     let source1 = ServiceId::Syncer(Blockchain::Monero, Network::Mainnet);
diff --git a/src/syncerd/types.rs b/src/syncerd/types.rs
index d293214d..e695443b 100644
--- a/src/syncerd/types.rs
+++ b/src/syncerd/types.rs
@@ -68,7 +68,6 @@ pub struct SweepAddress {
     pub id: TaskId,
     pub lifetime: u64,
     pub addendum: SweepAddressAddendum,
-    pub from_height: Option<u64>,
 }
 
 #[derive(Clone, Debug, Display, StrictEncode, StrictDecode, Eq, PartialEq, Hash)]
@@ -99,6 +98,7 @@ pub struct SweepMoneroAddress {
     pub destination_address: monero::Address,
     #[serde(with = "monero::util::amount::serde::as_xmr")]
     pub minimum_balance: monero::Amount,
+    pub from_height: Option<u64>,
 }
 
 #[derive(Clone, Debug, Display, StrictEncode, StrictDecode, Eq, PartialEq, Hash)]


Test patch:
diff --git a/tests/bitcoin.rs b/tests/bitcoin.rs
index 1bfd9e0f..2dbdba63 100644
--- a/tests/bitcoin.rs
+++ b/tests/bitcoin.rs
@@ -969,7 +969,6 @@ fn bitcoin_syncer_sweep_address_test() {
         task: Task::SweepAddress(SweepAddress {
             id: TaskId(0),
             lifetime: blocks,
-            from_height: None,
             retry: true,
             addendum: SweepAddressAddendum::Bitcoin(SweepBitcoinAddress {
                 source_secret_key,
@@ -1031,7 +1030,6 @@ fn bitcoin_syncer_sweep_address_test() {
         task: Task::SweepAddress(SweepAddress {
             id: TaskId(0),
             lifetime: blocks,
-            from_height: None,
             retry: true,
             addendum: SweepAddressAddendum::Bitcoin(SweepBitcoinAddress {
                 source_secret_key,
diff --git a/tests/monero.rs b/tests/monero.rs
index ad7578bf..b7a7f182 100644
--- a/tests/monero.rs
+++ b/tests/monero.rs
@@ -164,13 +164,13 @@ async fn monero_syncer_sweep_test() {
         task: Task::SweepAddress(SweepAddress {
             id: TaskId(0),
             lifetime: blocks + 40,
-            from_height: None,
             retry: true,
             addendum: SweepAddressAddendum::Monero(SweepMoneroAddress {
                 source_spend_key,
                 source_view_key,
                 destination_address,
                 minimum_balance: monero::Amount::from_pico(1000000000000),
+                from_height: None,
             }),
         }),
         source: SOURCE2.clone(),