mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-11 05:14:41 +00:00
Bitcoin ScannerFeed
This commit is contained in:
parent
e36b671f37
commit
ba3a6f9e91
8 changed files with 84 additions and 7 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -8141,6 +8141,7 @@ dependencies = [
|
||||||
"serai-message-queue",
|
"serai-message-queue",
|
||||||
"serai-processor-messages",
|
"serai-processor-messages",
|
||||||
"serai-processor-primitives",
|
"serai-processor-primitives",
|
||||||
|
"serai-processor-scanner",
|
||||||
"serai-processor-scheduler-primitives",
|
"serai-processor-scheduler-primitives",
|
||||||
"tokio",
|
"tokio",
|
||||||
"zalloc",
|
"zalloc",
|
||||||
|
|
|
@ -44,6 +44,7 @@ messages = { package = "serai-processor-messages", path = "../messages" }
|
||||||
|
|
||||||
primitives = { package = "serai-processor-primitives", path = "../primitives" }
|
primitives = { package = "serai-processor-primitives", path = "../primitives" }
|
||||||
scheduler = { package = "serai-processor-scheduler-primitives", path = "../scheduler/primitives" }
|
scheduler = { package = "serai-processor-scheduler-primitives", path = "../scheduler/primitives" }
|
||||||
|
scanner = { package = "serai-processor-scanner", path = "../scanner" }
|
||||||
|
|
||||||
message-queue = { package = "serai-message-queue", path = "../../message-queue" }
|
message-queue = { package = "serai-message-queue", path = "../../message-queue" }
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,10 @@ use serai_client::networks::bitcoin::Address;
|
||||||
|
|
||||||
use primitives::{ReceivedOutput, EventualityTracker};
|
use primitives::{ReceivedOutput, EventualityTracker};
|
||||||
|
|
||||||
use crate::{hash_bytes, scanner::scanner, output::Output, transaction::Eventuality};
|
use crate::{hash_bytes, scan::scanner, output::Output, transaction::Eventuality};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct BlockHeader(Header);
|
pub(crate) struct BlockHeader(pub(crate) Header);
|
||||||
impl primitives::BlockHeader for BlockHeader {
|
impl primitives::BlockHeader for BlockHeader {
|
||||||
fn id(&self) -> [u8; 32] {
|
fn id(&self) -> [u8; 32] {
|
||||||
hash_bytes(self.0.block_hash().to_raw_hash())
|
hash_bytes(self.0.block_hash().to_raw_hash())
|
||||||
|
@ -22,7 +22,7 @@ impl primitives::BlockHeader for BlockHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct Block(BBlock);
|
pub(crate) struct Block(pub(crate) BBlock);
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl primitives::Block for Block {
|
impl primitives::Block for Block {
|
||||||
|
|
|
@ -6,12 +6,19 @@
|
||||||
static ALLOCATOR: zalloc::ZeroizingAlloc<std::alloc::System> =
|
static ALLOCATOR: zalloc::ZeroizingAlloc<std::alloc::System> =
|
||||||
zalloc::ZeroizingAlloc(std::alloc::System);
|
zalloc::ZeroizingAlloc(std::alloc::System);
|
||||||
|
|
||||||
mod scanner;
|
// Internal utilities for scanning transactions
|
||||||
|
mod scan;
|
||||||
|
|
||||||
|
// Output trait satisfaction
|
||||||
mod output;
|
mod output;
|
||||||
|
// Transaction/SignableTransaction/Eventuality trait satisfaction
|
||||||
mod transaction;
|
mod transaction;
|
||||||
|
// Block trait satisfaction
|
||||||
mod block;
|
mod block;
|
||||||
|
|
||||||
|
// ScannerFeed trait satisfaction
|
||||||
|
mod scanner_feed;
|
||||||
|
|
||||||
pub(crate) fn hash_bytes(hash: bitcoin_serai::bitcoin::hashes::sha256d::Hash) -> [u8; 32] {
|
pub(crate) fn hash_bytes(hash: bitcoin_serai::bitcoin::hashes::sha256d::Hash) -> [u8; 32] {
|
||||||
use bitcoin_serai::bitcoin::hashes::Hash;
|
use bitcoin_serai::bitcoin::hashes::Hash;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ use serai_client::{
|
||||||
|
|
||||||
use primitives::{OutputType, ReceivedOutput};
|
use primitives::{OutputType, ReceivedOutput};
|
||||||
|
|
||||||
use crate::scanner::{offsets_for_key, presumed_origin, extract_serai_data};
|
use crate::scan::{offsets_for_key, presumed_origin, extract_serai_data};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash, Debug, Encode, Decode, BorshSerialize, BorshDeserialize)]
|
#[derive(Clone, PartialEq, Eq, Hash, Debug, Encode, Decode, BorshSerialize, BorshDeserialize)]
|
||||||
pub(crate) struct OutputId([u8; 36]);
|
pub(crate) struct OutputId([u8; 36]);
|
||||||
|
|
62
processor/bitcoin/src/scanner_feed.rs
Normal file
62
processor/bitcoin/src/scanner_feed.rs
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
use bitcoin_serai::rpc::{RpcError, Rpc as BRpc};
|
||||||
|
|
||||||
|
use serai_client::primitives::{NetworkId, Coin, Amount};
|
||||||
|
|
||||||
|
use scanner::ScannerFeed;
|
||||||
|
|
||||||
|
use crate::block::{BlockHeader, Block};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub(crate) struct Rpc(BRpc);
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl ScannerFeed for Rpc {
|
||||||
|
const NETWORK: NetworkId = NetworkId::Bitcoin;
|
||||||
|
const CONFIRMATIONS: u64 = 6;
|
||||||
|
const WINDOW_LENGTH: u64 = 6;
|
||||||
|
|
||||||
|
const TEN_MINUTES: u64 = 1;
|
||||||
|
|
||||||
|
type Block = Block;
|
||||||
|
|
||||||
|
type EphemeralError = RpcError;
|
||||||
|
|
||||||
|
async fn latest_finalized_block_number(&self) -> Result<u64, Self::EphemeralError> {
|
||||||
|
u64::try_from(self.0.get_latest_block_number().await?)
|
||||||
|
.unwrap()
|
||||||
|
.checked_sub(Self::CONFIRMATIONS)
|
||||||
|
.ok_or(RpcError::ConnectionError)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn unchecked_block_header_by_number(
|
||||||
|
&self,
|
||||||
|
number: u64,
|
||||||
|
) -> Result<<Self::Block as primitives::Block>::Header, Self::EphemeralError> {
|
||||||
|
Ok(BlockHeader(
|
||||||
|
self.0.get_block(&self.0.get_block_hash(number.try_into().unwrap()).await?).await?.header,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn unchecked_block_by_number(
|
||||||
|
&self,
|
||||||
|
number: u64,
|
||||||
|
) -> Result<Self::Block, Self::EphemeralError> {
|
||||||
|
Ok(Block(self.0.get_block(&self.0.get_block_hash(number.try_into().unwrap()).await?).await?))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dust(coin: Coin) -> Amount {
|
||||||
|
assert_eq!(coin, Coin::Bitcoin);
|
||||||
|
// 10,000 satoshis, or $5 if 1 BTC = 50,000 USD
|
||||||
|
Amount(10_000)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn cost_to_aggregate(
|
||||||
|
&self,
|
||||||
|
coin: Coin,
|
||||||
|
_reference_block: &Self::Block,
|
||||||
|
) -> Result<Amount, Self::EphemeralError> {
|
||||||
|
assert_eq!(coin, Coin::Bitcoin);
|
||||||
|
// TODO
|
||||||
|
Ok(Amount(0))
|
||||||
|
}
|
||||||
|
}
|
|
@ -71,8 +71,14 @@ pub trait ScannerFeed: 'static + Send + Sync + Clone {
|
||||||
|
|
||||||
/// The amount of blocks to process in parallel.
|
/// The amount of blocks to process in parallel.
|
||||||
///
|
///
|
||||||
/// This must be at least `1`. This value should be the worst-case latency to handle a block
|
/// This must be at least `1`. This value MUST be at least the worst-case latency to publish a
|
||||||
/// divided by the expected block time.
|
/// Batch for a block divided by the expected block time. Setting this value too low will risk a
|
||||||
|
/// backlog forming. Setting this value too high will only delay key rotation and forwarded
|
||||||
|
/// outputs.
|
||||||
|
// The latency to publish a Batch for a block is the latency of a provided transaction
|
||||||
|
// (1 minute), the latency of a signing protocol (1 minute), the latency of Serai to finalize a
|
||||||
|
// block (1 minute), and the latency to cosign such a block (5 minutes for the cosign distance
|
||||||
|
// plus 1 minute). Accordingly, this should be at least ~30 minutes, ideally 60 minutes.
|
||||||
const WINDOW_LENGTH: u64;
|
const WINDOW_LENGTH: u64;
|
||||||
|
|
||||||
/// The amount of blocks which will occur in 10 minutes (approximate).
|
/// The amount of blocks which will occur in 10 minutes (approximate).
|
||||||
|
|
Loading…
Reference in a new issue