mirror of
https://github.com/serai-dex/serai.git
synced 2024-12-25 04:59:31 +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 primitives::OutputType;
|
||||
|
||||
use crate::{db, hash_bytes};
|
||||
use crate::hash_bytes;
|
||||
|
||||
const KEY_DST: &[u8] = b"Serai Bitcoin Processor Key Offset";
|
||||
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 {
|
||||
let txid = hash_bytes(input.previous_output.txid.to_raw_hash());
|
||||
let vout = input.previous_output.vout;
|
||||
if let Some(address) = Address::new(ScriptBuf::from_bytes(
|
||||
db::ScriptPubKey::get(getter, txid, vout).expect("unknown output being spent by input"),
|
||||
)) {
|
||||
if let Some(address) =
|
||||
Address::new(crate::txindex::script_pubkey_for_on_chain_output(getter, txid, vout))
|
||||
{
|
||||
return Some(address);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,13 +14,27 @@
|
|||
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 scanner::ScannerFeed;
|
||||
|
||||
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>);
|
||||
|
||||
#[async_trait::async_trait]
|
||||
|
@ -40,6 +54,18 @@ impl<D: Db> ContinuallyRan for TxIndexTask<D> {
|
|||
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 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();
|
||||
|
||||
for tx in &block.txdata[1 ..] {
|
||||
for tx in &block.txdata {
|
||||
let txid = hash_bytes(tx.compute_txid().to_raw_hash());
|
||||
for (o, output) in tx.output.iter().enumerate() {
|
||||
let o = u32::try_from(o).unwrap();
|
||||
|
|
Loading…
Reference in a new issue