diff --git a/coins/monero/Cargo.toml b/coins/monero/Cargo.toml index d92cd3a0..b24adce0 100644 --- a/coins/monero/Cargo.toml +++ b/coins/monero/Cargo.toml @@ -7,6 +7,7 @@ authors = ["Luke Parker "] edition = "2021" [dependencies] +hex-literal = "0.3" lazy_static = "1" thiserror = "1" @@ -26,6 +27,7 @@ dalek-ff-group = { path = "../../crypto/dalek-ff-group", optional = true } transcript = { package = "flexible-transcript", path = "../../crypto/transcript", features = ["recommended"], optional = true } frost = { package = "modular-frost", path = "../../crypto/frost", features = ["ed25519"], optional = true } +base58-monero = "1" monero = "0.16" hex = "0.4" diff --git a/coins/monero/src/tests/address.rs b/coins/monero/src/tests/address.rs new file mode 100644 index 00000000..0bda391d --- /dev/null +++ b/coins/monero/src/tests/address.rs @@ -0,0 +1,45 @@ +use hex_literal::hex; + +use crate::wallet::address::{Network, AddressType, Address}; + +const SPEND: [u8; 32] = hex!("f8631661f6ab4e6fda310c797330d86e23a682f20d5bc8cc27b18051191f16d7"); +const VIEW: [u8; 32] = hex!("4a1535063ad1fee2dabbf909d4fd9a873e29541b401f0944754e17c9a41820ce"); + +const STANDARD: &'static str = "4B33mFPMq6mKi7Eiyd5XuyKRVMGVZz1Rqb9ZTyGApXW5d1aT7UBDZ89ewmnWFkzJ5wPd2SFbn313vCT8a4E2Qf4KQH4pNey"; + +const PAYMENT_ID: [u8; 8] = hex!("b8963a57855cf73f"); +const INTEGRATED: &'static str = "4Ljin4CrSNHKi7Eiyd5XuyKRVMGVZz1Rqb9ZTyGApXW5d1aT7UBDZ89ewmnWFkzJ5wPd2SFbn313vCT8a4E2Qf4KbaTH6MnpXSn88oBX35"; + +const SUB_SPEND: [u8; 32] = hex!("fe358188b528335ad1cfdc24a22a23988d742c882b6f19a602892eaab3c1b62b"); +const SUB_VIEW: [u8; 32] = hex!("9bc2b464de90d058468522098d5610c5019c45fd1711a9517db1eea7794f5470"); +const SUBADDRESS: &'static str = "8C5zHM5ud8nGC4hC2ULiBLSWx9infi8JUUmWEat4fcTf8J4H38iWYVdFmPCA9UmfLTZxD43RsyKnGEdZkoGij6csDeUnbEB"; + +#[test] +fn standard_address() { + let addr = Address::from_str(STANDARD, Network::Mainnet).unwrap(); + assert_eq!(addr.meta.network, Network::Mainnet); + assert_eq!(addr.meta.kind, AddressType::Standard); + assert_eq!(addr.meta.guaranteed, false); + assert_eq!(addr.spend.compress().to_bytes(), SPEND); + assert_eq!(addr.view.compress().to_bytes(), VIEW); +} + +#[test] +fn integrated_address() { + let addr = Address::from_str(INTEGRATED, Network::Mainnet).unwrap(); + assert_eq!(addr.meta.network, Network::Mainnet); + assert_eq!(addr.meta.kind, AddressType::Integrated(PAYMENT_ID)); + assert_eq!(addr.meta.guaranteed, false); + assert_eq!(addr.spend.compress().to_bytes(), SPEND); + assert_eq!(addr.view.compress().to_bytes(), VIEW); +} + +#[test] +fn subaddress() { + let addr = Address::from_str(SUBADDRESS, Network::Mainnet).unwrap(); + assert_eq!(addr.meta.network, Network::Mainnet); + assert_eq!(addr.meta.kind, AddressType::Subaddress); + assert_eq!(addr.meta.guaranteed, false); + assert_eq!(addr.spend.compress().to_bytes(), SUB_SPEND); + assert_eq!(addr.view.compress().to_bytes(), SUB_VIEW); +} diff --git a/coins/monero/src/tests/mod.rs b/coins/monero/src/tests/mod.rs index b42cbcff..d9b85f0c 100644 --- a/coins/monero/src/tests/mod.rs +++ b/coins/monero/src/tests/mod.rs @@ -1 +1,2 @@ mod clsag; +mod address; diff --git a/coins/monero/src/wallet/address.rs b/coins/monero/src/wallet/address.rs new file mode 100644 index 00000000..329f5435 --- /dev/null +++ b/coins/monero/src/wallet/address.rs @@ -0,0 +1,152 @@ +use std::string::ToString; + +use thiserror::Error; + +use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, edwards::{EdwardsPoint, CompressedEdwardsY}}; + +use base58_monero::base58::{encode_check, decode_check}; + +use crate::wallet::ViewPair; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum Network { + Mainnet, + Testnet, + Stagenet +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum AddressType { + Standard, + Integrated([u8; 8]), + Subaddress +} + +impl AddressType { + fn network_bytes(network: Network) -> (u8, u8, u8) { + match network { + Network::Mainnet => (18, 19, 42), + Network::Testnet => (53, 54, 63), + Network::Stagenet => (24, 25, 36) + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct AddressMeta { + pub network: Network, + pub kind: AddressType, + pub guaranteed: bool +} + +#[derive(Clone, Error, Debug)] +pub enum AddressError { + #[error("invalid address byte")] + InvalidByte, + #[error("invalid address encoding")] + InvalidEncoding, + #[error("invalid length")] + InvalidLength, + #[error("different network than expected")] + DifferentNetwork, + #[error("invalid key")] + InvalidKey +} + +impl AddressMeta { + fn to_byte(&self) -> u8 { + let bytes = AddressType::network_bytes(self.network); + let byte = match self.kind { + AddressType::Standard => bytes.0, + AddressType::Integrated(_) => bytes.1, + AddressType::Subaddress => bytes.2 + }; + byte | (if self.guaranteed { 1 << 7 } else { 0 }) + } + + // Returns an incomplete type in the case of Integrated addresses + fn from_byte(byte: u8) -> Result { + let actual = byte & 0b01111111; + let guaranteed = (byte >> 7) == 1; + + let mut meta = None; + for network in [Network::Mainnet, Network::Testnet, Network::Stagenet] { + let (standard, integrated, subaddress) = AddressType::network_bytes(network); + if let Some(kind) = match actual { + _ if actual == standard => Some(AddressType::Standard), + _ if actual == integrated => Some(AddressType::Integrated([0; 8])), + _ if actual == subaddress => Some(AddressType::Subaddress), + _ => None + } { + meta = Some(AddressMeta { network, kind, guaranteed }); + break; + } + } + + meta.ok_or(AddressError::InvalidByte) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct Address { + pub meta: AddressMeta, + pub spend: EdwardsPoint, + pub view: EdwardsPoint +} + +impl ViewPair { + pub fn address(&self, network: Network, kind: AddressType, guaranteed: bool) -> Address { + Address { + meta: AddressMeta { + network, + kind, + guaranteed + }, + spend: self.spend, + view: &self.view * &ED25519_BASEPOINT_TABLE + } + } +} + +impl ToString for Address { + fn to_string(&self) -> String { + let mut data = vec![self.meta.to_byte()]; + data.extend(self.spend.compress().to_bytes()); + data.extend(self.view.compress().to_bytes()); + if let AddressType::Integrated(id) = self.meta.kind { + data.extend(id); + } + encode_check(&data).unwrap() + } +} + +impl Address { + pub fn from_str(s: &str, network: Network) -> Result { + let raw = decode_check(s).map_err(|_| AddressError::InvalidEncoding)?; + if raw.len() == 1 { + Err(AddressError::InvalidLength)?; + } + + let mut meta = AddressMeta::from_byte(raw[0])?; + if meta.network != network { + Err(AddressError::DifferentNetwork)?; + } + + let len = match meta.kind { + AddressType::Standard | AddressType::Subaddress => 65, + AddressType::Integrated(_) => 73 + }; + if raw.len() != len { + Err(AddressError::InvalidLength)?; + } + + let spend = CompressedEdwardsY(raw[1 .. 33].try_into().unwrap()).decompress().ok_or(AddressError::InvalidKey)?; + let view = CompressedEdwardsY(raw[33 .. 65].try_into().unwrap()).decompress().ok_or(AddressError::InvalidKey)?; + + if let AddressType::Integrated(ref mut payment_id) = meta.kind { + payment_id.copy_from_slice(&raw[65 .. 73]); + } + + Ok(Address { meta, spend, view }) + } +} diff --git a/coins/monero/src/wallet/mod.rs b/coins/monero/src/wallet/mod.rs index e0287eb4..ca694744 100644 --- a/coins/monero/src/wallet/mod.rs +++ b/coins/monero/src/wallet/mod.rs @@ -6,6 +6,8 @@ use crate::{ transaction::Input }; +pub mod address; + mod scan; pub use scan::SpendableOutput; @@ -23,7 +25,7 @@ fn key_image_sort(x: &EdwardsPoint, y: &EdwardsPoint) -> std::cmp::Ordering { // https://github.com/monero-project/research-lab/issues/103 pub(crate) fn uniqueness(inputs: &[Input]) -> [u8; 32] { - let mut u = b"domain_separator".to_vec(); + let mut u = b"uniqueness".to_vec(); for input in inputs { match input { // If Gen, this should be the only input, making this loop somewhat pointless @@ -63,3 +65,9 @@ pub(crate) fn commitment_mask(shared_key: Scalar) -> Scalar { mask.extend(shared_key.to_bytes()); hash_to_scalar(&mask) } + +#[derive(Clone, Copy)] +pub struct ViewPair { + pub spend: EdwardsPoint, + pub view: Scalar +} diff --git a/coins/monero/src/wallet/scan.rs b/coins/monero/src/wallet/scan.rs index d8feb7da..c813169e 100644 --- a/coins/monero/src/wallet/scan.rs +++ b/coins/monero/src/wallet/scan.rs @@ -12,7 +12,7 @@ use crate::{ Commitment, serialize::{write_varint, read_32, read_scalar, read_point}, transaction::{Timelock, Transaction}, - wallet::{uniqueness, shared_key, amount_decryption, commitment_mask} + wallet::{ViewPair, uniqueness, shared_key, amount_decryption, commitment_mask} }; #[derive(Clone, PartialEq, Debug)] @@ -55,8 +55,8 @@ impl SpendableOutput { impl Transaction { pub fn scan( &self, - view: Scalar, - spend: EdwardsPoint + view: ViewPair, + guaranteed: bool ) -> (Vec, Timelock) { let mut extra = vec![]; write_varint(&u64::try_from(self.prefix.extra.len()).unwrap(), &mut extra).unwrap(); @@ -82,52 +82,53 @@ impl Transaction { for (o, output) in self.prefix.outputs.iter().enumerate() { // TODO: This may be replaceable by pubkeys[o] for pubkey in &pubkeys { + let key_offset = shared_key( + Some(uniqueness(&self.prefix.inputs)).filter(|_| guaranteed), + view.view, + pubkey, + o + ); + // P - shared == spend + if (output.key - (&key_offset * &ED25519_BASEPOINT_TABLE)) != view.spend { + continue; + } + + // Since we've found an output to us, get its amount let mut commitment = Commitment::zero(); - // P - shared == spend - let matches = |shared_key| (output.key - (&shared_key * &ED25519_BASEPOINT_TABLE)) == spend; - let test = |shared_key| Some(shared_key).filter(|shared_key| matches(*shared_key)); + // Miner transaction + if output.amount != 0 { + commitment.amount = output.amount; + // Regular transaction + } else { + let amount = match self.rct_signatures.base.ecdh_info.get(o) { + Some(amount) => amount_decryption(*amount, key_offset), + // This should never happen, yet it may be possible with miner transactions? + // Using get just decreases the possibility of a panic and lets us move on in that case + None => break + }; - // Get the traditional shared key and unique shared key, testing if either matches for this output - let traditional = test(shared_key(None, view, pubkey, o)); - let unique = test(shared_key(Some(uniqueness(&self.prefix.inputs)), view, pubkey, o)); - - // If either matches, grab it and decode the amount - if let Some(key_offset) = traditional.or(unique) { - // Miner transaction - if output.amount != 0 { - commitment.amount = output.amount; - // Regular transaction - } else { - let amount = match self.rct_signatures.base.ecdh_info.get(o) { - Some(amount) => amount_decryption(*amount, key_offset), - // This should never happen, yet it may be possible with miner transactions? - // Using get just decreases the possibility of a panic and lets us move on in that case - None => continue - }; - - // Rebuild the commitment to verify it - commitment = Commitment::new(commitment_mask(key_offset), amount); - // If this is a malicious commitment, move to the next output - // Any other R value will calculate to a different spend key and are therefore ignorable - if Some(&commitment.calculate()) != self.rct_signatures.base.commitments.get(o) { - break; - } + // Rebuild the commitment to verify it + commitment = Commitment::new(commitment_mask(key_offset), amount); + // If this is a malicious commitment, move to the next output + // Any other R value will calculate to a different spend key and are therefore ignorable + if Some(&commitment.calculate()) != self.rct_signatures.base.commitments.get(o) { + break; } - - if commitment.amount != 0 { - res.push(SpendableOutput { - tx: self.hash(), - o: o.try_into().unwrap(), - key: output.key, - key_offset, - commitment - }); - } - // Break to prevent public keys from being included multiple times, triggering multiple - // inclusions of the same output - break; } + + if commitment.amount != 0 { + res.push(SpendableOutput { + tx: self.hash(), + o: o.try_into().unwrap(), + key: output.key, + key_offset, + commitment + }); + } + // Break to prevent public keys from being included multiple times, triggering multiple + // inclusions of the same output + break; } } diff --git a/coins/monero/src/wallet/send/mod.rs b/coins/monero/src/wallet/send/mod.rs index 7c95d753..cf9ab33f 100644 --- a/coins/monero/src/wallet/send/mod.rs +++ b/coins/monero/src/wallet/send/mod.rs @@ -9,11 +9,7 @@ use curve25519_dalek::{ edwards::EdwardsPoint }; -use monero::{ - consensus::Encodable, - util::{key::PublicKey, address::{AddressType, Address}}, - blockdata::transaction::SubField -}; +use monero::{consensus::Encodable, PublicKey, blockdata::transaction::SubField}; #[cfg(feature = "multisig")] use frost::FrostError; @@ -29,7 +25,10 @@ use crate::{ }, transaction::{Input, Output, Timelock, TransactionPrefix, Transaction}, rpc::{Rpc, RpcError}, - wallet::{SpendableOutput, Decoys, key_image_sort, uniqueness, shared_key, commitment_mask, amount_encryption} + wallet::{ + address::{AddressType, Address}, SpendableOutput, Decoys, + key_image_sort, uniqueness, shared_key, commitment_mask, amount_encryption + } }; #[cfg(feature = "multisig")] use crate::frost::MultisigError; @@ -52,23 +51,23 @@ impl SendOutput { fn new( rng: &mut R, unique: [u8; 32], - output: (Address, u64, bool), + output: (Address, u64), o: usize ) -> SendOutput { let r = random_scalar(rng); let shared_key = shared_key( - Some(unique).filter(|_| output.2), + Some(unique).filter(|_| output.0.meta.guaranteed), r, - &output.0.public_view.point.decompress().expect("SendOutput::new requires valid addresses"), + &output.0.view, o ); - let spend = output.0.public_spend.point.decompress().expect("SendOutput::new requires valid addresses"); + let spend = output.0.spend; SendOutput { - R: match output.0.addr_type { + R: match output.0.meta.kind { AddressType::Standard => &r * &ED25519_BASEPOINT_TABLE, - AddressType::SubAddress => &r * spend, - AddressType::Integrated(_) => panic!("SendOutput::new doesn't support Integrated addresses") + AddressType::Integrated(_) => unimplemented!("SendOutput::new doesn't support Integrated addresses"), + AddressType::Subaddress => &r * spend }, dest: ((&shared_key * &ED25519_BASEPOINT_TABLE) + spend), commitment: Commitment::new(commitment_mask(shared_key), output.1), @@ -169,7 +168,7 @@ impl Fee { #[derive(Clone, PartialEq, Debug)] pub struct SignableTransaction { inputs: Vec, - payments: Vec<(Address, u64, bool)>, + payments: Vec<(Address, u64)>, outputs: Vec, fee: u64 } @@ -177,23 +176,16 @@ pub struct SignableTransaction { impl SignableTransaction { pub fn new( inputs: Vec, - payments: Vec<(Address, u64)>, + mut payments: Vec<(Address, u64)>, change_address: Option
, fee_rate: Fee ) -> Result { // Make sure all addresses are valid let test = |addr: Address| { - if !( - addr.public_view.point.decompress().is_some() && - addr.public_spend.point.decompress().is_some() - ) { - Err(TransactionError::InvalidAddress)?; - } - - match addr.addr_type { + match addr.meta.kind { AddressType::Standard => Ok(()), AddressType::Integrated(..) => Err(TransactionError::InvalidAddress), - AddressType::SubAddress => Ok(()) + AddressType::Subaddress => Ok(()) } }; @@ -250,11 +242,8 @@ impl SignableTransaction { Err(TransactionError::TooManyOutputs)?; } - let mut payments = payments.iter().map(|(address, amount)| (*address, *amount, false)).collect::>(); if change { - // Always use a unique key image for the change output - // TODO: Make this a config option - payments.push((change_address.unwrap(), in_amount - out_amount, true)); + payments.push((change_address.unwrap(), in_amount - out_amount)); } Ok( diff --git a/coins/monero/src/wallet/send/multisig.rs b/coins/monero/src/wallet/send/multisig.rs index 89eaa6d0..67a39d93 100644 --- a/coins/monero/src/wallet/send/multisig.rs +++ b/coins/monero/src/wallet/send/multisig.rs @@ -94,9 +94,8 @@ impl SignableTransaction { transcript.append_message(b"input_shared_key", &input.key_offset.to_bytes()); } for payment in &self.payments { - transcript.append_message(b"payment_address", &payment.0.as_bytes()); + transcript.append_message(b"payment_address", &payment.0.to_string().as_bytes()); transcript.append_message(b"payment_amount", &payment.1.to_le_bytes()); - transcript.append_message(b"payment_unique", &(if payment.2 { [1] } else { [0] })); } // Sort included before cloning it around diff --git a/coins/monero/tests/send.rs b/coins/monero/tests/send.rs index c8543d9f..a3585ce0 100644 --- a/coins/monero/tests/send.rs +++ b/coins/monero/tests/send.rs @@ -18,12 +18,7 @@ use transcript::RecommendedTranscript; #[cfg(feature = "multisig")] use frost::{curve::Ed25519, tests::{THRESHOLD, key_gen, sign}}; -use monero::{ - network::Network, - util::{key::PublicKey, address::Address} -}; - -use monero_serai::{random_scalar, wallet::SignableTransaction}; +use monero_serai::{random_scalar, wallet::{ViewPair, address::{Network, AddressType}, SignableTransaction}}; mod rpc; use crate::rpc::{rpc, mine_block}; @@ -73,11 +68,8 @@ async fn send_core(test: usize, multisig: bool) { } } - let addr = Address::standard( - Network::Mainnet, - PublicKey { point: spend_pub.compress() }, - PublicKey { point: (&view * &ED25519_BASEPOINT_TABLE).compress() } - ); + let view_pair = ViewPair { view, spend: spend_pub }; + let addr = view_pair.address(Network::Mainnet, AddressType::Standard, false); let fee = rpc.get_fee().await.unwrap(); @@ -99,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, spend_pub).0; + let mut outputs = tx.as_ref().unwrap().scan(view_pair, false).0; outputs.sort_by(|x, y| x.commitment.amount.cmp(&y.commitment.amount).reverse()); outputs.swap_remove(0) }; @@ -124,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, spend_pub).0.swap_remove(0); + let output = tx.scan(view_pair, false).0.swap_remove(0); amount += output.commitment.amount; outputs.push(output); } diff --git a/processor/src/coin/mod.rs b/processor/src/coin/mod.rs index fed65c26..79945665 100644 --- a/processor/src/coin/mod.rs +++ b/processor/src/coin/mod.rs @@ -77,7 +77,7 @@ pub trait Coin { ) -> Result<(Vec, Vec<::Id>), CoinError>; #[cfg(test)] - async fn mine_block(&self, address: Self::Address); + async fn mine_block(&self); #[cfg(test)] async fn test_send(&self, key: Self::Address); diff --git a/processor/src/coin/monero.rs b/processor/src/coin/monero.rs index 80d19a89..5e045892 100644 --- a/processor/src/coin/monero.rs +++ b/processor/src/coin/monero.rs @@ -2,17 +2,19 @@ use std::sync::Arc; use async_trait::async_trait; -use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar}; +use curve25519_dalek::scalar::Scalar; use dalek_ff_group as dfg; use transcript::RecommendedTranscript; use frost::{curve::Ed25519, MultisigKeys}; -use monero::{PublicKey, network::Network, util::address::Address}; use monero_serai::{ transaction::{Timelock, Transaction}, rpc::Rpc, - wallet::{Fee, SpendableOutput, SignableTransaction as MSignableTransaction, TransactionMachine} + wallet::{ + ViewPair, address::{Network, AddressType, Address}, + Fee, SpendableOutput, SignableTransaction as MSignableTransaction, TransactionMachine + } }; use crate::{coin::{CoinError, Output as OutputTrait, Coin}, view_key}; @@ -59,18 +61,28 @@ pub struct SignableTransaction( #[derive(Clone, Debug)] pub struct Monero { pub(crate) rpc: Rpc, - view: Scalar, - view_pub: PublicKey + view: Scalar } impl Monero { pub fn new(url: String) -> Monero { let view = view_key::(0).0; - Monero { - rpc: Rpc::new(url), - view, - view_pub: PublicKey { point: (&view * &ED25519_BASEPOINT_TABLE).compress() } - } + Monero { rpc: Rpc::new(url), view } + } + + fn view_pair(&self, spend: dfg::EdwardsPoint) -> ViewPair { + ViewPair { spend: spend.0, view: self.view } + } + + #[cfg(test)] + fn empty_view_pair(&self) -> ViewPair { + use group::Group; + self.view_pair(dfg::EdwardsPoint::generator()) + } + + #[cfg(test)] + fn empty_address(&self) -> Address { + self.empty_view_pair().address(Network::Mainnet, AddressType::Standard, false) } } @@ -100,7 +112,7 @@ impl Coin for Monero { const MAX_OUTPUTS: usize = 16; fn address(&self, key: dfg::EdwardsPoint) -> Self::Address { - Address::standard(Network::Mainnet, PublicKey { point: key.compress().0 }, self.view_pub) + self.view_pair(key).address(Network::Mainnet, AddressType::Standard, true) } async fn get_height(&self) -> Result { @@ -115,7 +127,7 @@ impl Coin for Monero { block .iter() .flat_map(|tx| { - let (outputs, timelock) = tx.scan(self.view, key.0); + let (outputs, timelock) = tx.scan(self.view_pair(key), true); if timelock == Timelock::None { outputs } else { @@ -178,13 +190,13 @@ impl Coin for Monero { } #[cfg(test)] - async fn mine_block(&self, address: Self::Address) { + async fn mine_block(&self) { #[derive(serde::Deserialize, Debug)] struct EmptyResponse {} let _: EmptyResponse = self.rpc.rpc_call("json_rpc", Some(serde_json::json!({ "method": "generateblocks", "params": { - "wallet_address": address.to_string(), + "wallet_address": self.empty_address().to_string(), "amount_of_blocks": 10 }, }))).await.unwrap(); @@ -192,31 +204,28 @@ impl Coin for Monero { #[cfg(test)] async fn test_send(&self, address: Self::Address) { - use group::Group; - use rand::rngs::OsRng; let height = self.get_height().await.unwrap(); - let temp = self.address(dfg::EdwardsPoint::generator()); - self.mine_block(temp).await; + self.mine_block().await; for _ in 0 .. 7 { - self.mine_block(temp).await; + self.mine_block().await; } let outputs = self.rpc .get_block_transactions_possible(height).await.unwrap() - .swap_remove(0).scan(self.view, dfg::EdwardsPoint::generator().0).0; + .swap_remove(0).scan(self.empty_view_pair(), false).0; let amount = outputs[0].commitment.amount; let fee = 1000000000; // TODO let tx = MSignableTransaction::new( outputs, vec![(address, amount - fee)], - Some(temp), + Some(self.empty_address()), self.rpc.get_fee().await.unwrap() ).unwrap().sign(&mut OsRng, &self.rpc, &Scalar::one()).await.unwrap(); self.rpc.publish_transaction(&tx).await.unwrap(); - self.mine_block(temp).await; + self.mine_block().await; } } diff --git a/processor/src/tests/mod.rs b/processor/src/tests/mod.rs index 728b0668..051ecad6 100644 --- a/processor/src/tests/mod.rs +++ b/processor/src/tests/mod.rs @@ -4,10 +4,6 @@ use async_trait::async_trait; use rand::rngs::OsRng; -use group::Group; - -use frost::curve::Curve; - use crate::{NetworkError, Network, coin::{Coin, Monero}, wallet::{WalletKeys, MemCoinDb, Wallet}}; #[derive(Clone)] @@ -55,7 +51,7 @@ impl Network for LocalNetwork { async fn test_send(coin: C, fee: C::Fee) { // Mine a block so there's a confirmed height - coin.mine_block(coin.address(::G::generator())).await; + coin.mine_block().await; let height = coin.get_height().await.unwrap(); let mut keys = frost::tests::key_gen::<_, C::Curve>(&mut OsRng); @@ -74,7 +70,7 @@ async fn test_send(coin: C, fee: C::Fee) { // Get the chain to a height where blocks have sufficient confirmations while (height + C::CONFIRMATIONS) > coin.get_height().await.unwrap() { - coin.mine_block(coin.address(::G::generator())).await; + coin.mine_block().await; } for wallet in wallets.iter_mut() {