Update monero-wallet tests to compile

Some are _consistently_ failing due to the inputs we attempt to spend being too
young. I'm unsure what's up with that. Most seem to pass _consistently_,
implying it's not a random issue yet some configuration/env aspect.
This commit is contained in:
Luke Parker
2024-06-28 16:04:08 -04:00
parent 891362a710
commit 8319d219d7
10 changed files with 191 additions and 218 deletions

View File

@@ -32,7 +32,7 @@ async fn select_n<'a, R: RngCore + CryptoRng>(
fingerprintable_canonical: bool, fingerprintable_canonical: bool,
) -> Result<Vec<(u64, [EdwardsPoint; 2])>, RpcError> { ) -> Result<Vec<(u64, [EdwardsPoint; 2])>, RpcError> {
// TODO: consider removing this extra RPC and expect the caller to handle it // TODO: consider removing this extra RPC and expect the caller to handle it
if fingerprintable_canonical && height > rpc.get_height().await? { if fingerprintable_canonical && (height > rpc.get_height().await?) {
// TODO: Don't use InternalError for the caller's failure // TODO: Don't use InternalError for the caller's failure
Err(RpcError::InternalError("decoys being requested from too young blocks"))?; Err(RpcError::InternalError("decoys being requested from too young blocks"))?;
} }

View File

@@ -1,140 +0,0 @@
use std::sync::{Arc, RwLock};
use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
use crate::{
WalletProtocol, address::MoneroAddress, FeeRate, SpendableOutput, Change, Decoys, SignableTransaction,
TransactionError, extra::MAX_ARBITRARY_DATA_SIZE,
};
#[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)]
struct SignableTransactionBuilderInternal {
protocol: WalletProtocol,
fee_rate: FeeRate,
r_seed: Option<Zeroizing<[u8; 32]>>,
inputs: Vec<(SpendableOutput, Decoys)>,
payments: Vec<(MoneroAddress, u64)>,
change_address: Change,
data: Vec<Vec<u8>>,
}
impl SignableTransactionBuilderInternal {
// Takes in the change address so users don't miss that they have to manually set one
// If they don't, all leftover funds will become part of the fee
fn new(protocol: WalletProtocol, fee_rate: FeeRate, change_address: Change) -> Self {
Self {
protocol,
fee_rate,
r_seed: None,
inputs: vec![],
payments: vec![],
change_address,
data: vec![],
}
}
fn set_r_seed(&mut self, r_seed: Zeroizing<[u8; 32]>) {
self.r_seed = Some(r_seed);
}
fn add_input(&mut self, input: (SpendableOutput, Decoys)) {
self.inputs.push(input);
}
fn add_inputs(&mut self, inputs: &[(SpendableOutput, Decoys)]) {
self.inputs.extend(inputs.iter().cloned());
}
fn add_payment(&mut self, dest: MoneroAddress, amount: u64) {
self.payments.push((dest, amount));
}
fn add_payments(&mut self, payments: &[(MoneroAddress, u64)]) {
self.payments.extend(payments);
}
fn add_data(&mut self, data: Vec<u8>) {
self.data.push(data);
}
}
/// A Transaction Builder for Monero transactions.
/// All methods provided will modify self while also returning a shallow copy, enabling efficient
/// chaining with a clean API.
/// In order to fork the builder at some point, clone will still return a deep copy.
#[derive(Debug)]
pub struct SignableTransactionBuilder(Arc<RwLock<SignableTransactionBuilderInternal>>);
impl Clone for SignableTransactionBuilder {
fn clone(&self) -> Self {
Self(Arc::new(RwLock::new((*self.0.read().unwrap()).clone())))
}
}
impl PartialEq for SignableTransactionBuilder {
fn eq(&self, other: &Self) -> bool {
*self.0.read().unwrap() == *other.0.read().unwrap()
}
}
impl Eq for SignableTransactionBuilder {}
impl Zeroize for SignableTransactionBuilder {
fn zeroize(&mut self) {
self.0.write().unwrap().zeroize()
}
}
impl SignableTransactionBuilder {
fn shallow_copy(&self) -> Self {
Self(self.0.clone())
}
pub fn new(protocol: WalletProtocol, fee_rate: FeeRate, change_address: Change) -> Self {
Self(Arc::new(RwLock::new(SignableTransactionBuilderInternal::new(
protocol,
fee_rate,
change_address,
))))
}
pub fn set_r_seed(&mut self, r_seed: Zeroizing<[u8; 32]>) -> Self {
self.0.write().unwrap().set_r_seed(r_seed);
self.shallow_copy()
}
pub fn add_input(&mut self, input: (SpendableOutput, Decoys)) -> Self {
self.0.write().unwrap().add_input(input);
self.shallow_copy()
}
pub fn add_inputs(&mut self, inputs: &[(SpendableOutput, Decoys)]) -> Self {
self.0.write().unwrap().add_inputs(inputs);
self.shallow_copy()
}
pub fn add_payment(&mut self, dest: MoneroAddress, amount: u64) -> Self {
self.0.write().unwrap().add_payment(dest, amount);
self.shallow_copy()
}
pub fn add_payments(&mut self, payments: &[(MoneroAddress, u64)]) -> Self {
self.0.write().unwrap().add_payments(payments);
self.shallow_copy()
}
pub fn add_data(&mut self, data: Vec<u8>) -> Result<Self, TransactionError> {
if data.len() > MAX_ARBITRARY_DATA_SIZE {
Err(TransactionError::TooMuchData)?;
}
self.0.write().unwrap().add_data(data);
Ok(self.shallow_copy())
}
pub fn build(self) -> Result<SignableTransaction, TransactionError> {
let read = self.0.read().unwrap();
SignableTransaction::new(
read.protocol,
read.r_seed.clone(),
read.inputs.clone(),
read.payments.clone(),
&read.change_address,
read.data.clone(),
read.fee_rate,
)
}
}

View File

@@ -321,11 +321,27 @@ impl SignableTransaction {
} }
} }
let res = SignableTransaction { rct_type, sender_view_key, inputs, payments, data, fee_rate }; let mut res =
SignableTransaction { rct_type, sender_view_key, inputs, payments, data, fee_rate };
res.validate()?; res.validate()?;
// Shuffle the payments
{
let mut rng = res.seeded_rng(b"shuffle_payments");
res.payments.shuffle(&mut rng);
}
Ok(res) Ok(res)
} }
pub fn fee_rate(&self) -> FeeRate {
self.fee_rate
}
pub fn fee(&self) -> u64 {
self.weight_and_fee().1
}
pub fn write<W: io::Write>(&self, w: &mut W) -> io::Result<()> { pub fn write<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
fn write_input<W: io::Write>(input: &(SpendableOutput, Decoys), w: &mut W) -> io::Result<()> { fn write_input<W: io::Write>(input: &(SpendableOutput, Decoys), w: &mut W) -> io::Result<()> {
input.0.write(w)?; input.0.write(w)?;
@@ -424,12 +440,6 @@ impl SignableTransaction {
key_images.push(key_image); key_images.push(key_image);
} }
// Shuffle the payments
{
let mut rng = self.seeded_rng(b"shuffle_payments");
self.payments.shuffle(&mut rng);
}
SignableTransactionWithKeyImages { intent: self, key_images } SignableTransactionWithKeyImages { intent: self, key_images }
} }

