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

Add ListBurns RPC #1178

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Conversation

GeorgeTsagk
Copy link
Member

Description

We're currently able to provably burn assets with tapd but we have no (easy) way of retrieving burn related historical data. This PR adds a DB table and exposes some new RPC methods/parameters to help keep track of burns.

When completing an asset burn, we add an entry to the new burns table. We also add a new ListBurns method which returns a list of all burns that pass the user-provided filters (asset id, group id, anchor txid)

Closes #1095

@coveralls
Copy link

coveralls commented Nov 7, 2024

Pull Request Test Coverage Report for Build 11816308677

Details

  • 30 of 167 (17.96%) changed or added relevant lines in 4 files are covered.
  • 28 unchanged lines in 7 files lost coverage.
  • Overall coverage decreased (-0.05%) to 40.56%

Changes Missing Coverage Covered Lines Changed/Added Lines %
tapdb/sqlc/transfers.sql.go 30 38 78.95%
rpcserver.go 0 31 0.0%
cmd/tapcli/assets.go 0 32 0.0%
tapdb/assets_store.go 0 66 0.0%
Files with Coverage Reduction New Missed Lines %
tapdb/addrs.go 2 79.04%
rpcserver.go 2 0.0%
tapchannel/aux_leaf_signer.go 2 35.92%
asset/asset.go 2 80.2%
tapgarden/caretaker.go 4 68.87%
commitment/tap.go 6 83.64%
universe/interface.go 10 51.12%
Totals Coverage Status
Change from base Build 11804776121: -0.05%
Covered Lines: 24721
Relevant Lines: 60949

💛 - Coveralls

Copy link
Member

@guggero guggero left a comment

Choose a reason for hiding this comment

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

Looks pretty good. I wonder if we should add a Golang based "migration" of sort that queries existing assets in the DB, checks if they're burns (cannot be done on SQL level alone) and then inserts them into the new table retroactively?
Perhaps we could add a mechanism that detects if any DB level migrations were executed. And if they were, we can assume an update happened and could run these Golang-level checks (which would need to be idempotent).

tapdb/assets_store.go Show resolved Hide resolved
tapdb/assets_store.go Outdated Show resolved Hide resolved
rpcserver.go Show resolved Hide resolved
rpcserver.go Show resolved Hide resolved
rpcserver.go Outdated Show resolved Hide resolved
taprpc/taprootassets.proto Show resolved Hide resolved
taprpc/taprootassets.yaml Outdated Show resolved Hide resolved
cmd/tapcli/assets.go Outdated Show resolved Hide resolved
cmd/tapcli/assets.go Outdated Show resolved Hide resolved
tapdb/sqlc/queries/transfers.sql Show resolved Hide resolved
@dstadulis dstadulis added this to the v0.5 (v0.4.2 rename) milestone Nov 11, 2024
Copy link
Member

@guggero guggero left a comment

Choose a reason for hiding this comment

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

Super close!

