@@ -108,6 +108,50 @@ const (
108108 EncodeSegwit
109109)
110110
111+ // ScriptKeyType denotes the type of script key used for an asset. This type is
112+ // serialized to the database, so we don't use iota for the values to ensure
113+ // they don't change by accident.
114+ type ScriptKeyType uint8
115+
116+ const (
117+ // ScriptKeyUnknown is the default script key type used for assets that
118+ // we don't know the type of. This should only be stored for assets
119+ // where we don't know the internal key of the script key (e.g. for
120+ // imported proofs).
121+ ScriptKeyUnknown ScriptKeyType = 0
122+
123+ // ScriptKeyBip86 is the script key type used for assets that use the
124+ // BIP86 style tweak (e.g. an empty tweak).
125+ ScriptKeyBip86 ScriptKeyType = 1
126+
127+ // ScriptKeyScriptPathExternal is the script key type used for assets
128+ // that use a script path that is defined by an external application.
129+ // Keys with script paths are normally not shown in asset balances and
130+ // by default aren't used for coin selection unless specifically
131+ // requested.
132+ ScriptKeyScriptPathExternal ScriptKeyType = 2
133+
134+ // ScriptKeyBurn is the script key type used for assets that are burned
135+ // and not spendable.
136+ ScriptKeyBurn ScriptKeyType = 3
137+
138+ // ScriptKeyTombstone is the script key type used for assets that are
139+ // not spendable and have been marked as tombstones. This is only the
140+ // case for zero-value assets that result from a non-interactive (TAP
141+ // address) send where no change was left over. The script key used for
142+ // this is a NUMS key that is not spendable.
143+ ScriptKeyTombstone ScriptKeyType = 4
144+
145+ // ScriptKeyScriptPathChannel is the script key type used for assets
146+ // that use a script path that is somehow related to Taproot Asset
147+ // Channels. That means the script key is either a funding key
148+ // (OP_TRUE), a commitment output key (to_local, to_remote, htlc), or a
149+ // HTLC second-level transaction output key.
150+ // Keys related to channels are not shown in asset balances (unless
151+ // specifically requested) and are _never_ used for coin selection.
152+ ScriptKeyScriptPathChannel ScriptKeyType = 5
153+ )
154+
111155var (
112156 // ZeroPrevID is the blank prev ID used for genesis assets and also
113157 // asset split leaves.
@@ -1005,14 +1049,8 @@ type TweakedScriptKey struct {
10051049 // public key. If this is nil, then a BIP-0086 tweak is assumed.
10061050 Tweak []byte
10071051
1008- // DeclaredKnown indicates that this script key has been explicitly
1009- // declared as being important to the local wallet, even if it might not
1010- // be fully known to the local wallet. This could perhaps also be named
1011- // "imported", though that might imply that the corresponding private
1012- // key was also somehow imported and available. The only relevance this
1013- // flag has is that assets with a declared key are shown in the asset
1014- // list/balance.
1015- DeclaredKnown bool
1052+ // Type is the type of script key that is being used.
1053+ Type ScriptKeyType
10161054}
10171055
10181056// IsEqual returns true is this tweaked script key is exactly equivalent to the
@@ -1083,12 +1121,9 @@ func (s *ScriptKey) IsEqual(otherScriptKey *ScriptKey) bool {
10831121// the local wallet or was explicitly declared to be known by using the
10841122// DeclareScriptKey RPC. Knowing the key conceptually means the key belongs to
10851123// the local wallet or is at least known by a software that operates on the
1086- // local wallet. The DeclaredAsKnown flag is never serialized in proofs, so this
1087- // is never explicitly set for keys foreign to the local wallet. Therefore, if
1088- // this method returns true for a script key, it means the asset with the script
1089- // key will be shown in the wallet balance.
1124+ // local wallet.
10901125func (s * ScriptKey ) DeclaredAsKnown () bool {
1091- return s .TweakedScriptKey != nil && s .TweakedScriptKey . DeclaredKnown
1126+ return s .TweakedScriptKey != nil && s .Type != ScriptKeyUnknown
10921127}
10931128
10941129// HasScriptPath returns true if we know the internals of the script key and
@@ -1098,15 +1133,55 @@ func (s *ScriptKey) HasScriptPath() bool {
10981133 return s .TweakedScriptKey != nil && len (s .TweakedScriptKey .Tweak ) > 0
10991134}
11001135
1136+ // DetermineType attempts to determine the type of the script key based on the
1137+ // information available. This method will only return ScriptKeyUnknown if the
1138+ // following condition is met:
1139+ // - The script key doesn't have a script path, but the final Taproot output
1140+ // key doesn't match a BIP-0086 key derived from the internal key. This will
1141+ // be the case for "foreign" script keys we import from proofs, where we set
1142+ // the internal key to the same key as the tweaked script key (because we
1143+ // don't know the internal key, as it's not part of the proof encoding).
1144+ func (s * ScriptKey ) DetermineType () ScriptKeyType {
1145+ // If we have an explicit script key type set, we can return that.
1146+ if s .TweakedScriptKey != nil &&
1147+ s .TweakedScriptKey .Type != ScriptKeyUnknown {
1148+
1149+ return s .TweakedScriptKey .Type
1150+ }
1151+
1152+ // If there is a known tweak, then we know that this is a script path
1153+ // key. We never return the channel type, since those keys should always
1154+ // be declared properly, and we never should need to guess their type.
1155+ if s .HasScriptPath () {
1156+ return ScriptKeyScriptPathExternal
1157+ }
1158+
1159+ // Is it the known NUMS key? Then this is a tombstone output.
1160+ if s .PubKey != nil && s .PubKey .IsEqual (NUMSPubKey ) {
1161+ return ScriptKeyTombstone
1162+ }
1163+
1164+ // Do we know the internal key? Then we can check whether it is a
1165+ // BIP-0086 key.
1166+ if s .PubKey != nil && s .TweakedScriptKey != nil &&
1167+ s .TweakedScriptKey .RawKey .PubKey != nil {
1168+
1169+ bip86 := NewScriptKeyBip86 (s .TweakedScriptKey .RawKey )
1170+ if bip86 .PubKey .IsEqual (s .PubKey ) {
1171+ return ScriptKeyBip86
1172+ }
1173+ }
1174+
1175+ return ScriptKeyUnknown
1176+ }
1177+
11011178// NewScriptKey constructs a ScriptKey with only the publicly available
11021179// information. This resulting key may or may not have a tweak applied to it.
11031180func NewScriptKey (key * btcec.PublicKey ) ScriptKey {
11041181 // Since we'll never query lnd for a tweaked key, it doesn't matter if
11051182 // we lose the parity information here. And this will only ever be
11061183 // serialized on chain in a 32-bit representation as well.
1107- key , _ = schnorr .ParsePubKey (
1108- schnorr .SerializePubKey (key ),
1109- )
1184+ key , _ = schnorr .ParsePubKey (schnorr .SerializePubKey (key ))
11101185 return ScriptKey {
11111186 PubKey : key ,
11121187 }
@@ -1118,9 +1193,7 @@ func NewScriptKey(key *btcec.PublicKey) ScriptKey {
11181193func NewScriptKeyBip86 (rawKey keychain.KeyDescriptor ) ScriptKey {
11191194 // Tweak the script key BIP-0086 style (such that we only commit to the
11201195 // internal key when signing).
1121- tweakedPubKey := txscript .ComputeTaprootKeyNoScript (
1122- rawKey .PubKey ,
1123- )
1196+ tweakedPubKey := txscript .ComputeTaprootKeyNoScript (rawKey .PubKey )
11241197
11251198 // Since we'll never query lnd for a tweaked key, it doesn't matter if
11261199 // we lose the parity information here. And this will only ever be
@@ -1133,6 +1206,7 @@ func NewScriptKeyBip86(rawKey keychain.KeyDescriptor) ScriptKey {
11331206 PubKey : tweakedPubKey ,
11341207 TweakedScriptKey : & TweakedScriptKey {
11351208 RawKey : rawKey ,
1209+ Type : ScriptKeyBip86 ,
11361210 },
11371211 }
11381212}
@@ -1526,7 +1600,7 @@ func (a *Asset) Copy() *Asset {
15261600
15271601 if a .ScriptKey .TweakedScriptKey != nil {
15281602 assetCopy .ScriptKey .TweakedScriptKey = & TweakedScriptKey {
1529- DeclaredKnown : a .ScriptKey .DeclaredKnown ,
1603+ Type : a .ScriptKey .Type ,
15301604 }
15311605 assetCopy .ScriptKey .RawKey = a .ScriptKey .RawKey
15321606
0 commit comments