Skip to content

Commit 4ed7bfe

Browse files
committed
tapdb: store namespace with universe sync config
In this commit, we fix an issue with universe sync config storage. With the old table schema, multiples entries could exist for the same Universe because the UNIQUE constraint did not function as intended. This was caused by NULL entries being treated as unique values vs. one value. The new table has one entry per Universe ID, which fixes this.
1 parent e695071 commit 4ed7bfe

File tree

7 files changed

+136
-28
lines changed

7 files changed

+136
-28
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DROP TABLE IF EXISTS federation_uni_sync_config;
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
DROP TABLE IF EXISTS federation_uni_sync_config;
2+
3+
-- This table contains universe (asset/asset group) specific federation sync
4+
-- configuration.
5+
CREATE TABLE IF NOT EXISTS federation_uni_sync_config (
6+
-- namespace is the string representation of the universe identifier, and
7+
-- ensures that there are no duplicate configs.
8+
namespace VARCHAR NOT NULL PRIMARY KEY,
9+
10+
-- This field contains the byte serialized ID of the asset to which this
11+
-- configuration is applicable.
12+
asset_id BLOB CHECK(length(asset_id) = 32) NULL,
13+
14+
-- This field contains the byte serialized compressed group key public key
15+
-- of the asset group to which this configuration is applicable.
16+
group_key BLOB CHECK(LENGTH(group_key) = 33) NULL,
17+
18+
-- This field is an enum representing the proof type stored in the given
19+
-- universe.
20+
proof_type TEXT NOT NULL CHECK(proof_type IN ('issuance', 'transfer')),
21+
22+
-- This field is a boolean that indicates whether or not the given universe
23+
-- should accept remote proof insertion via federation sync.
24+
allow_sync_insert BOOLEAN NOT NULL,
25+
26+
-- This field is a boolean that indicates whether or not the given universe
27+
-- should accept remote proof export via federation sync.
28+
allow_sync_export BOOLEAN NOT NULL,
29+
30+
-- Both the asset ID and group key cannot be null at the same time.
31+
CHECK (
32+
(asset_id IS NOT NULL AND group_key IS NULL) OR
33+
(asset_id IS NULL AND group_key IS NOT NULL)
34+
)
35+
);

tapdb/sqlc/models.go

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tapdb/sqlc/queries/universe.sql

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -327,20 +327,22 @@ ON CONFLICT(proof_type)
327327

328328
-- name: QueryFederationGlobalSyncConfigs :many
329329
SELECT proof_type, allow_sync_insert, allow_sync_export
330-
FROM federation_global_sync_config;
330+
FROM federation_global_sync_config
331+
ORDER BY proof_type;
331332

332333
-- name: UpsertFederationUniSyncConfig :exec
333334
INSERT INTO federation_uni_sync_config (
334-
asset_id, group_key, proof_type, allow_sync_insert, allow_sync_export
335+
namespace, asset_id, group_key, proof_type, allow_sync_insert, allow_sync_export
335336
)
336337
VALUES(
337-
@asset_id, @group_key, @proof_type, @allow_sync_insert, @allow_sync_export
338+
@namespace, @asset_id, @group_key, @proof_type, @allow_sync_insert, @allow_sync_export
338339
)
339-
ON CONFLICT(asset_id, group_key, proof_type)
340+
ON CONFLICT(namespace)
340341
DO UPDATE SET
341342
allow_sync_insert = @allow_sync_insert,
342343
allow_sync_export = @allow_sync_export;
343344

344345
-- name: QueryFederationUniSyncConfigs :many
345-
SELECT asset_id, group_key, proof_type, allow_sync_insert, allow_sync_export
346-
FROM federation_uni_sync_config;
346+
SELECT namespace, asset_id, group_key, proof_type, allow_sync_insert, allow_sync_export
347+
FROM federation_uni_sync_config
348+
ORDER BY group_key NULLS LAST, asset_id NULLS LAST, proof_type;

