Skip to content

Commit

Permalink
Fix lost sats bug (ordinals#2666)
Browse files Browse the repository at this point in the history
  • Loading branch information
raphjaph authored Nov 13, 2023
1 parent f878a3f commit 9d90e77
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 124 deletions.
8 changes: 6 additions & 2 deletions src/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2348,7 +2348,9 @@ mod tests {

#[test]
fn lost_sats_are_tracked_correctly() {
let context = Context::builder().arg("--index-sats").build();
let context = Context::builder()
.args(["--index-sats", "--first-inscription-height", "10"])
.build();
assert_eq!(context.index.statistic(Statistic::LostSats), 0);

context.mine_blocks(1);
Expand All @@ -2375,7 +2377,9 @@ mod tests {

#[test]
fn lost_sat_ranges_are_tracked_correctly() {
let context = Context::builder().arg("--index-sats").build();
let context = Context::builder()
.args(["--index-sats", "--first-inscription-height", "10"])
.build();

let null_ranges = || match context.index.list(OutPoint::null()).unwrap().unwrap() {
List::Unspent(ranges) => ranges,
Expand Down
247 changes: 125 additions & 122 deletions src/index/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,147 +410,150 @@ impl<'index> Updater<'_> {
.map(|unbound_inscriptions| unbound_inscriptions.value())
.unwrap_or(0);

{
let mut inscription_updater = InscriptionUpdater::new(
self.height,
&mut inscription_id_to_children,
&mut inscription_id_to_satpoint,
value_receiver,
&mut inscription_id_to_inscription_entry,
lost_sats,
&mut inscription_number_to_inscription_id,
cursed_inscription_count,
blessed_inscription_count,
&mut sequence_number_to_inscription_id,
&mut outpoint_to_value,
&mut sat_to_inscription_id,
&mut satpoint_to_inscription_id,
block.header.time,
unbound_inscriptions,
value_cache,
)?;

if self.index.index_sats {
let mut sat_to_satpoint = wtx.open_table(SAT_TO_SATPOINT)?;
let mut outpoint_to_sat_ranges = wtx.open_table(OUTPOINT_TO_SAT_RANGES)?;
let mut inscription_updater = InscriptionUpdater::new(
self.height,
&mut inscription_id_to_children,
&mut inscription_id_to_satpoint,
value_receiver,
&mut inscription_id_to_inscription_entry,
lost_sats,
&mut inscription_number_to_inscription_id,
cursed_inscription_count,
blessed_inscription_count,
&mut sequence_number_to_inscription_id,
&mut outpoint_to_value,
&mut sat_to_inscription_id,
&mut satpoint_to_inscription_id,
block.header.time,
unbound_inscriptions,
value_cache,
)?;

let mut coinbase_inputs = VecDeque::new();
if self.index.index_sats {
let mut sat_to_satpoint = wtx.open_table(SAT_TO_SATPOINT)?;
let mut outpoint_to_sat_ranges = wtx.open_table(OUTPOINT_TO_SAT_RANGES)?;

let h = Height(self.height);
if h.subsidy() > 0 {
let start = h.starting_sat();
coinbase_inputs.push_front((start.n(), (start + h.subsidy()).n()));
self.sat_ranges_since_flush += 1;
}
let mut coinbase_inputs = VecDeque::new();

for (tx_offset, (tx, txid)) in block.txdata.iter().enumerate().skip(1) {
log::trace!("Indexing transaction {tx_offset}…");
let h = Height(self.height);
if h.subsidy() > 0 {
let start = h.starting_sat();
coinbase_inputs.push_front((start.n(), (start + h.subsidy()).n()));
self.sat_ranges_since_flush += 1;
}

let mut input_sat_ranges = VecDeque::new();
for (tx_offset, (tx, txid)) in block.txdata.iter().enumerate().skip(1) {
log::trace!("Indexing transaction {tx_offset}…");

for input in &tx.input {
let key = input.previous_output.store();
let mut input_sat_ranges = VecDeque::new();

let sat_ranges = match self.range_cache.remove(&key) {
Some(sat_ranges) => {
self.outputs_cached += 1;
sat_ranges
}
None => outpoint_to_sat_ranges
.remove(&key)?
.ok_or_else(|| {
anyhow!("Could not find outpoint {} in index", input.previous_output)
})?
.value()
.to_vec(),
};
for input in &tx.input {
let key = input.previous_output.store();

for chunk in sat_ranges.chunks_exact(11) {
input_sat_ranges.push_back(SatRange::load(chunk.try_into().unwrap()));
let sat_ranges = match self.range_cache.remove(&key) {
Some(sat_ranges) => {
self.outputs_cached += 1;
sat_ranges
}
}

self.index_transaction_sats(
tx,
*txid,
&mut sat_to_satpoint,
&mut input_sat_ranges,
&mut sat_ranges_written,
&mut outputs_in_block,
&mut inscription_updater,
index_inscriptions,
)?;

coinbase_inputs.extend(input_sat_ranges);
}
None => outpoint_to_sat_ranges
.remove(&key)?
.ok_or_else(|| anyhow!("Could not find outpoint {} in index", input.previous_output))?
.value()
.to_vec(),
};

if let Some((tx, txid)) = block.txdata.get(0) {
self.index_transaction_sats(
tx,
*txid,
&mut sat_to_satpoint,
&mut coinbase_inputs,
&mut sat_ranges_written,
&mut outputs_in_block,
&mut inscription_updater,
index_inscriptions,
)?;
for chunk in sat_ranges.chunks_exact(11) {
input_sat_ranges.push_back(SatRange::load(chunk.try_into().unwrap()));
}
}

if !coinbase_inputs.is_empty() {
let mut lost_sat_ranges = outpoint_to_sat_ranges
.remove(&OutPoint::null().store())?
.map(|ranges| ranges.value().to_vec())
.unwrap_or_default();

for (start, end) in coinbase_inputs {
if !Sat(start).is_common() {
sat_to_satpoint.insert(
&start,
&SatPoint {
outpoint: OutPoint::null(),
offset: lost_sats,
}
.store(),
)?;
}
self.index_transaction_sats(
tx,
*txid,
&mut sat_to_satpoint,
&mut input_sat_ranges,
&mut sat_ranges_written,
&mut outputs_in_block,
&mut inscription_updater,
index_inscriptions,
)?;

coinbase_inputs.extend(input_sat_ranges);
}

lost_sat_ranges.extend_from_slice(&(start, end).store());
if let Some((tx, txid)) = block.txdata.get(0) {
self.index_transaction_sats(
tx,
*txid,
&mut sat_to_satpoint,
&mut coinbase_inputs,
&mut sat_ranges_written,
&mut outputs_in_block,
&mut inscription_updater,
index_inscriptions,
)?;
}

lost_sats += end - start;
if !coinbase_inputs.is_empty() {
let mut lost_sat_ranges = outpoint_to_sat_ranges
.remove(&OutPoint::null().store())?
.map(|ranges| ranges.value().to_vec())
.unwrap_or_default();

for (start, end) in coinbase_inputs {
if !Sat(start).is_common() {
sat_to_satpoint.insert(
&start,
&SatPoint {
outpoint: OutPoint::null(),
offset: lost_sats,
}
.store(),
)?;
}

outpoint_to_sat_ranges.insert(&OutPoint::null().store(), lost_sat_ranges.as_slice())?;
}
} else {
for (tx, txid) in block.txdata.iter().skip(1).chain(block.txdata.first()) {
inscription_updater.index_envelopes(tx, *txid, None)?;
}
}

self.index_block_inscription_numbers(
&mut height_to_last_sequence_number,
&inscription_updater,
index_inscriptions,
)?;
lost_sat_ranges.extend_from_slice(&(start, end).store());

statistic_to_count.insert(&Statistic::LostSats.key(), &inscription_updater.lost_sats)?;
lost_sats += end - start;
}

statistic_to_count.insert(
&Statistic::CursedInscriptions.key(),
&inscription_updater.cursed_inscription_count,
)?;
outpoint_to_sat_ranges.insert(&OutPoint::null().store(), lost_sat_ranges.as_slice())?;
}
} else {
for (tx, txid) in block.txdata.iter().skip(1).chain(block.txdata.first()) {
inscription_updater.index_envelopes(tx, *txid, None)?;
}
}

statistic_to_count.insert(
&Statistic::BlessedInscriptions.key(),
&inscription_updater.blessed_inscription_count,
)?;
self.index_block_inscription_numbers(
&mut height_to_last_sequence_number,
&inscription_updater,
index_inscriptions,
)?;

statistic_to_count.insert(
&Statistic::UnboundInscriptions.key(),
&inscription_updater.unbound_inscriptions,
)?;
}
statistic_to_count.insert(
&Statistic::LostSats.key(),
&if self.index.index_sats {
lost_sats
} else {
inscription_updater.lost_sats
},
)?;

statistic_to_count.insert(
&Statistic::CursedInscriptions.key(),
&inscription_updater.cursed_inscription_count,
)?;

statistic_to_count.insert(
&Statistic::BlessedInscriptions.key(),
&inscription_updater.blessed_inscription_count,
)?;

statistic_to_count.insert(
&Statistic::UnboundInscriptions.key(),
&inscription_updater.unbound_inscriptions,
)?;

if index.index_runes {
let mut outpoint_to_rune_balances = wtx.open_table(OUTPOINT_TO_RUNE_BALANCES)?;
Expand Down

0 comments on commit 9d90e77

Please sign in to comment.