mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 12:19:24 +00:00
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.
97 lines
3.7 KiB
Rust
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
|
|
}
|
|
}
|