Correct misc compilation errors

This commit is contained in:
Luke Parker 2024-08-20 16:39:03 -04:00
parent a2717d73f0
commit 2b47feafed
5 changed files with 70 additions and 27 deletions

View file

@ -13,9 +13,9 @@ impl<T: BorshSerialize + BorshDeserialize> Borshy for T {}
#[derive(BorshSerialize, BorshDeserialize)] #[derive(BorshSerialize, BorshDeserialize)]
pub(crate) struct SeraiKey<K: Borshy> { pub(crate) struct SeraiKey<K: Borshy> {
activation_block_number: u64, pub(crate) activation_block_number: u64,
retirement_block_number: Option<u64>, pub(crate) retirement_block_number: Option<u64>,
key: K, pub(crate) key: K,
} }
create_db!( create_db!(
@ -208,7 +208,7 @@ impl<S: ScannerFeed> ScannerDb<S> {
SerializedOutputs::set(txn, block_number, &buf); SerializedOutputs::set(txn, block_number, &buf);
} }
pub(crate) fn is_notable_block(getter: &impl Get, number: u64) -> bool { pub(crate) fn is_block_notable(getter: &impl Get, number: u64) -> bool {
NotableBlock::get(getter, number).is_some() NotableBlock::get(getter, number).is_some()
} }
} }

View file

@ -6,12 +6,21 @@ use primitives::{ReceivedOutput, Block};
mod db; mod db;
mod index; mod index;
mod scan;
mod eventuality;
mod report;
mod safe;
/// A feed usable to scan a blockchain. /// A feed usable to scan a blockchain.
/// ///
/// This defines the primitive types used, along with various getters necessary for indexing. /// This defines the primitive types used, along with various getters necessary for indexing.
#[async_trait::async_trait] #[async_trait::async_trait]
pub trait ScannerFeed: Send + Sync { pub trait ScannerFeed: Send + Sync {
/// The amount of confirmations required for a block to be finalized.
///
/// This value must be at least `1`.
const CONFIRMATIONS: u64;
/// The type of the key used to receive coins on this blockchain. /// The type of the key used to receive coins on this blockchain.
type Key: group::Group + group::GroupEncoding; type Key: group::Group + group::GroupEncoding;
@ -35,11 +44,19 @@ pub trait ScannerFeed: Send + Sync {
/// resolve without manual intervention. /// resolve without manual intervention.
type EphemeralError: Debug; type EphemeralError: Debug;
/// Fetch the number of the latest block.
///
/// The block number is its zero-indexed position within a linear view of the external network's
/// consensus. The genesis block accordingly has block number 0.
async fn latest_block_number(&self) -> Result<u64, Self::EphemeralError>;
/// Fetch the number of the latest finalized block. /// Fetch the number of the latest finalized block.
/// ///
/// The block number is its zero-indexed position within a linear view of the external network's /// The block number is its zero-indexed position within a linear view of the external network's
/// consensus. The genesis block accordingly has block number 0. /// consensus. The genesis block accordingly has block number 0.
async fn latest_finalized_block_number(&self) -> Result<u64, Self::EphemeralError>; async fn latest_finalized_block_number(&self) -> Result<u64, Self::EphemeralError> {
Ok(self.latest_block_number().await? - Self::CONFIRMATIONS)
}
/// Fetch a block by its number. /// Fetch a block by its number.
async fn block_by_number(&self, number: u64) -> Result<Self::Block, Self::EphemeralError>; async fn block_by_number(&self, number: u64) -> Result<Self::Block, Self::EphemeralError>;
@ -49,7 +66,7 @@ pub trait ScannerFeed: Send + Sync {
&self, &self,
block: &Self::Block, block: &Self::Block,
key: Self::Key, key: Self::Key,
) -> Result<Self::Output, Self::EphemeralError>; ) -> Result<Vec<Self::Output>, Self::EphemeralError>;
} }
/// A handle to immediately run an iteration of a task. /// A handle to immediately run an iteration of a task.

View file