tapdb/sqlc/universe.sql.go

Lines changed: 11 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tapdb/universe_federation.go

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,8 @@ func (u *UniverseFederationDB) UpsertFederationSyncConfig(
263263
}
264264

265265
// Upsert universe specific sync configs.
266-
for i := range uniSyncConfigs {
266+
for _, config := range uniSyncConfigs {
267267
var (
268-
config = uniSyncConfigs[i]
269-
270268
uniID = config.UniverseID
271269
groupPubKey []byte
272270
assetIDBytes []byte
@@ -285,6 +283,7 @@ func (u *UniverseFederationDB) UpsertFederationSyncConfig(
285283

286284
err := db.UpsertFederationUniSyncConfig(
287285
ctx, UpsertFedUniSyncConfigParams{
286+
Namespace: uniID.String(),
288287
AssetID: assetIDBytes,
289288
GroupKey: groupPubKey,
290289
ProofType: uniID.ProofType.String(),
@@ -379,20 +378,18 @@ func (u *UniverseFederationDB) QueryFederationSyncConfigs(
379378
[]*universe.FedUniSyncConfig, len(uniDbConfigs),
380379
)
381380

382-
for i := range uniDbConfigs {
383-
conf := uniDbConfigs[i]
384-
381+
for i, config := range uniDbConfigs {
385382
proofType, err := universe.ParseStrProofType(
386-
conf.ProofType,
383+
config.ProofType,
387384
)
388385
if err != nil {
389386
return err
390387
}
391388

392389
// Construct group key public key from bytes.
393390
var pubKey *btcec.PublicKey
394-
if conf.GroupKey != nil {
395-
pubKey, err = btcec.ParsePubKey(conf.GroupKey)
391+
if config.GroupKey != nil {
392+
pubKey, err = btcec.ParsePubKey(config.GroupKey)
396393
if err != nil {
397394
return fmt.Errorf("unable to parse "+
398395
"group key: %v", err)
@@ -401,7 +398,7 @@ func (u *UniverseFederationDB) QueryFederationSyncConfigs(
401398

402399
// Construct asset ID from bytes.
403400
var assetID asset.ID
404-
copy(assetID[:], conf.AssetID)
401+
copy(assetID[:], config.AssetID)
405402

406403
uniID := universe.Identifier{
407404
AssetID: assetID,
@@ -411,8 +408,8 @@ func (u *UniverseFederationDB) QueryFederationSyncConfigs(
411408

412409
uniConfigs[i] = &universe.FedUniSyncConfig{
413410
UniverseID: uniID,
414-
AllowSyncInsert: conf.AllowSyncInsert,
415-
AllowSyncExport: conf.AllowSyncExport,
411+
AllowSyncInsert: config.AllowSyncInsert,
412+
AllowSyncExport: config.AllowSyncExport,
416413
}
417414
}
418415
return nil

tapdb/universe_federation_test.go

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
"github.com/lightninglabs/taproot-assets/fn"
11+
"github.com/lightninglabs/taproot-assets/internal/test"
1112
"github.com/lightninglabs/taproot-assets/tapdb/sqlc"
1213
"github.com/lightninglabs/taproot-assets/universe"
1314
"github.com/lightningnetwork/lnd/clock"
@@ -114,9 +115,9 @@ func TestFederationConfigDefault(t *testing.T) {
114115
require.Equal(t, defaultGlobalSyncConfigs, globalConfig)
115116
}
116117

117-
// TestFederationGlobalConfigCRUD tests that we're able to properly update the
118-
// global and local federation configs.
119-
func TestFederationGlobalConfigCRUD(t *testing.T) {
118+
// TestFederationConfigCRUD tests that we're able to properly update the global
119+
// and local federation configs.
120+
func TestFederationConfigCRUD(t *testing.T) {
120121
t.Parallel()
121122

122123
testClock := clock.NewTestClock(time.Now())
@@ -166,7 +167,7 @@ func TestFederationGlobalConfigCRUD(t *testing.T) {
166167
expectedCfgs = append(newGlobalProof, newGlobalTransfer...)
167168
require.Equal(t, expectedCfgs, dbGlobalCfg)
168169

169-
// Finally, we should be able to update them both in the same txn.
170+
// We should be able to update them both in the same txn.
170171
for _, cfg := range expectedCfgs {
171172
cfg.AllowSyncInsert = false
172173
cfg.AllowSyncExport = false
@@ -178,4 +179,70 @@ func TestFederationGlobalConfigCRUD(t *testing.T) {
178179
dbGlobalCfg, _, err = fedDB.QueryFederationSyncConfigs(ctx)
179180
require.NoError(t, err)
180181
require.Equal(t, expectedCfgs, dbGlobalCfg)
182+
183+
// Finally, if we insert the current config again, we should see no
184+
// change in the returned configs.
185+
singleCfg := fn.MakeSlice(dbGlobalCfg[0])
186+
err = fedDB.UpsertFederationSyncConfig(ctx, singleCfg, nil)
187+
require.NoError(t, err)
188+
189+
dbGlobalCfg, _, err = fedDB.QueryFederationSyncConfigs(ctx)
190+
require.NoError(t, err)
191+
require.Equal(t, expectedCfgs, dbGlobalCfg)
192+
193+
// Now, create configs for specific assets.
194+
randAssetIDBytes := test.RandBytes(32)
195+
randGroupKey := test.RandPubKey(t)
196+
groupCfg := &universe.FedUniSyncConfig{
197+
UniverseID: universe.Identifier{
198+
GroupKey: randGroupKey,
199+
ProofType: universe.ProofTypeIssuance,
200+
},
201+
AllowSyncInsert: true,
202+
AllowSyncExport: false,
203+
}
204+
assetCfg := &universe.FedUniSyncConfig{
205+
UniverseID: universe.Identifier{
206+
ProofType: universe.ProofTypeTransfer,
207+
},
208+
AllowSyncInsert: false,
209+
AllowSyncExport: true,
210+
}
211+
copy(assetCfg.UniverseID.AssetID[:], randAssetIDBytes)
212+
213+
// Before insertion, there should be no asset-specific configs.
214+
_, dbLocalCfg, err := fedDB.QueryFederationSyncConfigs(ctx)
215+
require.NoError(t, err)
216+
require.Empty(t, dbLocalCfg)
217+
218+
// Next, store the asset configs and verify that we get the same configs
219+
// back from a query.
220+
localCfg := fn.MakeSlice(groupCfg, assetCfg)
221+
err = fedDB.UpsertFederationSyncConfig(ctx, nil, localCfg)
222+
require.NoError(t, err)
223+
224+
_, dbLocalCfg, err = fedDB.QueryFederationSyncConfigs(ctx)
225+
require.NoError(t, err)
226+
require.Equal(t, localCfg, dbLocalCfg)
227+
228+
// We should be able to overwrite a stored config.
229+
groupNewCfg := &universe.FedUniSyncConfig{
230+
UniverseID: universe.Identifier{
231+
GroupKey: randGroupKey,
232+
ProofType: universe.ProofTypeIssuance,
233+
},
234+
AllowSyncInsert: true,
235+
AllowSyncExport: true,
236+
}
237+
err = fedDB.UpsertFederationSyncConfig(
238+
ctx, nil, fn.MakeSlice(groupNewCfg),
239+
)
240+
require.NoError(t, err)
241+
242+
_, dbLocalCfg, err = fedDB.QueryFederationSyncConfigs(ctx)
243+
require.NoError(t, err)
244+
require.NotEqual(t, localCfg, dbLocalCfg)
245+
246+
localCfg = fn.MakeSlice(groupNewCfg, assetCfg)
247+
require.Equal(t, localCfg, dbLocalCfg)
181248
}

0 commit comments

Comments
 (0)