Skip to content

universe+tapdb: add new block_height field to universe_leaves use that to implement block height based supply tree queries #1596

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

Open
wants to merge 6 commits into
base: supply-commit-machine
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion tapdb/burn_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,17 @@ func insertBurnsInternal(ctx context.Context, db BaseUniverseStore,
IsBurn: true,
}

var blockHeight lfn.Option[uint32]
height := burnLeaf.BurnProof.BlockHeight
if height > 0 {
blockHeight = lfn.Some(height)
}

// Call the generic upsert function for the burn sub-tree to
// update DB records. MetaReveal is nil for burns.
_, err = universeUpsertProofLeaf(
ctx, db, subNs, supplycommit.BurnTreeType.String(),
groupKey, leafKey, leaf, nil,
groupKey, leafKey, leaf, nil, blockHeight,
)
if err != nil {
return nil, fmt.Errorf("unable to upsert burn "+
Expand Down
16 changes: 16 additions & 0 deletions tapdb/ignore_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,21 @@ func addTuplesInternal(ctx context.Context, db BaseUniverseStore,
"universe root: %w", err)
}

var blockHeight lfn.Option[uint32]
height := tup.IgnoreTuple.Val.BlockHeight
if height > 0 {
blockHeight = lfn.Some(height)
}

sqlBlockHeight := lfn.MapOptionZ(
blockHeight, func(num uint32) sql.NullInt32 {
return sql.NullInt32{
Int32: int32(num),
Valid: true,
}
},
)

scriptKey := ignoreTup.ScriptKey
err = db.UpsertUniverseLeaf(ctx, UpsertUniverseLeaf{
AssetGenesisID: assetGenID,
Expand All @@ -121,6 +136,7 @@ func addTuplesInternal(ctx context.Context, db BaseUniverseStore,
LeafNodeKey: smtKey[:],
LeafNodeNamespace: namespace,
MintingPoint: ignorePointBytes,
BlockHeight: sqlBlockHeight,
})
if err != nil {
return nil, fmt.Errorf("failed to upsert ignore "+
Expand Down
2 changes: 1 addition & 1 deletion tapdb/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ const (
// daemon.
//
// NOTE: This MUST be updated when a new migration is added.
LatestMigrationVersion = 39
LatestMigrationVersion = 40
)

// DatabaseBackend is an interface that contains all methods our different
Expand Down
22 changes: 18 additions & 4 deletions tapdb/multiverse.go
Original file line number Diff line number Diff line change
Expand Up @@ -776,11 +776,16 @@ func (b *MultiverseStore) UpsertProofLeaf(ctx context.Context,

execTxFunc := func(dbTx BaseMultiverseStore) error {
// Register issuance in the asset (group) specific universe
// tree.
var err error
// tree. We don't need to decode the whole proof, we just
// need the block height.
blockHeight, err := SparseDecodeBlockHeight(leaf.RawProof)
if err != nil {
return err
}

uniProof, err = universeUpsertProofLeaf(
ctx, dbTx, id.String(), id.ProofType.String(),
id.GroupKey, key, leaf, metaReveal,
id.GroupKey, key, leaf, metaReveal, blockHeight,
)
if err != nil {
return fmt.Errorf("failed universe upsert: %w", err)
Expand Down Expand Up @@ -847,13 +852,22 @@ func (b *MultiverseStore) UpsertProofLeafBatch(ctx context.Context,
for idx := range items {
item := items[idx]

// We don't need to decode the whole proof, we
// just need the block height.
blockHeight, err := SparseDecodeBlockHeight(
item.Leaf.RawProof,
)
if err != nil {
return err
}

// Upsert into the specific universe tree to
// start with.
uniProof, err := universeUpsertProofLeaf(
ctx, store, item.ID.String(),
item.ID.ProofType.String(),
item.ID.GroupKey, item.Key, item.Leaf,
item.MetaReveal,
item.MetaReveal, blockHeight,
)
if err != nil {
return fmt.Errorf("failed universe "+
Expand Down
1 change: 1 addition & 0 deletions tapdb/sqlc/migrations/000040_universe_leaf_height.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE universe_leaves DROP COLUMN block_height;
1 change: 1 addition & 0 deletions tapdb/sqlc/migrations/000040_universe_leaf_height.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE universe_leaves ADD COLUMN block_height INTEGER;
1 change: 1 addition & 0 deletions tapdb/sqlc/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tapdb/sqlc/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions tapdb/sqlc/queries/supply_tree.sql
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@ JOIN universe_supply_roots r
WHERE r.id = @supply_root_id AND
(l.sub_tree_type = sqlc.narg('sub_tree_type') OR sqlc.narg('sub_tree_type') IS NULL);

-- name: QuerySupplyLeavesByHeight :many
SELECT
leaves.script_key_bytes,
gen.gen_asset_id,
nodes.value AS supply_leaf_bytes,
nodes.sum AS sum_amt,
gen.asset_id,
leaves.block_height
FROM universe_leaves AS leaves
JOIN mssmt_nodes AS nodes
ON leaves.leaf_node_key = nodes.key
AND leaves.leaf_node_namespace = nodes.namespace
JOIN genesis_info_view AS gen
ON leaves.asset_genesis_id = gen.gen_asset_id
WHERE
leaves.leaf_node_namespace = @namespace AND
(leaves.block_height >= sqlc.narg('start_height') OR sqlc.narg('start_height') IS NULL) AND
(leaves.block_height <= sqlc.narg('end_height') OR sqlc.narg('end_height') IS NULL);

-- name: DeleteUniverseSupplyLeaves :exec
DELETE FROM universe_supply_leaves
WHERE supply_root_id = (
Expand Down
9 changes: 5 additions & 4 deletions tapdb/sqlc/queries/universe.sql
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,18 @@ WHERE namespace_root = @namespace_root;

-- name: UpsertUniverseLeaf :exec
INSERT INTO universe_leaves (
asset_genesis_id, script_key_bytes, universe_root_id, leaf_node_key,
leaf_node_namespace, minting_point
asset_genesis_id, script_key_bytes, universe_root_id, leaf_node_key,
leaf_node_namespace, minting_point, block_height
) VALUES (
@asset_genesis_id, @script_key_bytes, @universe_root_id, @leaf_node_key,
@leaf_node_namespace, @minting_point
@leaf_node_namespace, @minting_point, @block_height
) ON CONFLICT (minting_point, script_key_bytes, leaf_node_namespace)
-- This is a NOP, minting_point and script_key_bytes are the unique fields
-- that caused the conflict.
DO UPDATE SET minting_point = EXCLUDED.minting_point,
script_key_bytes = EXCLUDED.script_key_bytes,
leaf_node_namespace = EXCLUDED.leaf_node_namespace;
leaf_node_namespace = EXCLUDED.leaf_node_namespace,
block_height = EXCLUDED.block_height;

-- name: DeleteUniverseLeaves :exec
DELETE FROM universe_leaves
Expand Down
2 changes: 1 addition & 1 deletion tapdb/sqlc/schemas/generated_schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -899,7 +899,7 @@ CREATE TABLE "universe_leaves" (
universe_root_id BIGINT NOT NULL REFERENCES universe_roots(id),
leaf_node_key BLOB,
leaf_node_namespace VARCHAR NOT NULL
);
, block_height INTEGER);

CREATE INDEX universe_leaves_key_idx ON universe_leaves(leaf_node_key);

Expand Down
65 changes: 65 additions & 0 deletions tapdb/sqlc/supply_tree.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 9 additions & 5 deletions tapdb/sqlc/universe.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions tapdb/sqlutils.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tapdb

import (
"bytes"
"context"
"database/sql"
"encoding/binary"
Expand All @@ -14,7 +15,9 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/internal/test"
"github.com/lightninglabs/taproot-assets/proof"
"github.com/lightninglabs/taproot-assets/tapdb/sqlc"
lfn "github.com/lightningnetwork/lnd/fn/v2"
"github.com/stretchr/testify/require"
"golang.org/x/exp/constraints"
)
Expand Down Expand Up @@ -94,6 +97,25 @@ func sqlStr(s string) sql.NullString {
}
}

// SparseDecodeBlockHeight sparse decodes a proof to extract the block height.
func SparseDecodeBlockHeight(rawProof []byte) (lfn.Option[uint32], error) {
var blockHeightVal uint32
err := proof.SparseDecode(
bytes.NewReader(rawProof),
proof.BlockHeightRecord(&blockHeightVal),
)
if err != nil {
return lfn.None[uint32](), fmt.Errorf("unable to "+
"sparse decode proof: %w", err)
}

if blockHeightVal == 0 {
return lfn.None[uint32](), nil
}

return lfn.Some(blockHeightVal), nil
}

// extractSqlInt64 turns a NullInt64 into a numerical type. This can be useful
// when reading directly from the database, as this function handles extracting
// the inner value from the "option"-like struct.
Expand Down
Loading
Loading