var writeTxOpts AssetStoreTxOptions
return a.db.ExecTx(ctx, &writeTxOpts, func(q ActiveAssetsStore) error {
// Look up the transfer that relates to this txid.
// TODO(george): We assume there's a single burn in every txn,
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we need this TODO. If there are multiple burns in a transaction, we'd call InsertBurn multiple times with the same txid. But because they would all still be in the same transfer, we'd query the same transfer ID which is correct.

Copy link
Member

Choose a reason for hiding this comment

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

^ makes sense

return fmt.Errorf("unable to query asset transfers: %w",
err)
}
assetTransfer := assetTransfers[0]
Copy link
Member

Choose a reason for hiding this comment

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

Should check that we have exactly one result (which should always be the case when we query with an anchor TX hash).

Copy link
Member

Choose a reason for hiding this comment

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

Yeah otherwise, we'll panic here.

abt.asset_id,
abt.group_key,
abt.amount,
ct.txid AS anchor_txid -- Retrieving the txid from chain_txns
Copy link
Member

Choose a reason for hiding this comment

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

nit: missing full stop, here and below.

abt.amount,
ct.txid AS anchor_txid -- Retrieving the txid from chain_txns
FROM asset_burn_transfers abt
JOIN asset_transfers at ON abt.transfer_id = at.id
Copy link
Member

Choose a reason for hiding this comment

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

Looks like we don't need to join on asset_transfers? Since we don't seem to be using at anywhere.

Copy link
Member

Choose a reason for hiding this comment

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

Perhaps the idea was to return the full transfer information alongside the burn?

From the PoV of a future query CLI, I think that would be desirable.

// Let's insert a burn.
assetID := inputAsset.ID()
transferID := assetTransfers[0].ID
_, err = assetsStore.db.InsertBurn(ctx, sqlc.InsertBurnParams{
Copy link
Member

Choose a reason for hiding this comment

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

We'll want to test the actual AssetStore's QueryBurns and InsertBurn methods, not directly call into the DB-level methods.

in *taprpc.ListBurnsRequest) (*taprpc.ListBurnsResponse, error) {

burns, err := r.cfg.AssetStore.QueryBurns(
ctx, sqlc.QueryBurnsParams{
Copy link
Member

Choose a reason for hiding this comment

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

We should use the alias tapdb.QueryBurnsFilters here.

anchorTxidStr := ctx.String(anchorTxidName)
anchorTxid, err := hex.DecodeString(anchorTxidStr)
if err != nil {
return fmt.Errorf("invalid anchor txid")
Copy link
Member

Choose a reason for hiding this comment

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

nit: missing wrapped error.

@Roasbeef Roasbeef requested review from Roasbeef and removed request for ffranr November 14, 2024 03:00
var writeTxOpts AssetStoreTxOptions
return a.db.ExecTx(ctx, &writeTxOpts, func(q ActiveAssetsStore) error {
// Look up the transfer that relates to this txid.
// TODO(george): We assume there's a single burn in every txn,
Copy link
Member

Choose a reason for hiding this comment

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

^ makes sense

return fmt.Errorf("unable to query asset transfers: %w",
err)
}
assetTransfer := assetTransfers[0]
Copy link
Member

Choose a reason for hiding this comment

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

Yeah otherwise, we'll panic here.


return nil
})

Copy link
Member

Choose a reason for hiding this comment

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

Style nit: extra space.

@@ -2204,6 +2205,44 @@ func TestTransferOutputProofDeliveryStatus(t *testing.T) {
require.Equal(
t, randBlockHash[:], assetTransfers[0].AnchorTxBlockHash,
)

// Let's insert a burn.
Copy link
Member

Choose a reason for hiding this comment

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

How about we make another isolated unit test for this? This exiting test is already rather long/large.

abt.amount,
ct.txid AS anchor_txid -- Retrieving the txid from chain_txns
FROM asset_burn_transfers abt
JOIN asset_transfers at ON abt.transfer_id = at.id
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps the idea was to return the full transfer information alongside the burn?

From the PoV of a future query CLI, I think that would be desirable.

@@ -3312,12 +3314,56 @@ func (r *rpcServer) BurnAsset(ctx context.Context,
}
}

// At this point everything completed correctly, so we log this burn in
Copy link
Member

Choose a reason for hiding this comment

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

Hmm, perhaps we should do this further in the pipeline? So in the same db transaction that we insert the transfer.

Otherwise, if we crash here, then the burn is never inserted in the db, and we exit in an inconsistent state.

rpcBurns := fn.Map(burns, marshalRpcBurn)

return &taprpc.ListBurnsResponse{
Burns: rpcBurns,
Copy link
Member

Choose a reason for hiding this comment

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

Re other comment, I think it would be useful to include the full transfer here, also maybe the raw tx itself?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: 👀 In review
Development

Successfully merging this pull request may close these issues.

tapdb - [feature]: add new associative table to track asset burns ListBurns
5 participants