From a2c1a1d02a60a5a290d05b6719889d97b05bd51b Mon Sep 17 00:00:00 2001 From: raph Date: Sat, 23 Mar 2024 01:51:39 +0100 Subject: [PATCH] Fetch etching inputs using Bitcoin Core RPC (#3336) --- crates/test-bitcoincore-rpc/src/server.rs | 17 +++++--- crates/test-bitcoincore-rpc/src/state.rs | 6 +++ src/index.rs | 6 +-- src/index/entry.rs | 32 -------------- src/index/updater.rs | 3 +- src/index/updater/rune_updater.rs | 52 ++++++++--------------- 6 files changed, 38 insertions(+), 78 deletions(-) diff --git a/crates/test-bitcoincore-rpc/src/server.rs b/crates/test-bitcoincore-rpc/src/server.rs index a14ee1c438..5610e52810 100644 --- a/crates/test-bitcoincore-rpc/src/server.rs +++ b/crates/test-bitcoincore-rpc/src/server.rs @@ -607,8 +607,15 @@ impl Api for Server { blockhash: Option, ) -> Result { assert_eq!(blockhash, None, "Blockhash param is unsupported"); + let state = self.state(); + let current_height: u32 = (state.hashes.len() - 1).try_into().unwrap(); + let confirmations = state + .txid_to_block_height + .get(&txid) + .map(|tx_height| current_height - tx_height); + if verbose.unwrap_or(false) { - match self.state().transactions.get(&txid) { + match state.transactions.get(&txid) { Some(transaction) => Ok( serde_json::to_value(GetRawTransactionResult { in_active_chain: Some(true), @@ -628,8 +635,8 @@ impl Api for Server { n: n.try_into().unwrap(), value: Amount::from_sat(output.value), script_pub_key: GetRawTransactionResultVoutScriptPubKey { - asm: String::new(), - hex: Vec::new(), + asm: output.script_pubkey.to_asm_string(), + hex: output.script_pubkey.clone().into(), req_sigs: None, type_: None, addresses: Vec::new(), @@ -638,7 +645,7 @@ impl Api for Server { }) .collect(), blockhash: None, - confirmations: Some(1), + confirmations, time: None, blocktime: None, }) @@ -647,7 +654,7 @@ impl Api for Server { None => Err(Self::not_found()), } } else { - match self.state().transactions.get(&txid) { + match state.transactions.get(&txid) { Some(tx) => Ok(Value::String(hex::encode(serialize(tx)))), None => Err(Self::not_found()), } diff --git a/crates/test-bitcoincore-rpc/src/state.rs b/crates/test-bitcoincore-rpc/src/state.rs index aaac2849a9..28270d775c 100644 --- a/crates/test-bitcoincore-rpc/src/state.rs +++ b/crates/test-bitcoincore-rpc/src/state.rs @@ -19,6 +19,7 @@ pub struct State { pub network: Network, pub nonce: u32, pub transactions: BTreeMap, + pub txid_to_block_height: BTreeMap, pub utxos: BTreeMap, pub version: usize, pub receive_addresses: Vec
, @@ -49,6 +50,7 @@ impl State { nonce: 0, receive_addresses: Vec::new(), transactions: BTreeMap::new(), + txid_to_block_height: BTreeMap::new(), utxos: BTreeMap::new(), version, wallets: BTreeSet::new(), @@ -155,6 +157,10 @@ impl State { }; for tx in block.txdata.iter() { + self + .txid_to_block_height + .insert(tx.txid(), self.hashes.len().try_into().unwrap()); + for input in tx.input.iter() { if !input.previous_output.is_null() { assert!(self.utxos.remove(&input.previous_output).is_some()); diff --git a/src/index.rs b/src/index.rs index 67167e83be..6f8f4df5c1 100644 --- a/src/index.rs +++ b/src/index.rs @@ -2,8 +2,7 @@ use { self::{ entry::{ Entry, HeaderValue, InscriptionEntry, InscriptionEntryValue, InscriptionIdValue, - OutPointValue, OutputEntry, OutputValue, RuneEntryValue, RuneIdValue, SatPointValue, - SatRange, TxidValue, + OutPointValue, RuneEntryValue, RuneIdValue, SatPointValue, SatRange, TxidValue, }, event::Event, reorg::*, @@ -72,7 +71,6 @@ define_table! { HEIGHT_TO_LAST_SEQUENCE_NUMBER, u32, u32 } define_table! { HOME_INSCRIPTIONS, u32, InscriptionIdValue } define_table! { INSCRIPTION_ID_TO_SEQUENCE_NUMBER, InscriptionIdValue, u32 } define_table! { INSCRIPTION_NUMBER_TO_SEQUENCE_NUMBER, i32, u32 } -define_table! { OUTPOINT_TO_OUTPUT, &OutPointValue, OutputValue } define_table! { OUTPOINT_TO_RUNE_BALANCES, &OutPointValue, &[u8] } define_table! { OUTPOINT_TO_SAT_RANGES, &OutPointValue, &[u8] } define_table! { OUTPOINT_TO_VALUE, &OutPointValue, u64} @@ -208,7 +206,7 @@ impl BitcoinCoreRpcResultExt for Result { } pub struct Index { - client: Client, + pub(crate) client: Client, database: Database, durability: redb::Durability, event_sender: Option>, diff --git a/src/index/entry.rs b/src/index/entry.rs index e19f751c6e..47796eac54 100644 --- a/src/index/entry.rs +++ b/src/index/entry.rs @@ -28,26 +28,6 @@ impl Entry for Header { } } -#[derive(Debug, PartialEq, Copy, Clone)] -pub(super) struct OutputEntry { - pub(super) height: u32, - pub(super) taproot: bool, -} - -pub(super) type OutputValue = (u32, bool); - -impl Entry for OutputEntry { - type Value = OutputValue; - - fn load((height, taproot): Self::Value) -> Self { - Self { height, taproot } - } - - fn store(self) -> Self::Value { - (self.height, self.taproot) - } -} - #[derive(Debug, PartialEq, Copy, Clone, Serialize, Deserialize)] pub struct RuneEntry { pub burned: u128, @@ -570,16 +550,4 @@ mod tests { assert_eq!(actual, expected); } - - #[test] - fn output() { - let value = (0, true); - let entry = OutputEntry { - height: 0, - taproot: true, - }; - - assert_eq!(entry.store(), value); - assert_eq!(OutputEntry::load(value), entry); - } } diff --git a/src/index/updater.rs b/src/index/updater.rs index 4f5c0f8598..b5229d171b 100644 --- a/src/index/updater.rs +++ b/src/index/updater.rs @@ -580,7 +580,6 @@ impl<'index> Updater<'index> { if self.index.index_runes && self.height >= self.index.settings.first_rune_height() { let mut outpoint_to_rune_balances = wtx.open_table(OUTPOINT_TO_RUNE_BALANCES)?; - let mut outpoint_to_output = wtx.open_table(OUTPOINT_TO_OUTPUT)?; let mut rune_id_to_rune_entry = wtx.open_table(RUNE_ID_TO_RUNE_ENTRY)?; let mut rune_to_rune_id = wtx.open_table(RUNE_TO_RUNE_ID)?; let mut sequence_number_to_rune_id = wtx.open_table(SEQUENCE_NUMBER_TO_RUNE_ID)?; @@ -592,12 +591,12 @@ impl<'index> Updater<'index> { .unwrap_or(0); let mut rune_updater = RuneUpdater { + client: &self.index.client, height: self.height, id_to_entry: &mut rune_id_to_rune_entry, inscription_id_to_sequence_number: &mut inscription_id_to_sequence_number, minimum: Rune::minimum_at_height(self.index.settings.chain(), Height(self.height)), outpoint_to_balances: &mut outpoint_to_rune_balances, - outpoint_to_output: &mut outpoint_to_output, rune_to_id: &mut rune_to_rune_id, runes, sequence_number_to_rune_id: &mut sequence_number_to_rune_id, diff --git a/src/index/updater/rune_updater.rs b/src/index/updater/rune_updater.rs index af2ac0dc8c..210039a134 100644 --- a/src/index/updater/rune_updater.rs +++ b/src/index/updater/rune_updater.rs @@ -24,13 +24,13 @@ pub(crate) struct RuneUpdate { pub(crate) supply: u128, } -pub(super) struct RuneUpdater<'a, 'tx> { +pub(super) struct RuneUpdater<'a, 'tx, 'client> { + pub(super) client: &'client Client, pub(super) height: u32, pub(super) id_to_entry: &'a mut Table<'tx, RuneIdValue, RuneEntryValue>, pub(super) inscription_id_to_sequence_number: &'a Table<'tx, InscriptionIdValue, u32>, pub(super) minimum: Rune, pub(super) outpoint_to_balances: &'a mut Table<'tx, &'static OutPointValue, &'static [u8]>, - pub(super) outpoint_to_output: &'a mut Table<'tx, &'static OutPointValue, OutputValue>, pub(super) rune_to_id: &'a mut Table<'tx, u128, RuneIdValue>, pub(super) runes: u64, pub(super) sequence_number_to_rune_id: &'a mut Table<'tx, u32, RuneIdValue>, @@ -40,7 +40,7 @@ pub(super) struct RuneUpdater<'a, 'tx> { pub(super) updates: HashMap, } -impl<'a, 'tx> RuneUpdater<'a, 'tx> { +impl<'a, 'tx, 'client> RuneUpdater<'a, 'tx, 'client> { pub(super) fn index_runes(&mut self, tx_index: u32, tx: &Transaction, txid: Txid) -> Result<()> { let runestone = Runestone::from_transaction(tx); @@ -222,33 +222,6 @@ impl<'a, 'tx> RuneUpdater<'a, 'tx> { )?; } - for input in tx.input.iter() { - if input.previous_output.is_null() { - continue; - } - - self - .outpoint_to_output - .remove(&input.previous_output.store())? - .unwrap(); - } - - for (vout, output) in tx.output.iter().enumerate() { - let outpoint = OutPoint { - txid, - vout: vout.try_into().unwrap(), - }; - - self.outpoint_to_output.insert( - &outpoint.store(), - OutputEntry { - height: self.height, - taproot: output.script_pubkey.is_v1_p2tr(), - } - .store(), - )?; - } - // increment entries with burned runes for (id, amount) in burned { self.updates.entry(id).or_default().burned += amount; @@ -402,16 +375,25 @@ impl<'a, 'tx> RuneUpdater<'a, 'tx> { continue; } - let Some(output) = self - .outpoint_to_output - .get(&input.previous_output.store())? + let Some(tx_info) = self + .client + .get_raw_transaction_info(&input.previous_output.txid, None) + .into_option()? else { panic!("input not in UTXO set: {}", input.previous_output); }; - let output = OutputEntry::load(output.value()); + let taproot = tx_info.vout[input.previous_output.vout.into_usize()] + .script_pub_key + .script()? + .is_v1_p2tr(); + + let mature = tx_info + .confirmations + .map(|confirmations| confirmations >= RUNE_COMMIT_INTERVAL) + .unwrap_or_default(); - if output.taproot && self.height >= output.height + RUNE_COMMIT_INTERVAL { + if taproot && mature { return Ok(true); } }