mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-23 12:09:37 +00:00
Differentiate BlockHeader from Block
This commit is contained in:
parent
2b47feafed
commit
951872b026
5 changed files with 53 additions and 48 deletions
|
@ -5,7 +5,7 @@
|
|||
use core::fmt::Debug;
|
||||
use std::io;
|
||||
|
||||
use group::GroupEncoding;
|
||||
use group::{Group, GroupEncoding};
|
||||
|
||||
use serai_primitives::Balance;
|
||||
|
||||
|
@ -137,9 +137,8 @@ pub trait ReceivedOutput<K: GroupEncoding, A>:
|
|||
fn read<R: io::Read>(reader: &mut R) -> io::Result<Self>;
|
||||
}
|
||||
|
||||
/// A block from an external network.
|
||||
#[async_trait::async_trait]
|
||||
pub trait Block: Send + Sync + Sized + Clone + Debug {
|
||||
/// A block header from an external network.
|
||||
pub trait BlockHeader: Send + Sync + Sized + Clone + Debug {
|
||||
/// The type used to identify blocks.
|
||||
type Id: 'static + Id;
|
||||
/// The ID of this block.
|
||||
|
@ -148,6 +147,31 @@ pub trait Block: Send + Sync + Sized + Clone + Debug {
|
|||
fn parent(&self) -> Self::Id;
|
||||
}
|
||||
|
||||
/// A block from an external network.
|
||||
///
|
||||
/// A block is defined as a consensus event associated with a set of transactions. It is not
|
||||
/// necessary to literally define it as whatever the external network defines as a block. For
|
||||
/// external networks which finalize block(s), this block type should be a representation of all
|
||||
/// transactions within a period finalization (whether block or epoch).
|
||||
#[async_trait::async_trait]
|
||||
pub trait Block: Send + Sync + Sized + Clone + Debug {
|
||||
/// The type used for this block's header.
|
||||
type Header: BlockHeader;
|
||||
|
||||
/// The type used to represent keys on this external network.
|
||||
type Key: Group + GroupEncoding;
|
||||
/// The type used to represent addresses on this external network.
|
||||
type Address;
|
||||
/// The type used to represent received outputs on this external network.
|
||||
type Output: ReceivedOutput<Self::Key, Self::Address>;
|
||||
|
||||
/// The ID of this block.
|
||||
fn id(&self) -> <Self::Header as BlockHeader>::Id;
|
||||
|
||||
/// Scan all outputs within this block to find the outputs spendable by this key.
|
||||
fn scan_for_outputs(&self, key: Self::Key) -> Vec<Self::Output>;
|
||||
}
|
||||
|
||||
/// A wrapper for a group element which implements the borsh traits.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct BorshG<G: GroupEncoding>(pub G);
|
||||
|
|
|
@ -5,7 +5,7 @@ use serai_db::{Get, DbTxn, create_db};
|
|||
|
||||
use primitives::{Id, ReceivedOutput, Block, BorshG};
|
||||
|
||||
use crate::ScannerFeed;
|
||||
use crate::{ScannerFeed, BlockIdFor, KeyFor, OutputFor};
|
||||
|
||||
// The DB macro doesn't support `BorshSerialize + BorshDeserialize` as a bound, hence this.
|
||||
trait Borshy: BorshSerialize + BorshDeserialize {}
|
||||
|
@ -64,25 +64,25 @@ create_db!(
|
|||
|
||||
pub(crate) struct ScannerDb<S: ScannerFeed>(PhantomData<S>);
|
||||
impl<S: ScannerFeed> ScannerDb<S> {
|
||||
pub(crate) fn set_block(txn: &mut impl DbTxn, number: u64, id: <S::Block as Block>::Id) {
|
||||
pub(crate) fn set_block(txn: &mut impl DbTxn, number: u64, id: BlockIdFor<S>) {
|
||||
BlockId::set(txn, number, &id);
|
||||
BlockNumber::set(txn, id, &number);
|
||||
}
|
||||
pub(crate) fn block_id(getter: &impl Get, number: u64) -> Option<<S::Block as Block>::Id> {
|
||||
pub(crate) fn block_id(getter: &impl Get, number: u64) -> Option<BlockIdFor<S>> {
|
||||
BlockId::get(getter, number)
|
||||
}
|
||||
pub(crate) fn block_number(getter: &impl Get, id: <S::Block as Block>::Id) -> Option<u64> {
|
||||
pub(crate) fn block_number(getter: &impl Get, id: BlockIdFor<S>) -> Option<u64> {
|
||||
BlockNumber::get(getter, id)
|
||||
}
|
||||
|
||||
// activation_block_number is inclusive, so the key will be scanned for starting at the specified
|
||||
// block
|
||||
pub(crate) fn queue_key(txn: &mut impl DbTxn, activation_block_number: u64, key: S::Key) {
|
||||
pub(crate) fn queue_key(txn: &mut impl DbTxn, activation_block_number: u64, key: KeyFor<S>) {
|
||||
// Set this block as notable
|
||||
NotableBlock::set(txn, activation_block_number, &());
|
||||
|
||||
// Push the key
|
||||
let mut keys: Vec<SeraiKey<BorshG<S::Key>>> = ActiveKeys::get(txn).unwrap_or(vec![]);
|
||||
let mut keys: Vec<SeraiKey<BorshG<KeyFor<S>>>> = ActiveKeys::get(txn).unwrap_or(vec![]);
|
||||
for key_i in &keys {
|
||||
if key == key_i.key.0 {
|
||||
panic!("queueing a key prior queued");
|
||||
|
@ -97,8 +97,8 @@ impl<S: ScannerFeed> ScannerDb<S> {
|
|||
}
|
||||
// retirement_block_number is inclusive, so the key will no longer be scanned for as of the
|
||||
// specified block
|
||||
pub(crate) fn retire_key(txn: &mut impl DbTxn, retirement_block_number: u64, key: S::Key) {
|
||||
let mut keys: Vec<SeraiKey<BorshG<S::Key>>> =
|
||||
pub(crate) fn retire_key(txn: &mut impl DbTxn, retirement_block_number: u64, key: KeyFor<S>) {
|
||||
let mut keys: Vec<SeraiKey<BorshG<KeyFor<S>>>> =
|
||||
ActiveKeys::get(txn).expect("retiring key yet no active keys");
|
||||
|
||||
assert!(keys.len() > 1, "retiring our only key");
|
||||
|
@ -118,15 +118,11 @@ impl<S: ScannerFeed> ScannerDb<S> {
|
|||
}
|
||||
panic!("retiring key yet not present in keys")
|
||||
}
|
||||
pub(crate) fn keys(getter: &impl Get) -> Option<Vec<SeraiKey<BorshG<S::Key>>>> {
|
||||
pub(crate) fn keys(getter: &impl Get) -> Option<Vec<SeraiKey<BorshG<KeyFor<S>>>>> {
|
||||
ActiveKeys::get(getter)
|
||||
}
|
||||
|
||||
pub(crate) fn set_start_block(
|
||||
txn: &mut impl DbTxn,
|
||||
start_block: u64,
|
||||
id: <S::Block as Block>::Id,
|
||||
) {
|
||||
pub(crate) fn set_start_block(txn: &mut impl DbTxn, start_block: u64, id: BlockIdFor<S>) {
|
||||
Self::set_block(txn, start_block, id);
|
||||
LatestFinalizedBlock::set(txn, &start_block);
|
||||
LatestScannableBlock::set(txn, &start_block);
|
||||
|
@ -189,11 +185,7 @@ impl<S: ScannerFeed> ScannerDb<S> {
|
|||
HighestAcknowledgedBlock::get(getter)
|
||||
}
|
||||
|
||||
pub(crate) fn set_outputs(
|
||||
txn: &mut impl DbTxn,
|
||||
block_number: u64,
|
||||
outputs: Vec<impl ReceivedOutput<S::Key, S::Address>>,
|
||||
) {
|
||||
pub(crate) fn set_outputs(txn: &mut impl DbTxn, block_number: u64, outputs: Vec<OutputFor<S>>) {
|
||||
if outputs.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use serai_db::{Db, DbTxn};
|
||||
|
||||
use primitives::{Id, Block};
|
||||
use primitives::{Id, BlockHeader};
|
||||
|
||||
// TODO: Localize to IndexDb?
|
||||
use crate::{db::ScannerDb, ScannerFeed, ContinuallyRan};
|
||||
|
@ -43,7 +43,7 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for IndexFinalizedTask<D, S> {
|
|||
|
||||
// Index the hashes of all blocks until the latest finalized block
|
||||
for b in (our_latest_finalized + 1) ..= latest_finalized {
|
||||
let block = match self.feed.block_by_number(b).await {
|
||||
let block = match self.feed.block_header_by_number(b).await {
|
||||
Ok(block) => block,
|
||||
Err(e) => Err(format!("couldn't fetch block {b}: {e:?}"))?,
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ use core::{fmt::Debug, time::Duration};
|
|||
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use primitives::{ReceivedOutput, Block};
|
||||
use primitives::{ReceivedOutput, BlockHeader, Block};
|
||||
|
||||
mod db;
|
||||
mod index;
|
||||
|
@ -21,15 +21,6 @@ pub trait ScannerFeed: Send + Sync {
|
|||
/// This value must be at least `1`.
|
||||
const CONFIRMATIONS: u64;
|
||||
|
||||
/// The type of the key used to receive coins on this blockchain.
|
||||
type Key: group::Group + group::GroupEncoding;
|
||||
|
||||
/// The type of the address used to specify who to send coins to on this blockchain.
|
||||
type Address;
|
||||
|
||||
/// The type representing a received (and spendable) output.
|
||||
type Output: ReceivedOutput<Self::Key, Self::Address>;
|
||||
|
||||
/// The representation of a block for this blockchain.
|
||||
///
|
||||
/// A block is defined as a consensus event associated with a set of transactions. It is not
|
||||
|
@ -58,17 +49,20 @@ pub trait ScannerFeed: Send + Sync {
|
|||
Ok(self.latest_block_number().await? - Self::CONFIRMATIONS)
|
||||
}
|
||||
|
||||
/// Fetch a block header by its number.
|
||||
async fn block_header_by_number(
|
||||
&self,
|
||||
number: u64,
|
||||
) -> Result<<Self::Block as Block>::Header, Self::EphemeralError>;
|
||||
|
||||
/// Fetch a block by its number.
|
||||
async fn block_by_number(&self, number: u64) -> Result<Self::Block, Self::EphemeralError>;
|
||||
|
||||
/// Scan a block for its outputs.
|
||||
async fn scan_for_outputs(
|
||||
&self,
|
||||
block: &Self::Block,
|
||||
key: Self::Key,
|
||||
) -> Result<Vec<Self::Output>, Self::EphemeralError>;
|
||||
}
|
||||
|
||||
type BlockIdFor<S> = <<<S as ScannerFeed>::Block as Block>::Header as BlockHeader>::Id;
|
||||
type KeyFor<S> = <<S as ScannerFeed>::Block as Block>::Key;
|
||||
type OutputFor<S> = <<S as ScannerFeed>::Block as Block>::Output;
|
||||
|
||||
/// A handle to immediately run an iteration of a task.
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct RunNowHandle(mpsc::Sender<()>);
|
||||
|
|
|
@ -60,12 +60,7 @@ impl<D: Db, S: ScannerFeed> ContinuallyRan for ScanForOutputsTask<D, S> {
|
|||
continue;
|
||||
}
|
||||
|
||||
for output in self
|
||||
.feed
|
||||
.scan_for_outputs(&block, key.key.0)
|
||||
.await
|
||||
.map_err(|e| format!("failed to scan block {b}: {e:?}"))?
|
||||
{
|
||||
for output in block.scan_for_outputs(key.key.0) {
|
||||
assert_eq!(output.key(), key.key.0);
|
||||
// TODO: Check for dust
|
||||
outputs.push(output);
|
||||
|
|
Loading…
Reference in a new issue