diff --git a/coins/monero/rpc/src/lib.rs b/coins/monero/rpc/src/lib.rs index f7eb88ae..27fe1fd7 100644 --- a/coins/monero/rpc/src/lib.rs +++ b/coins/monero/rpc/src/lib.rs @@ -23,7 +23,6 @@ use serde_json::{Value, json}; use monero_serai::{ io::*, - Protocol, transaction::{Input, Timelock, Transaction}, block::Block, }; @@ -154,9 +153,6 @@ pub enum RpcError { /// 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]>), @@ -210,42 +206,6 @@ 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 @@ -305,10 +265,12 @@ pub trait Rpc: Sync + Clone + Debug { } /// Get the active blockchain protocol version. - async fn get_protocol(&self) -> Result { + /// + /// This is specifically the major version within the most recent block header. + async fn get_protocol(&self) -> Result { #[derive(Deserialize, Debug)] struct ProtocolResponse { - major_version: usize, + major_version: u8, } #[derive(Deserialize, Debug)] @@ -317,16 +279,11 @@ pub trait Rpc: Sync + Clone + Debug { } Ok( - match self + self .json_rpc_call::("get_last_block_header", None) .await? .block_header - .major_version - { - 13 | 14 => Protocol::v14, - 15 | 16 => Protocol::v16, - protocol => Err(RpcError::UnsupportedProtocol(protocol))?, - }, + .major_version, ) } @@ -789,28 +746,27 @@ pub trait Rpc: Sync + Clone + Debug { /// /// This may be manipulated to unsafe levels and MUST be sanity checked. // TODO: Take a sanity check argument - 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() { - #[derive(Deserialize, Debug)] - struct FeeResponse { - status: String, - fees: Vec, - quantization_mask: u64, - } + async fn get_fee_rate(&self, priority: FeePriority) -> Result { + #[derive(Deserialize, Debug)] + struct FeeResponse { + status: String, + fees: Option>, + fee: u64, + quantization_mask: u64, + } - let res: FeeResponse = self - .json_rpc_call( - "get_fee_estimate", - Some(json!({ "grace_blocks": GRACE_BLOCKS_FOR_FEE_ESTIMATE })), - ) - .await?; + let res: FeeResponse = self + .json_rpc_call( + "get_fee_estimate", + Some(json!({ "grace_blocks": GRACE_BLOCKS_FOR_FEE_ESTIMATE })), + ) + .await?; + if res.status != "OK" { + Err(RpcError::InvalidFee)?; + } + + if let Some(fees) = res.fees { // https://github.com/monero-project/monero/blob/94e67bf96bbc010241f29ada6abc89f49a81759c/ // src/wallet/wallet2.cpp#L7615-L7620 let priority_idx = usize::try_from(if priority.fee_priority() >= 4 { @@ -820,15 +776,27 @@ pub trait Rpc: Sync + Clone + Debug { }) .map_err(|_| RpcError::InvalidPriority)?; - if res.status != "OK" { - Err(RpcError::InvalidFee) - } else if priority_idx >= res.fees.len() { + if priority_idx >= fees.len() { Err(RpcError::InvalidPriority) } else { - FeeRate::new(res.fees[priority_idx], res.quantization_mask) + FeeRate::new(fees[priority_idx], res.quantization_mask) } } else { - get_fee_rate_v14(self, priority).await + // 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]; + + FeeRate::new(res.fee * fee_multiplier, res.quantization_mask) } } diff --git a/coins/monero/src/lib.rs b/coins/monero/src/lib.rs index 1b5d37b5..fc157232 100644 --- a/coins/monero/src/lib.rs +++ b/coins/monero/src/lib.rs @@ -1,26 +1,19 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] +// #![deny(missing_docs)] // TODO #![cfg_attr(not(feature = "std"), no_std)] -use std_shims::io as stdio; - -use zeroize::Zeroize; - pub use monero_io as io; pub use monero_generators as generators; pub use monero_primitives as primitives; mod merkle; -use monero_io as serialize; -use serialize::{read_byte, read_u16}; - /// Ring Signature structs and functionality. pub mod ring_signatures; /// RingCT structs and functionality. pub mod ringct; -use ringct::RctType; /// Transaction structs. pub mod transaction; @@ -30,123 +23,3 @@ pub mod block; pub const DEFAULT_LOCK_WINDOW: usize = 10; pub const COINBASE_LOCK_WINDOW: usize = 60; pub const BLOCK_TIME: usize = 120; - -/// Monero protocol version. -/// -/// v15 is omitted as v15 was simply v14 and v16 being active at the same time, with regards to the -/// transactions supported. Accordingly, v16 should be used during v15. -#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] -#[allow(non_camel_case_types)] -pub enum Protocol { - v14, - v16, - Custom { - ring_len: usize, - bp_plus: bool, - optimal_rct_type: RctType, - view_tags: bool, - v16_fee: bool, - }, -} - -impl Protocol { - /// Amount of ring members under this protocol version. - pub fn ring_len(&self) -> usize { - match self { - Protocol::v14 => 11, - Protocol::v16 => 16, - Protocol::Custom { ring_len, .. } => *ring_len, - } - } - - /// Whether or not the specified version uses Bulletproofs or Bulletproofs+. - /// - /// This method will likely be reworked when versions not using Bulletproofs at all are added. - pub fn bp_plus(&self) -> bool { - match self { - Protocol::v14 => false, - Protocol::v16 => true, - Protocol::Custom { bp_plus, .. } => *bp_plus, - } - } - - // TODO: Make this an Option when we support pre-RCT protocols - pub fn optimal_rct_type(&self) -> RctType { - match self { - Protocol::v14 => RctType::Clsag, - Protocol::v16 => RctType::BulletproofsPlus, - Protocol::Custom { optimal_rct_type, .. } => *optimal_rct_type, - } - } - - /// Whether or not the specified version uses view tags. - pub fn view_tags(&self) -> bool { - match self { - Protocol::v14 => false, - Protocol::v16 => true, - Protocol::Custom { view_tags, .. } => *view_tags, - } - } - - /// Whether or not the specified version uses the fee algorithm from Monero - /// hard fork version 16 (released in v18 binaries). - pub fn v16_fee(&self) -> bool { - match self { - Protocol::v14 => false, - Protocol::v16 => true, - Protocol::Custom { v16_fee, .. } => *v16_fee, - } - } - - pub fn write(&self, w: &mut W) -> stdio::Result<()> { - match self { - Protocol::v14 => w.write_all(&[0, 14]), - Protocol::v16 => w.write_all(&[0, 16]), - Protocol::Custom { ring_len, bp_plus, optimal_rct_type, view_tags, v16_fee } => { - // Custom, version 0 - w.write_all(&[1, 0])?; - w.write_all(&u16::try_from(*ring_len).unwrap().to_le_bytes())?; - w.write_all(&[u8::from(*bp_plus)])?; - w.write_all(&[optimal_rct_type.to_byte()])?; - w.write_all(&[u8::from(*view_tags)])?; - w.write_all(&[u8::from(*v16_fee)]) - } - } - } - - pub fn read(r: &mut R) -> stdio::Result { - Ok(match read_byte(r)? { - // Monero protocol - 0 => match read_byte(r)? { - 14 => Protocol::v14, - 16 => Protocol::v16, - _ => Err(stdio::Error::other("unrecognized monero protocol"))?, - }, - // Custom - 1 => match read_byte(r)? { - 0 => Protocol::Custom { - ring_len: read_u16(r)?.into(), - bp_plus: match read_byte(r)? { - 0 => false, - 1 => true, - _ => Err(stdio::Error::other("invalid bool serialization"))?, - }, - optimal_rct_type: RctType::from_byte(read_byte(r)?) - .ok_or_else(|| stdio::Error::other("invalid RctType serialization"))?, - view_tags: match read_byte(r)? { - 0 => false, - 1 => true, - _ => Err(stdio::Error::other("invalid bool serialization"))?, - }, - v16_fee: match read_byte(r)? { - 0 => false, - 1 => true, - _ => Err(stdio::Error::other("invalid bool serialization"))?, - }, - }, - _ => Err(stdio::Error::other("unrecognized custom protocol serialization"))?, - }, - _ => Err(stdio::Error::other("unrecognized protocol serialization"))?, - }) - } -} diff --git a/coins/monero/src/ringct.rs b/coins/monero/src/ringct.rs index 0e61f95d..80f17b90 100644 --- a/coins/monero/src/ringct.rs +++ b/coins/monero/src/ringct.rs @@ -17,7 +17,6 @@ use crate::{ io::*, generators::hash_to_point, ringct::{mlsag::Mlsag, clsag::Clsag, borromean::BorromeanRange, bulletproofs::Bulletproof}, - Protocol, }; /// Generate a key image for a given key. Defined as `x * hash_to_point(xG)`. @@ -227,10 +226,13 @@ pub enum RctPrunable { } impl RctPrunable { - pub fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize) -> usize { + #[rustfmt::skip] + pub fn fee_weight(bp_plus: bool, ring_len: usize, inputs: usize, outputs: usize) -> usize { // 1 byte for number of BPs (technically a VarInt, yet there's always just zero or one) - 1 + Bulletproof::fee_weight(protocol.bp_plus(), outputs) + - (inputs * (Clsag::fee_weight(protocol.ring_len()) + 32)) + 1 + + Bulletproof::fee_weight(bp_plus, outputs) + + // There's both the CLSAG and the pseudo-out + (inputs * (Clsag::fee_weight(ring_len) + 32)) } pub fn write(&self, w: &mut W, rct_type: RctType) -> io::Result<()> { @@ -383,8 +385,14 @@ impl RctSignatures { } } - pub fn fee_weight(protocol: Protocol, inputs: usize, outputs: usize, fee: u64) -> usize { - RctBase::fee_weight(outputs, fee) + RctPrunable::fee_weight(protocol, inputs, outputs) + pub fn fee_weight( + bp_plus: bool, + ring_len: usize, + inputs: usize, + outputs: usize, + fee: u64, + ) -> usize { + RctBase::fee_weight(outputs, fee) + RctPrunable::fee_weight(bp_plus, ring_len, inputs, outputs) } pub fn write(&self, w: &mut W) -> io::Result<()> { diff --git a/coins/monero/src/transaction.rs b/coins/monero/src/transaction.rs index b374c01e..5e492751 100644 --- a/coins/monero/src/transaction.rs +++ b/coins/monero/src/transaction.rs @@ -13,7 +13,6 @@ use crate::{ primitives::keccak256, ring_signatures::RingSignature, ringct::{bulletproofs::Bulletproof, RctType, RctBase, RctPrunable, RctSignatures}, - Protocol, }; #[derive(Clone, PartialEq, Eq, Debug)] @@ -254,15 +253,19 @@ pub struct Transaction { } impl Transaction { + // TODO: Replace ring_len, decoy_weights for &[&[usize]], where the inner buf is the decoy + // offsets pub fn fee_weight( - protocol: Protocol, + view_tags: bool, + bp_plus: bool, + ring_len: usize, decoy_weights: &[usize], outputs: usize, extra: usize, fee: u64, ) -> usize { - TransactionPrefix::fee_weight(decoy_weights, outputs, protocol.view_tags(), extra) + - RctSignatures::fee_weight(protocol, decoy_weights.len(), outputs, fee) + TransactionPrefix::fee_weight(decoy_weights, outputs, view_tags, extra) + + RctSignatures::fee_weight(bp_plus, ring_len, decoy_weights.len(), outputs, fee) } pub fn write(&self, w: &mut W) -> io::Result<()> { diff --git a/coins/monero/wallet/src/lib.rs b/coins/monero/wallet/src/lib.rs index 371c06bf..cb2aba22 100644 --- a/coins/monero/wallet/src/lib.rs +++ b/coins/monero/wallet/src/lib.rs @@ -4,7 +4,10 @@ #![cfg_attr(not(feature = "std"), no_std)] use core::ops::Deref; -use std_shims::collections::{HashSet, HashMap}; +use std_shims::{ + io, + collections::{HashSet, HashMap}, +}; use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; @@ -15,9 +18,9 @@ use curve25519_dalek::{ }; use monero_serai::{ - io::write_varint, + io::{read_byte, read_u16, write_varint}, primitives::{Commitment, keccak256, keccak256_to_scalar}, - ringct::EncryptedAmount, + ringct::{RctType, EncryptedAmount}, transaction::Input, }; pub use monero_serai as monero; @@ -58,6 +61,137 @@ pub use send::TransactionMachine; #[cfg(test)] mod tests; +/// Monero protocol version. +/// +/// v15 is omitted as v15 was simply v14 and v16 being active at the same time, with regards to the +/// transactions supported. Accordingly, v16 should be used during v15. +#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] +#[allow(non_camel_case_types)] +pub enum Protocol { + v14, + v16, + Custom { + ring_len: usize, + bp_plus: bool, + optimal_rct_type: RctType, + view_tags: bool, + v16_fee: bool, + }, +} + +impl TryFrom for Protocol { + type Error = (); + fn try_from(version: u8) -> Result { + Ok(match version { + 14 => Protocol::v14, // TODO: 13 | 14? + 15 | 16 => Protocol::v16, + _ => Err(())?, + }) + } +} + +impl Protocol { + /// Amount of ring members under this protocol version. + pub fn ring_len(&self) -> usize { + match self { + Protocol::v14 => 11, + Protocol::v16 => 16, + Protocol::Custom { ring_len, .. } => *ring_len, + } + } + + /// Whether or not the specified version uses Bulletproofs or Bulletproofs+. + /// + /// This method will likely be reworked when versions not using Bulletproofs at all are added. + pub fn bp_plus(&self) -> bool { + match self { + Protocol::v14 => false, + Protocol::v16 => true, + Protocol::Custom { bp_plus, .. } => *bp_plus, + } + } + + // TODO: Make this an Option when we support pre-RCT protocols + pub fn optimal_rct_type(&self) -> RctType { + match self { + Protocol::v14 => RctType::Clsag, + Protocol::v16 => RctType::BulletproofsPlus, + Protocol::Custom { optimal_rct_type, .. } => *optimal_rct_type, + } + } + + /// Whether or not the specified version uses view tags. + pub fn view_tags(&self) -> bool { + match self { + Protocol::v14 => false, + Protocol::v16 => true, + Protocol::Custom { view_tags, .. } => *view_tags, + } + } + + /// Whether or not the specified version uses the fee algorithm from Monero + /// hard fork version 16 (released in v18 binaries). + pub fn v16_fee(&self) -> bool { + match self { + Protocol::v14 => false, + Protocol::v16 => true, + Protocol::Custom { v16_fee, .. } => *v16_fee, + } + } + + pub fn write(&self, w: &mut W) -> io::Result<()> { + match self { + Protocol::v14 => w.write_all(&[0, 14]), + Protocol::v16 => w.write_all(&[0, 16]), + Protocol::Custom { ring_len, bp_plus, optimal_rct_type, view_tags, v16_fee } => { + // Custom, version 0 + w.write_all(&[1, 0])?; + w.write_all(&u16::try_from(*ring_len).unwrap().to_le_bytes())?; + w.write_all(&[u8::from(*bp_plus)])?; + w.write_all(&[optimal_rct_type.to_byte()])?; + w.write_all(&[u8::from(*view_tags)])?; + w.write_all(&[u8::from(*v16_fee)]) + } + } + } + + pub fn read(r: &mut R) -> io::Result { + Ok(match read_byte(r)? { + // Monero protocol + 0 => match read_byte(r)? { + 14 => Protocol::v14, + 16 => Protocol::v16, + _ => Err(io::Error::other("unrecognized monero protocol"))?, + }, + // Custom + 1 => match read_byte(r)? { + 0 => Protocol::Custom { + ring_len: read_u16(r)?.into(), + bp_plus: match read_byte(r)? { + 0 => false, + 1 => true, + _ => Err(io::Error::other("invalid bool serialization"))?, + }, + optimal_rct_type: RctType::from_byte(read_byte(r)?) + .ok_or_else(|| io::Error::other("invalid RctType serialization"))?, + view_tags: match read_byte(r)? { + 0 => false, + 1 => true, + _ => Err(io::Error::other("invalid bool serialization"))?, + }, + v16_fee: match read_byte(r)? { + 0 => false, + 1 => true, + _ => Err(io::Error::other("invalid bool serialization"))?, + }, + }, + _ => Err(io::Error::other("unrecognized custom protocol serialization"))?, + }, + _ => Err(io::Error::other("unrecognized protocol serialization"))?, + }) + } +} + fn key_image_sort(x: &EdwardsPoint, y: &EdwardsPoint) -> core::cmp::Ordering { x.compress().to_bytes().cmp(&y.compress().to_bytes()).reverse() } diff --git a/coins/monero/wallet/src/send/builder.rs b/coins/monero/wallet/src/send/builder.rs index eeb8e93b..9567ed83 100644 --- a/coins/monero/wallet/src/send/builder.rs +++ b/coins/monero/wallet/src/send/builder.rs @@ -2,9 +2,8 @@ use std::sync::{Arc, RwLock}; use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing}; -use monero_serai::Protocol; use crate::{ - address::MoneroAddress, FeeRate, SpendableOutput, Change, Decoys, SignableTransaction, + Protocol, address::MoneroAddress, FeeRate, SpendableOutput, Change, Decoys, SignableTransaction, TransactionError, extra::MAX_ARBITRARY_DATA_SIZE, }; diff --git a/coins/monero/wallet/src/send/mod.rs b/coins/monero/wallet/src/send/mod.rs index c0820c16..72a02e02 100644 --- a/coins/monero/wallet/src/send/mod.rs +++ b/coins/monero/wallet/src/send/mod.rs @@ -26,7 +26,6 @@ pub use monero_rpc::{FeePriority, FeeRate}; use monero_serai::{ io::*, primitives::{Commitment, keccak256}, - Protocol, ringct::{ generate_key_image, clsag::{ClsagError, ClsagContext, Clsag}, @@ -36,6 +35,7 @@ use monero_serai::{ transaction::{Input, Output, Timelock, TransactionPrefix, Transaction}, }; use crate::{ + Protocol, address::{Network, AddressSpec, MoneroAddress}, ViewPair, SpendableOutput, Decoys, PaymentId, ExtraField, Extra, key_image_sort, uniqueness, shared_key, commitment_mask, compact_amount_encryption, @@ -239,7 +239,15 @@ fn calculate_weight_and_fee( let mut iters = 0; let max_iters = 5; while !done { - weight = Transaction::fee_weight(protocol, decoy_weights, n_outputs, extra, fee); + weight = Transaction::fee_weight( + protocol.view_tags(), + protocol.bp_plus(), + protocol.ring_len(), + decoy_weights, + n_outputs, + extra, + fee, + ); let fee_calculated_from_weight = fee_rate.calculate_fee_from_weight(weight); diff --git a/coins/monero/wallet/tests/decoys.rs b/coins/monero/wallet/tests/decoys.rs index 776b34bb..e5103646 100644 --- a/coins/monero/wallet/tests/decoys.rs +++ b/coins/monero/wallet/tests/decoys.rs @@ -1,6 +1,6 @@ use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ - monero::{transaction::Transaction, Protocol, DEFAULT_LOCK_WINDOW}, + monero::{transaction::Transaction, DEFAULT_LOCK_WINDOW}, rpc::{OutputResponse, Rpc}, SpendableOutput, }; diff --git a/coins/monero/wallet/tests/runner.rs b/coins/monero/wallet/tests/runner.rs index 3fba109d..11dcf797 100644 --- a/coins/monero/wallet/tests/runner.rs +++ b/coins/monero/wallet/tests/runner.rs @@ -109,9 +109,6 @@ pub async fn rpc() -> SimpleRequestRpc { // Mine 40 blocks to ensure decoy availability rpc.generate_blocks(&addr, 40).await.unwrap(); - // Make sure we recognize the protocol - rpc.get_protocol().await.unwrap(); - rpc } @@ -171,6 +168,7 @@ macro_rules! test { }; use monero_wallet::{ + Protocol, address::{Network, AddressSpec}, ViewPair, Scanner, Change, DecoySelection, Decoys, FeePriority, SignableTransaction, SignableTransactionBuilder, @@ -212,11 +210,11 @@ macro_rules! test { let miner_tx = get_miner_tx_output(&rpc, &view).await; - let protocol = rpc.get_protocol().await.unwrap(); + let protocol = Protocol::try_from(rpc.get_protocol().await.unwrap()).unwrap(); let builder = SignableTransactionBuilder::new( protocol, - rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), Change::new( &ViewPair::new( &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE, diff --git a/coins/monero/wallet/tests/send.rs b/coins/monero/wallet/tests/send.rs index 48c8aaa1..c6885398 100644 --- a/coins/monero/wallet/tests/send.rs +++ b/coins/monero/wallet/tests/send.rs @@ -2,10 +2,7 @@ use rand_core::OsRng; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ - monero::{transaction::Transaction, Protocol}, - rpc::Rpc, - extra::Extra, - address::SubaddressIndex, + monero::transaction::Transaction, Protocol, rpc::Rpc, extra::Extra, address::SubaddressIndex, ReceivedOutput, SpendableOutput, DecoySelection, Decoys, SignableTransactionBuilder, }; @@ -109,7 +106,7 @@ test!( let mut builder = SignableTransactionBuilder::new( protocol, - rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), Change::new(&change_view, false), ); add_inputs(protocol, &rpc, vec![outputs.first().unwrap().clone()], &mut builder).await; @@ -293,7 +290,7 @@ test!( let mut builder = SignableTransactionBuilder::new( protocol, - rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(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 ec3ff793..019f1ec8 100644 --- a/coins/monero/wallet/tests/wallet2_compatibility.rs +++ b/coins/monero/wallet/tests/wallet2_compatibility.rs @@ -92,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_rate(daemon_rpc.get_protocol().await.unwrap(), FeePriority::Unimportant) + // .get_fee_rate(FeePriority::Unimportant) // .await // .unwrap(); diff --git a/processor/src/networks/monero.rs b/processor/src/networks/monero.rs index bd9f93b2..fb5393ad 100644 --- a/processor/src/networks/monero.rs +++ b/processor/src/networks/monero.rs @@ -15,7 +15,8 @@ use frost::{curve::Ed25519, ThresholdKeys}; use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ - monero::{Protocol, ringct::RctType, transaction::Transaction, block::Block}, + monero::{ringct::RctType, transaction::Transaction, block::Block}, + Protocol, rpc::{RpcError, Rpc}, ViewPair, Scanner, address::{Network as MoneroNetwork, SubaddressIndex, AddressSpec}, @@ -315,25 +316,14 @@ impl Monero { let fee_rate = self.median_fee(&block_for_fee).await?; // Get the protocol for the specified block number - // For now, this should just be v16, the latest deployed protocol, since there's no upcoming - // hard fork to be mindful of - let get_protocol = || Protocol::v16; - #[cfg(not(test))] - let protocol = get_protocol(); + let protocol = Protocol::try_from(block_for_fee.header.major_version) + .map_err(|()| NetworkError::ConnectionError)?; // If this is a test, we won't be using a mainnet node and need a distinct protocol // determination // Just use whatever the node expects #[cfg(test)] - let protocol = self.rpc.get_protocol().await.unwrap(); - - // Hedge against the above codegen failing by having an always included runtime check - if !cfg!(test) { - assert_eq!(protocol, get_protocol()); - } - - // Check a fork hasn't occurred which this processor hasn't been updated for - assert_eq!(protocol, self.rpc.get_protocol().await.map_err(map_rpc_err)?); + let protocol = Protocol::try_from(self.rpc.get_protocol().await.unwrap()).unwrap(); let spendable_outputs = inputs.iter().map(|input| input.0.clone()).collect::>(); @@ -774,7 +764,7 @@ impl Network for Monero { // The dust should always be sufficient for the fee let fee = Monero::DUST; - let protocol = self.rpc.get_protocol().await.unwrap(); + let protocol = Protocol::try_from(self.rpc.get_protocol().await.unwrap()).unwrap(); let decoys = Decoys::fingerprintable_canonical_select( &mut OsRng, @@ -795,7 +785,7 @@ impl Network for Monero { vec![(address.into(), amount - fee)], &Change::fingerprintable(Some(Self::test_address().into())), vec![], - self.rpc.get_fee_rate(protocol, FeePriority::Unimportant).await.unwrap(), + self.rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), ) .unwrap() .sign(&mut OsRng, &Zeroizing::new(Scalar::ONE.0)) diff --git a/tests/full-stack/src/tests/mint_and_burn.rs b/tests/full-stack/src/tests/mint_and_burn.rs index b2faa6b2..0d4cbbbd 100644 --- a/tests/full-stack/src/tests/mint_and_burn.rs +++ b/tests/full-stack/src/tests/mint_and_burn.rs @@ -349,7 +349,8 @@ 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}, + monero::{io::decompress_point, transaction::Timelock}, + Protocol, rpc::Rpc, ViewPair, Scanner, DecoySelection, Decoys, Change, FeePriority, SignableTransaction, address::{Network, AddressType, AddressMeta, MoneroAddress}, @@ -397,7 +398,7 @@ async fn mint_and_burn_test() { )], &Change::new(&view_pair, false), vec![Shorthand::transfer(None, serai_addr).encode()], - rpc.get_fee_rate(Protocol::v16, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), ) .unwrap() .sign(&mut OsRng, &Zeroizing::new(Scalar::ONE)) diff --git a/tests/processor/src/networks.rs b/tests/processor/src/networks.rs index 0dbfad69..2916315a 100644 --- a/tests/processor/src/networks.rs +++ b/tests/processor/src/networks.rs @@ -438,7 +438,8 @@ impl Wallet { use monero_simple_request_rpc::SimpleRequestRpc; use monero_wallet::{ rpc::Rpc, - monero::{Protocol, io::decompress_point}, + monero::io::decompress_point, + Protocol, address::{Network, AddressType, AddressMeta, Address}, SpendableOutput, DecoySelection, Decoys, Change, FeePriority, Scanner, SignableTransaction, @@ -492,7 +493,7 @@ impl Wallet { vec![(to_addr, AMOUNT)], &Change::new(view_pair, false), data, - rpc.get_fee_rate(Protocol::v16, FeePriority::Unimportant).await.unwrap(), + rpc.get_fee_rate(FeePriority::Unimportant).await.unwrap(), ) .unwrap() .sign(&mut OsRng, spend_key)