mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-22 19:49: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};
|
||||
|
||||
|
@ -124,19 +124,25 @@ impl ViewPair {
|
|||
pub struct Scanner {
|
||||
pair: ViewPair,
|
||||
network: Network,
|
||||
guaranteed: bool,
|
||||
pub(crate) subaddresses: HashMap<CompressedEdwardsY, (u32, u32)>,
|
||||
pub(crate) burning_bug: Option<HashSet<CompressedEdwardsY>>,
|
||||
}
|
||||
|
||||
impl Zeroize for Scanner {
|
||||
fn zeroize(&mut self) {
|
||||
self.pair.zeroize();
|
||||
self.network.zeroize();
|
||||
self.guaranteed.zeroize();
|
||||
|
||||
// These may not be effective, unfortunately
|
||||
for (mut key, mut value) in self.subaddresses.drain() {
|
||||
key.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 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();
|
||||
subaddresses.insert(pair.spend.compress(), (0, 0));
|
||||
Scanner { pair, network, guaranteed, subaddresses }
|
||||
Scanner { pair, network, subaddresses, burning_bug }
|
||||
}
|
||||
|
||||
pub fn address(&self) -> Address {
|
||||
Address::new(
|
||||
AddressMeta {
|
||||
network: self.network,
|
||||
kind: if self.guaranteed {
|
||||
kind: if self.burning_bug.is_none() {
|
||||
AddressType::Featured(false, None, true)
|
||||
} else {
|
||||
AddressType::Standard
|
||||
|
@ -181,7 +193,7 @@ impl Scanner {
|
|||
Address::new(
|
||||
AddressMeta {
|
||||
network: self.network,
|
||||
kind: if self.guaranteed {
|
||||
kind: if self.burning_bug.is_none() {
|
||||
AddressType::Featured(true, None, true)
|
||||
} else {
|
||||
AddressType::Subaddress
|
||||
|
|
|
@ -95,7 +95,7 @@ impl SpendableOutput {
|
|||
}
|
||||
|
||||
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 keys;
|
||||
let extra = if let Ok(extra) = extra {
|
||||
|
@ -108,9 +108,17 @@ impl Scanner {
|
|||
|
||||
let mut res = vec![];
|
||||
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 {
|
||||
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,
|
||||
key,
|
||||
o,
|
||||
|
@ -173,6 +181,10 @@ impl Scanner {
|
|||
subaddress: (0, 0),
|
||||
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
|
||||
// inclusions of the same output
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::sync::Mutex;
|
||||
use std::{sync::Mutex, collections::HashSet};
|
||||
#[cfg(feature = "multisig")]
|
||||
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 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 fee = rpc.get_fee().await.unwrap();
|
||||
|
|
|
@ -72,7 +72,7 @@ impl Monero {
|
|||
}
|
||||
|
||||
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)]
|
||||
|
@ -81,7 +81,7 @@ impl Monero {
|
|||
Scanner::from_view(
|
||||
ViewPair::new(*dfg::EdwardsPoint::generator(), Scalar::one()),
|
||||
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> {
|
||||
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()
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue