Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always store script pubkey in output table #4254

Merged
merged 9 commits into from
Mar 6, 2025
46 changes: 45 additions & 1 deletion src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ mod utxo_entry;
#[cfg(test)]
pub(crate) mod testing;

const SCHEMA_VERSION: u64 = 30;
const SCHEMA_VERSION: u64 = 31;

define_multimap_table! { SAT_TO_SEQUENCE_NUMBER, u64, u32 }
define_multimap_table! { SEQUENCE_NUMBER_TO_CHILDREN, u32, u32 }
Expand Down Expand Up @@ -2455,12 +2455,56 @@ impl Index {
txout,
)))
}

#[cfg(test)]
pub(crate) fn list_all_spks(&self) -> Result<Vec<ScriptBuf>> {
let rtx = self.database.begin_read()?;
let mut spks = Vec::new();

for entry in rtx.open_table(OUTPOINT_TO_UTXO_ENTRY)?.iter()? {
let (_outpoint, utxo_entry) = entry?;

spks.push(ScriptBuf::from_bytes(
utxo_entry.value().parse(self).script_pubkey().to_vec(),
));
}

Ok(spks)
}
}

#[cfg(test)]
mod tests {
use {super::*, crate::index::testing::Context};

#[test]
fn list_all_spks() {
let context = Context::builder().build();

context.mine_blocks(2);

let tx_1 = TransactionTemplate {
inputs: &[(1, 0, 0, Default::default())],
fee: 0,
recipient: Some(address(0)),
..default()
};

let tx_2 = TransactionTemplate {
inputs: &[(2, 0, 0, Default::default())],
fee: 0,
recipient: Some(address(1)),
..default()
};

context.core.broadcast_tx(tx_1);
context.core.broadcast_tx(tx_2);

context.mine_blocks(1);

assert_eq!(context.index.list_all_spks().unwrap().len(), 4);
}

#[test]
fn height_limit() {
{
Expand Down
14 changes: 4 additions & 10 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -574,9 +574,7 @@ impl Updater<'_> {

let mut entry = UtxoEntryBuf::new();
entry.push_value(txout.value.to_sat(), self.index);
if self.index.index_addresses {
entry.push_script_pubkey(txout.script_pubkey.as_bytes(), self.index);
}
entry.push_script_pubkey(txout.script_pubkey.as_bytes());

entry
};
Expand Down Expand Up @@ -632,9 +630,7 @@ impl Updater<'_> {
}
}

if self.index.index_addresses {
self.index_transaction_output_script_pubkeys(tx, &mut output_utxo_entries);
}
self.index_transaction_output_script_pubkeys(tx, &mut output_utxo_entries);

if index_inscriptions {
inscription_updater.index_inscriptions(
Expand Down Expand Up @@ -685,9 +681,7 @@ impl Updater<'_> {

let mut new_utxo_entry = UtxoEntryBuf::new();
new_utxo_entry.push_sat_ranges(&lost_sat_ranges, self.index);
if self.index.index_addresses {
new_utxo_entry.push_script_pubkey(&[], self.index);
}
new_utxo_entry.push_script_pubkey(&[]);

*utxo_entry = UtxoEntryBuf::merged(utxo_entry, &new_utxo_entry, self.index);
}
Expand Down Expand Up @@ -725,7 +719,7 @@ impl Updater<'_> {
output_utxo_entries: &mut [UtxoEntryBuf],
) {
for (vout, txout) in tx.output.iter().enumerate() {
output_utxo_entries[vout].push_script_pubkey(txout.script_pubkey.as_bytes(), self.index);
output_utxo_entries[vout].push_script_pubkey(txout.script_pubkey.as_bytes());
}
}

