Move Protocol to monero-wallet

This commit is contained in:
Luke Parker
2024-06-21 14:14:15 -04:00
parent 6f61861d4b
commit b5b9d4a871
14 changed files with 233 additions and 253 deletions

View File

@@ -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<R: io::Read>(reader: &mut R) -> io::Result<u64> {
Ok(vi)
}
async fn get_fee_rate_v14(rpc: &impl Rpc, priority: FeePriority) -> Result<FeeRate, RpcError> {
#[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<Protocol, RpcError> {
///
/// This is specifically the major version within the most recent block header.
async fn get_protocol(&self) -> Result<u8, RpcError> {
#[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::<LastHeaderResponse>("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<FeeRate, RpcError> {
// 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<u64>,
quantization_mask: u64,
}
async fn get_fee_rate(&self, priority: FeePriority) -> Result<FeeRate, RpcError> {
#[derive(Deserialize, Debug)]
struct FeeResponse {
status: String,
fees: Option<Vec<u64>>,
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)
}
}

View File

@@ -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<W: stdio::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: stdio::Read>(r: &mut R) -> stdio::Result<Protocol> {
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"))?,
})
}
}

View File

@@ -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<W: 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<W: Write>(&self, w: &mut W) -> io::Result<()> {

View File

@@ -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<W: Write>(&self, w: &mut W) -> io::Result<()> {

View File

@@ -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<u8> for Protocol {
type Error = ();
fn try_from(version: u8) -> Result<Self, ()> {
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<W: io::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: io::Read>(r: &mut R) -> io::Result<Protocol> {
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()
}

View File

@@ -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,
};

View File

@@ -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);

View File

@@ -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,
};

View File

@@ -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,

View File

@@ -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;

View File

@@ -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();

View File

@@ -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::<Vec<_>>();
@@ -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))

View File

@@ -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))

View File

@@ -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)