View File

@@ -1,5 +1,5 @@
use monero_serai::transaction::Transaction; use monero_serai::transaction::Transaction;
use monero_wallet::{rpc::Rpc, TransactionError, extra::MAX_ARBITRARY_DATA_SIZE}; use monero_wallet::{rpc::Rpc, extra::MAX_ARBITRARY_DATA_SIZE, send::SendError};
mod runner; mod runner;
@@ -56,7 +56,7 @@ test!(
let mut data = vec![b'a'; MAX_ARBITRARY_DATA_SIZE + 1]; let mut data = vec![b'a'; MAX_ARBITRARY_DATA_SIZE + 1];
// Make sure we get an error if we try to add it to the TX // Make sure we get an error if we try to add it to the TX
assert_eq!(builder.add_data(data.clone()), Err(TransactionError::TooMuchData)); assert_eq!(builder.add_data(data.clone()), Err(SendError::TooMuchData));
// Reduce data size and retry. The data will now be 255 bytes long (including the added // Reduce data size and retry. The data will now be 255 bytes long (including the added
// marker), exactly // marker), exactly

View File

@@ -3,7 +3,7 @@ use monero_wallet::{
DEFAULT_LOCK_WINDOW, DEFAULT_LOCK_WINDOW,
transaction::Transaction, transaction::Transaction,
rpc::{OutputResponse, Rpc}, rpc::{OutputResponse, Rpc},
SpendableOutput, scan::SpendableOutput,
}; };
mod runner; mod runner;
@@ -24,12 +24,12 @@ test!(
), ),
( (
// Then make a second tx1 // Then make a second tx1
|protocol: Protocol, rpc: SimpleRequestRpc, mut builder: Builder, addr, state: _| async move { |rct_type: RctType, rpc: SimpleRequestRpc, mut builder: Builder, addr, state: _| async move {
let output_tx0: SpendableOutput = state; let output_tx0: SpendableOutput = state;
let decoys = Decoys::fingerprintable_canonical_select( let decoys = Decoys::fingerprintable_canonical_select(
&mut OsRng, &mut OsRng,
&rpc, &rpc,
protocol.ring_len(), ring_len(rct_type),
rpc.get_height().await.unwrap(), rpc.get_height().await.unwrap(),
&[output_tx0.clone()], &[output_tx0.clone()],
) )
@@ -40,7 +40,7 @@ test!(
builder.add_inputs(&inputs); builder.add_inputs(&inputs);
builder.add_payment(addr, 1000000000000); builder.add_payment(addr, 1000000000000);
(builder.build().unwrap(), (protocol, output_tx0)) (builder.build().unwrap(), (rct_type, output_tx0))
}, },
// Then make sure DSA selects freshly unlocked output from tx1 as a decoy // Then make sure DSA selects freshly unlocked output from tx1 as a decoy
|rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move { |rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move {
@@ -61,14 +61,14 @@ test!(
// Select decoys using spendable output from tx0 as the real, and make sure DSA selects // Select decoys using spendable output from tx0 as the real, and make sure DSA selects
// the freshly unlocked output from tx1 as a decoy // the freshly unlocked output from tx1 as a decoy
let (protocol, output_tx0): (Protocol, SpendableOutput) = state; let (rct_type, output_tx0): (RctType, SpendableOutput) = state;
let mut selected_fresh_decoy = false; let mut selected_fresh_decoy = false;
let mut attempts = 1000; let mut attempts = 1000;
while !selected_fresh_decoy && attempts > 0 { while !selected_fresh_decoy && attempts > 0 {
let decoys = Decoys::fingerprintable_canonical_select( let decoys = Decoys::fingerprintable_canonical_select(
&mut OsRng, // TODO: use a seeded RNG to consistently select the latest output &mut OsRng, // TODO: use a seeded RNG to consistently select the latest output
&rpc, &rpc,
protocol.ring_len(), ring_len(rct_type),
height, height,
&[output_tx0.clone()], &[output_tx0.clone()],
) )
@@ -101,12 +101,12 @@ test!(
), ),
( (
// Then make a second tx1 // Then make a second tx1
|protocol: Protocol, rpc: SimpleRequestRpc, mut builder: Builder, addr, state: _| async move { |rct_type: RctType, rpc: SimpleRequestRpc, mut builder: Builder, addr, state: _| async move {
let output_tx0: SpendableOutput = state; let output_tx0: SpendableOutput = state;
let decoys = Decoys::select( let decoys = Decoys::select(
&mut OsRng, &mut OsRng,
&rpc, &rpc,
protocol.ring_len(), ring_len(rct_type),
rpc.get_height().await.unwrap(), rpc.get_height().await.unwrap(),
&[output_tx0.clone()], &[output_tx0.clone()],
) )
@@ -117,7 +117,7 @@ test!(
builder.add_inputs(&inputs); builder.add_inputs(&inputs);
builder.add_payment(addr, 1000000000000); builder.add_payment(addr, 1000000000000);
(builder.build().unwrap(), (protocol, output_tx0)) (builder.build().unwrap(), (rct_type, output_tx0))
}, },
// Then make sure DSA selects freshly unlocked output from tx1 as a decoy // Then make sure DSA selects freshly unlocked output from tx1 as a decoy
|rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move { |rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move {
@@ -138,14 +138,14 @@ test!(
// Select decoys using spendable output from tx0 as the real, and make sure DSA selects // Select decoys using spendable output from tx0 as the real, and make sure DSA selects
// the freshly unlocked output from tx1 as a decoy // the freshly unlocked output from tx1 as a decoy
let (protocol, output_tx0): (Protocol, SpendableOutput) = state; let (rct_type, output_tx0): (RctType, SpendableOutput) = state;
let mut selected_fresh_decoy = false; let mut selected_fresh_decoy = false;
let mut attempts = 1000; let mut attempts = 1000;
while !selected_fresh_decoy && attempts > 0 { while !selected_fresh_decoy && attempts > 0 {
let decoys = Decoys::select( let decoys = Decoys::select(
&mut OsRng, // TODO: use a seeded RNG to consistently select the latest output &mut OsRng, // TODO: use a seeded RNG to consistently select the latest output
&rpc, &rpc,
protocol.ring_len(), ring_len(rct_type),
height, height,
&[output_tx0.clone()], &[output_tx0.clone()],
) )

View File

@@ -3,8 +3,8 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_POINT;
use monero_serai::transaction::Transaction; use monero_serai::transaction::Transaction;
use monero_wallet::{ use monero_wallet::{
rpc::Rpc, rpc::Rpc,
Eventuality,
address::{AddressType, AddressMeta, MoneroAddress}, address::{AddressType, AddressMeta, MoneroAddress},
send::Eventuality,
}; };
mod runner; mod runner;
@@ -50,9 +50,8 @@ test!(
), ),
4, 4,
); );
builder.set_r_seed(Zeroizing::new([0xbb; 32]));
let tx = builder.build().unwrap(); let tx = builder.build().unwrap();
let eventuality = tx.eventuality().unwrap(); let eventuality = Eventuality::from(tx.clone());
assert_eq!( assert_eq!(
eventuality, eventuality,
Eventuality::read::<&[u8]>(&mut eventuality.serialize().as_ref()).unwrap() Eventuality::read::<&[u8]>(&mut eventuality.serialize().as_ref()).unwrap()

View File

@@ -0,0 +1,85 @@
use zeroize::{Zeroize, Zeroizing};
use curve25519_dalek::Scalar;
use monero_wallet::{
primitives::Decoys,
ringct::RctType,
rpc::FeeRate,
address::MoneroAddress,
scan::SpendableOutput,
send::{Change, SendError, SignableTransaction},
extra::MAX_ARBITRARY_DATA_SIZE,
};
/// A builder for Monero transactions.
#[derive(Clone, PartialEq, Eq, Zeroize, Debug)]
pub struct SignableTransactionBuilder {
rct_type: RctType,
sender_view_key: Zeroizing<Scalar>,
inputs: Vec<(SpendableOutput, Decoys)>,
payments: Vec<(MoneroAddress, u64)>,
change: Change,
data: Vec<Vec<u8>>,
fee_rate: FeeRate,
}
impl SignableTransactionBuilder {
pub fn new(
rct_type: RctType,
sender_view_key: Zeroizing<Scalar>,
change: Change,
fee_rate: FeeRate,
) -> Self {
Self {
rct_type,
sender_view_key,
inputs: vec![],
payments: vec![],
change,
data: vec![],
fee_rate,
}
}
pub fn add_input(&mut self, input: (SpendableOutput, Decoys)) -> &mut Self {
self.inputs.push(input);
self
}
#[allow(unused)]
pub fn add_inputs(&mut self, inputs: &[(SpendableOutput, Decoys)]) -> &mut Self {
self.inputs.extend(inputs.iter().cloned());
self
}
pub fn add_payment(&mut self, dest: MoneroAddress, amount: u64) -> &mut Self {
self.payments.push((dest, amount));
self
}
#[allow(unused)]
pub fn add_payments(&mut self, payments: &[(MoneroAddress, u64)]) -> &mut Self {
self.payments.extend(payments);
self
}
#[allow(unused)]
pub fn add_data(&mut self, data: Vec<u8>) -> Result<&mut Self, SendError> {
if data.len() > MAX_ARBITRARY_DATA_SIZE {
Err(SendError::TooMuchData)?;
}
self.data.push(data);
Ok(self)
}
pub fn build(self) -> Result<SignableTransaction, SendError> {
SignableTransaction::new(
self.rct_type,
self.sender_view_key,
self.inputs,
self.payments,
self.change,
self.data,
self.fee_rate,
)
}
}

View File

@@ -10,13 +10,25 @@ use tokio::sync::Mutex;
use monero_simple_request_rpc::SimpleRequestRpc; use monero_simple_request_rpc::SimpleRequestRpc;
use monero_wallet::{ use monero_wallet::{
ringct::RctType,
transaction::Transaction, transaction::Transaction,
rpc::Rpc, rpc::{Rpc, FeeRate},
ViewPair, Scanner, ViewPair,
address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress}, address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress},
SpendableOutput, FeeRate, scan::{SpendableOutput, Scanner},
}; };
mod builder;
pub use builder::SignableTransactionBuilder;
pub fn ring_len(rct_type: RctType) -> usize {
match rct_type {
RctType::ClsagBulletproof => 11,
RctType::ClsagBulletproofPlus => 16,
_ => panic!("ring size unknown for RctType"),
}
}
pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) { pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) {
let spend = Scalar::random(&mut OsRng); let spend = Scalar::random(&mut OsRng);
let spend_pub = &spend * ED25519_BASEPOINT_TABLE; let spend_pub = &spend * ED25519_BASEPOINT_TABLE;
@@ -56,7 +68,7 @@ pub async fn mine_until_unlocked(rpc: &SimpleRequestRpc, addr: &str, tx_hash: [u
.await .await
.unwrap() .unwrap()
.into_iter() .into_iter()
.all(|output| output.is_some()) .any(|output| output.is_none())
{ {
height = rpc.generate_blocks(addr, 1).await.unwrap().1 + 1; height = rpc.generate_blocks(addr, 1).await.unwrap().1 + 1;
} }
@@ -159,8 +171,6 @@ macro_rules! test {
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar}; use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar};
#[cfg(feature = "multisig")]
use transcript::{Transcript, RecommendedTranscript};
#[cfg(feature = "multisig")] #[cfg(feature = "multisig")]
use frost::{ use frost::{
curve::Ed25519, curve::Ed25519,
@@ -169,15 +179,19 @@ macro_rules! test {
}; };
use monero_wallet::{ use monero_wallet::{
Protocol, primitives::Decoys,
ringct::RctType,
rpc::FeePriority,
address::{Network, AddressSpec}, address::{Network, AddressSpec},
ViewPair, Scanner, Change, DecoySelection, Decoys, FeePriority, ViewPair,
SignableTransaction, SignableTransactionBuilder, DecoySelection,
scan::Scanner,
send::{Change, SignableTransaction},
}; };
use runner::{ use runner::{
random_address, rpc, mine_until_unlocked, get_miner_tx_output, SignableTransactionBuilder, ring_len, random_address, rpc, mine_until_unlocked,
check_weight_and_fee, get_miner_tx_output, check_weight_and_fee,
}; };
type Builder = SignableTransactionBuilder; type Builder = SignableTransactionBuilder;
@@ -206,16 +220,21 @@ macro_rules! test {
let rpc = rpc().await; let rpc = rpc().await;
let view = ViewPair::new(spend_pub, Zeroizing::new(Scalar::random(&mut OsRng))); let view_priv = Zeroizing::new(Scalar::random(&mut OsRng));
let view = ViewPair::new(spend_pub, view_priv.clone());
let addr = view.address(Network::Mainnet, AddressSpec::Standard); let addr = view.address(Network::Mainnet, AddressSpec::Standard);
let miner_tx = get_miner_tx_output(&rpc, &view).await; let miner_tx = get_miner_tx_output(&rpc, &view).await;
let protocol = Protocol::try_from(rpc.get_protocol().await.unwrap()).unwrap(); let rct_type = match rpc.get_hardfork_version().await.unwrap() {
14 => RctType::ClsagBulletproof,
15 | 16 => RctType::ClsagBulletproofPlus,
_ => panic!("unrecognized hardfork version"),
};
let builder = SignableTransactionBuilder::new( let builder = SignableTransactionBuilder::new(
protocol, rct_type,
rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), view_priv,
Change::new( Change::new(
&ViewPair::new( &ViewPair::new(
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE, &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
@@ -223,6 +242,7 @@ macro_rules! test {
), ),
false false
), ),
rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(),
); );
let sign = |tx: SignableTransaction| { let sign = |tx: SignableTransaction| {
@@ -239,16 +259,7 @@ macro_rules! test {
{ {
let mut machines = HashMap::new(); let mut machines = HashMap::new();
for i in (1 ..= THRESHOLD).map(|i| Participant::new(i).unwrap()) { for i in (1 ..= THRESHOLD).map(|i| Participant::new(i).unwrap()) {
machines.insert( machines.insert(i, tx.clone().multisig(&keys[&i]).unwrap());
i,
tx
.clone()
.multisig(
&keys[&i],
RecommendedTranscript::new(b"Monero Serai Test Transaction"),
)
.unwrap(),
);
} }
frost::tests::sign_without_caching(&mut OsRng, machines, &[]) frost::tests::sign_without_caching(&mut OsRng, machines, &[])
@@ -266,7 +277,7 @@ macro_rules! test {
let decoys = Decoys::fingerprintable_canonical_select( let decoys = Decoys::fingerprintable_canonical_select(
&mut OsRng, &mut OsRng,
&rpc, &rpc,
protocol.ring_len(), ring_len(rct_type),
rpc.get_height().await.unwrap(), rpc.get_height().await.unwrap(),
&[miner_tx.clone()], &[miner_tx.clone()],
) )
@@ -290,7 +301,7 @@ macro_rules! test {
$( $(
let (tx, state) = ($tx)( let (tx, state) = ($tx)(
protocol, rct_type,
rpc.clone(), rpc.clone(),
builder.clone(), builder.clone(),
next_addr, next_addr,

View File

@@ -2,15 +2,22 @@ use rand_core::OsRng;
use monero_simple_request_rpc::SimpleRequestRpc; use monero_simple_request_rpc::SimpleRequestRpc;
use monero_wallet::{ use monero_wallet::{
transaction::Transaction, Protocol, rpc::Rpc, extra::Extra, address::SubaddressIndex, primitives::Decoys,
ReceivedOutput, SpendableOutput, DecoySelection, Decoys, SignableTransactionBuilder, ringct::RctType,
transaction::Transaction,
rpc::Rpc,
address::SubaddressIndex,
extra::Extra,
scan::{ReceivedOutput, SpendableOutput},
DecoySelection,
}; };
mod runner; mod runner;
use runner::{SignableTransactionBuilder, ring_len};
// Set up inputs, select decoys, then add them to the TX builder // Set up inputs, select decoys, then add them to the TX builder
async fn add_inputs( async fn add_inputs(
protocol: Protocol, rct_type: RctType,
rpc: &SimpleRequestRpc, rpc: &SimpleRequestRpc,
outputs: Vec<ReceivedOutput>, outputs: Vec<ReceivedOutput>,
builder: &mut SignableTransactionBuilder, builder: &mut SignableTransactionBuilder,
@@ -23,7 +30,7 @@ async fn add_inputs(
let decoys = Decoys::fingerprintable_canonical_select( let decoys = Decoys::fingerprintable_canonical_select(
&mut OsRng, &mut OsRng,
rpc, rpc,
protocol.ring_len(), ring_len(rct_type),
rpc.get_height().await.unwrap(), rpc.get_height().await.unwrap(),
&spendable_outputs, &spendable_outputs,
) )
@@ -66,8 +73,8 @@ test!(
}, },
), ),
( (
|protocol: Protocol, rpc, mut builder: Builder, addr, outputs: Vec<ReceivedOutput>| async move { |rct_type: RctType, rpc, mut builder: Builder, addr, outputs: Vec<ReceivedOutput>| async move {
add_inputs(protocol, &rpc, outputs, &mut builder).await; add_inputs(rct_type, &rpc, outputs, &mut builder).await;
builder.add_payment(addr, 6); builder.add_payment(addr, 6);
(builder.build().unwrap(), ()) (builder.build().unwrap(), ())
}, },
@@ -96,20 +103,20 @@ test!(
}, },
), ),
( (
|protocol, rpc: SimpleRequestRpc, _, _, outputs: Vec<ReceivedOutput>| async move { |rct_type, rpc: SimpleRequestRpc, _, _, outputs: Vec<ReceivedOutput>| async move {
use monero_wallet::FeePriority; use monero_wallet::rpc::FeePriority;
let change_view = ViewPair::new( let view_priv = Zeroizing::new(Scalar::random(&mut OsRng));
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE, let change_view =
Zeroizing::new(Scalar::random(&mut OsRng)), ViewPair::new(&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE, view_priv.clone());
);
let mut builder = SignableTransactionBuilder::new( let mut builder = SignableTransactionBuilder::new(
protocol, rct_type,
rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), view_priv,
Change::new(&change_view, false), Change::new(&change_view, false),
rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(),
); );
add_inputs(protocol, &rpc, vec![outputs.first().unwrap().clone()], &mut builder).await; add_inputs(rct_type, &rpc, vec![outputs.first().unwrap().clone()], &mut builder).await;
// Send to a subaddress // Send to a subaddress
let sub_view = ViewPair::new( let sub_view = ViewPair::new(
@@ -161,8 +168,8 @@ test!(
}, },
), ),
( (
|protocol: Protocol, rpc, mut builder: Builder, addr, outputs: Vec<ReceivedOutput>| async move { |rct_type: RctType, rpc, mut builder: Builder, addr, outputs: Vec<ReceivedOutput>| async move {
add_inputs(protocol, &rpc, outputs, &mut builder).await; add_inputs(rct_type, &rpc, outputs, &mut builder).await;
builder.add_payment(addr, 2); builder.add_payment(addr, 2);
(builder.build().unwrap(), ()) (builder.build().unwrap(), ())
}, },
@@ -188,8 +195,8 @@ test!(
}, },
), ),
( (
|protocol: Protocol, rpc, mut builder: Builder, addr, outputs: Vec<ReceivedOutput>| async move { |rct_type: RctType, rpc, mut builder: Builder, addr, outputs: Vec<ReceivedOutput>| async move {
add_inputs(protocol, &rpc, outputs, &mut builder).await; add_inputs(rct_type, &rpc, outputs, &mut builder).await;
for i in 0 .. 15 { for i in 0 .. 15 {
builder.add_payment(addr, i + 1); builder.add_payment(addr, i + 1);
@@ -228,8 +235,8 @@ test!(
}, },
), ),
( (
|protocol: Protocol, rpc, mut builder: Builder, _, outputs: Vec<ReceivedOutput>| async move { |rct_type: RctType, rpc, mut builder: Builder, _, outputs: Vec<ReceivedOutput>| async move {
add_inputs(protocol, &rpc, outputs, &mut builder).await; add_inputs(rct_type, &rpc, outputs, &mut builder).await;
let view = runner::random_address().1; let view = runner::random_address().1;
let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new()));
@@ -285,15 +292,16 @@ test!(
}, },
), ),
( (
|protocol, rpc: SimpleRequestRpc, _, addr, outputs: Vec<ReceivedOutput>| async move { |rct_type, rpc: SimpleRequestRpc, _, addr, outputs: Vec<ReceivedOutput>| async move {
use monero_wallet::FeePriority; use monero_wallet::rpc::FeePriority;
let mut builder = SignableTransactionBuilder::new( let mut builder = SignableTransactionBuilder::new(
protocol, rct_type,
rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), Zeroizing::new(Scalar::random(&mut OsRng)),
Change::fingerprintable(None), Change::fingerprintable(None),
rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(),
); );
add_inputs(protocol, &rpc, vec![outputs.first().unwrap().clone()], &mut builder).await; add_inputs(rct_type, &rpc, vec![outputs.first().unwrap().clone()], &mut builder).await;
builder.add_payment(addr, 10000); builder.add_payment(addr, 10000);
builder.add_payment(addr, 50000); builder.add_payment(addr, 50000);

View File

@@ -11,7 +11,7 @@ use monero_wallet::{
rpc::Rpc, rpc::Rpc,
address::{Network, AddressSpec, SubaddressIndex, MoneroAddress}, address::{Network, AddressSpec, SubaddressIndex, MoneroAddress},
extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra, PaymentId}, extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra, PaymentId},
Scanner, scan::Scanner,
}; };
mod runner; mod runner;