Expand Down
47 changes: 17 additions & 30 deletions src/index/utxo_entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ enum Sats<'a> {
/// by that many 11-byte sat range entries, otherwise the total output value
/// stored as a varint.
///
/// If `--index-addresses`, the script pubkey stored as a varint followed by
/// that many bytes of data.
/// The script pubkey stored as a varint followed by that many bytes of data.
///
/// If `--index-inscriptions`, the list of inscriptions stored as
/// `(sequence_number, offset)`, with the sequence number stored as a u32 and
Expand All @@ -43,7 +42,6 @@ pub struct UtxoEntry {
impl UtxoEntry {
pub fn parse(&self, index: &Index) -> ParsedUtxoEntry {
let sats;
let mut script_pubkey = None;
let mut inscriptions = None;

let mut offset = 0;
Expand All @@ -61,14 +59,12 @@ impl UtxoEntry {
offset += varint_len;
};

if index.index_addresses {
let (script_pubkey_len, varint_len) = varint::decode(&self.bytes[offset..]).unwrap();
offset += varint_len;
let (script_pubkey_len, varint_len) = varint::decode(&self.bytes[offset..]).unwrap();
offset += varint_len;

let script_pubkey_len: usize = script_pubkey_len.try_into().unwrap();
script_pubkey = Some(&self.bytes[offset..offset + script_pubkey_len]);
offset += script_pubkey_len;
}
let script_pubkey_len = usize::try_from(script_pubkey_len).unwrap();
let script_pubkey = Some(&self.bytes[offset..offset + script_pubkey_len]);
offset += script_pubkey_len;

if index.index_inscriptions {
inscriptions = Some(&self.bytes[offset..self.bytes.len()]);
Expand Down Expand Up @@ -214,7 +210,7 @@ impl UtxoEntryBuf {
varint::encode_to_vec(value.into(), &mut self.vec);

#[cfg(debug_assertions)]
self.advance_state(State::NeedSats, State::NeedScriptPubkey, index);
self.advance_state(State::NeedSats, State::NeedScriptPubkey);
}

pub fn push_sat_ranges(&mut self, sat_ranges: &[u8], index: &Index) {
Expand All @@ -225,24 +221,23 @@ impl UtxoEntryBuf {
self.vec.extend(sat_ranges);

#[cfg(debug_assertions)]
self.advance_state(State::NeedSats, State::NeedScriptPubkey, index);
self.advance_state(State::NeedSats, State::NeedScriptPubkey);
}

pub fn push_script_pubkey(&mut self, script_pubkey: &[u8], index: &Index) {
assert!(index.index_addresses);
pub fn push_script_pubkey(&mut self, script_pubkey: &[u8]) {
varint::encode_to_vec(script_pubkey.len().try_into().unwrap(), &mut self.vec);
self.vec.extend(script_pubkey);

#[cfg(debug_assertions)]
self.advance_state(State::NeedScriptPubkey, State::Valid, index);
self.advance_state(State::NeedScriptPubkey, State::Valid);
}

pub fn push_inscriptions(&mut self, inscriptions: &[u8], index: &Index) {
assert!(index.index_inscriptions);
self.vec.extend(inscriptions);

#[cfg(debug_assertions)]
self.advance_state(State::Valid, State::Valid, index);
self.advance_state(State::Valid, State::Valid);
}

pub fn push_inscription(&mut self, sequence_number: u32, satpoint_offset: u64, index: &Index) {
Expand All @@ -251,17 +246,13 @@ impl UtxoEntryBuf {
varint::encode_to_vec(satpoint_offset.into(), &mut self.vec);

#[cfg(debug_assertions)]
self.advance_state(State::Valid, State::Valid, index);
self.advance_state(State::Valid, State::Valid);
}

#[cfg(debug_assertions)]
fn advance_state(&mut self, expected_state: State, new_state: State, index: &Index) {
fn advance_state(&mut self, expected_state: State, new_state: State) {
assert!(self.state == expected_state);
self.state = new_state;

if self.state == State::NeedScriptPubkey && !index.index_addresses {
self.state = State::Valid;
}
}

pub fn merged(a: &UtxoEntry, b: &UtxoEntry, index: &Index) -> Self {
Expand All @@ -278,11 +269,9 @@ impl UtxoEntryBuf {
merged.push_value(0, index);
}

if index.index_addresses {
assert!(a_parsed.script_pubkey().is_empty());
assert!(b_parsed.script_pubkey().is_empty());
merged.push_script_pubkey(&[], index);
}
assert!(a_parsed.script_pubkey().is_empty());
assert!(b_parsed.script_pubkey().is_empty());
merged.push_script_pubkey(&[]);

if index.index_inscriptions {
merged.push_inscriptions(a_parsed.inscriptions(), index);
Expand All @@ -301,9 +290,7 @@ impl UtxoEntryBuf {
utxo_entry.push_value(0, index);
}

if index.index_addresses {
utxo_entry.push_script_pubkey(&[], index);
}
utxo_entry.push_script_pubkey(&[]);

utxo_entry
}
Expand Down
Loading