From 53267a46c815fd4a1c374a6a5ae9456720bf8342 Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 9 Jul 2022 18:53:52 -0400 Subject: [PATCH] Return Timelocked instead of (Timelock, Vec) Timelocked doesn't expose the Vec yet requires calling not_locked(), unlocked(Timelock), or ignore_timelock(). --- coins/monero/src/transaction.rs | 13 +++++++++++++ coins/monero/src/wallet/scan.rs | 30 +++++++++++++++++++++++++++--- coins/monero/tests/send.rs | 4 ++-- processor/build.rs | 3 +++ processor/src/coin/monero.rs | 13 +++---------- 5 files changed, 48 insertions(+), 15 deletions(-) create mode 100644 processor/build.rs diff --git a/coins/monero/src/transaction.rs b/coins/monero/src/transaction.rs index 32c68750..9c3ea5bc 100644 --- a/coins/monero/src/transaction.rs +++ b/coins/monero/src/transaction.rs @@ -1,3 +1,5 @@ +use core::cmp::Ordering; + use curve25519_dalek::edwards::EdwardsPoint; use crate::{hash, serialize::*, ringct::{RctPrunable, RctSignatures}}; @@ -131,6 +133,17 @@ impl Timelock { } } +impl PartialOrd for Timelock { + fn partial_cmp(&self, other: &Self) -> Option { + match (self, other) { + (Timelock::None, _) => Some(Ordering::Less), + (Timelock::Block(a), Timelock::Block(b)) => a.partial_cmp(b), + (Timelock::Time(a), Timelock::Time(b)) => a.partial_cmp(b), + _ => None + } + } +} + #[derive(Clone, PartialEq, Debug)] pub struct TransactionPrefix { pub version: u64, diff --git a/coins/monero/src/wallet/scan.rs b/coins/monero/src/wallet/scan.rs index c813169e..8ca7797f 100644 --- a/coins/monero/src/wallet/scan.rs +++ b/coins/monero/src/wallet/scan.rs @@ -24,6 +24,30 @@ pub struct SpendableOutput { pub commitment: Commitment } +pub struct Timelocked(Timelock, Vec); +impl Timelocked { + pub fn timelock(&self) -> Timelock { + self.0 + } + + pub fn not_locked(&self) -> Vec { + if self.0 == Timelock::None { + return self.1.clone(); + } + vec![] + } + + /// Returns None if the Timelocks aren't comparable. Returns Some(vec![]) if none are unlocked + pub fn unlocked(&self, timelock: Timelock) -> Option> { + // If the Timelocks are comparable, return the outputs if they're now unlocked + self.0.partial_cmp(&timelock).filter(|_| self.0 <= timelock).map(|_| self.1.clone()) + } + + pub fn ignore_timelock(&self) -> Vec { + self.1.clone() + } +} + impl SpendableOutput { pub fn serialize(&self) -> Vec { let mut res = Vec::with_capacity(32 + 1 + 32 + 32 + 40); @@ -57,7 +81,7 @@ impl Transaction { &self, view: ViewPair, guaranteed: bool - ) -> (Vec, Timelock) { + ) -> Timelocked { let mut extra = vec![]; write_varint(&u64::try_from(self.prefix.extra.len()).unwrap(), &mut extra).unwrap(); extra.extend(&self.prefix.extra); @@ -75,7 +99,7 @@ impl Transaction { pubkeys = m_pubkeys.iter().map(|key| key.point.decompress()).filter_map(|key| key).collect(); } else { - return (vec![], self.prefix.timelock); + return Timelocked(self.prefix.timelock, vec![]); }; let mut res = vec![]; @@ -132,6 +156,6 @@ impl Transaction { } } - (res, self.prefix.timelock) + Timelocked(self.prefix.timelock, res) } } diff --git a/coins/monero/tests/send.rs b/coins/monero/tests/send.rs index a3585ce0..c875a023 100644 --- a/coins/monero/tests/send.rs +++ b/coins/monero/tests/send.rs @@ -91,7 +91,7 @@ async fn send_core(test: usize, multisig: bool) { // Grab the largest output available let output = { - let mut outputs = tx.as_ref().unwrap().scan(view_pair, false).0; + let mut outputs = tx.as_ref().unwrap().scan(view_pair, false).ignore_timelock(); outputs.sort_by(|x, y| x.commitment.amount.cmp(&y.commitment.amount).reverse()); outputs.swap_remove(0) }; @@ -116,7 +116,7 @@ async fn send_core(test: usize, multisig: bool) { for i in (start + 1) .. (start + 9) { let tx = rpc.get_block_transactions(i).await.unwrap().swap_remove(0); - let output = tx.scan(view_pair, false).0.swap_remove(0); + let output = tx.scan(view_pair, false).ignore_timelock().swap_remove(0); amount += output.commitment.amount; outputs.push(output); } diff --git a/processor/build.rs b/processor/build.rs new file mode 100644 index 00000000..a8fb5e40 --- /dev/null +++ b/processor/build.rs @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rustc-link-arg=-zmuldefs"); +} diff --git a/processor/src/coin/monero.rs b/processor/src/coin/monero.rs index 980dedde..192650cd 100644 --- a/processor/src/coin/monero.rs +++ b/processor/src/coin/monero.rs @@ -9,7 +9,7 @@ use transcript::RecommendedTranscript; use frost::{curve::Ed25519, FrostKeys}; use monero_serai::{ - transaction::{Timelock, Transaction}, + transaction::Transaction, rpc::Rpc, wallet::{ ViewPair, address::{Network, AddressType, Address}, @@ -126,14 +126,7 @@ impl Coin for Monero { async fn get_outputs(&self, block: &Self::Block, key: dfg::EdwardsPoint) -> Vec { block .iter() - .flat_map(|tx| { - let (outputs, timelock) = tx.scan(self.view_pair(key), true); - if timelock == Timelock::None { - outputs - } else { - vec![] - } - }) + .flat_map(|tx| tx.scan(self.view_pair(key), true).not_locked()) .map(Output::from) .collect() } @@ -215,7 +208,7 @@ impl Coin for Monero { let outputs = self.rpc .get_block_transactions_possible(height).await.unwrap() - .swap_remove(0).scan(self.empty_view_pair(), false).0; + .swap_remove(0).scan(self.empty_view_pair(), false).ignore_timelock(); let amount = outputs[0].commitment.amount; let fee = 1000000000; // TODO