Call flush_key

This commit is contained in:
Luke Parker
2024-08-29 16:27:00 -04:00
parent 8db76ed67c
commit 4f6d91037e
4 changed files with 68 additions and 23 deletions

View File

@@ -11,7 +11,8 @@ use serai_coins_primitives::OutInstructionWithBalance;
use primitives::{EncodableG, Address, ReceivedOutput}; use primitives::{EncodableG, Address, ReceivedOutput};
use crate::{ use crate::{
lifetime::LifetimeStage, ScannerFeed, KeyFor, AddressFor, OutputFor, Return, lifetime::{LifetimeStage, Lifetime},
ScannerFeed, KeyFor, AddressFor, OutputFor, Return,
scan::next_to_scan_for_outputs_block, scan::next_to_scan_for_outputs_block,
}; };
@@ -30,6 +31,7 @@ pub(crate) struct SeraiKey<K> {
pub(crate) stage: LifetimeStage, pub(crate) stage: LifetimeStage,
pub(crate) activation_block_number: u64, pub(crate) activation_block_number: u64,
pub(crate) block_at_which_reporting_starts: u64, pub(crate) block_at_which_reporting_starts: u64,
pub(crate) block_at_which_forwarding_starts: Option<u64>,
} }
pub(crate) struct OutputWithInInstruction<S: ScannerFeed> { pub(crate) struct OutputWithInInstruction<S: ScannerFeed> {
@@ -82,7 +84,7 @@ create_db!(
/* /*
A block is notable if one of three conditions are met: A block is notable if one of three conditions are met:
1) We activated a key within this block. 1) We activated a key within this block (or explicitly forward to an activated key).
2) We retired a key within this block. 2) We retired a key within this block.
3) We received outputs within this block. 3) We received outputs within this block.
@@ -120,9 +122,32 @@ impl<S: ScannerFeed> ScannerGlobalDb<S> {
// TODO: Panic if we've ever seen this key before // TODO: Panic if we've ever seen this key before
// Push the key // Fetch the existing keys
let mut keys: Vec<SeraiKeyDbEntry<EncodableG<KeyFor<S>>>> = let mut keys: Vec<SeraiKeyDbEntry<EncodableG<KeyFor<S>>>> =
ActiveKeys::get(txn).unwrap_or(vec![]); ActiveKeys::get(txn).unwrap_or(vec![]);
// If this new key retires a key, mark the block at which forwarding explicitly occurs notable
// This lets us obtain synchrony over the transactions we'll make to accomplish this
if let Some(key_retired_by_this) = keys.last() {
NotableBlock::set(
txn,
Lifetime::calculate::<S>(
// The 'current block number' used for this calculation
activation_block_number,
// The activation block of the key we're getting the lifetime of
key_retired_by_this.activation_block_number,
// The activation block of the key which will retire this key
Some(activation_block_number),
)
.block_at_which_forwarding_starts
.expect(
"didn't calculate the block forwarding starts at despite passing the next key's info",
),
&(),
);
}
// Push and save the next key
keys.push(SeraiKeyDbEntry { activation_block_number, key: EncodableG(key) }); keys.push(SeraiKeyDbEntry { activation_block_number, key: EncodableG(key) });
ActiveKeys::set(txn, &keys); ActiveKeys::set(txn, &keys);
} }
@@ -185,8 +210,8 @@ impl<S: ScannerFeed> ScannerGlobalDb<S> {
if block_number < raw_keys[i].activation_block_number { if block_number < raw_keys[i].activation_block_number {
continue; continue;
} }
let (stage, block_at_which_reporting_starts) = let Lifetime { stage, block_at_which_reporting_starts, block_at_which_forwarding_starts } =
LifetimeStage::calculate_stage_and_reporting_start_block::<S>( Lifetime::calculate::<S>(
block_number, block_number,
raw_keys[i].activation_block_number, raw_keys[i].activation_block_number,
raw_keys.get(i + 1).map(|key| key.activation_block_number), raw_keys.get(i + 1).map(|key| key.activation_block_number),
@@ -196,6 +221,7 @@ impl<S: ScannerFeed> ScannerGlobalDb<S> {
stage, stage,
activation_block_number: raw_keys[i].activation_block_number, activation_block_number: raw_keys[i].activation_block_number,
block_at_which_reporting_starts, block_at_which_reporting_starts,
block_at_which_forwarding_starts,
}); });
} }
assert!(keys.len() <= 2, "more than two keys active"); assert!(keys.len() <= 2, "more than two keys active");

View File

@@ -341,8 +341,15 @@ impl<D: Db, S: ScannerFeed, Sch: Scheduler<S>> ContinuallyRan for EventualityTas
intake_eventualities::<S>(&mut txn, new_eventualities); intake_eventualities::<S>(&mut txn, new_eventualities);
} }
// Now that we've intaked any Eventualities caused, check if we're retiring any keys
for key in &keys { for key in &keys {
// If this is the block at which forwarding starts for this key, flush it
// We do this after we issue the above update for any efficiencies gained by doing so
if key.block_at_which_forwarding_starts == Some(b) {
assert!(key.key != keys.last().unwrap().key);
self.scheduler.flush_key(&mut txn, key.key, keys.last().unwrap().key);
}
// Now that we've intaked any Eventualities caused, check if we're retiring any keys
if key.stage == LifetimeStage::Finishing { if key.stage == LifetimeStage::Finishing {
let eventualities = EventualityDb::<S>::eventualities(&txn, key.key); let eventualities = EventualityDb::<S>::eventualities(&txn, key.key);
// TODO: This assumes the Scheduler is empty // TODO: This assumes the Scheduler is empty

View File

@@ -35,17 +35,25 @@ pub(crate) enum LifetimeStage {
Finishing, Finishing,
} }
impl LifetimeStage { /// The lifetime of the multisig, including various block numbers.
/// Get the stage of its lifetime this multisig is in, and the block at which we start reporting pub(crate) struct Lifetime {
/// outputs to it. pub(crate) stage: LifetimeStage,
pub(crate) block_at_which_reporting_starts: u64,
// This is only Some if the next key's activation block number is passed to calculate, and the
// stage is at least `LifetimeStage::Active.`
pub(crate) block_at_which_forwarding_starts: Option<u64>,
}
impl Lifetime {
/// Get the lifetime of this multisig.
/// ///
/// Panics if the multisig being calculated for isn't actually active and a variety of other /// Panics if the multisig being calculated for isn't actually active and a variety of other
/// insane cases. /// insane cases.
pub(crate) fn calculate_stage_and_reporting_start_block<S: ScannerFeed>( pub(crate) fn calculate<S: ScannerFeed>(
block_number: u64, block_number: u64,
activation_block_number: u64, activation_block_number: u64,
next_keys_activation_block_number: Option<u64>, next_keys_activation_block_number: Option<u64>,
) -> (Self, u64) { ) -> Self {
assert!( assert!(
activation_block_number >= block_number, activation_block_number >= block_number,
"calculating lifetime stage for an inactive multisig" "calculating lifetime stage for an inactive multisig"
@@ -55,14 +63,14 @@ impl LifetimeStage {
let active_yet_not_reporting_end_block = let active_yet_not_reporting_end_block =
activation_block_number + S::CONFIRMATIONS + S::TEN_MINUTES; activation_block_number + S::CONFIRMATIONS + S::TEN_MINUTES;
// The exclusive end block is the inclusive start block // The exclusive end block is the inclusive start block
let reporting_start_block = active_yet_not_reporting_end_block; let block_at_which_reporting_starts = active_yet_not_reporting_end_block;
if block_number < active_yet_not_reporting_end_block { if block_number < active_yet_not_reporting_end_block {
return (LifetimeStage::ActiveYetNotReporting, reporting_start_block); return Lifetime { stage: LifetimeStage::ActiveYetNotReporting, block_at_which_reporting_starts, block_at_which_forwarding_starts: None };
} }
let Some(next_keys_activation_block_number) = next_keys_activation_block_number else { let Some(next_keys_activation_block_number) = next_keys_activation_block_number else {
// If there is no next multisig, this is the active multisig // If there is no next multisig, this is the active multisig
return (LifetimeStage::Active, reporting_start_block); return Lifetime { stage: LifetimeStage::Active, block_at_which_reporting_starts, block_at_which_forwarding_starts: None };
}; };
assert!( assert!(
@@ -70,19 +78,22 @@ impl LifetimeStage {
"next set of keys activated before this multisig activated" "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 = let new_active_yet_not_reporting_end_block =
next_keys_activation_block_number + S::CONFIRMATIONS + S::TEN_MINUTES; next_keys_activation_block_number + S::CONFIRMATIONS + S::TEN_MINUTES;
let new_active_and_used_for_change_end_block =
new_active_yet_not_reporting_end_block + S::CONFIRMATIONS;
// The exclusive end block is the inclusive start block
let block_at_which_forwarding_starts = Some(new_active_and_used_for_change_end_block);
// If the new multisig is still having its activation block finalized on-chain, this multisig
// is still active (step 3)
if block_number < new_active_yet_not_reporting_end_block { if block_number < new_active_yet_not_reporting_end_block {
return (LifetimeStage::Active, reporting_start_block); return Lifetime { stage: LifetimeStage::Active, block_at_which_reporting_starts, block_at_which_forwarding_starts };
} }
// Step 4 details a further CONFIRMATIONS // 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 { if block_number < new_active_and_used_for_change_end_block {
return (LifetimeStage::UsingNewForChange, reporting_start_block); return Lifetime { stage: LifetimeStage::UsingNewForChange, block_at_which_reporting_starts, block_at_which_forwarding_starts };
} }
// Step 5 details a further 6 hours // Step 5 details a further 6 hours
@@ -90,10 +101,10 @@ impl LifetimeStage {
let new_active_and_forwarded_to_end_block = let new_active_and_forwarded_to_end_block =
new_active_and_used_for_change_end_block + (6 * 6 * S::TEN_MINUTES); new_active_and_used_for_change_end_block + (6 * 6 * S::TEN_MINUTES);
if block_number < new_active_and_forwarded_to_end_block { if block_number < new_active_and_forwarded_to_end_block {
return (LifetimeStage::Forwarding, reporting_start_block); return Lifetime { stage: LifetimeStage::Forwarding, block_at_which_reporting_starts, block_at_which_forwarding_starts };
} }
// Step 6 // Step 6
(LifetimeStage::Finishing, reporting_start_block) Lifetime { stage: LifetimeStage::Finishing, block_at_which_reporting_starts, block_at_which_forwarding_starts }
} }
} }

View File

@@ -102,7 +102,8 @@ The following timeline is established:
5) For the next 6 hours, all non-`Branch` outputs received are immediately 5) For the next 6 hours, all non-`Branch` outputs received are immediately
forwarded to the new multisig. Only external transactions to the new multisig forwarded to the new multisig. Only external transactions to the new multisig
are included in `Batch`s. are included in `Batch`s. Any outputs not yet transferred as change are
explicitly transferred.
The new multisig infers the `InInstruction`, and refund address, for The new multisig infers the `InInstruction`, and refund address, for
forwarded `External` outputs via reading what they were for the original forwarded `External` outputs via reading what they were for the original