mirror of
https://github.com/serai-dex/serai.git
synced 2025-01-13 06:14:44 +00:00
Add section documenting the safety of txindex upon reorganizations
This commit is contained in:
parent
9b8c8f8231
commit
3ac0265f07
2 changed files with 32 additions and 6 deletions
|
@ -16,7 +16,7 @@ use serai_client::networks::bitcoin::Address;
|
||||||
use serai_db::Get;
|
use serai_db::Get;
|
||||||
use primitives::OutputType;
|
use primitives::OutputType;
|
||||||
|
|
||||||
use crate::{db, hash_bytes};
|
use crate::hash_bytes;
|
||||||
|
|
||||||
const KEY_DST: &[u8] = b"Serai Bitcoin Processor Key Offset";
|
const KEY_DST: &[u8] = b"Serai Bitcoin Processor Key Offset";
|
||||||
static BRANCH_BASE_OFFSET: LazyLock<<Secp256k1 as Ciphersuite>::F> =
|
static BRANCH_BASE_OFFSET: LazyLock<<Secp256k1 as Ciphersuite>::F> =
|
||||||
|
@ -62,9 +62,9 @@ pub(crate) fn presumed_origin(getter: &impl Get, tx: &Transaction) -> Option<Add
|
||||||
for input in &tx.input {
|
for input in &tx.input {
|
||||||
let txid = hash_bytes(input.previous_output.txid.to_raw_hash());
|
let txid = hash_bytes(input.previous_output.txid.to_raw_hash());
|
||||||
let vout = input.previous_output.vout;
|
let vout = input.previous_output.vout;
|
||||||
if let Some(address) = Address::new(ScriptBuf::from_bytes(
|
if let Some(address) =
|
||||||
db::ScriptPubKey::get(getter, txid, vout).expect("unknown output being spent by input"),
|
Address::new(crate::txindex::script_pubkey_for_on_chain_output(getter, txid, vout))
|
||||||
)) {
|
{
|
||||||
return Some(address);
|
return Some(address);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,27 @@
|
||||||
This task builds that index.
|
This task builds that index.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use serai_db::{DbTxn, Db};
|
use bitcoin_serai::bitcoin::ScriptBuf;
|
||||||
|
|
||||||
|
use serai_db::{Get, DbTxn, Db};
|
||||||
|
|
||||||
use primitives::task::ContinuallyRan;
|
use primitives::task::ContinuallyRan;
|
||||||
use scanner::ScannerFeed;
|
use scanner::ScannerFeed;
|
||||||
|
|
||||||
use crate::{db, rpc::Rpc, hash_bytes};
|
use crate::{db, rpc::Rpc, hash_bytes};
|
||||||
|
|
||||||
|
pub(crate) fn script_pubkey_for_on_chain_output(
|
||||||
|
getter: &impl Get,
|
||||||
|
txid: [u8; 32],
|
||||||
|
vout: u32,
|
||||||
|
) -> ScriptBuf {
|
||||||
|
// We index every single output on the blockchain, so this shouldn't be possible
|
||||||
|
ScriptBuf::from_bytes(
|
||||||
|
db::ScriptPubKey::get(getter, txid, vout)
|
||||||
|
.expect("requested script public key for unknown output"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct TxIndexTask<D: Db>(Rpc<D>);
|
pub(crate) struct TxIndexTask<D: Db>(Rpc<D>);
|
||||||
|
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
|
@ -40,6 +54,18 @@ impl<D: Db> ContinuallyRan for TxIndexTask<D> {
|
||||||
Rpc::<D>::CONFIRMATIONS
|
Rpc::<D>::CONFIRMATIONS
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
/*
|
||||||
|
`finalized_block_number` is the latest block number minus confirmations. The blockchain may
|
||||||
|
undetectably re-organize though, as while the scanner will maintain an index of finalized
|
||||||
|
blocks and panics on reorganization, this runs prior to the scanner and that index.
|
||||||
|
|
||||||
|
A reorganization of `CONFIRMATIONS` blocks is still an invariant. Even if that occurs, this
|
||||||
|
saves the script public keys *by the transaction hash an output index*. Accordingly, it isn't
|
||||||
|
invalidated on reorganization. The only risk would be if the new chain reorganized to
|
||||||
|
include a transaction to Serai which we didn't index the parents of. If that happens, we'll
|
||||||
|
panic when we scan the transaction, causing the invariant to be detected.
|
||||||
|
*/
|
||||||
|
|
||||||
let finalized_block_number_in_db = db::LatestBlockToYieldAsFinalized::get(&self.0.db);
|
let finalized_block_number_in_db = db::LatestBlockToYieldAsFinalized::get(&self.0.db);
|
||||||
let next_block = finalized_block_number_in_db.map_or(0, |block| block + 1);
|
let next_block = finalized_block_number_in_db.map_or(0, |block| block + 1);
|
||||||
|
|
||||||
|
@ -63,7 +89,7 @@ impl<D: Db> ContinuallyRan for TxIndexTask<D> {
|
||||||
|
|
||||||
let mut txn = self.0.db.txn();
|
let mut txn = self.0.db.txn();
|
||||||
|
|
||||||
for tx in &block.txdata[1 ..] {
|
for tx in &block.txdata {
|
||||||
let txid = hash_bytes(tx.compute_txid().to_raw_hash());
|
let txid = hash_bytes(tx.compute_txid().to_raw_hash());
|
||||||
for (o, output) in tx.output.iter().enumerate() {
|
for (o, output) in tx.output.iter().enumerate() {
|
||||||
let o = u32::try_from(o).unwrap();
|
let o = u32::try_from(o).unwrap();
|
||||||
|
|
Loading…
Reference in a new issue