Skip to content

Commit

Permalink
tapdb: update InsertScriptKey to allow flipping known to true
Browse files Browse the repository at this point in the history
In this commit, we update `InsertScriptKey` to allow flipping known to
true, if it was false before.

This is useful as at times a script key from a smart contract might have
been inserting on disk, but with declared known as false. Then if we
tried to insert it again, with known as true, the upsert logic would end
up making no change on disk.
  • Loading branch information
Roasbeef committed Nov 13, 2024
1 parent d79e141 commit d453f81
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 2 deletions.
1 change: 1 addition & 0 deletions tapdb/addrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -689,6 +689,7 @@ func (t *TapAddressBook) InsertScriptKey(ctx context.Context,
return fmt.Errorf("error inserting internal key: %w",
err)
}

_, err = q.UpsertScriptKey(ctx, NewScriptKey{
InternalKeyID: internalKeyID,
TweakedScriptKey: scriptKey.PubKey.SerializeCompressed(),
Expand Down
113 changes: 113 additions & 0 deletions tapdb/addrs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package tapdb
import (
"context"
"database/sql"
"fmt"
"math/rand"
"testing"
"time"
Expand All @@ -11,9 +12,11 @@ import (
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/lndclient"
"github.com/lightninglabs/taproot-assets/address"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/internal/test"
"github.com/lightninglabs/taproot-assets/tapdb/sqlc"
"github.com/lightningnetwork/lnd/clock"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnrpc"
"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -644,3 +647,113 @@ func TestAddressEventQuery(t *testing.T) {
})
}
}

// randScriptKey makes a random script key with a tweak.
func randScriptKey(t *testing.T) asset.ScriptKey {
scriptKey := asset.RandScriptKey(t)
scriptKey.TweakedScriptKey = &asset.TweakedScriptKey{
RawKey: keychain.KeyDescriptor{
PubKey: asset.RandScriptKey(t).PubKey,
},
}

return scriptKey
}

// insertScriptKeyWithNull is a helper function that inserts a script key with a
// a NULL value for declared known. We use this so we can insert a NULL vs an
// actual value. It is identical to the InsertScriptKey.
func insertScriptKeyWithNull(ctx context.Context, key asset.ScriptKey,
) func(AddrBook) error {

return func(q AddrBook) error {
internalKeyID, err := insertInternalKey(
ctx, q, key.RawKey,
)
if err != nil {
return fmt.Errorf("error inserting internal key: %w",
err)
}

_, err = q.UpsertScriptKey(ctx, NewScriptKey{
InternalKeyID: internalKeyID,
TweakedScriptKey: key.PubKey.SerializeCompressed(),
Tweak: key.Tweak,
DeclaredKnown: sql.NullBool{
Valid: false,
},
})
return err
}
}

func assertKeyKnowledge(t *testing.T, ctx context.Context,
addrBook *TapAddressBook, scriptKey asset.ScriptKey, known bool) {

dbScriptKey, err := addrBook.FetchScriptKey(ctx, scriptKey.PubKey)
require.NoError(t, err)
require.Equal(t, known, dbScriptKey.DeclaredKnown)
}

// TestScriptKeyKnownUpsert tests that we can insert a script key, then insert
// it again declared as known.
func TestScriptKeyKnownUpsert(t *testing.T) {
t.Parallel()

// First, make a new addr book instance we'll use in the test below.
testClock := clock.NewTestClock(time.Now())
addrBook, _ := newAddrBook(t, testClock)

ctx := context.Background()

// In this test, we insert the known field as false, and make sure we
// can flip it back to true.
t.Run("false_to_true", func(t *testing.T) {
known := false
scriptKey := randScriptKey(t)

// We'll insert a random script key into the database. We won't
// declare it as known though.
err := addrBook.InsertScriptKey(ctx, scriptKey, known)
require.NoError(t, err)

// We'll fetch the script key and confirm that it's not known.
assertKeyKnowledge(t, ctx, addrBook, scriptKey, known)

known = true

// We'll now insert it again, but this time declare it as known.
err = addrBook.InsertScriptKey(ctx, scriptKey, known)
require.NoError(t, err)

// We'll fetch the script key and confirm that it's known.
assertKeyKnowledge(t, ctx, addrBook, scriptKey, known)
})

// In this test, we insert a NULL value, and make sure that it can still
// be set to true.
t.Run("null_to_true", func(t *testing.T) {
known := false
scriptKey := randScriptKey(t)

// We'll lift the internal routine of InsertScriptKey so we can
// insert an actual NULL here.
err := addrBook.db.ExecTx(
ctx, &AddrBookTxOptions{},
insertScriptKeyWithNull(ctx, scriptKey),
)
require.NoError(t, err)

// We'll fetch the script key and confirm that it's not known.
assertKeyKnowledge(t, ctx, addrBook, scriptKey, known)

known = true

// We'll now insert it again, but this time declare it as known.
err = addrBook.InsertScriptKey(ctx, scriptKey, known)
require.NoError(t, err)

// We'll fetch the script key and confirm that it's known.
assertKeyKnowledge(t, ctx, addrBook, scriptKey, known)
})
}
10 changes: 9 additions & 1 deletion tapdb/sqlc/assets.sql.go

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

10 changes: 9 additions & 1 deletion tapdb/sqlc/queries/assets.sql
Original file line number Diff line number Diff line change
Expand Up @@ -854,7 +854,15 @@ INSERT INTO script_keys (
) ON CONFLICT (tweaked_script_key)
-- As a NOP, we just set the script key to the one that triggered the
-- conflict.
DO UPDATE SET tweaked_script_key = EXCLUDED.tweaked_script_key
DO UPDATE SET
tweaked_script_key = EXCLUDED.tweaked_script_key,
-- If the script key was previously unknown, we'll update to the new
-- value.
declared_known = CASE
WHEN script_keys.declared_known IS NULL OR script_keys.declared_known = FALSE
THEN COALESCE(EXCLUDED.declared_known, script_keys.declared_known)
ELSE script_keys.declared_known
END
RETURNING script_key_id;

-- name: FetchScriptKeyIDByTweakedKey :one
Expand Down

0 comments on commit d453f81

Please sign in to comment.