Files
serai/processor/scanner/src/lifetime.rs
Luke Parker bc0cc5a754 Decide flow between scan/eventuality/report
Scan now only handles External outputs, with an associated essay going over
why. Scan directly creates the InInstruction (prior planned to be done in
Report), and Eventuality is declared to end up yielding the outputs.

That will require making the Eventuality flow two-stage. One stage to evaluate
existing Eventualities and yield outputs, and one stage to incorporate new
Eventualities before advancing the scan window.
2024-09-19 23:36:32 -07:00

97 lines
3.7 KiB
Rust

use crate::ScannerFeed;
/// An enum representing the stage of a multisig within its lifetime.
///
/// This corresponds to `spec/processor/Multisig Rotation.md`, which details steps 1-8 of the
/// rotation process. Steps 7-8 regard a multisig which isn't retiring yet retired, and
/// accordingly, no longer exists, so they are not modelled here (as this only models active
/// multisigs. Inactive multisigs aren't represented in the first place).
pub(crate) enum LifetimeStage {
/// A new multisig, once active, shouldn't actually start receiving coins until several blocks
/// later. If any UI is premature in sending to this multisig, we delay to report the outputs to
/// prevent some DoS concerns.
///
/// This represents steps 1-3 for a new multisig.
ActiveYetNotReporting,
/// Active with all outputs being reported on-chain.
///
/// This represents step 4 onwards for a new multisig.
Active,
/// Retiring with all outputs being reported on-chain.
///
/// This represents step 4 for a retiring multisig.
UsingNewForChange,
/// Retiring with outputs being forwarded, reported on-chain once forwarded.
///
/// This represents step 5 for a retiring multisig.
Forwarding,
/// Retiring with only existing obligations being handled.
///
/// This represents step 6 for a retiring multisig.
///
/// Steps 7 and 8 are represented by the retiring multisig no longer existing, and these states
/// are only for multisigs which actively exist.
Finishing,
}
impl LifetimeStage {
/// Get the stage of its lifetime this multisig is in based on when the next multisig's key
/// activates.
///
/// Panics if the multisig being calculated for isn't actually active and a variety of other
/// insane cases.
pub(crate) fn calculate<S: ScannerFeed>(
block_number: u64,
activation_block_number: u64,
next_keys_activation_block_number: Option<u64>,
) -> Self {
assert!(
activation_block_number >= block_number,
"calculating lifetime stage for an inactive multisig"
);
// This is exclusive, not inclusive, since we want a CONFIRMATIONS + 10 minutes window and the
// activation block itself is the first block within this window
let active_yet_not_reporting_end_block =
activation_block_number + S::CONFIRMATIONS + S::TEN_MINUTES;
if block_number < active_yet_not_reporting_end_block {
return LifetimeStage::ActiveYetNotReporting;
}
let Some(next_keys_activation_block_number) = next_keys_activation_block_number else {
// If there is no next multisig, this is the active multisig
return LifetimeStage::Active;
};
assert!(
next_keys_activation_block_number > active_yet_not_reporting_end_block,
"next set of keys activated before this multisig activated"
);
// If the new multisig is still having its activation block finalized on-chain, this multisig
// is still active (step 3)
let new_active_yet_not_reporting_end_block =
next_keys_activation_block_number + S::CONFIRMATIONS + S::TEN_MINUTES;
if block_number < new_active_yet_not_reporting_end_block {
return LifetimeStage::Active;
}
// Step 4 details a further CONFIRMATIONS
let new_active_and_used_for_change_end_block =
new_active_yet_not_reporting_end_block + S::CONFIRMATIONS;
if block_number < new_active_and_used_for_change_end_block {
return LifetimeStage::UsingNewForChange;
}
// Step 5 details a further 6 hours
// 6 hours = 6 * 60 minutes = 6 * 6 * 10 minutes
let new_active_and_forwarded_to_end_block =
new_active_and_used_for_change_end_block + (6 * 6 * S::TEN_MINUTES);
if block_number < new_active_and_forwarded_to_end_block {
return LifetimeStage::Forwarding;
}
// Step 6
LifetimeStage::Finishing
}
}