Page MenuHomePhabricator

[Chronik] Add `VerifyContext`, `verify` and `TokenTx` to bitcoinsuite-slp
ClosedPublic

Authored by tobias_ruck on Dec 28 2023, 17:47.

Details

Summary
  1. Add TokenTx and TokenTxEntry to represent a verified tx.
  2. Add VerifyContext with a verify method to verify a ColoredTx. The context bundles all the data required to verify txs.
  3. Add a few common helper consts and functions to simplify tests.
  4. Add a boatload of test_verify_* tests to test all kinds of scenarios.

There is one panic in VerifyContext (instead of returning a Result) to simplify the code; it indicates the context has been used incorrectly, which is usually a good application for panics.

Test Plan

cargo test -p bitcoinsuite-slp

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

Fabien requested changes to this revision.Jan 2 2024, 11:11

Most of the comments below come from the fact that is_total_burn is not really a proper name. It's an invalidity indicator that would turn the tx into a burn.

chronik/bitcoinsuite-slp/src/token_tx.rs
55 ↗(On Diff #43788)

How can this overflow the 64 bits in a single TokenTxEntry ?

chronik/bitcoinsuite-slp/src/verify.rs
209 ↗(On Diff #43788)

nit: under these defaults it's a total burn

224 ↗(On Diff #43788)

Maybe you should not rely on the template default and override all the relevant parts that are not already extracted from the section itself, e.g. here setting actual_burn_amount to input_sum as well (even if it's the template default).

246 ↗(On Diff #43788)

dito

254 ↗(On Diff #43788)

I don't think a valid genesis is burning all the inputs :)
Maybe the default should be zero, might be less confusing than relying on the boolean only and have conflicting info from both fields

300 ↗(On Diff #43788)

Since you can have 0 amount outputs, the burn amount might be equal to the input amount. Should you set the flag in this case ?

305 ↗(On Diff #43788)

Same as genesis

390 ↗(On Diff #43788)

Can the continue actually happen under normal circumstances ?

393 ↗(On Diff #43788)

Maybe comment that validation of the presence of NFT1 GROUP is already done at this stage and is_total_burn is set if that verification failed

This revision now requires changes to proceed.Jan 2 2024, 11:11
chronik/bitcoinsuite-slp/src/token_tx.rs
55 ↗(On Diff #43788)

A TokenTxEntry is for one type/kind of token in a tx (maybe a name change makes sense?), so two SLP inputs set to 0xffffffffffffffff would already overflow

chronik/bitcoinsuite-slp/src/verify.rs
209 ↗(On Diff #43788)

Good point; "total burn" here implies that the rules have been broken and all input tokens are burned unconditionally.

What do you think about renaming it to is_invalid? That way it's clearer that the meaning is that the section doesn't contribute to the tx

224 ↗(On Diff #43788)

Yes, I think setting the default template to zero-ish values and then overriding them would make it a bit more readable. I don't think any other field than actual_burn_amount should be set differently though, as the rest kind of forwards the fields from the coloring

254 ↗(On Diff #43788)

Yes; a GENESIS can't ever have a token burn (because the token can't exist before it comes into existence), so using a 0 default accomplishes the same thing and is a bit more readable.

300 ↗(On Diff #43788)

Maybe, but the flag's intention is to later remove all outputs and set them to None.

305 ↗(On Diff #43788)

Yes, and here too the burn amount will always be 0 anyway as we can't calculate the amounts sent for unknown tokens.

390 ↗(On Diff #43788)

Yes, absolutely, there can be XEC-only inputs, which will have None as the spent_tokens.

393 ↗(On Diff #43788)

Yes, good point. Renaming is_total_burn might also help

bytesofman added inline comments.
chronik/bitcoinsuite-slp/src/structs.rs
153 ↗(On Diff #43788)

does it make sense to organize SLP and ALP under the same GenesisInfo?

we might expect different token standards to diverge, use different names, different structs, etc.

i'm not familiar on what kind of duplications starting a distinct bitcoinsuite-alp would entail. Does though seem almost like a happy coincidence that both protocols have a GenesisInfo which is kinda sorta the same but not totally.

If it is best to have all the token parsing in one place -- e.g. we want to test various token txs and make sure they are not confused for one another -- mb it should be bitcoinsuite-tokens instead of bitcoinsuite-slp

chronik/bitcoinsuite-slp/src/structs.rs
153 ↗(On Diff #43788)

I was thinking about doing an enum for the GenesisInfo, but then we'd have 3 different variants: one for SLP V1+NFT1, one for Mint Vault and one for ALP.

In the end, it's easier to just use one type where some fields are set and others are None.

Agree on the bitcoinsuite-token; the name was set a bunch of months ago before ALP even had its own name.

One thing that might be worth discussing (now that you bring it up) is how we store the GenesisInfo in the DB. Right now it's encoded using postcard, so we have to be extra careful when changing GenesisInfo, because adding a field could garble all existing GenesisInfo.

There's three ways we could do it IMO:

  1. No change: Just store the GenesisInfo and hope we don't need to update, if we do, just add a few tests making sure we don't garble anything. Maybe add a test already to make sure that is possible (e.g. adding a new field at the end)
  2. enum: Store an enum in the DB (either by chaning GenesisInfo to an enum or by simply adding a 1 variant DbGenesisInfo which we can later add a new variant to)
  3. protobuf: Store the GenesisInfo in a protobuf encoded byte string, this way we can add and remove fields pretty freely since protobuf is optimized for this exact usecase. We'd have to add a new proto file and build it in chronik-db, similar to chronik-proto, or just add it to chronik-proto and export there.

This is probably more of a question for @Fabien

chronik/bitcoinsuite-slp/src/structs.rs
153 ↗(On Diff #43788)

mb it should be bitcoinsuite-tokens instead of bitcoinsuite-slp

100%, though it should be another diff

Does though seem almost like a happy coincidence that both protocols have a GenesisInfo which is kinda sorta the same but not totally.

In general I would agree, but in this case it's not a happy coincidence. Both SLPv2 and ALP are SLP inheritants, so they are designed to be mostly similar and make the transition easier.
Looking at the structure the differences are very limited and imo using the same structure is the most simple and efficient solution for this special case.

we might expect different token standards to diverge, use different names, different structs, etc.

I'm expecting at least one out of the 3 standards to get deprecated before this happen to be problematic. Also I'd rather avoid adding more complicated code to fix a problem that doesn't exist (yet). Worst case the cost is a reindex.

So I prefer solution 1.

rename is_total_burn -> is_invalid, change template to something more intuitive, add comments to NFT1 GROUP bare burn check

The build failed due to an unexpected infrastructure outage. The administrators have been notified to investigate. Sorry for the inconvenience.
This revision is now accepted and ready to land.Jan 4 2024, 21:03