Skip to content

Commit

Permalink
Merge pull request lightninglabs#765 from lightninglabs/tap-channels-…
Browse files Browse the repository at this point in the history
…prep-1

[tap channels preparation 1/?]: Add QueryInternalKey and QueryScriptKey RPCs, pre-fill script key info in vPSBT
  • Loading branch information
Roasbeef authored Jan 30, 2024
2 parents cd916e7 + 3e7d61d commit eb3ed93
Show file tree
Hide file tree
Showing 22 changed files with 1,304 additions and 170 deletions.
4 changes: 4 additions & 0 deletions address/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ var (
// the local database.
ErrScriptKeyNotFound = errors.New("script key not found")

// ErrInternalKeyNotFound is returned when an internal key is not found
// in the local database.
ErrInternalKeyNotFound = errors.New("internal key not found")

// ErrUnknownVersion is returned when encountering an address with an
// unrecognised version number.
ErrUnknownVersion = errors.New("address: unknown version number")
Expand Down
34 changes: 29 additions & 5 deletions asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -426,8 +426,10 @@ func (w *Witness) Decode(r io.Reader) error {
return stream.Decode(r)
}

// DeepEqual returns true if this witness is equal with the given witness.
func (w *Witness) DeepEqual(o *Witness) bool {
// DeepEqual returns true if this witness is equal with the given witness. If
// the skipTxWitness boolean is set, the TxWitness field of the Witness is not
// compared.
func (w *Witness) DeepEqual(skipTxWitness bool, o *Witness) bool {
if w == nil || o == nil {
return w == o
}
Expand All @@ -436,11 +438,17 @@ func (w *Witness) DeepEqual(o *Witness) bool {
return false
}

if !reflect.DeepEqual(w.TxWitness, o.TxWitness) {
if !w.SplitCommitment.DeepEqual(o.SplitCommitment) {
return false
}

return w.SplitCommitment.DeepEqual(o.SplitCommitment)
// If we're not comparing the TxWitness, we're done. This might be
// useful when comparing witnesses of segregated witness version assets.
if skipTxWitness {
return true
}

return reflect.DeepEqual(w.TxWitness, o.TxWitness)
}

// ScriptVersion denotes the asset script versioning scheme.
Expand Down Expand Up @@ -1398,6 +1406,20 @@ func (a *Asset) Copy() *Asset {

// DeepEqual returns true if this asset is equal with the given asset.
func (a *Asset) DeepEqual(o *Asset) bool {
return a.deepEqual(false, o)
}

// DeepEqualAllowSegWitIgnoreTxWitness returns true if this asset is equal with
// the given asset, ignoring the TxWitness field of the Witness if the asset
// version is v1.
func (a *Asset) DeepEqualAllowSegWitIgnoreTxWitness(o *Asset) bool {
return a.deepEqual(true, o)
}

// deepEqual returns true if this asset is equal with the given asset. The
// allowSegWitIgnoreTxWitness flag is used to determine whether the TxWitness
// field of the Witness should be ignored if the asset version is v1.
func (a *Asset) deepEqual(allowSegWitIgnoreTxWitness bool, o *Asset) bool {
if a.Version != o.Version {
return false
}
Expand Down Expand Up @@ -1437,7 +1459,9 @@ func (a *Asset) DeepEqual(o *Asset) bool {
}

for i := range a.PrevWitnesses {
if !a.PrevWitnesses[i].DeepEqual(&o.PrevWitnesses[i]) {
oPrevWitness := &o.PrevWitnesses[i]
skipTxWitness := a.Version == V1 && allowSegWitIgnoreTxWitness
if !a.PrevWitnesses[i].DeepEqual(skipTxWitness, oPrevWitness) {
return false
}
}
Expand Down
58 changes: 52 additions & 6 deletions itest/assertions.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/proof"
"github.com/lightninglabs/taproot-assets/taprpc"
wrpc "github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
"github.com/lightninglabs/taproot-assets/taprpc/tapdevrpc"
unirpc "github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightninglabs/taproot-assets/universe"
"github.com/lightningnetwork/lnd/lnrpc/chainrpc"
Expand All @@ -36,6 +38,16 @@ var (
statusCompleted = taprpc.AddrEventStatus_ADDR_EVENT_STATUS_COMPLETED
)

// tapClient is an interface that covers all currently available RPC interfaces
// a client should implement.
type tapClient interface {
taprpc.TaprootAssetsClient
wrpc.AssetWalletClient
tapdevrpc.TapDevClient
mintrpc.MintClient
unirpc.UniverseClient
}

// AssetCheck is a function type that checks an RPC asset's property.
type AssetCheck func(a *taprpc.Asset) error

Expand Down Expand Up @@ -593,7 +605,7 @@ func VerifyProofBlob(t *testing.T, tapClient taprpc.TaprootAssetsClient,

// AssertAddrCreated makes sure an address was created correctly for the given
// asset.
func AssertAddrCreated(t *testing.T, client taprpc.TaprootAssetsClient,
func AssertAddrCreated(t *testing.T, client tapClient,
expected *taprpc.Asset, actual *taprpc.Addr) {

// Was the address created correctly?
Expand Down Expand Up @@ -631,6 +643,43 @@ func AssertAddrCreated(t *testing.T, client taprpc.TaprootAssetsClient,

// Does the address in the list contain all information we expect?
AssertAddr(t, expected, rpcAddr)

// We also make sure we can query the script and internal keys of the
// address correctly.
scriptKeyResp, err := client.QueryScriptKey(
ctxt, &wrpc.QueryScriptKeyRequest{
TweakedScriptKey: actual.ScriptKey,
},
)
require.NoError(t, err)
require.NotNil(t, scriptKeyResp.ScriptKey)
require.NotNil(t, scriptKeyResp.ScriptKey.KeyDesc)
require.NotNil(t, scriptKeyResp.ScriptKey.KeyDesc.KeyLoc)
require.EqualValues(
t, asset.TaprootAssetsKeyFamily,
scriptKeyResp.ScriptKey.KeyDesc.KeyLoc.KeyFamily,
)
require.NotEqual(
t, scriptKeyResp.ScriptKey.PubKey,
scriptKeyResp.ScriptKey.KeyDesc.RawKeyBytes,
)

internalKeyResp, err := client.QueryInternalKey(
ctxt, &wrpc.QueryInternalKeyRequest{
InternalKey: actual.InternalKey,
},
)
require.NoError(t, err)
require.NotNil(t, internalKeyResp.InternalKey)
require.NotNil(t, internalKeyResp.InternalKey.KeyLoc)
require.EqualValues(
t, asset.TaprootAssetsKeyFamily,
internalKeyResp.InternalKey.KeyLoc.KeyFamily,
)
require.Equal(
t, actual.InternalKey,
internalKeyResp.InternalKey.RawKeyBytes,
)
}

// AssertAddrEvent makes sure the given address was detected by the given
Expand Down Expand Up @@ -850,11 +899,8 @@ func AssertAddr(t *testing.T, expected *taprpc.Asset, actual *taprpc.Addr) {
if expected.AssetGroup == nil {
require.Nil(t, actual.GroupKey)
} else {
// TODO(guggero): Address 33-byte vs. 32-byte issue in encoded
// address vs. database.
require.Equal(
t, expected.AssetGroup.TweakedGroupKey[1:],
actual.GroupKey[1:],
t, expected.AssetGroup.TweakedGroupKey, actual.GroupKey,
)
}

Expand All @@ -863,7 +909,7 @@ func AssertAddr(t *testing.T, expected *taprpc.Asset, actual *taprpc.Addr) {
require.NotEqual(t, expected.ScriptKey, actual.ScriptKey)
}

// assertEqualAsset asserts that two taprpc.Asset objects are equal, ignoring
// AssertAsset asserts that two taprpc.Asset objects are equal, ignoring
// node-specific fields like if script keys are local, if the asset is spent,
// or if the anchor information is populated.
func AssertAsset(t *testing.T, expected, actual *taprpc.Asset) {
Expand Down
16 changes: 10 additions & 6 deletions itest/loadtest/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/lightninglabs/taproot-assets/taprpc"
"github.com/lightninglabs/taproot-assets/taprpc/assetwalletrpc"
"github.com/lightninglabs/taproot-assets/taprpc/mintrpc"
"github.com/lightninglabs/taproot-assets/taprpc/tapdevrpc"
"github.com/lightninglabs/taproot-assets/taprpc/universerpc"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/stretchr/testify/require"
Expand All @@ -34,9 +35,10 @@ var (
type rpcClient struct {
cfg *TapConfig
taprpc.TaprootAssetsClient
universerpc.UniverseClient
mintrpc.MintClient
assetwalletrpc.AssetWalletClient
tapdevrpc.TapDevClient
mintrpc.MintClient
universerpc.UniverseClient
}

// assetIDWithBalance returns the asset ID of an asset that has at least the
Expand Down Expand Up @@ -166,16 +168,18 @@ func getTapClient(t *testing.T, ctx context.Context,
require.NoError(t, err)

assetsClient := taprpc.NewTaprootAssetsClient(conn)
universeClient := universerpc.NewUniverseClient(conn)
mintMintClient := mintrpc.NewMintClient(conn)
assetWalletClient := assetwalletrpc.NewAssetWalletClient(conn)
devClient := tapdevrpc.NewTapDevClient(conn)
mintMintClient := mintrpc.NewMintClient(conn)
universeClient := universerpc.NewUniverseClient(conn)

client := &rpcClient{
cfg: cfg,
TaprootAssetsClient: assetsClient,
UniverseClient: universeClient,
MintClient: mintMintClient,
AssetWalletClient: assetWalletClient,
TapDevClient: devClient,
MintClient: mintMintClient,
UniverseClient: universeClient,
}

t.Cleanup(func() {
Expand Down
8 changes: 8 additions & 0 deletions perms/perms.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ var (
Entity: "assets",
Action: "write",
}},
"/assetwalletrpc.AssetWallet/QueryInternalKey": {{
Entity: "assets",
Action: "read",
}},
"/assetwalletrpc.AssetWallet/QueryScriptKey": {{
Entity: "assets",
Action: "read",
}},
"/assetwalletrpc.AssetWallet/ProveAssetOwnership": {{
Entity: "assets",
Action: "write",
Expand Down
8 changes: 7 additions & 1 deletion proof/append.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,13 @@ func CreateTransitionProof(prevOut wire.OutPoint,
}

// Make sure the committed asset matches the root asset exactly.
if !committedRoot.DeepEqual(rootAsset) {
// We allow the TxWitness to mismatch for assets with version 1
// as they would not include the witness when the proof is
// created.
if !committedRoot.DeepEqualAllowSegWitIgnoreTxWitness(
rootAsset,
) {

return nil, fmt.Errorf("root asset mismatch")
}

Expand Down
Loading

0 comments on commit eb3ed93

Please sign in to comment.