@ -8,7 +8,7 @@ use serai_db::{Db, DbTxn};
use primitives::{Id, Block}; use primitives::{Id, Block};
// TODO: Localize to ReportDb? // TODO: Localize to ReportDb?
use crate::{db::ScannerDb, ScannerFeed}; use crate::{db::ScannerDb, ScannerFeed, ContinuallyRan};
struct ReportTask<D: Db, S: ScannerFeed> { struct ReportTask<D: Db, S: ScannerFeed> {
db: D, db: D,
@ -20,8 +20,10 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for ReportTask<D, S> {
async fn run_iteration(&mut self) -> Result<bool, String> { async fn run_iteration(&mut self) -> Result<bool, String> {
let highest_reportable = { let highest_reportable = {
// Fetch the latest scanned and latest checked block // Fetch the latest scanned and latest checked block
let next_to_scan = ScannerDb::<S>::next_to_scan_for_outputs_block(&self.db).expect("ReportTask run before writing the start block"); let next_to_scan = ScannerDb::<S>::next_to_scan_for_outputs_block(&self.db)
let next_to_check = ScannerDb::<S>::next_to_check_for_eventualities_block(&self.db).expect("ReportTask run before writing the start block"); .expect("ReportTask run before writing the start block");
let next_to_check = ScannerDb::<S>::next_to_check_for_eventualities_block(&self.db)
.expect("ReportTask run before writing the start block");
// If we haven't done any work, return // If we haven't done any work, return
if (next_to_scan == 0) || (next_to_check == 0) { if (next_to_scan == 0) || (next_to_check == 0) {
return Ok(false); return Ok(false);
@ -31,10 +33,11 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for ReportTask<D, S> {
last_scanned.min(last_checked) last_scanned.min(last_checked)
}; };
let next_to_potentially_report = ScannerDb::<S>::next_block_to_potentially_report(&self.db).expect("ReportTask run before writing the start block"); let next_to_potentially_report = ScannerDb::<S>::next_to_potentially_report_block(&self.db)
.expect("ReportTask run before writing the start block");
for b in next_to_potentially_report ..= highest_reportable { for b in next_to_potentially_report ..= highest_reportable {
if ScannerDb::<S>::is_block_notable(b) { if ScannerDb::<S>::is_block_notable(&self.db, b) {
todo!("TODO: Make Batches, which requires handling Forwarded within this crate"); todo!("TODO: Make Batches, which requires handling Forwarded within this crate");
} }

View file

@ -5,7 +5,7 @@ use serai_db::{Db, DbTxn};
use primitives::{Id, Block}; use primitives::{Id, Block};
// TODO: Localize to SafeDb? // TODO: Localize to SafeDb?
use crate::{db::ScannerDb, ScannerFeed}; use crate::{db::ScannerDb, ScannerFeed, ContinuallyRan};
/* /*
We mark blocks safe to scan when they're no more than `(CONFIRMATIONS - 1)` blocks after the We mark blocks safe to scan when they're no more than `(CONFIRMATIONS - 1)` blocks after the
@ -27,7 +27,8 @@ struct SafeToScanTask<D: Db, S: ScannerFeed> {
impl<D: Db, S: ScannerFeed> ContinuallyRan for SafeToScanTask<D, S> { impl<D: Db, S: ScannerFeed> ContinuallyRan for SafeToScanTask<D, S> {
async fn run_iteration(&mut self) -> Result<bool, String> { async fn run_iteration(&mut self) -> Result<bool, String> {
// First, we fetch the highest acknowledged block // First, we fetch the highest acknowledged block
let Some(highest_acknowledged_block) = ScannerDb::<S>::highest_acknowledged_block(&self.db) else { let Some(highest_acknowledged_block) = ScannerDb::<S>::highest_acknowledged_block(&self.db)
else {
// If no blocks have been acknowledged, we don't mark any safe // If no blocks have been acknowledged, we don't mark any safe
// Once the start block (implicitly safe) has been acknowledged, we proceed from there // Once the start block (implicitly safe) has been acknowledged, we proceed from there
return Ok(false); return Ok(false);
@ -38,13 +39,15 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for SafeToScanTask<D, S> {
// If we've decided to report (or not report) a block, we know if it needs acknowledgement // If we've decided to report (or not report) a block, we know if it needs acknowledgement
// (and accordingly is pending acknowledgement) // (and accordingly is pending acknowledgement)
// Accordingly, the block immediately before this is the latest block with a known status // Accordingly, the block immediately before this is the latest block with a known status
ScannerDb::<S>::next_block_to_potentially_report(&self.db).expect("SafeToScanTask run before writing the start block") - 1 ScannerDb::<S>::next_to_potentially_report_block(&self.db)
.expect("SafeToScanTask run before writing the start block") -
1
}; };
let mut oldest_pending_acknowledgement = None; let mut oldest_pending_acknowledgement = None;
for b in (highest_acknowledged_block + 1) ..= latest_block_known_if_pending_acknowledgement { for b in (highest_acknowledged_block + 1) ..= latest_block_known_if_pending_acknowledgement {
// If the block isn't notable, immediately flag it as acknowledged // If the block isn't notable, immediately flag it as acknowledged
if !ScannerDb::<S>::is_block_notable(b) { if !ScannerDb::<S>::is_block_notable(&self.db, b) {
let mut txn = self.db.txn(); let mut txn = self.db.txn();
ScannerDb::<S>::set_highest_acknowledged_block(&mut txn, b); ScannerDb::<S>::set_highest_acknowledged_block(&mut txn, b);
txn.commit(); txn.commit();
@ -61,13 +64,19 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for SafeToScanTask<D, S> {
// acknowledgement, and the oldest block still pending acknowledgement is in the future, // acknowledgement, and the oldest block still pending acknowledgement is in the future,
// we know the safe block to scan to is // we know the safe block to scan to is
// `>= latest_block_known_if_pending_acknowledgement + (CONFIRMATIONS - 1)` // `>= latest_block_known_if_pending_acknowledgement + (CONFIRMATIONS - 1)`
let oldest_pending_acknowledgement = oldest_pending_acknowledgement.unwrap_or(latest_block_known_if_pending_acknowledgement); let oldest_pending_acknowledgement =
oldest_pending_acknowledgement.unwrap_or(latest_block_known_if_pending_acknowledgement);
let old_safe_block = ScannerDb::<S>::latest_scannable_block(&self.db)
.expect("SafeToScanTask run before writing the start block");
let new_safe_block = oldest_pending_acknowledgement +
(S::CONFIRMATIONS.checked_sub(1).expect("CONFIRMATIONS wasn't at least 1"));
// Update the latest scannable block // Update the latest scannable block
let mut txn = self.db.txn(); let mut txn = self.db.txn();
ScannerDb::<S>::set_latest_scannable_block(oldest_pending_acknowledgement + (CONFIRMATIONS - 1)); ScannerDb::<S>::set_latest_scannable_block(&mut txn, new_safe_block);
txn.commit(); txn.commit();
Ok(next_to_potentially_report <= highest_reportable) Ok(old_safe_block != new_safe_block)
} }
} }

View file

@ -1,9 +1,9 @@
use serai_db::{Db, DbTxn}; use serai_db::{Db, DbTxn};
use primitives::{Id, Block}; use primitives::{Id, ReceivedOutput, Block};
// TODO: Localize to ScanDb? // TODO: Localize to ScanDb?
use crate::{db::ScannerDb, ScannerFeed}; use crate::{db::ScannerDb, ScannerFeed, ContinuallyRan};
struct ScanForOutputsTask<D: Db, S: ScannerFeed> { struct ScanForOutputsTask<D: Db, S: ScannerFeed> {
db: D, db: D,
@ -14,9 +14,11 @@ struct ScanForOutputsTask<D: Db, S: ScannerFeed> {
impl<D: Db, S: ScannerFeed> ContinuallyRan for ScanForOutputsTask<D, S> { impl<D: Db, S: ScannerFeed> ContinuallyRan for ScanForOutputsTask<D, S> {
async fn run_iteration(&mut self) -> Result<bool, String> { async fn run_iteration(&mut self) -> Result<bool, String> {
// Fetch the safe to scan block // Fetch the safe to scan block
let latest_scannable = ScannerDb::<S>::latest_scannable_block(&self.db).expect("ScanForOutputsTask run before writing the start block"); let latest_scannable = ScannerDb::<S>::latest_scannable_block(&self.db)
.expect("ScanForOutputsTask run before writing the start block");
// Fetch the next block to scan // Fetch the next block to scan
let next_to_scan = ScannerDb::<S>::next_to_scan_for_outputs_block(&self.db).expect("ScanForOutputsTask run before writing the start block"); let next_to_scan = ScannerDb::<S>::next_to_scan_for_outputs_block(&self.db)
.expect("ScanForOutputsTask run before writing the start block");
for b in next_to_scan ..= latest_scannable { for b in next_to_scan ..= latest_scannable {
let block = match self.feed.block_by_number(b).await { let block = match self.feed.block_by_number(b).await {
@ -26,15 +28,22 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for ScanForOutputsTask<D, S> {
// Check the ID of this block is the expected ID // Check the ID of this block is the expected ID
{ {
let expected = ScannerDb::<S>::block_id(b).expect("scannable block didn't have its ID saved"); let expected =
ScannerDb::<S>::block_id(&self.db, b).expect("scannable block didn't have its ID saved");
if block.id() != expected { if block.id() != expected {
panic!("finalized chain reorganized from {} to {} at {}", hex::encode(expected), hex::encode(block.id()), b); panic!(
"finalized chain reorganized from {} to {} at {}",
hex::encode(expected),
hex::encode(block.id()),
b
);
} }
} }
log::info!("scanning block: {} ({b})", hex::encode(block.id())); log::info!("scanning block: {} ({b})", hex::encode(block.id()));
let keys = ScannerDb::<S>::keys(&self.db).expect("scanning for a blockchain without any keys set"); let mut keys =
ScannerDb::<S>::keys(&self.db).expect("scanning for a blockchain without any keys set");
// Remove all the retired keys // Remove all the retired keys
while let Some(retire_at) = keys[0].retirement_block_number { while let Some(retire_at) = keys[0].retirement_block_number {
if retire_at <= b { if retire_at <= b {
@ -51,8 +60,13 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for ScanForOutputsTask<D, S> {
continue; continue;
} }
for output in network.scan_for_outputs(&block, key).awaits { for output in self
assert_eq!(output.key(), key); .feed
.scan_for_outputs(&block, key.key.0)
.await
.map_err(|e| format!("failed to scan block {b}: {e:?}"))?
{
assert_eq!(output.key(), key.key.0);
// TODO: Check for dust // TODO: Check for dust
outputs.push(output); outputs.push(output);
} }