Monero Planner

Finishes the Monero processor.
This commit is contained in:
Luke Parker
2024-09-14 04:24:48 -04:00
parent e23176deeb
commit 0616085109
13 changed files with 406 additions and 755 deletions

View File

@@ -4,7 +4,7 @@
use core::{fmt::Debug, future::Future};
use serai_primitives::{Coin, Amount};
use serai_primitives::Amount;
use primitives::{ReceivedOutput, Payment};
use scanner::{ScannerFeed, KeyFor, AddressFor, OutputFor, EventualityFor, BlockFor};
@@ -48,9 +48,6 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
/// resolve manual intervention/changing the arguments.
type EphemeralError: Debug;
/// The type representing a fee rate to use for transactions.
type FeeRate: Send + Clone + Copy;
/// The type representing a signable transaction.
type SignableTransaction: SignableTransaction;
@@ -59,11 +56,6 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
/// The maximum amount of outputs allowed in a transaction, including the change output.
const MAX_OUTPUTS: usize;
/// Obtain the fee rate to pay.
///
/// This must be constant to the block and coin.
fn fee_rate(block: &BlockFor<S>, coin: Coin) -> Self::FeeRate;
/// The branch address for this key of Serai's.
fn branch_address(key: KeyFor<S>) -> AddressFor<S>;
/// The change address for this key of Serai's.
@@ -76,11 +68,12 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
/// The fee rate, inputs, and payments, will all be for the same coin. The returned fee is
/// denominated in this coin.
fn calculate_fee(
fee_rate: Self::FeeRate,
&self,
reference_block: &BlockFor<S>,
inputs: Vec<OutputFor<S>>,
payments: Vec<Payment<AddressFor<S>>>,
change: Option<KeyFor<S>>,
) -> Amount;
) -> impl Send + Future<Output = Result<Amount, Self::EphemeralError>>;
/// Plan a transaction.
///
@@ -91,7 +84,7 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
/// output must be created.
fn plan(
&self,
fee_rate: Self::FeeRate,
reference_block: &BlockFor<S>,
inputs: Vec<OutputFor<S>>,
payments: Vec<Payment<AddressFor<S>>>,
change: Option<KeyFor<S>>,
@@ -112,7 +105,7 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
fn plan_transaction_with_fee_amortization(
&self,
operating_costs: &mut u64,
fee_rate: Self::FeeRate,
reference_block: &BlockFor<S>,
inputs: Vec<OutputFor<S>>,
mut payments: Vec<Payment<AddressFor<S>>>,
mut change: Option<KeyFor<S>>,
@@ -156,7 +149,8 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
// Sort payments from high amount to low amount
payments.sort_by(|a, b| a.balance().amount.0.cmp(&b.balance().amount.0).reverse());
let mut fee = Self::calculate_fee(fee_rate, inputs.clone(), payments.clone(), change).0;
let mut fee =
self.calculate_fee(reference_block, inputs.clone(), payments.clone(), change).await?.0;
let mut amortized = 0;
while !payments.is_empty() {
// We need to pay the fee, and any accrued operating costs, minus what we've already
@@ -176,7 +170,10 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
if payments.last().unwrap().balance().amount.0 <= (per_payment_fee + S::dust(coin).0) {
amortized += payments.pop().unwrap().balance().amount.0;
// Recalculate the fee and try again
fee = Self::calculate_fee(fee_rate, inputs.clone(), payments.clone(), change).0;
fee = self
.calculate_fee(reference_block, inputs.clone(), payments.clone(), change)
.await?
.0;
continue;
}
// Break since all of these payments shouldn't be dropped
@@ -237,7 +234,7 @@ pub trait TransactionPlanner<S: ScannerFeed, A>: 'static + Send + Sync {
let has_change = change.is_some();
let PlannedTransaction { signable, eventuality, auxilliary } =
self.plan(fee_rate, inputs, payments, change).await?;
self.plan(reference_block, inputs, payments, change).await?;
Ok(Some(AmortizePlannedTransaction {
effected_payments,
has_change,

View File

@@ -56,7 +56,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
.planner
.plan_transaction_with_fee_amortization(
&mut operating_costs,
P::fee_rate(block, coin),
block,
to_aggregate,
vec![],
Some(key_for_change),
@@ -176,7 +176,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
.plan_transaction_with_fee_amortization(
// Uses 0 as there's no operating costs to incur/amortize here
&mut 0,
P::fee_rate(block, coin),
block,
vec![output],
payments,
None,
@@ -254,7 +254,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
.planner
.plan_transaction_with_fee_amortization(
&mut operating_costs,
P::fee_rate(block, coin),
block,
outputs.clone(),
tree[0]
.payments::<S>(coin, &branch_address, tree[0].value())
@@ -327,7 +327,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> Scheduler<S, P> {
.planner
.plan_transaction_with_fee_amortization(
&mut operating_costs,
P::fee_rate(block, coin),
block,
outputs,
vec![],
Some(to),
@@ -487,7 +487,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
// This uses 0 for the operating costs as we don't incur any here
// If the output can't pay for itself to be forwarded, we simply drop it
&mut 0,
P::fee_rate(block, forward.balance().coin),
block,
vec![forward.clone()],
vec![Payment::new(P::forwarding_address(forward_to_key), forward.balance(), None)],
None,
@@ -508,7 +508,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, ()>> SchedulerTrait<S> for Schedul
// This uses 0 for the operating costs as we don't incur any here
// If the output can't pay for itself to be returned, we simply drop it
&mut 0,
P::fee_rate(block, out_instruction.balance().coin),
block,
vec![to_return.output().clone()],
vec![out_instruction],
None,

View File

@@ -86,7 +86,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
.planner
.plan_transaction_with_fee_amortization(
&mut operating_costs,
P::fee_rate(block, coin),
block,
to_aggregate,
vec![],
Some(key_for_change),
@@ -229,7 +229,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
.planner
.plan_transaction_with_fee_amortization(
&mut operating_costs,
P::fee_rate(block, coin),
block,
outputs.clone(),
tree[0]
.payments::<S>(coin, &branch_address, tree[0].value())
@@ -323,7 +323,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
.plan_transaction_with_fee_amortization(
// Uses 0 as there's no operating costs to incur/amortize here
&mut 0,
P::fee_rate(block, coin),
block,
vec![branch_output],
payments,
None,
@@ -379,7 +379,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
.planner
.plan_transaction_with_fee_amortization(
&mut operating_costs,
P::fee_rate(block, coin),
block,
outputs,
vec![],
Some(to),
@@ -505,7 +505,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
// This uses 0 for the operating costs as we don't incur any here
// If the output can't pay for itself to be forwarded, we simply drop it
&mut 0,
P::fee_rate(block, forward.balance().coin),
block,
vec![forward.clone()],
vec![Payment::new(P::forwarding_address(forward_to_key), forward.balance(), None)],
None,
@@ -526,7 +526,7 @@ impl<S: ScannerFeed, P: TransactionPlanner<S, EffectedReceivedOutputs<S>>> Sched
// This uses 0 for the operating costs as we don't incur any here
// If the output can't pay for itself to be returned, we simply drop it
&mut 0,
P::fee_rate(block, out_instruction.balance().coin),
block,
vec![to_return.output().clone()],
vec![out_instruction],
None,