mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-23 06:35:07 +01:00
watchtower/blob: add taproot Commitment type
This commit is contained in:
parent
d84a98e3db
commit
5960253357
3 changed files with 263 additions and 57 deletions
|
@ -27,6 +27,10 @@ const (
|
||||||
// anchor channel. The key differences are that the to_remote is
|
// anchor channel. The key differences are that the to_remote is
|
||||||
// encumbered by a 1 block CSV and so is thus a P2WSH output.
|
// encumbered by a 1 block CSV and so is thus a P2WSH output.
|
||||||
AnchorCommitment
|
AnchorCommitment
|
||||||
|
|
||||||
|
// TaprootCommitment represents the commitment transaction of a simple
|
||||||
|
// taproot channel.
|
||||||
|
TaprootCommitment
|
||||||
)
|
)
|
||||||
|
|
||||||
// ToLocalInput constructs the input that will be used to spend the to_local
|
// ToLocalInput constructs the input that will be used to spend the to_local
|
||||||
|
@ -61,9 +65,10 @@ func (c CommitmentType) ToRemoteInput(info *lnwallet.BreachRetribution) (
|
||||||
info.LocalOutputSignDesc, 0,
|
info.LocalOutputSignDesc, 0,
|
||||||
), nil
|
), nil
|
||||||
|
|
||||||
case AnchorCommitment:
|
case AnchorCommitment, TaprootCommitment:
|
||||||
// Anchor channels have a CSV-encumbered to-remote output. We'll
|
// Anchor and Taproot channels have a CSV-encumbered to-remote
|
||||||
// construct a CSV input and assign the proper CSV delay of 1.
|
// output. We'll construct a CSV input and assign the proper CSV
|
||||||
|
// delay of 1.
|
||||||
return input.NewCsvInput(
|
return input.NewCsvInput(
|
||||||
&info.LocalOutpoint, witnessType,
|
&info.LocalOutpoint, witnessType,
|
||||||
info.LocalOutputSignDesc, 0, 1,
|
info.LocalOutputSignDesc, 0, 1,
|
||||||
|
@ -80,6 +85,9 @@ func (c CommitmentType) ToLocalWitnessType() (input.WitnessType, error) {
|
||||||
case LegacyTweaklessCommitment, LegacyCommitment, AnchorCommitment:
|
case LegacyTweaklessCommitment, LegacyCommitment, AnchorCommitment:
|
||||||
return input.CommitmentRevoke, nil
|
return input.CommitmentRevoke, nil
|
||||||
|
|
||||||
|
case TaprootCommitment:
|
||||||
|
return input.TaprootCommitmentRevoke, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
||||||
}
|
}
|
||||||
|
@ -97,6 +105,9 @@ func (c CommitmentType) ToRemoteWitnessType() (input.WitnessType, error) {
|
||||||
case AnchorCommitment:
|
case AnchorCommitment:
|
||||||
return input.CommitmentToRemoteConfirmed, nil
|
return input.CommitmentToRemoteConfirmed, nil
|
||||||
|
|
||||||
|
case TaprootCommitment:
|
||||||
|
return input.TaprootRemoteCommitSpend, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
||||||
}
|
}
|
||||||
|
@ -115,6 +126,10 @@ func (c CommitmentType) ToRemoteWitnessSize() (int, error) {
|
||||||
case AnchorCommitment:
|
case AnchorCommitment:
|
||||||
return input.ToRemoteConfirmedWitnessSize, nil
|
return input.ToRemoteConfirmedWitnessSize, nil
|
||||||
|
|
||||||
|
// Taproot channels spend a confirmed P2SH output.
|
||||||
|
case TaprootCommitment:
|
||||||
|
return input.TaprootToRemoteWitnessSize, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("unknown commitment type: %v", c)
|
return 0, fmt.Errorf("unknown commitment type: %v", c)
|
||||||
}
|
}
|
||||||
|
@ -134,6 +149,9 @@ func (c CommitmentType) ToLocalWitnessSize() (int, error) {
|
||||||
case AnchorCommitment:
|
case AnchorCommitment:
|
||||||
return input.ToLocalPenaltyWitnessSize, nil
|
return input.ToLocalPenaltyWitnessSize, nil
|
||||||
|
|
||||||
|
case TaprootCommitment:
|
||||||
|
return input.TaprootToLocalRevokeWitnessSize, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0, fmt.Errorf("unknown commitment type: %v", c)
|
return 0, fmt.Errorf("unknown commitment type: %v", c)
|
||||||
}
|
}
|
||||||
|
@ -143,21 +161,22 @@ func (c CommitmentType) ToLocalWitnessSize() (int, error) {
|
||||||
func (c CommitmentType) ParseRawSig(witness wire.TxWitness) (lnwire.Sig,
|
func (c CommitmentType) ParseRawSig(witness wire.TxWitness) (lnwire.Sig,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
|
// Check that the witness has at least one item since this is required
|
||||||
|
// for all commitment types to follow.
|
||||||
|
if len(witness) < 1 {
|
||||||
|
return lnwire.Sig{}, fmt.Errorf("the witness should have at " +
|
||||||
|
"least one element")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the first witness element is non-nil. This is to ensure
|
||||||
|
// that the witness length checks below do not panic.
|
||||||
|
if witness[0] == nil {
|
||||||
|
return lnwire.Sig{}, fmt.Errorf("the first witness element " +
|
||||||
|
"should not be nil")
|
||||||
|
}
|
||||||
|
|
||||||
switch c {
|
switch c {
|
||||||
case LegacyCommitment, LegacyTweaklessCommitment, AnchorCommitment:
|
case LegacyCommitment, LegacyTweaklessCommitment, AnchorCommitment:
|
||||||
// Check that the witness has at least one item.
|
|
||||||
if len(witness) < 1 {
|
|
||||||
return lnwire.Sig{}, fmt.Errorf("the witness should " +
|
|
||||||
"have at least one element")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that the first witness element is non-nil. This is to
|
|
||||||
// ensure that the witness length check below does not panic.
|
|
||||||
if witness[0] == nil {
|
|
||||||
return lnwire.Sig{}, fmt.Errorf("the first witness " +
|
|
||||||
"element should not be nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the DER-encoded signature from the first position of
|
// Parse the DER-encoded signature from the first position of
|
||||||
// the resulting witness. We trim an extra byte to remove the
|
// the resulting witness. We trim an extra byte to remove the
|
||||||
// sighash flag.
|
// sighash flag.
|
||||||
|
@ -167,6 +186,16 @@ func (c CommitmentType) ParseRawSig(witness wire.TxWitness) (lnwire.Sig,
|
||||||
// signature.
|
// signature.
|
||||||
return lnwire.NewSigFromECDSARawSignature(rawSignature)
|
return lnwire.NewSigFromECDSARawSignature(rawSignature)
|
||||||
|
|
||||||
|
case TaprootCommitment:
|
||||||
|
rawSignature := witness[0]
|
||||||
|
if len(rawSignature) > 64 {
|
||||||
|
rawSignature = witness[0][:len(witness[0])-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-encode the schnorr signature into a fixed-size 64 byte
|
||||||
|
// signature.
|
||||||
|
return lnwire.NewSigFromSchnorrRawSignature(rawSignature)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return lnwire.Sig{}, fmt.Errorf("unknown commitment type: %v",
|
return lnwire.Sig{}, fmt.Errorf("unknown commitment type: %v",
|
||||||
c)
|
c)
|
||||||
|
@ -190,6 +219,11 @@ func (c CommitmentType) NewJusticeKit(sweepScript []byte,
|
||||||
sweepScript, breachInfo, withToRemote,
|
sweepScript, breachInfo, withToRemote,
|
||||||
), nil
|
), nil
|
||||||
|
|
||||||
|
case TaprootCommitment:
|
||||||
|
return newTaprootJusticeKit(
|
||||||
|
sweepScript, breachInfo, withToRemote,
|
||||||
|
)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
||||||
}
|
}
|
||||||
|
@ -207,6 +241,9 @@ func (c CommitmentType) EmptyJusticeKit() (JusticeKit, error) {
|
||||||
legacyJusticeKit: legacyJusticeKit{},
|
legacyJusticeKit: legacyJusticeKit{},
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
|
case TaprootCommitment:
|
||||||
|
return &taprootJusticeKit{}, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
return nil, fmt.Errorf("unknown commitment type: %v", c)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
|
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
|
||||||
|
"github.com/btcsuite/btcd/btcec/v2/schnorr"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
|
@ -17,6 +18,8 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const csvDelay = uint32(144)
|
||||||
|
|
||||||
func makePubKey() *btcec.PublicKey {
|
func makePubKey() *btcec.PublicKey {
|
||||||
priv, _ := btcec.NewPrivateKey()
|
priv, _ := btcec.NewPrivateKey()
|
||||||
return priv.PubKey()
|
return priv.PubKey()
|
||||||
|
@ -39,6 +42,15 @@ func makeAddr(size int) []byte {
|
||||||
return addr
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func makeSchnorrSig(i int) lnwire.Sig {
|
||||||
|
var sigBytes [64]byte
|
||||||
|
binary.BigEndian.PutUint64(sigBytes[:8], uint64(i))
|
||||||
|
|
||||||
|
sig, _ := lnwire.NewSigFromSchnorrRawSignature(sigBytes[:])
|
||||||
|
|
||||||
|
return sig
|
||||||
|
}
|
||||||
|
|
||||||
type descriptorTest struct {
|
type descriptorTest struct {
|
||||||
name string
|
name string
|
||||||
encVersion Type
|
encVersion Type
|
||||||
|
@ -46,7 +58,6 @@ type descriptorTest struct {
|
||||||
sweepAddr []byte
|
sweepAddr []byte
|
||||||
revPubKey *btcec.PublicKey
|
revPubKey *btcec.PublicKey
|
||||||
delayPubKey *btcec.PublicKey
|
delayPubKey *btcec.PublicKey
|
||||||
csvDelay uint32
|
|
||||||
commitToLocalSig lnwire.Sig
|
commitToLocalSig lnwire.Sig
|
||||||
hasCommitToRemote bool
|
hasCommitToRemote bool
|
||||||
commitToRemotePubKey *btcec.PublicKey
|
commitToRemotePubKey *btcec.PublicKey
|
||||||
|
@ -63,7 +74,6 @@ var descriptorTests = []descriptorTest{
|
||||||
sweepAddr: makeAddr(22),
|
sweepAddr: makeAddr(22),
|
||||||
revPubKey: makePubKey(),
|
revPubKey: makePubKey(),
|
||||||
delayPubKey: makePubKey(),
|
delayPubKey: makePubKey(),
|
||||||
csvDelay: 144,
|
|
||||||
commitToLocalSig: makeSig(1),
|
commitToLocalSig: makeSig(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -73,7 +83,6 @@ var descriptorTests = []descriptorTest{
|
||||||
sweepAddr: makeAddr(22),
|
sweepAddr: makeAddr(22),
|
||||||
revPubKey: makePubKey(),
|
revPubKey: makePubKey(),
|
||||||
delayPubKey: makePubKey(),
|
delayPubKey: makePubKey(),
|
||||||
csvDelay: 144,
|
|
||||||
commitToLocalSig: makeSig(1),
|
commitToLocalSig: makeSig(1),
|
||||||
hasCommitToRemote: true,
|
hasCommitToRemote: true,
|
||||||
commitToRemotePubKey: makePubKey(),
|
commitToRemotePubKey: makePubKey(),
|
||||||
|
@ -86,7 +95,6 @@ var descriptorTests = []descriptorTest{
|
||||||
sweepAddr: makeAddr(34),
|
sweepAddr: makeAddr(34),
|
||||||
revPubKey: makePubKey(),
|
revPubKey: makePubKey(),
|
||||||
delayPubKey: makePubKey(),
|
delayPubKey: makePubKey(),
|
||||||
csvDelay: 144,
|
|
||||||
commitToLocalSig: makeSig(1),
|
commitToLocalSig: makeSig(1),
|
||||||
encErr: ErrUnknownBlobType,
|
encErr: ErrUnknownBlobType,
|
||||||
},
|
},
|
||||||
|
@ -97,7 +105,6 @@ var descriptorTests = []descriptorTest{
|
||||||
sweepAddr: makeAddr(34),
|
sweepAddr: makeAddr(34),
|
||||||
revPubKey: makePubKey(),
|
revPubKey: makePubKey(),
|
||||||
delayPubKey: makePubKey(),
|
delayPubKey: makePubKey(),
|
||||||
csvDelay: 144,
|
|
||||||
commitToLocalSig: makeSig(1),
|
commitToLocalSig: makeSig(1),
|
||||||
decErr: ErrUnknownBlobType,
|
decErr: ErrUnknownBlobType,
|
||||||
},
|
},
|
||||||
|
@ -108,7 +115,6 @@ var descriptorTests = []descriptorTest{
|
||||||
sweepAddr: makeAddr(0),
|
sweepAddr: makeAddr(0),
|
||||||
revPubKey: makePubKey(),
|
revPubKey: makePubKey(),
|
||||||
delayPubKey: makePubKey(),
|
delayPubKey: makePubKey(),
|
||||||
csvDelay: 144,
|
|
||||||
commitToLocalSig: makeSig(1),
|
commitToLocalSig: makeSig(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -118,7 +124,6 @@ var descriptorTests = []descriptorTest{
|
||||||
sweepAddr: makeAddr(MaxSweepAddrSize),
|
sweepAddr: makeAddr(MaxSweepAddrSize),
|
||||||
revPubKey: makePubKey(),
|
revPubKey: makePubKey(),
|
||||||
delayPubKey: makePubKey(),
|
delayPubKey: makePubKey(),
|
||||||
csvDelay: 144,
|
|
||||||
commitToLocalSig: makeSig(1),
|
commitToLocalSig: makeSig(1),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -128,10 +133,30 @@ var descriptorTests = []descriptorTest{
|
||||||
sweepAddr: makeAddr(MaxSweepAddrSize + 1),
|
sweepAddr: makeAddr(MaxSweepAddrSize + 1),
|
||||||
revPubKey: makePubKey(),
|
revPubKey: makePubKey(),
|
||||||
delayPubKey: makePubKey(),
|
delayPubKey: makePubKey(),
|
||||||
csvDelay: 144,
|
|
||||||
commitToLocalSig: makeSig(1),
|
commitToLocalSig: makeSig(1),
|
||||||
encErr: ErrSweepAddressToLong,
|
encErr: ErrSweepAddressToLong,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "taproot to-local only",
|
||||||
|
encVersion: TypeAltruistTaprootCommit,
|
||||||
|
decVersion: TypeAltruistTaprootCommit,
|
||||||
|
sweepAddr: makeAddr(34),
|
||||||
|
revPubKey: makePubKey(),
|
||||||
|
delayPubKey: makePubKey(),
|
||||||
|
commitToLocalSig: makeSchnorrSig(1),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot to-local and to-remote",
|
||||||
|
encVersion: TypeAltruistTaprootCommit,
|
||||||
|
decVersion: TypeAltruistTaprootCommit,
|
||||||
|
sweepAddr: makeAddr(34),
|
||||||
|
revPubKey: makePubKey(),
|
||||||
|
delayPubKey: makePubKey(),
|
||||||
|
commitToLocalSig: makeSchnorrSig(1),
|
||||||
|
hasCommitToRemote: true,
|
||||||
|
commitToRemotePubKey: makePubKey(),
|
||||||
|
commitToRemoteSig: makeSchnorrSig(2),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestBlobJusticeKitEncryptDecrypt asserts that encrypting and decrypting a
|
// TestBlobJusticeKitEncryptDecrypt asserts that encrypting and decrypting a
|
||||||
|
@ -154,7 +179,7 @@ func testBlobJusticeKitEncryptDecrypt(t *testing.T, test descriptorTest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
breachInfo := &lnwallet.BreachRetribution{
|
breachInfo := &lnwallet.BreachRetribution{
|
||||||
RemoteDelay: test.csvDelay,
|
RemoteDelay: csvDelay,
|
||||||
KeyRing: &lnwallet.CommitmentKeyRing{
|
KeyRing: &lnwallet.CommitmentKeyRing{
|
||||||
ToLocalKey: test.delayPubKey,
|
ToLocalKey: test.delayPubKey,
|
||||||
ToRemoteKey: test.commitToRemotePubKey,
|
ToRemoteKey: test.commitToRemotePubKey,
|
||||||
|
@ -221,6 +246,8 @@ type remoteWitnessTest struct {
|
||||||
name string
|
name string
|
||||||
blobType Type
|
blobType Type
|
||||||
expWitnessScript func(pk *btcec.PublicKey) []byte
|
expWitnessScript func(pk *btcec.PublicKey) []byte
|
||||||
|
expWitnessStack func(sig input.Signature) wire.TxWitness
|
||||||
|
createSig func(*btcec.PrivateKey, []byte) input.Signature
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestJusticeKitRemoteWitnessConstruction tests that a JusticeKit returns the
|
// TestJusticeKitRemoteWitnessConstruction tests that a JusticeKit returns the
|
||||||
|
@ -234,6 +261,21 @@ func TestJusticeKitRemoteWitnessConstruction(t *testing.T) {
|
||||||
expWitnessScript: func(pk *btcec.PublicKey) []byte {
|
expWitnessScript: func(pk *btcec.PublicKey) []byte {
|
||||||
return pk.SerializeCompressed()
|
return pk.SerializeCompressed()
|
||||||
},
|
},
|
||||||
|
expWitnessStack: func(
|
||||||
|
sig input.Signature) wire.TxWitness {
|
||||||
|
|
||||||
|
sigBytes := append(
|
||||||
|
sig.Serialize(),
|
||||||
|
byte(txscript.SigHashAll),
|
||||||
|
)
|
||||||
|
|
||||||
|
return [][]byte{sigBytes}
|
||||||
|
},
|
||||||
|
createSig: func(priv *btcec.PrivateKey,
|
||||||
|
digest []byte) input.Signature {
|
||||||
|
|
||||||
|
return ecdsa.Sign(priv, digest)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "anchor commitment",
|
name: "anchor commitment",
|
||||||
|
@ -242,6 +284,42 @@ func TestJusticeKitRemoteWitnessConstruction(t *testing.T) {
|
||||||
script, _ := input.CommitScriptToRemoteConfirmed(pk)
|
script, _ := input.CommitScriptToRemoteConfirmed(pk)
|
||||||
return script
|
return script
|
||||||
},
|
},
|
||||||
|
expWitnessStack: func(
|
||||||
|
sig input.Signature) wire.TxWitness {
|
||||||
|
|
||||||
|
sigBytes := append(
|
||||||
|
sig.Serialize(),
|
||||||
|
byte(txscript.SigHashAll),
|
||||||
|
)
|
||||||
|
|
||||||
|
return [][]byte{sigBytes}
|
||||||
|
},
|
||||||
|
createSig: func(priv *btcec.PrivateKey,
|
||||||
|
digest []byte) input.Signature {
|
||||||
|
|
||||||
|
return ecdsa.Sign(priv, digest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot commitment",
|
||||||
|
blobType: TypeAltruistTaprootCommit,
|
||||||
|
expWitnessScript: func(pk *btcec.PublicKey) []byte {
|
||||||
|
tree, _ := input.NewRemoteCommitScriptTree(pk)
|
||||||
|
|
||||||
|
return tree.SettleLeaf.Script
|
||||||
|
},
|
||||||
|
expWitnessStack: func(
|
||||||
|
sig input.Signature) wire.TxWitness {
|
||||||
|
|
||||||
|
return [][]byte{sig.Serialize()}
|
||||||
|
},
|
||||||
|
createSig: func(priv *btcec.PrivateKey,
|
||||||
|
digest []byte) input.Signature {
|
||||||
|
|
||||||
|
sig, _ := schnorr.Sign(priv, digest)
|
||||||
|
|
||||||
|
return sig
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -252,8 +330,8 @@ func TestJusticeKitRemoteWitnessConstruction(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testJusticeKitRemoteWitnessConstruction(
|
func testJusticeKitRemoteWitnessConstruction(t *testing.T,
|
||||||
t *testing.T, test remoteWitnessTest) {
|
test remoteWitnessTest) {
|
||||||
|
|
||||||
// Generate the to-remote pubkey.
|
// Generate the to-remote pubkey.
|
||||||
toRemotePrivKey, err := btcec.NewPrivateKey()
|
toRemotePrivKey, err := btcec.NewPrivateKey()
|
||||||
|
@ -268,7 +346,7 @@ func testJusticeKitRemoteWitnessConstruction(
|
||||||
// Sign a message using the to-remote private key. The exact message
|
// Sign a message using the to-remote private key. The exact message
|
||||||
// doesn't matter as we won't be validating the signature's validity.
|
// doesn't matter as we won't be validating the signature's validity.
|
||||||
digest := bytes.Repeat([]byte("a"), 32)
|
digest := bytes.Repeat([]byte("a"), 32)
|
||||||
rawToRemoteSig := ecdsa.Sign(toRemotePrivKey, digest)
|
rawToRemoteSig := test.createSig(toRemotePrivKey, digest)
|
||||||
|
|
||||||
// Convert the DER-encoded signature into a fixed-size sig.
|
// Convert the DER-encoded signature into a fixed-size sig.
|
||||||
commitToRemoteSig, err := lnwire.NewSigFromSignature(rawToRemoteSig)
|
commitToRemoteSig, err := lnwire.NewSigFromSignature(rawToRemoteSig)
|
||||||
|
@ -298,24 +376,122 @@ func testJusticeKitRemoteWitnessConstruction(
|
||||||
expToRemoteScript := test.expWitnessScript(toRemotePrivKey.PubKey())
|
expToRemoteScript := test.expWitnessScript(toRemotePrivKey.PubKey())
|
||||||
require.Equal(t, expToRemoteScript, witness[1])
|
require.Equal(t, expToRemoteScript, witness[1])
|
||||||
|
|
||||||
// Compute the expected first element, by appending a sighash all byte
|
// Compute the expected signature.
|
||||||
// to our raw DER-encoded signature.
|
expWitnessStack := test.expWitnessStack(rawToRemoteSig)
|
||||||
rawToRemoteSigWithSigHash := append(
|
|
||||||
rawToRemoteSig.Serialize(), byte(txscript.SigHashAll),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Assert that the expected witness stack is returned.
|
|
||||||
expWitnessStack := wire.TxWitness{
|
|
||||||
rawToRemoteSigWithSigHash,
|
|
||||||
}
|
|
||||||
require.Equal(t, expWitnessStack, witness[:1])
|
require.Equal(t, expWitnessStack, witness[:1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type localWitnessTest struct {
|
||||||
|
name string
|
||||||
|
blobType Type
|
||||||
|
expWitnessScript func(delay, rev *btcec.PublicKey) []byte
|
||||||
|
expWitnessStack func(sig input.Signature) wire.TxWitness
|
||||||
|
witnessScriptIndex int
|
||||||
|
createSig func(*btcec.PrivateKey, []byte) input.Signature
|
||||||
|
}
|
||||||
|
|
||||||
// TestJusticeKitToLocalWitnessConstruction tests that a JusticeKit returns the
|
// TestJusticeKitToLocalWitnessConstruction tests that a JusticeKit returns the
|
||||||
// proper to-local witness script and to-local witness stack for spending the
|
// proper to-local witness script and to-local witness stack for spending the
|
||||||
// revocation path.
|
// revocation path.
|
||||||
func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
|
func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
|
||||||
csvDelay := uint32(144)
|
tests := []localWitnessTest{
|
||||||
|
{
|
||||||
|
name: "legacy commitment",
|
||||||
|
blobType: TypeAltruistCommit,
|
||||||
|
expWitnessScript: func(delay,
|
||||||
|
rev *btcec.PublicKey) []byte {
|
||||||
|
|
||||||
|
script, _ := input.CommitScriptToSelf(
|
||||||
|
csvDelay, delay, rev,
|
||||||
|
)
|
||||||
|
|
||||||
|
return script
|
||||||
|
},
|
||||||
|
expWitnessStack: func(
|
||||||
|
sig input.Signature) wire.TxWitness {
|
||||||
|
|
||||||
|
sigBytes := append(
|
||||||
|
sig.Serialize(),
|
||||||
|
byte(txscript.SigHashAll),
|
||||||
|
)
|
||||||
|
|
||||||
|
return [][]byte{sigBytes, {1}}
|
||||||
|
},
|
||||||
|
witnessScriptIndex: 2,
|
||||||
|
createSig: func(priv *btcec.PrivateKey,
|
||||||
|
digest []byte) input.Signature {
|
||||||
|
|
||||||
|
return ecdsa.Sign(priv, digest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "anchor commitment",
|
||||||
|
blobType: TypeAltruistAnchorCommit,
|
||||||
|
expWitnessScript: func(delay,
|
||||||
|
rev *btcec.PublicKey) []byte {
|
||||||
|
|
||||||
|
script, _ := input.CommitScriptToSelf(
|
||||||
|
csvDelay, delay, rev,
|
||||||
|
)
|
||||||
|
|
||||||
|
return script
|
||||||
|
},
|
||||||
|
witnessScriptIndex: 2,
|
||||||
|
expWitnessStack: func(
|
||||||
|
sig input.Signature) wire.TxWitness {
|
||||||
|
|
||||||
|
sigBytes := append(
|
||||||
|
sig.Serialize(),
|
||||||
|
byte(txscript.SigHashAll),
|
||||||
|
)
|
||||||
|
|
||||||
|
return [][]byte{sigBytes, {1}}
|
||||||
|
},
|
||||||
|
createSig: func(priv *btcec.PrivateKey,
|
||||||
|
digest []byte) input.Signature {
|
||||||
|
|
||||||
|
return ecdsa.Sign(priv, digest)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "taproot commitment",
|
||||||
|
blobType: TypeAltruistTaprootCommit,
|
||||||
|
expWitnessScript: func(delay,
|
||||||
|
rev *btcec.PublicKey) []byte {
|
||||||
|
|
||||||
|
script, _ := input.NewLocalCommitScriptTree(
|
||||||
|
csvDelay, delay, rev,
|
||||||
|
)
|
||||||
|
|
||||||
|
return script.RevocationLeaf.Script
|
||||||
|
},
|
||||||
|
witnessScriptIndex: 1,
|
||||||
|
expWitnessStack: func(
|
||||||
|
sig input.Signature) wire.TxWitness {
|
||||||
|
|
||||||
|
return [][]byte{sig.Serialize()}
|
||||||
|
},
|
||||||
|
createSig: func(priv *btcec.PrivateKey,
|
||||||
|
digest []byte) input.Signature {
|
||||||
|
|
||||||
|
sig, _ := schnorr.Sign(priv, digest)
|
||||||
|
|
||||||
|
return sig
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
testJusticeKitToLocalWitnessConstruction(t, test)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testJusticeKitToLocalWitnessConstruction(t *testing.T,
|
||||||
|
test localWitnessTest) {
|
||||||
|
|
||||||
// Generate the revocation and delay private keys.
|
// Generate the revocation and delay private keys.
|
||||||
revPrivKey, err := btcec.NewPrivateKey()
|
revPrivKey, err := btcec.NewPrivateKey()
|
||||||
|
@ -327,13 +503,13 @@ func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
|
||||||
// Sign a message using the revocation private key. The exact message
|
// Sign a message using the revocation private key. The exact message
|
||||||
// doesn't matter as we won't be validating the signature's validity.
|
// doesn't matter as we won't be validating the signature's validity.
|
||||||
digest := bytes.Repeat([]byte("a"), 32)
|
digest := bytes.Repeat([]byte("a"), 32)
|
||||||
rawRevSig := ecdsa.Sign(revPrivKey, digest)
|
rawRevSig := test.createSig(revPrivKey, digest)
|
||||||
|
|
||||||
// Convert the DER-encoded signature into a fixed-size sig.
|
// Convert the DER-encoded signature into a fixed-size sig.
|
||||||
commitToLocalSig, err := lnwire.NewSigFromSignature(rawRevSig)
|
commitToLocalSig, err := lnwire.NewSigFromSignature(rawRevSig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
commitType, err := TypeAltruistCommit.CommitmentType(nil)
|
commitType, err := test.blobType.CommitmentType(nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
breachInfo := &lnwallet.BreachRetribution{
|
breachInfo := &lnwallet.BreachRetribution{
|
||||||
|
@ -350,28 +526,18 @@ func TestJusticeKitToLocalWitnessConstruction(t *testing.T) {
|
||||||
|
|
||||||
// Compute the expected to-local script, which is a function of the CSV
|
// Compute the expected to-local script, which is a function of the CSV
|
||||||
// delay, revocation pubkey and delay pubkey.
|
// delay, revocation pubkey and delay pubkey.
|
||||||
expToLocalScript, err := input.CommitScriptToSelf(
|
expToLocalScript := test.expWitnessScript(
|
||||||
csvDelay, delayPrivKey.PubKey(), revPrivKey.PubKey(),
|
delayPrivKey.PubKey(), revPrivKey.PubKey(),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Compute the to-local script that is returned by the justice kit.
|
// Compute the to-local script that is returned by the justice kit.
|
||||||
_, witness, err := justiceKit.ToLocalOutputSpendInfo()
|
_, witness, err := justiceKit.ToLocalOutputSpendInfo()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Assert that the expected to-local script matches the actual script.
|
// Assert that the expected to-local script matches the actual script.
|
||||||
require.Equal(t, expToLocalScript, witness[2])
|
require.Equal(t, expToLocalScript, witness[test.witnessScriptIndex])
|
||||||
|
|
||||||
// Compute the expected signature in the bottom element of the stack, by
|
// Finally, validate the witness.
|
||||||
// appending a sighash all flag to the raw DER signature.
|
expWitnessStack := test.expWitnessStack(rawRevSig)
|
||||||
rawRevSigWithSigHash := append(
|
require.Equal(t, expWitnessStack, witness[:test.witnessScriptIndex])
|
||||||
rawRevSig.Serialize(), byte(txscript.SigHashAll),
|
|
||||||
)
|
|
||||||
|
|
||||||
// Finally, validate against our expected witness stack.
|
|
||||||
expWitnessStack := wire.TxWitness{
|
|
||||||
rawRevSigWithSigHash,
|
|
||||||
{1},
|
|
||||||
}
|
|
||||||
require.Equal(t, expWitnessStack, witness[:2])
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,9 @@ func (t Type) CommitmentType(chanType *channeldb.ChannelType) (CommitmentType,
|
||||||
error) {
|
error) {
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
case t.Has(FlagTaprootChannel):
|
||||||
|
return TaprootCommitment, nil
|
||||||
|
|
||||||
case t.Has(FlagAnchorChannel):
|
case t.Has(FlagAnchorChannel):
|
||||||
return AnchorCommitment, nil
|
return AnchorCommitment, nil
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue