Skip to content

Commit d9b57fe

Browse files
Roasbeefguggero
authored andcommitted
universe: allow FetchMultiverseLeaves to multi-query
In this commit, we modify the FetchMultiverseLeaves method to allow it to return either all the leaves, or a subset of leaves filtered by the `MultiverseLeafDesc` type. In the future, we can further extend this to use postgres batch queries so we can get the resp in a single round trip.
1 parent de3db34 commit d9b57fe

File tree

2 files changed

+180
-101
lines changed

2 files changed

+180
-101
lines changed

tapdb/multiverse.go

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,54 +1031,81 @@ func (b *MultiverseStore) DeleteUniverse(ctx context.Context,
10311031
// asset ID, and group key. If both asset ID and group key is nil, all leaves
10321032
// for the given proof type will be returned.
10331033
func (b *MultiverseStore) FetchLeaves(ctx context.Context,
1034-
assetID *asset.ID, groupKey *btcec.PublicKey,
1035-
proofType universe.ProofType) ([]universe.Identifier, error) {
1034+
universeTargets []universe.MultiverseLeafDesc,
1035+
proofType universe.ProofType) ([]universe.MultiverseLeaf, error) {
1036+
1037+
queries := make([]QueryMultiverseLeaves, 0, len(universeTargets))
1038+
switch len(universeTargets) {
1039+
// If we don't have any targets, then we'll have just a single query to
1040+
// return all universe leaves for the proof type.
1041+
case 0:
1042+
queries = append(queries, QueryMultiverseLeaves{
1043+
ProofType: proofType.String(),
1044+
})
1045+
1046+
// Otherwise, we'll do a query for each universe target specified.
1047+
default:
1048+
for _, uniTarget := range universeTargets {
1049+
var assetIDBytes, groupKeyBytes []byte
10361050

1037-
var assetIDBytes, groupKeyBytes []byte
1038-
if assetID != nil {
1039-
assetIDBytes = assetID[:]
1040-
}
1041-
if groupKey != nil {
1042-
groupKeyBytes = schnorr.SerializePubKey(groupKey)
1051+
uniTarget.WhenLeft(func(a asset.ID) {
1052+
assetIDBytes = a[:]
1053+
})
1054+
uniTarget.WhenRight(func(g btcec.PublicKey) {
1055+
groupKeyBytes = schnorr.SerializePubKey(&g)
1056+
})
1057+
1058+
queries = append(queries, QueryMultiverseLeaves{
1059+
ProofType: proofType.String(),
1060+
AssetID: assetIDBytes,
1061+
GroupKey: groupKeyBytes,
1062+
})
1063+
}
10431064
}
10441065

10451066
var (
10461067
readTx = NewBaseUniverseReadTx()
1047-
ids []universe.Identifier
1068+
leaves []universe.MultiverseLeaf
10481069
)
10491070
dbErr := b.db.ExecTx(ctx, &readTx, func(q BaseMultiverseStore) error {
1050-
leaves, err := q.QueryMultiverseLeaves(
1051-
ctx, QueryMultiverseLeaves{
1052-
ProofType: proofType.String(),
1053-
AssetID: assetIDBytes,
1054-
GroupKey: groupKeyBytes,
1055-
},
1056-
)
1057-
if err != nil {
1058-
return err
1059-
}
1071+
leaves = nil
10601072

1061-
ids = make([]universe.Identifier, len(leaves))
1062-
for i, leaf := range leaves {
1063-
ids[i].ProofType = proofType
1064-
if len(leaf.AssetID) > 0 {
1065-
copy(ids[i].AssetID[:], leaf.AssetID)
1073+
for _, query := range queries {
1074+
dbLeaves, err := q.QueryMultiverseLeaves(ctx, query)
1075+
if err != nil {
1076+
return err
10661077
}
1067-
if len(leaf.GroupKey) > 0 {
1068-
ids[i].GroupKey, err = schnorr.ParsePubKey(
1069-
leaf.GroupKey,
1070-
)
1071-
if err != nil {
1072-
return err
1078+
1079+
for _, leaf := range dbLeaves {
1080+
var id universe.Identifier
1081+
1082+
id.ProofType = proofType
1083+
if len(leaf.AssetID) > 0 {
1084+
copy(id.AssetID[:], leaf.AssetID)
10731085
}
1086+
if len(leaf.GroupKey) > 0 {
1087+
id.GroupKey, err = schnorr.ParsePubKey(
1088+
leaf.GroupKey,
1089+
)
1090+
if err != nil {
1091+
return err
1092+
}
1093+
}
1094+
1095+
leaves = append(leaves, universe.MultiverseLeaf{
1096+
ID: id,
1097+
LeafNode: mssmt.NewLeafNode(
1098+
leaf.UniverseRootHash,
1099+
uint64(leaf.UniverseRootSum),
1100+
),
1101+
})
10741102
}
10751103
}
1076-
10771104
return nil
10781105
})
10791106
if dbErr != nil {
10801107
return nil, dbErr
10811108
}
10821109

1083-
return ids, nil
1110+
return leaves, nil
10841111
}

tapdb/universe_test.go

Lines changed: 121 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -116,20 +116,22 @@ func newTestUniverseWithDb(db *BaseDB,
116116
return NewBaseUniverseTree(dbTxer, id), db
117117
}
118118

119-
func assertIDInList(t *testing.T, leaves []universe.Identifier,
119+
func assertIDInList(t *testing.T, leaves []universe.MultiverseLeaf,
120120
id universe.Identifier) {
121121

122-
require.True(t, fn.Any(leaves, func(l universe.Identifier) bool {
122+
require.True(t, fn.Any(leaves, func(l universe.MultiverseLeaf) bool {
123123
switch {
124-
case l.AssetID != asset.ID{}:
125-
return l.AssetID == id.AssetID
124+
case l.ID.AssetID != asset.ID{}:
125+
return l.ID.AssetID == id.AssetID
126126

127-
case l.GroupKey != nil:
127+
case l.ID.GroupKey != nil:
128128
if id.GroupKey == nil {
129129
return false
130130
}
131131

132-
return test.SchnorrKeysEqual(t, l.GroupKey, id.GroupKey)
132+
return test.SchnorrKeysEqual(
133+
t, l.ID.GroupKey, id.GroupKey,
134+
)
133135

134136
default:
135137
require.Fail(t, "invalid leaf")
@@ -250,12 +252,12 @@ func TestUniverseIssuanceProofs(t *testing.T) {
250252

251253
// The multiverse tree should be empty at this point.
252254
issuanceLeaves, err := multiverse.FetchLeaves(
253-
ctx, nil, nil, universe.ProofTypeIssuance,
255+
ctx, nil, universe.ProofTypeIssuance,
254256
)
255257
require.NoError(t, err)
256258
require.Len(t, issuanceLeaves, 0)
257259
transferLeaves, err := multiverse.FetchLeaves(
258-
ctx, nil, nil, universe.ProofTypeTransfer,
260+
ctx, nil, universe.ProofTypeTransfer,
259261
)
260262
require.NoError(t, err)
261263
require.Len(t, transferLeaves, 0)
@@ -337,7 +339,7 @@ func TestUniverseIssuanceProofs(t *testing.T) {
337339
// The multiverse tree should just have a single leaf, since we inserted
338340
// proofs into the same universe.
339341
multiverseLeaves, err := multiverse.FetchLeaves(
340-
ctx, nil, nil, id.ProofType,
342+
ctx, nil, id.ProofType,
341343
)
342344
require.NoError(t, err)
343345
require.Len(t, multiverseLeaves, 1)
@@ -887,10 +889,10 @@ func TestMultiverseRootSum(t *testing.T) {
887889
}
888890

889891
testCases := []testCase{
890-
// If we insert two transfers into a transfer tree, then the
891-
// sum should be the sum of the leaf values. The leaf value
892-
// here is itself the root sum of an transfer tree, or the
893-
// number of transfers in a transfer tree.
892+
// If we insert two transfers into a transfer tree, then the sum
893+
// should be the sum of the leaf values. The leaf value here is
894+
// itself the root sum of a transfer tree, or the number of
895+
// transfers in a transfer tree.
894896
{
895897
name: "transfer sum",
896898
finalSum: 4,
@@ -922,6 +924,28 @@ func TestMultiverseRootSum(t *testing.T) {
922924
},
923925
},
924926
},
927+
928+
// We also want to make sure we can insert both transfer and
929+
// issuance proofs at the same time without any conflicts.
930+
{
931+
name: "transfer and issuance sum",
932+
finalSum: 3,
933+
// By specifying this as "unspecified" we signal we want
934+
// both transfer and issuance proofs. The final sum will
935+
// therefore be the same for both trees.
936+
proofType: universe.ProofTypeUnspecified,
937+
leaves: []leaf{
938+
{
939+
sumAmt: 14,
940+
},
941+
{
942+
sumAmt: 20,
943+
},
944+
{
945+
sumAmt: 20,
946+
},
947+
},
948+
},
925949
}
926950

927951
runTestCase := func(t *testing.T, tc testCase) {
@@ -931,88 +955,116 @@ func TestMultiverseRootSum(t *testing.T) {
931955

932956
// The multiverse tree should be empty at this point.
933957
issuanceLeaves, err := multiverse.FetchLeaves(
934-
ctx, nil, nil, universe.ProofTypeIssuance,
958+
ctx, nil, universe.ProofTypeIssuance,
935959
)
936960
require.NoError(t, err)
937961
require.Len(t, issuanceLeaves, 0)
938962
transferLeaves, err := multiverse.FetchLeaves(
939-
ctx, nil, nil, universe.ProofTypeTransfer,
963+
ctx, nil, universe.ProofTypeTransfer,
940964
)
941965
require.NoError(t, err)
942966
require.Len(t, transferLeaves, 0)
943967

944-
leaves := make([]universe.Leaf, len(tc.leaves))
945-
ids := make([]universe.Identifier, len(tc.leaves))
946-
for i, testLeaf := range tc.leaves {
947-
id := randUniverseID(
948-
t, false, withProofType(tc.proofType),
949-
)
950-
951-
ids[i] = id
968+
ids := make([]universe.Identifier, 0, len(tc.leaves))
969+
for range tc.leaves {
970+
ids = append(ids, randUniverseID(t, false))
971+
}
952972

953-
assetGen := asset.RandGenesis(t, asset.Normal)
954-
leaf := randMintingLeaf(t, assetGen, id.GroupKey)
955-
leaf.Amt = testLeaf.sumAmt
973+
insertLeaves := func(proofType universe.ProofType) {
974+
for i, testLeaf := range tc.leaves {
975+
id := ids[i]
976+
id.ProofType = proofType
956977

957-
leaves[i] = leaf
978+
assetGen := asset.RandGenesis(t, asset.Normal)
979+
leaf := randMintingLeaf(
980+
t, assetGen, id.GroupKey,
981+
)
982+
leaf.Amt = testLeaf.sumAmt
958983

959-
targetKey := randLeafKey(t)
984+
targetKey := randLeafKey(t)
960985

961-
// For transfer proofs, we'll modify the witness asset
962-
// proof to look more like a transfer.
963-
if tc.proofType == universe.ProofTypeTransfer {
964-
prevWitnesses := leaf.Asset.PrevWitnesses
965-
prevWitnesses[0].TxWitness = [][]byte{
966-
{1}, {1}, {1},
986+
// For transfer proofs, we'll modify the witness
987+
// asset proof to look more like a transfer.
988+
if proofType == universe.ProofTypeTransfer {
989+
prevWitnesses := leaf.Asset.PrevWitnesses
990+
prevWitnesses[0].TxWitness = [][]byte{
991+
{1}, {1}, {1},
992+
}
993+
prevID := prevWitnesses[0].PrevID
994+
prevID.OutPoint.Hash = [32]byte{1}
967995
}
968-
prevWitnesses[0].PrevID.OutPoint.Hash = [32]byte{1}
969-
}
970-
971-
_, err := multiverse.UpsertProofLeaf(
972-
ctx, id, targetKey, &leaf, nil,
973-
)
974-
require.NoError(t, err)
975-
976-
// If we should add more than one under this ID, then
977-
// we'll generate another instance.
978-
if tc.doubleUp {
979-
targetKey = randLeafKey(t)
980996

981997
_, err := multiverse.UpsertProofLeaf(
982998
ctx, id, targetKey, &leaf, nil,
983999
)
9841000
require.NoError(t, err)
1001+
1002+
// If we should add more than one under this ID,
1003+
// then we'll generate another instance.
1004+
if tc.doubleUp {
1005+
targetKey = randLeafKey(t)
1006+
1007+
_, err := multiverse.UpsertProofLeaf(
1008+
ctx, id, targetKey, &leaf, nil,
1009+
)
1010+
require.NoError(t, err)
1011+
}
1012+
1013+
// The multiverse tree should now have one more
1014+
// leaf.
1015+
multiverseLeaves, err := multiverse.FetchLeaves(
1016+
ctx, nil, proofType,
1017+
)
1018+
require.NoError(t, err)
1019+
require.Len(t, multiverseLeaves, i+1)
1020+
1021+
// And we should actually find the leaf we just
1022+
// inserted.
1023+
assertIDInList(t, multiverseLeaves, id)
9851024
}
1025+
}
9861026

987-
// The multiverse tree should now have one more leaf.
988-
multiverseLeaves, err := multiverse.FetchLeaves(
989-
ctx, nil, nil, tc.proofType,
1027+
checkSum := func(proofType universe.ProofType) {
1028+
rootNode, err := multiverse.MultiverseRootNode(
1029+
ctx, proofType,
9901030
)
9911031
require.NoError(t, err)
992-
require.Len(t, multiverseLeaves, i+1)
9931032

994-
// And we should actually find the leaf we just
995-
// inserted.
996-
assertIDInList(t, multiverseLeaves, id)
997-
}
998-
999-
// If we fetch the root value of the tree, it should be
1000-
// the same as the finalSum.
1001-
rootNode, err := multiverse.RootNode(ctx, tc.proofType)
1002-
require.NoError(t, err)
1033+
rootNode.WhenSome(
1034+
func(rootNode universe.MultiverseRoot) {
1035+
require.EqualValues(
1036+
t, tc.finalSum,
1037+
rootNode.NodeSum(),
1038+
)
1039+
},
1040+
)
10031041

1004-
require.EqualValues(t, tc.finalSum, rootNode.NodeSum())
1042+
// We now delete the whole universe and expect the
1043+
// multiverse leave to also disappear.
1044+
id := ids[0]
1045+
id.ProofType = proofType
1046+
_, err = multiverse.DeleteUniverse(ctx, id)
1047+
require.NoError(t, err)
10051048

1006-
// We now delete the whole universe and expect the multiverse
1007-
// leave to also disappear.
1008-
_, err = multiverse.DeleteUniverse(ctx, ids[0])
1009-
require.NoError(t, err)
1049+
multiverseLeaves, err := multiverse.FetchLeaves(
1050+
ctx, nil, proofType,
1051+
)
1052+
require.NoError(t, err)
1053+
require.Len(t, multiverseLeaves, len(ids)-1)
1054+
}
10101055

1011-
multiverseLeaves, err := multiverse.FetchLeaves(
1012-
ctx, nil, nil, tc.proofType,
1013-
)
1014-
require.NoError(t, err)
1015-
require.Len(t, multiverseLeaves, len(ids)-1)
1056+
// If we fetch the root value of the tree, it should be the same
1057+
// as the finalSum.
1058+
if tc.proofType == universe.ProofTypeUnspecified {
1059+
insertLeaves(universe.ProofTypeIssuance)
1060+
insertLeaves(universe.ProofTypeTransfer)
1061+
1062+
checkSum(universe.ProofTypeIssuance)
1063+
checkSum(universe.ProofTypeTransfer)
1064+
} else {
1065+
insertLeaves(tc.proofType)
1066+
checkSum(tc.proofType)
1067+
}
10161068
}
10171069

10181070
for _, testCase := range testCases {

0 commit comments

Comments
 (0)