mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-23 03:59:22 +00:00
This commit is contained in:
parent
5751204a98
commit
5a1f011db8
4 changed files with 38 additions and 14 deletions
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::{HashSet, HashMap};
|
||||||
|
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
|
|
||||||
|
@ -124,19 +124,25 @@ impl ViewPair {
|
||||||
pub struct Scanner {
|
pub struct Scanner {
|
||||||
pair: ViewPair,
|
pair: ViewPair,
|
||||||
network: Network,
|
network: Network,
|
||||||
guaranteed: bool,
|
|
||||||
pub(crate) subaddresses: HashMap<CompressedEdwardsY, (u32, u32)>,
|
pub(crate) subaddresses: HashMap<CompressedEdwardsY, (u32, u32)>,
|
||||||
|
pub(crate) burning_bug: Option<HashSet<CompressedEdwardsY>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Zeroize for Scanner {
|
impl Zeroize for Scanner {
|
||||||
fn zeroize(&mut self) {
|
fn zeroize(&mut self) {
|
||||||
self.pair.zeroize();
|
self.pair.zeroize();
|
||||||
self.network.zeroize();
|
self.network.zeroize();
|
||||||
self.guaranteed.zeroize();
|
|
||||||
|
// These may not be effective, unfortunately
|
||||||
for (mut key, mut value) in self.subaddresses.drain() {
|
for (mut key, mut value) in self.subaddresses.drain() {
|
||||||
key.zeroize();
|
key.zeroize();
|
||||||
value.zeroize();
|
value.zeroize();
|
||||||
}
|
}
|
||||||
|
if let Some(ref mut burning_bug) = self.burning_bug.take() {
|
||||||
|
for mut output in burning_bug.drain() {
|
||||||
|
output.zeroize();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,17 +155,23 @@ impl Drop for Scanner {
|
||||||
impl ZeroizeOnDrop for Scanner {}
|
impl ZeroizeOnDrop for Scanner {}
|
||||||
|
|
||||||
impl Scanner {
|
impl Scanner {
|
||||||
pub fn from_view(pair: ViewPair, network: Network, guaranteed: bool) -> Scanner {
|
// For burning bug immune addresses (Featured Address w/ the Guaranteed feature), pass None
|
||||||
|
// For traditional Monero address, provide a HashSet of all historically scanned output keys
|
||||||
|
pub fn from_view(
|
||||||
|
pair: ViewPair,
|
||||||
|
network: Network,
|
||||||
|
burning_bug: Option<HashSet<CompressedEdwardsY>>,
|
||||||
|
) -> Scanner {
|
||||||
let mut subaddresses = HashMap::new();
|
let mut subaddresses = HashMap::new();
|
||||||
subaddresses.insert(pair.spend.compress(), (0, 0));
|
subaddresses.insert(pair.spend.compress(), (0, 0));
|
||||||
Scanner { pair, network, guaranteed, subaddresses }
|
Scanner { pair, network, subaddresses, burning_bug }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn address(&self) -> Address {
|
pub fn address(&self) -> Address {
|
||||||
Address::new(
|
Address::new(
|
||||||
AddressMeta {
|
AddressMeta {
|
||||||
network: self.network,
|
network: self.network,
|
||||||
kind: if self.guaranteed {
|
kind: if self.burning_bug.is_none() {
|
||||||
AddressType::Featured(false, None, true)
|
AddressType::Featured(false, None, true)
|
||||||
} else {
|
} else {
|
||||||
AddressType::Standard
|
AddressType::Standard
|
||||||
|
@ -181,7 +193,7 @@ impl Scanner {
|
||||||
Address::new(
|
Address::new(
|
||||||
AddressMeta {
|
AddressMeta {
|
||||||
network: self.network,
|
network: self.network,
|
||||||
kind: if self.guaranteed {
|
kind: if self.burning_bug.is_none() {
|
||||||
AddressType::Featured(true, None, true)
|
AddressType::Featured(true, None, true)
|
||||||
} else {
|
} else {
|
||||||
AddressType::Subaddress
|
AddressType::Subaddress
|
||||||
|
|
|
@ -95,7 +95,7 @@ impl SpendableOutput {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scanner {
|
impl Scanner {
|
||||||
pub fn scan(&self, tx: &Transaction) -> Timelocked {
|
pub fn scan(&mut self, tx: &Transaction) -> Timelocked {
|
||||||
let extra = Extra::deserialize(&mut Cursor::new(&tx.prefix.extra));
|
let extra = Extra::deserialize(&mut Cursor::new(&tx.prefix.extra));
|
||||||
let keys;
|
let keys;
|
||||||
let extra = if let Ok(extra) = extra {
|
let extra = if let Ok(extra) = extra {
|
||||||
|
@ -108,9 +108,17 @@ impl Scanner {
|
||||||
|
|
||||||
let mut res = vec![];
|
let mut res = vec![];
|
||||||
for (o, output) in tx.prefix.outputs.iter().enumerate() {
|
for (o, output) in tx.prefix.outputs.iter().enumerate() {
|
||||||
|
// https://github.com/serai-dex/serai/issues/102
|
||||||
|
let output_key_compressed = output.key.compress();
|
||||||
|
if let Some(burning_bug) = self.burning_bug.as_ref() {
|
||||||
|
if burning_bug.contains(&output_key_compressed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for key in &keys {
|
for key in &keys {
|
||||||
let (view_tag, key_offset, payment_id_xor) = shared_key(
|
let (view_tag, key_offset, payment_id_xor) = shared_key(
|
||||||
if self.guaranteed { Some(uniqueness(&tx.prefix.inputs)) } else { None },
|
if self.burning_bug.is_none() { Some(uniqueness(&tx.prefix.inputs)) } else { None },
|
||||||
&self.pair.view,
|
&self.pair.view,
|
||||||
key,
|
key,
|
||||||
o,
|
o,
|
||||||
|
@ -173,6 +181,10 @@ impl Scanner {
|
||||||
subaddress: (0, 0),
|
subaddress: (0, 0),
|
||||||
payment_id,
|
payment_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if let Some(burning_bug) = self.burning_bug.as_mut() {
|
||||||
|
burning_bug.insert(output_key_compressed);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Break to prevent public keys from being included multiple times, triggering multiple
|
// Break to prevent public keys from being included multiple times, triggering multiple
|
||||||
// inclusions of the same output
|
// inclusions of the same output
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::sync::Mutex;
|
use std::{sync::Mutex, collections::HashSet};
|
||||||
#[cfg(feature = "multisig")]
|
#[cfg(feature = "multisig")]
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
@ -75,7 +75,7 @@ async fn send_core(test: usize, multisig: bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
let view_pair = ViewPair::new(spend_pub, view);
|
let view_pair = ViewPair::new(spend_pub, view);
|
||||||
let scanner = Scanner::from_view(view_pair, Network::Mainnet, false);
|
let mut scanner = Scanner::from_view(view_pair, Network::Mainnet, Some(HashSet::new()));
|
||||||
let addr = scanner.address();
|
let addr = scanner.address();
|
||||||
|
|
||||||
let fee = rpc.get_fee().await.unwrap();
|
let fee = rpc.get_fee().await.unwrap();
|
||||||
|
|
|
@ -72,7 +72,7 @@ impl Monero {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scanner(&self, spend: dfg::EdwardsPoint) -> Scanner {
|
fn scanner(&self, spend: dfg::EdwardsPoint) -> Scanner {
|
||||||
Scanner::from_view(ViewPair::new(spend.0, self.view), Network::Mainnet, true)
|
Scanner::from_view(ViewPair::new(spend.0, self.view), Network::Mainnet, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -81,7 +81,7 @@ impl Monero {
|
||||||
Scanner::from_view(
|
Scanner::from_view(
|
||||||
ViewPair::new(*dfg::EdwardsPoint::generator(), Scalar::one()),
|
ViewPair::new(*dfg::EdwardsPoint::generator(), Scalar::one()),
|
||||||
Network::Mainnet,
|
Network::Mainnet,
|
||||||
false,
|
Some(std::collections::HashSet::new()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ impl Coin for Monero {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_outputs(&self, block: &Self::Block, key: dfg::EdwardsPoint) -> Vec<Self::Output> {
|
async fn get_outputs(&self, block: &Self::Block, key: dfg::EdwardsPoint) -> Vec<Self::Output> {
|
||||||
let scanner = self.scanner(key);
|
let mut scanner = self.scanner(key);
|
||||||
block.iter().flat_map(|tx| scanner.scan(tx).not_locked()).map(Output::from).collect()
|
block.iter().flat_map(|tx| scanner.scan(tx).not_locked()).map(Output::from).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue