Skip to content

Conversation

@lifofifoX
Copy link
Collaborator

Attempts to fix #4208.

It currently has failing tests that I don't know how best to handle.

@raphjaph
Copy link
Collaborator

In order to fix the tests you will have to filter out all outputs in the balances struct that are OP_RETURN. This function has access to self.index so there should be a way to easily get that information.

  #[track_caller]
  pub(crate) fn assert_runes(
    &self,
    mut runes: impl AsMut<[(RuneId, RuneEntry)]>,
    mut balances: impl AsMut<[(OutPoint, Vec<(RuneId, u128)>)]>,
  ) {
    let runes = runes.as_mut();
    runes.sort_by_key(|(id, _)| *id);

    let balances = balances.as_mut();
    balances.sort_by_key(|(outpoint, _)| *outpoint);

    for (_, balances) in balances.iter_mut() {
      balances.sort_by_key(|(id, _)| *id);
    }

    pretty_assert_eq!(runes, self.index.runes().unwrap());

    pretty_assert_eq!(balances, self.index.get_rune_balances().unwrap());

    let mut outstanding: HashMap<RuneId, u128> = HashMap::new();

    for (_, balances) in balances {
      for (id, balance) in balances {
        *outstanding.entry(*id).or_default() += *balance;
      }
    }

    for (id, entry) in runes {
      pretty_assert_eq!(
        outstanding.get(id).copied().unwrap_or_default(),
        entry.supply() - entry.burned
      );
    }
  }

@lifofifoX
Copy link
Collaborator Author

@raphjaph Added the check. Ended up being a more involved change, but working well.

Comment on lines +200 to +209
if !tx.output[vout].script_pubkey.is_op_return() {
if let Some(sender) = self.event_sender {
sender.blocking_send(Event::RuneTransferred {
outpoint,
block_height: self.height,
txid,
rune_id: id,
amount: balance.0,
})?;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really consume this event_sender so I'm unsure if people would want sending to an OP_RETURN to be an event.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, same. I thought it'd be a good idea to keep existing behavior there. But could argue both ways.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm leaning towards yes, I'll let @casey chime in if he sees this

@raphjaph
Copy link
Collaborator

Apologies for letting this sit so long. You were on the right track but were just missing a call to make tests simpler. I've made the changes, please have a look and let me know if this looks good @lifofifoX

@lifofifoX
Copy link
Collaborator Author

@raphjaph Changes look good to me!

Copy link
Collaborator

@casey casey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always panic on unexpected errors in tests, or when we're looking something up in the index that we expect to be there. This kind of defensive programming can catch a lot of bugs.

We should definitely not change the behavior of the event sender. This is a conceptually separate change, even though it's related to OP_RETURNs. If the client is relying on getting this information, than it could be a tricky bug if they don't.

if self
.index
.get_output_script(outpoint)
.ok()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably unwrap and panic here.

for (id, entry) in runes {
pretty_assert_eq!(
outstanding.get(id).copied().unwrap_or_default(),
outstanding.get(id).copied().unwrap_or_default() - burned_balances,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add assert above which asserts that burned_balances is correct, similar to the above asserts.

balances.sort_by_key(|(outpoint, _)| *outpoint);

for (_, balances) in balances.iter_mut() {
let mut burned_balances = 0;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would just call this burned. It's not really "balances" because it's just a number. Balances so named because it's a map.

}

#[cfg(test)]
pub fn get_output_script(&self, output: &OutPoint) -> Result<ScriptBuf> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this return an error? Test functions should just panic and not return errors, since an error can be ignored and a panic cannot.

.index
.get_output_script(outpoint)
.ok()
.is_some_and(|script| script.is_op_return())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also unwrap. If we expect the output script to be in the index, it is a fatal error for it not to be, and we want to panic so we notice.

rune_id: id,
amount: balance.0,
})?;
if !tx.output[vout].script_pubkey.is_op_return() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reduces the amount of information a listener gets. This is a separate change and should be done in a separate PR.

let outpoint_to_utxo_entry = rtx.open_table(OUTPOINT_TO_UTXO_ENTRY)?;
let entry = outpoint_to_utxo_entry
.get(&output.store())?
.ok_or_else(|| anyhow!("UTXO entry not found for output: {:?}", output))?;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these panic?

} else {
self
.get_output_info(*output)?
.ok_or_else(|| anyhow!("output {output} not found"))?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these panic?

@raphjaph
Copy link
Collaborator

@lifofifoX any thoughts on the review comments?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Blocked

Development

Successfully merging this pull request may close these issues.

/r/utxo does not know about rune burns

3 participants