Handle Monero fee logic properly in the processor

This commit is contained in:
Luke Parker
2024-07-06 18:46:41 -04:00
parent 6357bc0ed4
commit 9f7dbf2132
3 changed files with 53 additions and 27 deletions

View File

@@ -181,7 +181,7 @@ async fn select_decoys<R: RngCore + CryptoRng>(
// TODO: Create a TX with less than the target amount, as allowed by the protocol // TODO: Create a TX with less than the target amount, as allowed by the protocol
let high = distribution[distribution.len() - DEFAULT_LOCK_WINDOW]; let high = distribution[distribution.len() - DEFAULT_LOCK_WINDOW];
if high.saturating_sub(COINBASE_LOCK_WINDOW as u64) < if high.saturating_sub(u64::try_from(COINBASE_LOCK_WINDOW).unwrap()) <
u64::try_from(inputs.len() * ring_len).unwrap() u64::try_from(inputs.len() * ring_len).unwrap()
{ {
Err(RpcError::InternalError("not enough coinbase candidates".to_string()))?; Err(RpcError::InternalError("not enough coinbase candidates".to_string()))?;

View File

@@ -137,8 +137,8 @@ pub async fn rpc() -> SimpleRequestRpc {
&Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE, &Scalar::random(&mut OsRng) * ED25519_BASEPOINT_TABLE,
); );
// Mine 40 blocks to ensure decoy availability // Mine 80 blocks to ensure decoy availability
rpc.generate_blocks(&addr, 40).await.unwrap(); rpc.generate_blocks(&addr, 80).await.unwrap();
rpc rpc
} }

View File

@@ -244,6 +244,11 @@ fn map_rpc_err(err: RpcError) -> NetworkError {
NetworkError::ConnectionError NetworkError::ConnectionError
} }
enum MakeSignableTransactionResult {
Fee(u64),
SignableTransaction(MSignableTransaction),
}
impl Monero { impl Monero {
pub async fn new(url: String) -> Monero { pub async fn new(url: String) -> Monero {
let mut res = SimpleRequestRpc::new(url.clone()).await; let mut res = SimpleRequestRpc::new(url.clone()).await;
@@ -299,7 +304,7 @@ impl Monero {
payments: &[Payment<Self>], payments: &[Payment<Self>],
change: &Option<Address>, change: &Option<Address>,
calculating_fee: bool, calculating_fee: bool,
) -> Result<Option<MSignableTransaction>, NetworkError> { ) -> Result<Option<MakeSignableTransactionResult>, NetworkError> {
for payment in payments { for payment in payments {
assert_eq!(payment.balance.coin, Coin::Monero); assert_eq!(payment.balance.coin, Coin::Monero);
} }
@@ -362,11 +367,7 @@ impl Monero {
let payments = payments let payments = payments
.into_iter() .into_iter()
// If we're solely estimating the fee, don't actually specify an amount .map(|payment| (payment.address.into(), payment.balance.amount.0))
// This won't affect the fee calculation yet will ensure we don't hit an out of funds error
.map(|payment| {
(payment.address.into(), if calculating_fee { 0 } else { payment.balance.amount.0 })
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
match MSignableTransaction::new( match MSignableTransaction::new(
@@ -379,7 +380,13 @@ impl Monero {
vec![], vec![],
fee_rate, fee_rate,
) { ) {
Ok(signable) => Ok(Some(signable)), Ok(signable) => Ok(Some({
if calculating_fee {
MakeSignableTransactionResult::Fee(signable.fee())
} else {
MakeSignableTransactionResult::SignableTransaction(signable)
}
})),
Err(e) => match e { Err(e) => match e {
SendError::UnsupportedRctType => { SendError::UnsupportedRctType => {
panic!("trying to use an RctType unsupported by monero-wallet") panic!("trying to use an RctType unsupported by monero-wallet")
@@ -403,8 +410,24 @@ impl Monero {
inputs, inputs,
outputs outputs
); );
match fee {
Some(fee) => {
// If we're solely calculating the fee, return the fee this TX will cost
if calculating_fee {
Ok(Some(MakeSignableTransactionResult::Fee(fee)))
} else {
// If we're actually trying to make the TX, return None
Ok(None) Ok(None)
} }
}
// We didn't have enough funds to even cover the outputs
None => {
// Ensure we're not misinterpreting this
assert!(outputs > inputs);
Ok(None)
}
}
}
SendError::MaliciousSerialization | SendError::ClsagError(_) | SendError::FrostError(_) => { SendError::MaliciousSerialization | SendError::ClsagError(_) | SendError::FrostError(_) => {
panic!("supposedly unreachable (at this time) Monero error: {e}"); panic!("supposedly unreachable (at this time) Monero error: {e}");
} }
@@ -594,12 +617,14 @@ impl Network for Monero {
payments: &[Payment<Self>], payments: &[Payment<Self>],
change: &Option<Address>, change: &Option<Address>,
) -> Result<Option<u64>, NetworkError> { ) -> Result<Option<u64>, NetworkError> {
Ok( let res = self
self
.make_signable_transaction(block_number, &[0; 32], inputs, payments, change, true) .make_signable_transaction(block_number, &[0; 32], inputs, payments, change, true)
.await? .await?;
.map(|signable| signable.fee()), let Some(res) = res else { return Ok(None) };
) let MakeSignableTransactionResult::Fee(fee) = res else {
panic!("told make_signable_transaction calculating_fee and got transaction")
};
Ok(Some(fee))
} }
async fn signable_transaction( async fn signable_transaction(
@@ -612,16 +637,17 @@ impl Network for Monero {
change: &Option<Address>, change: &Option<Address>,
(): &(), (): &(),
) -> Result<Option<(Self::SignableTransaction, Self::Eventuality)>, NetworkError> { ) -> Result<Option<(Self::SignableTransaction, Self::Eventuality)>, NetworkError> {
Ok( let res = self
self
.make_signable_transaction(block_number, plan_id, inputs, payments, change, false) .make_signable_transaction(block_number, plan_id, inputs, payments, change, false)
.await? .await?;
.map(|signable| { let Some(res) = res else { return Ok(None) };
let MakeSignableTransactionResult::SignableTransaction(signable) = res else {
panic!("told make_signable_transaction not calculating_fee and got fee")
};
let signable = SignableTransaction(signable); let signable = SignableTransaction(signable);
let eventuality = signable.0.clone().into(); let eventuality = signable.0.clone().into();
(signable, eventuality) Ok(Some((signable, eventuality)))
}),
)
} }
async fn attempt_sign( async fn attempt_sign(