From 08b95abdd8c7caa5f7cd8e43062c17488ee88a1a Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sun, 16 Jun 2024 19:59:25 -0400 Subject: [PATCH] Document the RPC --- coins/monero/rpc/simple-request/src/lib.rs | 12 +- coins/monero/rpc/src/lib.rs | 278 ++++++++++++------ coins/monero/src/bin/reserialize_chain.rs | 4 +- coins/monero/wallet/src/decoys.rs | 32 +- coins/monero/wallet/src/lib.rs | 2 +- coins/monero/wallet/src/scan.rs | 16 +- coins/monero/wallet/src/send/builder.rs | 8 +- coins/monero/wallet/src/send/mod.rs | 10 +- coins/monero/wallet/tests/add_data.rs | 2 +- coins/monero/wallet/tests/decoys.rs | 21 +- coins/monero/wallet/tests/eventuality.rs | 1 + coins/monero/wallet/tests/runner.rs | 20 +- coins/monero/wallet/tests/scan.rs | 2 +- coins/monero/wallet/tests/send.rs | 19 +- .../wallet/tests/wallet2_compatibility.rs | 23 +- processor/src/networks/monero.rs | 10 +- tests/full-stack/src/lib.rs | 3 +- tests/full-stack/src/tests/mint_and_burn.rs | 13 +- tests/processor/src/lib.rs | 6 +- tests/processor/src/networks.rs | 4 +- 20 files changed, 289 insertions(+), 197 deletions(-) diff --git a/coins/monero/rpc/simple-request/src/lib.rs b/coins/monero/rpc/simple-request/src/lib.rs index 636852b0..33651309 100644 --- a/coins/monero/rpc/simple-request/src/lib.rs +++ b/coins/monero/rpc/simple-request/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] -// #![deny(missing_docs)] // TODO +#![deny(missing_docs)] use std::{sync::Arc, io::Read, time::Duration}; @@ -14,7 +14,7 @@ use simple_request::{ Response, Client, }; -use monero_rpc::{RpcError, RpcConnection, Rpc}; +use monero_rpc::{RpcError, Rpc}; const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); @@ -64,7 +64,7 @@ impl SimpleRequestRpc { /// /// A daemon requiring authentication can be used via including the username and password in the /// URL. - pub async fn new(url: String) -> Result, RpcError> { + pub async fn new(url: String) -> Result { Self::with_custom_timeout(url, DEFAULT_TIMEOUT).await } @@ -75,7 +75,7 @@ impl SimpleRequestRpc { pub async fn with_custom_timeout( mut url: String, request_timeout: Duration, - ) -> Result, RpcError> { + ) -> Result { let authentication = if url.contains('@') { // Parse out the username and password let url_clone = url; @@ -123,7 +123,7 @@ impl SimpleRequestRpc { Authentication::Unauthenticated(Client::with_connection_pool()) }; - Ok(Rpc::new(SimpleRequestRpc { authentication, url, request_timeout })) + Ok(SimpleRequestRpc { authentication, url, request_timeout }) } } @@ -281,7 +281,7 @@ impl SimpleRequestRpc { } #[async_trait] -impl RpcConnection for SimpleRequestRpc { +impl Rpc for SimpleRequestRpc { async fn post(&self, route: &str, body: Vec) -> Result, RpcError> { tokio::time::timeout(self.request_timeout, self.inner_post(route, body)) .await diff --git a/coins/monero/rpc/src/lib.rs b/coins/monero/rpc/src/lib.rs index b7726043..91d4938c 100644 --- a/coins/monero/rpc/src/lib.rs +++ b/coins/monero/rpc/src/lib.rs @@ -1,6 +1,6 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] -// #![deny(missing_docs)] // TODO +#![deny(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] use core::fmt::Debug; @@ -33,35 +33,63 @@ use monero_serai::{ // src/wallet/wallet2.cpp#L121 const GRACE_BLOCKS_FOR_FEE_ESTIMATE: u64 = 10; -/// Fee struct, defined as a per-unit cost and a mask for rounding purposes. +/// A struct containing a fee rate. +/// +/// The fee rate is defined as a per-weight cost, along with a mask for rounding purposes. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] -pub struct Fee { +pub struct FeeRate { + /// The fee per-weight of the transaction. pub per_weight: u64, + /// The mask to round with. pub mask: u64, } -impl Fee { +impl FeeRate { + /// Construct a new fee rate. + pub fn new(per_weight: u64, mask: u64) -> Result { + if (per_weight == 0) || (mask == 0) { + Err(RpcError::InvalidFee)?; + } + Ok(FeeRate { per_weight, mask }) + } + + /// Calculate the fee to use from the weight. + /// + /// This function may panic if any of the `FeeRate`'s fields are zero. pub fn calculate_fee_from_weight(&self, weight: usize) -> u64 { - let fee = (((self.per_weight * u64::try_from(weight).unwrap()) + self.mask - 1) / self.mask) * - self.mask; + let fee = self.per_weight * u64::try_from(weight).unwrap(); + let fee = ((fee + self.mask - 1) / self.mask) * self.mask; debug_assert_eq!(weight, self.calculate_weight_from_fee(fee), "Miscalculated weight from fee"); fee } + /// Calculate the weight from the fee. + /// + /// This function may panic if any of the `FeeRate`'s fields are zero. pub fn calculate_weight_from_fee(&self, fee: u64) -> usize { usize::try_from(fee / self.per_weight).unwrap() } } -/// Fee priority, determining how quickly a transaction is included in a block. +/// The priority for the fee. +/// +/// Higher-priority transactions will be included in blocks earlier. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[allow(non_camel_case_types)] pub enum FeePriority { + /// The `Unimportant` priority, as defined by Monero. Unimportant, + /// The `Normal` priority, as defined by Monero. Normal, + /// The `Elevated` priority, as defined by Monero. Elevated, + /// The `Priority` priority, as defined by Monero. Priority, - Custom { priority: u32 }, + /// A custom priority. + Custom { + /// The numeric representation of the priority, as used within the RPC. + priority: u32, + }, } /// https://github.com/monero-project/monero/blob/ac02af92867590ca80b2779a7bbeafa99ff94dcb/ @@ -79,9 +107,9 @@ impl FeePriority { } #[derive(Deserialize, Debug)] -pub struct EmptyResponse {} +struct EmptyResponse {} #[derive(Deserialize, Debug)] -pub struct JsonRpcResponse { +struct JsonRpcResponse { result: T, } @@ -98,36 +126,52 @@ struct TransactionsResponse { txs: Vec, } +/// The response to an output query. #[derive(Deserialize, Debug)] pub struct OutputResponse { + /// The height of the block this output was added to the chain in. pub height: usize, + /// If the output is unlocked, per the node's local view. pub unlocked: bool, - key: String, - mask: String, - txid: String, + /// The output's key. + pub key: String, + /// The output's commitment. + pub mask: String, + /// The transaction which created this output. + pub txid: String, } +/// An error from the RPC. #[derive(Clone, PartialEq, Eq, Debug)] #[cfg_attr(feature = "std", derive(thiserror::Error))] pub enum RpcError { + /// An internal error. #[cfg_attr(feature = "std", error("internal error ({0})"))] InternalError(&'static str), + /// A connection error with the node. #[cfg_attr(feature = "std", error("connection error ({0})"))] ConnectionError(String), + /// The node is invalid per the expected protocol. #[cfg_attr(feature = "std", error("invalid node ({0})"))] InvalidNode(String), + /// The node is running an unsupported protocol. #[cfg_attr(feature = "std", error("unsupported protocol version ({0})"))] UnsupportedProtocol(usize), + /// Requested transactions weren't found. #[cfg_attr(feature = "std", error("transactions not found"))] TransactionsNotFound(Vec<[u8; 32]>), - #[cfg_attr(feature = "std", error("invalid point ({0})"))] - InvalidPoint(String), + /// The transaction was pruned. + /// + /// Pruned transactions are not supported at this time. #[cfg_attr(feature = "std", error("pruned transaction"))] PrunedTransaction, + /// A transaction (sent or received) was invalid. #[cfg_attr(feature = "std", error("invalid transaction ({0:?})"))] InvalidTransaction([u8; 32]), + /// The returned fee was unusable. #[cfg_attr(feature = "std", error("unexpected fee response"))] InvalidFee, + /// The priority intended for use wasn't usable. #[cfg_attr(feature = "std", error("invalid priority"))] InvalidPriority, } @@ -142,9 +186,11 @@ fn hash_hex(hash: &str) -> Result<[u8; 32], RpcError> { fn rpc_point(point: &str) -> Result { decompress_point( - rpc_hex(point)?.try_into().map_err(|_| RpcError::InvalidPoint(point.to_string()))?, + rpc_hex(point)? + .try_into() + .map_err(|_| RpcError::InvalidNode(format!("invalid point: {point}")))?, ) - .ok_or_else(|| RpcError::InvalidPoint(point.to_string())) + .ok_or_else(|| RpcError::InvalidNode(format!("invalid point: {point}"))) } // Read an EPEE VarInt, distinct from the VarInts used throughout the rest of the protocol @@ -164,33 +210,63 @@ fn read_epee_vi(reader: &mut R) -> io::Result { Ok(vi) } +async fn get_fee_rate_v14(rpc: &impl Rpc, priority: FeePriority) -> Result { + #[derive(Deserialize, Debug)] + struct FeeResponseV14 { + status: String, + fee: u64, + quantization_mask: u64, + } + + // https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/ + // src/wallet/wallet2.cpp#L7569-L7584 + // https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/ + // src/wallet/wallet2.cpp#L7660-L7661 + let priority_idx = + usize::try_from(if priority.fee_priority() == 0 { 1 } else { priority.fee_priority() - 1 }) + .map_err(|_| RpcError::InvalidPriority)?; + let multipliers = [1, 5, 25, 1000]; + if priority_idx >= multipliers.len() { + // though not an RPC error, it seems sensible to treat as such + Err(RpcError::InvalidPriority)?; + } + let fee_multiplier = multipliers[priority_idx]; + + let res: FeeResponseV14 = rpc + .json_rpc_call( + "get_fee_estimate", + Some(json!({ "grace_blocks": GRACE_BLOCKS_FOR_FEE_ESTIMATE })), + ) + .await?; + + if res.status != "OK" { + Err(RpcError::InvalidFee)?; + } + + FeeRate::new(res.fee * fee_multiplier, res.quantization_mask) +} + +/// An RPC connection to a Monero daemon. +/// +/// This is abstract such that users can use an HTTP library (which being their choice), a +/// Tor/i2p-based transport, or even a memory buffer an external service somehow routes. #[async_trait] -pub trait RpcConnection: Clone + Debug { +pub trait Rpc: Sync + Clone + Debug { /// Perform a POST request to the specified route with the specified body. /// /// The implementor is left to handle anything such as authentication. async fn post(&self, route: &str, body: Vec) -> Result, RpcError>; -} - -// TODO: Make this provided methods for RpcConnection? -#[derive(Clone, Debug)] -pub struct Rpc(R); -impl Rpc { - pub fn new(connection: R) -> Self { - Self(connection) - } /// Perform a RPC call to the specified route with the provided parameters. /// /// This is NOT a JSON-RPC call. They use a route of "json_rpc" and are available via /// `json_rpc_call`. - pub async fn rpc_call( + async fn rpc_call( &self, route: &str, params: Option, ) -> Result { let res = self - .0 .post( route, if let Some(params) = params { @@ -206,8 +282,8 @@ impl Rpc { .map_err(|_| RpcError::InvalidNode(format!("response wasn't json: {res_str}"))) } - /// Perform a JSON-RPC call with the specified method with the provided parameters - pub async fn json_rpc_call( + /// Perform a JSON-RPC call with the specified method with the provided parameters. + async fn json_rpc_call( &self, method: &str, params: Option, @@ -220,12 +296,12 @@ impl Rpc { } /// Perform a binary call to the specified route with the provided parameters. - pub async fn bin_call(&self, route: &str, params: Vec) -> Result, RpcError> { - self.0.post(route, params).await + async fn bin_call(&self, route: &str, params: Vec) -> Result, RpcError> { + self.post(route, params).await } /// Get the active blockchain protocol version. - pub async fn get_protocol(&self) -> Result { + async fn get_protocol(&self) -> Result { #[derive(Deserialize, Debug)] struct ProtocolResponse { major_version: usize, @@ -250,7 +326,11 @@ impl Rpc { ) } - pub async fn get_height(&self) -> Result { + /// Get the height of the Monero blockchain. + /// + /// The height is defined as the amount of blocks on the blockchain. For a blockchain with only + /// its genesis block, the height will be 1. + async fn get_height(&self) -> Result { #[derive(Deserialize, Debug)] struct HeightResponse { height: usize, @@ -258,7 +338,11 @@ impl Rpc { Ok(self.rpc_call::, HeightResponse>("get_height", None).await?.height) } - pub async fn get_transactions(&self, hashes: &[[u8; 32]]) -> Result, RpcError> { + /// Get the specified transactions. + /// + /// The received transactions will be hashed in order to verify the correct transactions were + /// returned. + async fn get_transactions(&self, hashes: &[[u8; 32]]) -> Result, RpcError> { if hashes.is_empty() { return Ok(vec![]); } @@ -322,13 +406,19 @@ impl Rpc { .collect() } - pub async fn get_transaction(&self, tx: [u8; 32]) -> Result { + /// Get the specified transaction. + /// + /// The received transaction will be hashed in order to verify the correct transaction was + /// returned. + async fn get_transaction(&self, tx: [u8; 32]) -> Result { self.get_transactions(&[tx]).await.map(|mut txs| txs.swap_remove(0)) } - /// Get the hash of a block from the node by the block's numbers. - /// This function does not verify the returned block hash is actually for the number in question. - pub async fn get_block_hash(&self, number: usize) -> Result<[u8; 32], RpcError> { + /// Get the hash of a block from the node. + /// + /// `number` is the block's zero-indexed position on the blockchain (`0` for the genesis block, + /// `height - 1` for the latest block). + async fn get_block_hash(&self, number: usize) -> Result<[u8; 32], RpcError> { #[derive(Deserialize, Debug)] struct BlockHeaderResponse { hash: String, @@ -344,8 +434,9 @@ impl Rpc { } /// Get a block from the node by its hash. - /// This function does not verify the returned block actually has the hash in question. - pub async fn get_block(&self, hash: [u8; 32]) -> Result { + /// + /// The received block will be hashed in order to verify the correct block was returned. + async fn get_block(&self, hash: [u8; 32]) -> Result { #[derive(Deserialize, Debug)] struct BlockResponse { blob: String, @@ -362,7 +453,11 @@ impl Rpc { Ok(block) } - pub async fn get_block_by_number(&self, number: usize) -> Result { + /// Get a block from the node by its number. + /// + /// `number` is the block's zero-indexed position on the blockchain (`0` for the genesis block, + /// `height - 1` for the latest block). + async fn get_block_by_number(&self, number: usize) -> Result { #[derive(Deserialize, Debug)] struct BlockResponse { blob: String, @@ -389,14 +484,26 @@ impl Rpc { } } - pub async fn get_block_transactions(&self, hash: [u8; 32]) -> Result, RpcError> { + /// Get the transactions within a block. + /// + /// This function returns all transactions in the block, including the miner's transaction. + /// + /// This function does not verify the returned transactions are the ones committed to by the + /// block's header. + async fn get_block_transactions(&self, hash: [u8; 32]) -> Result, RpcError> { let block = self.get_block(hash).await?; let mut res = vec![block.miner_tx]; res.extend(self.get_transactions(&block.txs).await?); Ok(res) } - pub async fn get_block_transactions_by_number( + /// Get the transactions within a block. + /// + /// This function returns all transactions in the block, including the miner's transaction. + /// + /// This function does not verify the returned transactions are the ones committed to by the + /// block's header. + async fn get_block_transactions_by_number( &self, number: usize, ) -> Result, RpcError> { @@ -404,7 +511,7 @@ impl Rpc { } /// Get the output indexes of the specified transaction. - pub async fn get_o_indexes(&self, hash: [u8; 32]) -> Result, RpcError> { + async fn get_o_indexes(&self, hash: [u8; 32]) -> Result, RpcError> { /* TODO: Use these when a suitable epee serde lib exists @@ -558,13 +665,10 @@ impl Rpc { .map_err(|_| RpcError::InvalidNode("invalid binary response".to_string())) } - /// Get the output distribution, from the specified height to the specified height (both - /// inclusive). - pub async fn get_output_distribution( - &self, - from: usize, - to: usize, - ) -> Result, RpcError> { + /// Get the output distribution. + /// + /// `from` and `to` are heights, not block numbers, and inclusive. + async fn get_output_distribution(&self, from: usize, to: usize) -> Result, RpcError> { #[derive(Deserialize, Debug)] struct Distribution { distribution: Vec, @@ -591,8 +695,8 @@ impl Rpc { Ok(distributions.distributions.swap_remove(0).distribution) } - /// Get the specified outputs from the RingCT (zero-amount) pool - pub async fn get_outs(&self, indexes: &[u64]) -> Result, RpcError> { + /// Get the specified outputs from the RingCT (zero-amount) pool. + async fn get_outs(&self, indexes: &[u64]) -> Result, RpcError> { #[derive(Deserialize, Debug)] struct OutsResponse { status: String, @@ -624,7 +728,13 @@ impl Rpc { /// /// The timelock being satisfied is distinct from being free of the 10-block lock applied to all /// Monero transactions. - pub async fn get_unlocked_outputs( + /// + /// The node is trusted for if the output is unlocked unless `fingerprintable_canonical` is set + /// to true. If `fingerprintable_canonical` is set to true, the node's local view isn't used, yet + /// the transaction's timelock is checked to be unlocked at the specified `height`. This offers a + /// canonical decoy selection, yet is fingerprintable as time-based timelocks aren't evaluated + /// (and considered locked, preventing their selection). + async fn get_unlocked_outputs( &self, indexes: &[u64], height: usize, @@ -671,47 +781,15 @@ impl Rpc { .collect() } - async fn get_fee_v14(&self, priority: FeePriority) -> Result { - #[derive(Deserialize, Debug)] - struct FeeResponseV14 { - status: String, - fee: u64, - quantization_mask: u64, - } - - // https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/ - // src/wallet/wallet2.cpp#L7569-L7584 - // https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/ - // src/wallet/wallet2.cpp#L7660-L7661 - let priority_idx = - usize::try_from(if priority.fee_priority() == 0 { 1 } else { priority.fee_priority() - 1 }) - .map_err(|_| RpcError::InvalidPriority)?; - let multipliers = [1, 5, 25, 1000]; - if priority_idx >= multipliers.len() { - // though not an RPC error, it seems sensible to treat as such - Err(RpcError::InvalidPriority)?; - } - let fee_multiplier = multipliers[priority_idx]; - - let res: FeeResponseV14 = self - .json_rpc_call( - "get_fee_estimate", - Some(json!({ "grace_blocks": GRACE_BLOCKS_FOR_FEE_ESTIMATE })), - ) - .await?; - - if res.status != "OK" { - Err(RpcError::InvalidFee)?; - } - - Ok(Fee { per_weight: res.fee * fee_multiplier, mask: res.quantization_mask }) - } - - /// Get the currently estimated fee from the node. + /// Get the currently estimated fee rate from the node. /// /// This may be manipulated to unsafe levels and MUST be sanity checked. // TODO: Take a sanity check argument - pub async fn get_fee(&self, protocol: Protocol, priority: FeePriority) -> Result { + async fn get_fee_rate( + &self, + protocol: Protocol, + priority: FeePriority, + ) -> Result { // TODO: Implement wallet2's adjust_priority which by default automatically uses a lower // priority than provided depending on the backlog in the pool if protocol.v16_fee() { @@ -743,14 +821,15 @@ impl Rpc { } else if priority_idx >= res.fees.len() { Err(RpcError::InvalidPriority) } else { - Ok(Fee { per_weight: res.fees[priority_idx], mask: res.quantization_mask }) + FeeRate::new(res.fees[priority_idx], res.quantization_mask) } } else { - self.get_fee_v14(priority).await + get_fee_rate_v14(self, priority).await } } - pub async fn publish_transaction(&self, tx: &Transaction) -> Result<(), RpcError> { + /// Publish a transaction. + async fn publish_transaction(&self, tx: &Transaction) -> Result<(), RpcError> { #[allow(dead_code)] #[derive(Deserialize, Debug)] struct SendRawResponse { @@ -778,8 +857,11 @@ impl Rpc { Ok(()) } + /// Generate blocks, with the specified address receiving the block reward. + /// + /// Returns the hashes of the generated blocks and the last block's number. // TODO: Take &Address, not &str? - pub async fn generate_blocks( + async fn generate_blocks( &self, address: &str, block_count: usize, diff --git a/coins/monero/src/bin/reserialize_chain.rs b/coins/monero/src/bin/reserialize_chain.rs index 93b7a0e3..56748331 100644 --- a/coins/monero/src/bin/reserialize_chain.rs +++ b/coins/monero/src/bin/reserialize_chain.rs @@ -20,7 +20,7 @@ mod binaries { pub(crate) use tokio::task::JoinHandle; - pub(crate) async fn check_block(rpc: Arc>, block_i: usize) { + pub(crate) async fn check_block(rpc: Arc, block_i: usize) { let hash = loop { match rpc.get_block_hash(block_i).await { Ok(hash) => break hash, @@ -158,7 +158,7 @@ mod binaries { } async fn get_outs( - rpc: &Rpc, + rpc: &SimpleRequestRpc, amount: u64, indexes: &[u64], ) -> Vec<[EdwardsPoint; 2]> { diff --git a/coins/monero/wallet/src/decoys.rs b/coins/monero/wallet/src/decoys.rs index ee4b4695..a0258621 100644 --- a/coins/monero/wallet/src/decoys.rs +++ b/coins/monero/wallet/src/decoys.rs @@ -10,7 +10,7 @@ use rand_distr::num_traits::Float; use curve25519_dalek::edwards::EdwardsPoint; use monero_serai::{DEFAULT_LOCK_WINDOW, COINBASE_LOCK_WINDOW, BLOCK_TIME}; -use monero_rpc::{RpcError, RpcConnection, Rpc}; +use monero_rpc::{RpcError, Rpc}; use crate::SpendableOutput; const RECENT_WINDOW: usize = 15; @@ -19,9 +19,9 @@ const BLOCKS_PER_YEAR: usize = 365 * 24 * 60 * 60 / BLOCK_TIME; const TIP_APPLICATION: f64 = (DEFAULT_LOCK_WINDOW * BLOCK_TIME) as f64; #[allow(clippy::too_many_arguments)] -async fn select_n<'a, R: RngCore + CryptoRng, RPC: RpcConnection>( +async fn select_n<'a, R: RngCore + CryptoRng>( rng: &mut R, - rpc: &Rpc, + rpc: &impl Rpc, distribution: &[u64], height: usize, high: u64, @@ -129,9 +129,9 @@ fn offset(ring: &[u64]) -> Vec { res } -async fn select_decoys( +async fn select_decoys( rng: &mut R, - rpc: &Rpc, + rpc: &impl Rpc, ring_len: usize, height: usize, inputs: &[SpendableOutput], @@ -278,20 +278,17 @@ pub use monero_serai::primitives::Decoys; #[cfg(feature = "std")] #[async_trait::async_trait] pub trait DecoySelection { - async fn select( + async fn select( rng: &mut R, - rpc: &Rpc, + rpc: &impl Rpc, ring_len: usize, height: usize, inputs: &[SpendableOutput], ) -> Result, RpcError>; - async fn fingerprintable_canonical_select< - R: Send + Sync + RngCore + CryptoRng, - RPC: Send + Sync + RpcConnection, - >( + async fn fingerprintable_canonical_select( rng: &mut R, - rpc: &Rpc, + rpc: &impl Rpc, ring_len: usize, height: usize, inputs: &[SpendableOutput], @@ -303,9 +300,9 @@ pub trait DecoySelection { impl DecoySelection for Decoys { /// Select decoys using the same distribution as Monero. Relies on the monerod RPC /// response for an output's unlocked status, minimizing trips to the daemon. - async fn select( + async fn select( rng: &mut R, - rpc: &Rpc, + rpc: &impl Rpc, ring_len: usize, height: usize, inputs: &[SpendableOutput], @@ -321,12 +318,9 @@ impl DecoySelection for Decoys { /// /// TODO: upstream change to monerod get_outs RPC to accept a height param for checking /// output's unlocked status and remove all usage of fingerprintable_canonical - async fn fingerprintable_canonical_select< - R: Send + Sync + RngCore + CryptoRng, - RPC: Send + Sync + RpcConnection, - >( + async fn fingerprintable_canonical_select( rng: &mut R, - rpc: &Rpc, + rpc: &impl Rpc, ring_len: usize, height: usize, inputs: &[SpendableOutput], diff --git a/coins/monero/wallet/src/lib.rs b/coins/monero/wallet/src/lib.rs index e8f2b029..371c06bf 100644 --- a/coins/monero/wallet/src/lib.rs +++ b/coins/monero/wallet/src/lib.rs @@ -47,7 +47,7 @@ pub mod decoys { pub use decoys::{DecoySelection, Decoys}; mod send; -pub use send::{FeePriority, Fee, TransactionError, Change, SignableTransaction, Eventuality}; +pub use send::{FeePriority, FeeRate, TransactionError, Change, SignableTransaction, Eventuality}; #[cfg(feature = "std")] pub use send::SignableTransactionBuilder; #[cfg(feature = "multisig")] diff --git a/coins/monero/wallet/src/scan.rs b/coins/monero/wallet/src/scan.rs index b8fa67e6..2f4e0eb3 100644 --- a/coins/monero/wallet/src/scan.rs +++ b/coins/monero/wallet/src/scan.rs @@ -9,7 +9,7 @@ use zeroize::{Zeroize, ZeroizeOnDrop}; use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar, edwards::EdwardsPoint}; -use monero_rpc::{RpcError, RpcConnection, Rpc}; +use monero_rpc::{RpcError, Rpc}; use monero_serai::{ io::*, primitives::Commitment, @@ -240,10 +240,7 @@ pub struct SpendableOutput { impl SpendableOutput { /// Update the spendable output's global index. This is intended to be called if a /// re-organization occurred. - pub async fn refresh_global_index( - &mut self, - rpc: &Rpc, - ) -> Result<(), RpcError> { + pub async fn refresh_global_index(&mut self, rpc: &impl Rpc) -> Result<(), RpcError> { self.global_index = *rpc .get_o_indexes(self.output.absolute.tx) .await? @@ -254,10 +251,7 @@ impl SpendableOutput { Ok(()) } - pub async fn from( - rpc: &Rpc, - output: ReceivedOutput, - ) -> Result { + pub async fn from(rpc: &impl Rpc, output: ReceivedOutput) -> Result { let mut output = SpendableOutput { output, global_index: 0 }; output.refresh_global_index(rpc).await?; Ok(output) @@ -466,9 +460,9 @@ impl Scanner { /// transactions is a dead giveaway for which transactions you successfully scanned. This /// function obtains the output indexes for the miner transaction, incrementing from there /// instead. - pub async fn scan( + pub async fn scan( &mut self, - rpc: &Rpc, + rpc: &impl Rpc, block: &Block, ) -> Result>, RpcError> { let mut index = rpc.get_o_indexes(block.miner_tx.hash()).await?[0]; diff --git a/coins/monero/wallet/src/send/builder.rs b/coins/monero/wallet/src/send/builder.rs index d4016a05..eeb8e93b 100644 --- a/coins/monero/wallet/src/send/builder.rs +++ b/coins/monero/wallet/src/send/builder.rs @@ -4,14 +4,14 @@ use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; use monero_serai::Protocol; use crate::{ - address::MoneroAddress, Fee, SpendableOutput, Change, Decoys, SignableTransaction, + address::MoneroAddress, FeeRate, SpendableOutput, Change, Decoys, SignableTransaction, TransactionError, extra::MAX_ARBITRARY_DATA_SIZE, }; #[derive(Clone, PartialEq, Eq, Debug, Zeroize, ZeroizeOnDrop)] struct SignableTransactionBuilderInternal { protocol: Protocol, - fee_rate: Fee, + fee_rate: FeeRate, r_seed: Option>, inputs: Vec<(SpendableOutput, Decoys)>, @@ -23,7 +23,7 @@ struct SignableTransactionBuilderInternal { 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: Protocol, fee_rate: Fee, change_address: Change) -> Self { + fn new(protocol: Protocol, fee_rate: FeeRate, change_address: Change) -> Self { Self { protocol, fee_rate, @@ -88,7 +88,7 @@ impl SignableTransactionBuilder { Self(self.0.clone()) } - pub fn new(protocol: Protocol, fee_rate: Fee, change_address: Change) -> Self { + pub fn new(protocol: Protocol, fee_rate: FeeRate, change_address: Change) -> Self { Self(Arc::new(RwLock::new(SignableTransactionBuilderInternal::new( protocol, fee_rate, diff --git a/coins/monero/wallet/src/send/mod.rs b/coins/monero/wallet/src/send/mod.rs index 67709456..c0820c16 100644 --- a/coins/monero/wallet/src/send/mod.rs +++ b/coins/monero/wallet/src/send/mod.rs @@ -22,7 +22,7 @@ use curve25519_dalek::{ use frost::FrostError; use monero_rpc::RpcError; -pub use monero_rpc::{Fee, FeePriority}; +pub use monero_rpc::{FeePriority, FeeRate}; use monero_serai::{ io::*, primitives::{Commitment, keccak256}, @@ -216,7 +216,7 @@ fn calculate_weight_and_fee( decoy_weights: &[usize], n_outputs: usize, extra: usize, - fee_rate: Fee, + fee_rate: FeeRate, ) -> (usize, u64) { // Starting the fee at 0 here is different than core Monero's wallet2.cpp, which starts its fee // calculation with an estimate. @@ -291,7 +291,7 @@ pub struct SignableTransaction { payments: Vec, data: Vec>, fee: u64, - fee_rate: Fee, + fee_rate: FeeRate, } /// Specification for a change output. @@ -398,7 +398,7 @@ impl SignableTransaction { payments: Vec<(MoneroAddress, u64)>, change: &Change, data: Vec>, - fee_rate: Fee, + fee_rate: FeeRate, ) -> Result { // Make sure there's only one payment ID let mut has_payment_id = { @@ -559,7 +559,7 @@ impl SignableTransaction { self.fee } - pub fn fee_rate(&self) -> Fee { + pub fn fee_rate(&self) -> FeeRate { self.fee_rate } diff --git a/coins/monero/wallet/tests/add_data.rs b/coins/monero/wallet/tests/add_data.rs index f1f42f86..995f43b0 100644 --- a/coins/monero/wallet/tests/add_data.rs +++ b/coins/monero/wallet/tests/add_data.rs @@ -1,5 +1,5 @@ use monero_serai::transaction::Transaction; -use monero_wallet::{TransactionError, extra::MAX_ARBITRARY_DATA_SIZE}; +use monero_wallet::{rpc::Rpc, TransactionError, extra::MAX_ARBITRARY_DATA_SIZE}; mod runner; diff --git a/coins/monero/wallet/tests/decoys.rs b/coins/monero/wallet/tests/decoys.rs index cb53a06b..776b34bb 100644 --- a/coins/monero/wallet/tests/decoys.rs +++ b/coins/monero/wallet/tests/decoys.rs @@ -1,6 +1,9 @@ -use monero_rpc::{Rpc, OutputResponse}; -use monero_serai::{transaction::Transaction, Protocol, DEFAULT_LOCK_WINDOW}; -use monero_wallet::SpendableOutput; +use monero_simple_request_rpc::SimpleRequestRpc; +use monero_wallet::{ + monero::{transaction::Transaction, Protocol, DEFAULT_LOCK_WINDOW}, + rpc::{OutputResponse, Rpc}, + SpendableOutput, +}; mod runner; @@ -12,7 +15,7 @@ test!( builder.add_payment(addr, 2000000000000); (builder.build().unwrap(), ()) }, - |rpc: Rpc<_>, tx: Transaction, mut scanner: Scanner, ()| async move { + |rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, ()| async move { let output = scanner.scan_transaction(&tx).not_locked().swap_remove(0); assert_eq!(output.commitment().amount, 2000000000000); SpendableOutput::from(&rpc, output).await.unwrap() @@ -20,7 +23,7 @@ test!( ), ( // Then make a second tx1 - |protocol: Protocol, rpc: Rpc<_>, mut builder: Builder, addr, state: _| async move { + |protocol: Protocol, rpc: SimpleRequestRpc, mut builder: Builder, addr, state: _| async move { let output_tx0: SpendableOutput = state; let decoys = Decoys::fingerprintable_canonical_select( &mut OsRng, @@ -39,7 +42,7 @@ test!( (builder.build().unwrap(), (protocol, output_tx0)) }, // Then make sure DSA selects freshly unlocked output from tx1 as a decoy - |rpc: Rpc<_>, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move { + |rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move { use rand_core::OsRng; let height = rpc.get_height().await.unwrap(); @@ -89,7 +92,7 @@ test!( builder.add_payment(addr, 2000000000000); (builder.build().unwrap(), ()) }, - |rpc: Rpc<_>, tx: Transaction, mut scanner: Scanner, ()| async move { + |rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, ()| async move { let output = scanner.scan_transaction(&tx).not_locked().swap_remove(0); assert_eq!(output.commitment().amount, 2000000000000); SpendableOutput::from(&rpc, output).await.unwrap() @@ -97,7 +100,7 @@ test!( ), ( // Then make a second tx1 - |protocol: Protocol, rpc: Rpc<_>, mut builder: Builder, addr, state: _| async move { + |protocol: Protocol, rpc: SimpleRequestRpc, mut builder: Builder, addr, state: _| async move { let output_tx0: SpendableOutput = state; let decoys = Decoys::select( &mut OsRng, @@ -116,7 +119,7 @@ test!( (builder.build().unwrap(), (protocol, output_tx0)) }, // Then make sure DSA selects freshly unlocked output from tx1 as a decoy - |rpc: Rpc<_>, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move { + |rpc: SimpleRequestRpc, tx: Transaction, mut scanner: Scanner, state: (_, _)| async move { use rand_core::OsRng; let height = rpc.get_height().await.unwrap(); diff --git a/coins/monero/wallet/tests/eventuality.rs b/coins/monero/wallet/tests/eventuality.rs index 20cb5cbb..14f255e5 100644 --- a/coins/monero/wallet/tests/eventuality.rs +++ b/coins/monero/wallet/tests/eventuality.rs @@ -2,6 +2,7 @@ use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; use monero_serai::transaction::Transaction; use monero_wallet::{ + rpc::Rpc, Eventuality, address::{AddressType, AddressMeta, MoneroAddress}, }; diff --git a/coins/monero/wallet/tests/runner.rs b/coins/monero/wallet/tests/runner.rs index 12799384..3fba109d 100644 --- a/coins/monero/wallet/tests/runner.rs +++ b/coins/monero/wallet/tests/runner.rs @@ -8,13 +8,13 @@ use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE, scalar::Scalar}; use tokio::sync::Mutex; -use monero_rpc::Rpc; use monero_simple_request_rpc::SimpleRequestRpc; -use monero_serai::{transaction::Transaction, DEFAULT_LOCK_WINDOW}; use monero_wallet::{ + monero::transaction::Transaction, + rpc::Rpc, ViewPair, Scanner, address::{Network, AddressType, AddressSpec, AddressMeta, MoneroAddress}, - SpendableOutput, Fee, + SpendableOutput, FeeRate, }; pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) { @@ -34,7 +34,7 @@ pub fn random_address() -> (Scalar, ViewPair, MoneroAddress) { // TODO: Support transactions already on-chain // TODO: Don't have a side effect of mining blocks more blocks than needed under race conditions -pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_hash: [u8; 32]) { +pub async fn mine_until_unlocked(rpc: &SimpleRequestRpc, addr: &str, tx_hash: [u8; 32]) { // mine until tx is in a block let mut height = rpc.get_height().await.unwrap(); let mut found = false; @@ -52,11 +52,11 @@ pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_has // Mine until tx's outputs are unlocked let o_indexes: Vec = rpc.get_o_indexes(tx_hash).await.unwrap(); while rpc - .get_outs(&o_indexes) + .get_unlocked_outputs(&o_indexes, height, false) .await .unwrap() .into_iter() - .all(|o| (!(o.unlocked && height >= (o.height + DEFAULT_LOCK_WINDOW)))) + .all(|output| output.is_some()) { height = rpc.generate_blocks(addr, 1).await.unwrap().1 + 1; } @@ -64,7 +64,7 @@ pub async fn mine_until_unlocked(rpc: &Rpc, addr: &str, tx_has // Mines 60 blocks and returns an unlocked miner TX output. #[allow(dead_code)] -pub async fn get_miner_tx_output(rpc: &Rpc, view: &ViewPair) -> SpendableOutput { +pub async fn get_miner_tx_output(rpc: &SimpleRequestRpc, view: &ViewPair) -> SpendableOutput { let mut scanner = Scanner::from_view(view.clone(), Some(HashSet::new())); // Mine 60 blocks to unlock a miner TX @@ -79,7 +79,7 @@ pub async fn get_miner_tx_output(rpc: &Rpc, view: &ViewPair) - } /// Make sure the weight and fee match the expected calculation. -pub fn check_weight_and_fee(tx: &Transaction, fee_rate: Fee) { +pub fn check_weight_and_fee(tx: &Transaction, fee_rate: FeeRate) { let fee = tx.rct_signatures.base.fee; let weight = tx.weight(); @@ -90,7 +90,7 @@ pub fn check_weight_and_fee(tx: &Transaction, fee_rate: Fee) { assert_eq!(fee, expected_fee); } -pub async fn rpc() -> Rpc { +pub async fn rpc() -> SimpleRequestRpc { let rpc = SimpleRequestRpc::new("http://serai:seraidex@127.0.0.1:18081".to_string()).await.unwrap(); @@ -216,7 +216,7 @@ macro_rules! test { let builder = SignableTransactionBuilder::new( protocol, - rpc.get_fee(protocol, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), Change::new( &ViewPair::new( &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE, diff --git a/coins/monero/wallet/tests/scan.rs b/coins/monero/wallet/tests/scan.rs index 51cc4d94..b4d24eb8 100644 --- a/coins/monero/wallet/tests/scan.rs +++ b/coins/monero/wallet/tests/scan.rs @@ -1,7 +1,7 @@ use rand_core::RngCore; use monero_serai::transaction::Transaction; -use monero_wallet::{address::SubaddressIndex, extra::PaymentId}; +use monero_wallet::{rpc::Rpc, address::SubaddressIndex, extra::PaymentId}; mod runner; diff --git a/coins/monero/wallet/tests/send.rs b/coins/monero/wallet/tests/send.rs index 94aa8131..48c8aaa1 100644 --- a/coins/monero/wallet/tests/send.rs +++ b/coins/monero/wallet/tests/send.rs @@ -1,11 +1,12 @@ use rand_core::OsRng; -use monero_serai::{transaction::Transaction, Protocol}; -use monero_rpc::Rpc; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ - extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, DecoySelection, Decoys, - SignableTransactionBuilder, + monero::{transaction::Transaction, Protocol}, + rpc::Rpc, + extra::Extra, + address::SubaddressIndex, + ReceivedOutput, SpendableOutput, DecoySelection, Decoys, SignableTransactionBuilder, }; mod runner; @@ -13,7 +14,7 @@ mod runner; // Set up inputs, select decoys, then add them to the TX builder async fn add_inputs( protocol: Protocol, - rpc: &Rpc, + rpc: &SimpleRequestRpc, outputs: Vec, builder: &mut SignableTransactionBuilder, ) { @@ -98,7 +99,7 @@ test!( }, ), ( - |protocol, rpc: Rpc<_>, _, _, outputs: Vec| async move { + |protocol, rpc: SimpleRequestRpc, _, _, outputs: Vec| async move { use monero_wallet::FeePriority; let change_view = ViewPair::new( @@ -108,7 +109,7 @@ test!( let mut builder = SignableTransactionBuilder::new( protocol, - rpc.get_fee(protocol, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), Change::new(&change_view, false), ); add_inputs(protocol, &rpc, vec![outputs.first().unwrap().clone()], &mut builder).await; @@ -287,12 +288,12 @@ test!( }, ), ( - |protocol, rpc: Rpc<_>, _, addr, outputs: Vec| async move { + |protocol, rpc: SimpleRequestRpc, _, addr, outputs: Vec| async move { use monero_wallet::FeePriority; let mut builder = SignableTransactionBuilder::new( protocol, - rpc.get_fee(protocol, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), Change::fingerprintable(None), ); add_inputs(protocol, &rpc, vec![outputs.first().unwrap().clone()], &mut builder).await; diff --git a/coins/monero/wallet/tests/wallet2_compatibility.rs b/coins/monero/wallet/tests/wallet2_compatibility.rs index fa162510..ec3ff793 100644 --- a/coins/monero/wallet/tests/wallet2_compatibility.rs +++ b/coins/monero/wallet/tests/wallet2_compatibility.rs @@ -5,10 +5,10 @@ use rand_core::{OsRng, RngCore}; use serde::Deserialize; use serde_json::json; -use monero_serai::transaction::Transaction; -use monero_rpc::{EmptyResponse, Rpc}; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ + monero::transaction::Transaction, + rpc::Rpc, address::{Network, AddressSpec, SubaddressIndex, MoneroAddress}, extra::{MAX_TX_EXTRA_NONCE_SIZE, Extra, PaymentId}, Scanner, @@ -16,7 +16,10 @@ use monero_wallet::{ mod runner; -async fn make_integrated_address(rpc: &Rpc, payment_id: [u8; 8]) -> String { +#[derive(Deserialize, Debug)] +struct EmptyResponse {} + +async fn make_integrated_address(rpc: &SimpleRequestRpc, payment_id: [u8; 8]) -> String { #[derive(Debug, Deserialize)] struct IntegratedAddressResponse { integrated_address: String, @@ -33,7 +36,7 @@ async fn make_integrated_address(rpc: &Rpc, payment_id: [u8; 8 res.integrated_address } -async fn initialize_rpcs() -> (Rpc, Rpc, String) { +async fn initialize_rpcs() -> (SimpleRequestRpc, SimpleRequestRpc, String) { let wallet_rpc = SimpleRequestRpc::new("http://127.0.0.1:18082".to_string()).await.unwrap(); let daemon_rpc = runner::rpc().await; @@ -89,7 +92,7 @@ async fn from_wallet_rpc_to_self(spec: AddressSpec) { // TODO: Needs https://github.com/monero-project/monero/pull/9260 // let fee_rate = daemon_rpc - // .get_fee(daemon_rpc.get_protocol().await.unwrap(), FeePriority::Unimportant) + // .get_fee_rate(daemon_rpc.get_protocol().await.unwrap(), FeePriority::Unimportant) // .await // .unwrap(); @@ -173,7 +176,7 @@ test!( .add_payment(MoneroAddress::from_str(Network::Mainnet, &wallet_rpc_addr).unwrap(), 1000000); (builder.build().unwrap(), wallet_rpc) }, - |_, tx: Transaction, _, data: Rpc| async move { + |_, tx: Transaction, _, data: SimpleRequestRpc| async move { // confirm receipt let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -207,7 +210,7 @@ test!( .add_payment(MoneroAddress::from_str(Network::Mainnet, &addr.address).unwrap(), 1000000); (builder.build().unwrap(), (wallet_rpc, addr.account_index)) }, - |_, tx: Transaction, _, data: (Rpc, u32)| async move { + |_, tx: Transaction, _, data: (SimpleRequestRpc, u32)| async move { // confirm receipt let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -259,7 +262,7 @@ test!( ]); (builder.build().unwrap(), (wallet_rpc, daemon_rpc, addrs.address_index)) }, - |_, tx: Transaction, _, data: (Rpc, Rpc, u32)| async move { + |_, tx: Transaction, _, data: (SimpleRequestRpc, SimpleRequestRpc, u32)| async move { // confirm receipt let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -304,7 +307,7 @@ test!( builder.add_payment(MoneroAddress::from_str(Network::Mainnet, &addr).unwrap(), 1000000); (builder.build().unwrap(), (wallet_rpc, payment_id)) }, - |_, tx: Transaction, _, data: (Rpc, [u8; 8])| async move { + |_, tx: Transaction, _, data: (SimpleRequestRpc, [u8; 8])| async move { // confirm receipt let _: EmptyResponse = data.0.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data @@ -339,7 +342,7 @@ test!( (builder.build().unwrap(), wallet_rpc) }, - |_, tx: Transaction, _, data: Rpc| async move { + |_, tx: Transaction, _, data: SimpleRequestRpc| async move { // confirm receipt let _: EmptyResponse = data.json_rpc_call("refresh", None).await.unwrap(); let transfer: TransfersResponse = data diff --git a/processor/src/networks/monero.rs b/processor/src/networks/monero.rs index dd792035..bd9f93b2 100644 --- a/processor/src/networks/monero.rs +++ b/processor/src/networks/monero.rs @@ -19,7 +19,7 @@ use monero_wallet::{ rpc::{RpcError, Rpc}, ViewPair, Scanner, address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec}, - Fee, SpendableOutput, Change, DecoySelection, Decoys, TransactionError, + FeeRate, SpendableOutput, Change, DecoySelection, Decoys, TransactionError, SignableTransaction as MSignableTransaction, Eventuality, TransactionMachine, }; @@ -222,7 +222,7 @@ impl BlockTrait for Block { #[derive(Clone, Debug)] pub struct Monero { - rpc: Rpc, + rpc: SimpleRequestRpc, } // Shim required for testing/debugging purposes due to generic arguments also necessitating trait // bounds @@ -275,7 +275,7 @@ impl Monero { scanner } - async fn median_fee(&self, block: &Block) -> Result { + async fn median_fee(&self, block: &Block) -> Result { let mut fees = vec![]; for tx_hash in &block.txs { let tx = @@ -294,7 +294,7 @@ impl Monero { let fee = fees.get(fees.len() / 2).copied().unwrap_or(0); // TODO: Set a sane minimum fee - Ok(Fee { per_weight: fee.max(1500000), mask: 10000 }) + Ok(FeeRate::new(fee.max(1500000), 10000).unwrap()) } async fn make_signable_transaction( @@ -795,7 +795,7 @@ impl Network for Monero { vec![(address.into(), amount - fee)], &Change::fingerprintable(Some(Self::test_address().into())), vec![], - self.rpc.get_fee(protocol, FeePriority::Unimportant).await.unwrap(), + self.rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), ) .unwrap() .sign(&mut OsRng, &Zeroizing::new(Scalar::ONE.0)) diff --git a/tests/full-stack/src/lib.rs b/tests/full-stack/src/lib.rs index e4241b92..509a67fa 100644 --- a/tests/full-stack/src/lib.rs +++ b/tests/full-stack/src/lib.rs @@ -53,8 +53,9 @@ impl Handles { pub async fn monero( &self, ops: &DockerOperations, - ) -> monero_wallet::rpc::Rpc { + ) -> monero_simple_request_rpc::SimpleRequestRpc { use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::rpc::Rpc; let rpc = ops.handle(&self.monero.0).host_port(self.monero.1).unwrap(); let rpc = format!("http://{RPC_USER}:{RPC_PASS}@{}:{}", rpc.0, rpc.1); diff --git a/tests/full-stack/src/tests/mint_and_burn.rs b/tests/full-stack/src/tests/mint_and_burn.rs index ebcc0883..b2faa6b2 100644 --- a/tests/full-stack/src/tests/mint_and_burn.rs +++ b/tests/full-stack/src/tests/mint_and_burn.rs @@ -89,6 +89,7 @@ async fn mint_and_burn_test() { let monero_blocks = { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; use monero_wallet::{ + rpc::Rpc, ViewPair, address::{Network, AddressSpec}, }; @@ -128,6 +129,8 @@ async fn mint_and_burn_test() { } { + use monero_wallet::rpc::Rpc; + let rpc = handles.monero(ops).await; for (block, txs) in &monero_blocks { @@ -347,6 +350,7 @@ async fn mint_and_burn_test() { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; use monero_wallet::{ monero::{io::decompress_point, Protocol, transaction::Timelock}, + rpc::Rpc, ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction, address::{Network, AddressType, AddressMeta, MoneroAddress}, }; @@ -393,7 +397,7 @@ async fn mint_and_burn_test() { )], &Change::new(&view_pair, false), vec![Shorthand::transfer(None, serai_addr).encode()], - rpc.get_fee(Protocol::v16, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(Protocol::v16, FeePriority::Unimportant).await.unwrap(), ) .unwrap() .sign(&mut OsRng, &Zeroizing::new(Scalar::ONE)) @@ -482,7 +486,10 @@ async fn mint_and_burn_test() { // Get the current blocks let mut start_bitcoin_block = handles[0].bitcoin(&ops).await.get_latest_block_number().await.unwrap(); - let mut start_monero_block = handles[0].monero(&ops).await.get_height().await.unwrap(); + let mut start_monero_block = { + use monero_wallet::rpc::Rpc; + handles[0].monero(&ops).await.get_height().await.unwrap() + }; // Burn the sriBTC/sriXMR { @@ -574,7 +581,7 @@ async fn mint_and_burn_test() { // Verify the received Monero TX { - use monero_wallet::{ViewPair, Scanner}; + use monero_wallet::{rpc::Rpc, ViewPair, Scanner}; let rpc = handles[0].monero(&ops).await; let mut scanner = Scanner::from_view( ViewPair::new(monero_spend, Zeroizing::new(monero_view)), diff --git a/tests/processor/src/lib.rs b/tests/processor/src/lib.rs index e7ff6f14..0399b043 100644 --- a/tests/processor/src/lib.rs +++ b/tests/processor/src/lib.rs @@ -275,6 +275,7 @@ impl Coordinator { } NetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::rpc::Rpc; // Monero's won't, so call get_height if handle @@ -405,6 +406,7 @@ impl Coordinator { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ + rpc::Rpc, ViewPair, address::{Network, AddressSpec}, }; @@ -516,6 +518,7 @@ impl Coordinator { } NetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::rpc::Rpc; let rpc = SimpleRequestRpc::new(rpc_url).await.expect("couldn't connect to the Monero RPC"); let to = rpc.get_height().await.unwrap(); @@ -576,7 +579,7 @@ impl Coordinator { } NetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; - use monero_wallet::monero::transaction::Transaction; + use monero_wallet::{rpc::Rpc, monero::transaction::Transaction}; let rpc = SimpleRequestRpc::new(rpc_url) .await @@ -676,6 +679,7 @@ impl Coordinator { } NetworkId::Monero => { use monero_simple_request_rpc::SimpleRequestRpc; + use monero_wallet::rpc::Rpc; let rpc = SimpleRequestRpc::new(rpc_url) .await diff --git a/tests/processor/src/networks.rs b/tests/processor/src/networks.rs index c00dea68..0dbfad69 100644 --- a/tests/processor/src/networks.rs +++ b/tests/processor/src/networks.rs @@ -191,6 +191,7 @@ impl Wallet { use curve25519_dalek::{constants::ED25519_BASEPOINT_POINT, scalar::Scalar}; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ + rpc::Rpc, ViewPair, Scanner, address::{Network, AddressSpec}, }; @@ -436,6 +437,7 @@ impl Wallet { use curve25519_dalek::constants::ED25519_BASEPOINT_POINT; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ + rpc::Rpc, monero::{Protocol, io::decompress_point}, address::{Network, AddressType, AddressMeta, Address}, SpendableOutput, DecoySelection, Decoys, Change, FeePriority, Scanner, @@ -490,7 +492,7 @@ impl Wallet { vec![(to_addr, AMOUNT)], &Change::new(view_pair, false), data, - rpc.get_fee(Protocol::v16, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(Protocol::v16, FeePriority::Unimportant).await.unwrap(), ) .unwrap() .sign(&mut OsRng, spend_key)