mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-11-10 06:07:16 +01:00
watchtower: convert JusticeKit to interface
In this commit, we convert the `JusticeKit` struct to an interface. Then, we add two implementations of that interface: 1) The `legacyJusticeKit` which implements all the methods of `JusticeKit` 2) The `anchorJusticKit` which wraps the `legacyJusticeKit` and just re-implements the `ToRemoteOutputSpendInfo` method since.
This commit is contained in:
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/btcsuite/btcd/btcutil/txsort"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
@@ -247,25 +246,11 @@ func (t *backupTask) craftSessionPayload(
|
||||
|
||||
var hint blob.BreachHint
|
||||
|
||||
// First, copy over the sweep pkscript, the pubkeys used to derive the
|
||||
// to-local script, and the remote CSV delay.
|
||||
keyRing := t.breachInfo.KeyRing
|
||||
justiceKit := &blob.JusticeKit{
|
||||
BlobType: t.blobType,
|
||||
SweepAddress: t.sweepPkScript,
|
||||
RevocationPubKey: toBlobPubKey(keyRing.RevocationKey),
|
||||
LocalDelayPubKey: toBlobPubKey(keyRing.ToLocalKey),
|
||||
CSVDelay: t.breachInfo.RemoteDelay,
|
||||
}
|
||||
|
||||
// If this commitment has an output that pays to us, copy the to-remote
|
||||
// pubkey into the justice kit. This serves as the indicator to the
|
||||
// tower that we expect the breaching transaction to have a non-dust
|
||||
// output to spend from.
|
||||
if t.toRemoteInput != nil {
|
||||
justiceKit.CommitToRemotePubKey = toBlobPubKey(
|
||||
keyRing.ToRemoteKey,
|
||||
)
|
||||
justiceKit, err := t.commitmentType.NewJusticeKit(
|
||||
t.sweepPkScript, t.breachInfo, t.toRemoteInput != nil,
|
||||
)
|
||||
if err != nil {
|
||||
return hint, nil, err
|
||||
}
|
||||
|
||||
// Now, begin construction of the justice transaction. We'll start with
|
||||
@@ -348,9 +333,9 @@ func (t *backupTask) craftSessionPayload(
|
||||
// field
|
||||
switch inp.WitnessType() {
|
||||
case toLocalWitnessType:
|
||||
justiceKit.CommitToLocalSig = signature
|
||||
justiceKit.AddToLocalSig(signature)
|
||||
case toRemoteWitnessType:
|
||||
justiceKit.CommitToRemoteSig = signature
|
||||
justiceKit.AddToRemoteSig(signature)
|
||||
default:
|
||||
return hint, nil, fmt.Errorf("invalid witness type: %v",
|
||||
inp.WitnessType())
|
||||
@@ -365,18 +350,10 @@ func (t *backupTask) craftSessionPayload(
|
||||
// Then, we'll encrypt the computed justice kit using the full breach
|
||||
// transaction id, which will allow the tower to recover the contents
|
||||
// after the transaction is seen in the chain or mempool.
|
||||
encBlob, err := justiceKit.Encrypt(key)
|
||||
encBlob, err := blob.Encrypt(justiceKit, key)
|
||||
if err != nil {
|
||||
return hint, nil, err
|
||||
}
|
||||
|
||||
return hint, encBlob, nil
|
||||
}
|
||||
|
||||
// toBlobPubKey serializes the given pubkey into a blob.PubKey that can be set
|
||||
// as a field on a blob.JusticeKit.
|
||||
func toBlobPubKey(pubKey *btcec.PublicKey) blob.PubKey {
|
||||
var blobPubKey blob.PubKey
|
||||
copy(blobPubKey[:], pubKey.SerializeCompressed())
|
||||
return blobPubKey
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package wtclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
@@ -25,8 +25,7 @@ import (
|
||||
const csvDelay uint32 = 144
|
||||
|
||||
var (
|
||||
zeroPK [33]byte
|
||||
zeroSig [64]byte
|
||||
zeroSig = makeSig(0)
|
||||
|
||||
revPrivBytes = []byte{
|
||||
0x8f, 0x4b, 0x51, 0x83, 0xa9, 0x34, 0xbd, 0x5f,
|
||||
@@ -65,6 +64,7 @@ type backupTaskTest struct {
|
||||
expSweepScript []byte
|
||||
signer input.Signer
|
||||
chanType channeldb.ChannelType
|
||||
commitType blob.CommitmentType
|
||||
}
|
||||
|
||||
// genTaskTest creates a instance of a backupTaskTest using the passed
|
||||
@@ -210,6 +210,7 @@ func genTaskTest(
|
||||
expSweepScript: sweepAddr,
|
||||
signer: signer,
|
||||
chanType: chanType,
|
||||
commitType: commitType,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,60 +568,35 @@ func testBackupTask(t *testing.T, test backupTaskTest) {
|
||||
require.NoError(t, err, "unable to decrypt blob")
|
||||
|
||||
keyRing := test.breachInfo.KeyRing
|
||||
expToLocalPK := keyRing.ToLocalKey.SerializeCompressed()
|
||||
expRevPK := keyRing.RevocationKey.SerializeCompressed()
|
||||
expToRemotePK := keyRing.ToRemoteKey.SerializeCompressed()
|
||||
expToLocalPK := keyRing.ToLocalKey
|
||||
expRevPK := keyRing.RevocationKey
|
||||
expToRemotePK := keyRing.ToRemoteKey
|
||||
|
||||
// Assert that the blob contained the serialized revocation and to-local
|
||||
// pubkeys.
|
||||
require.Equal(t, expRevPK, jKit.RevocationPubKey[:])
|
||||
require.Equal(t, expToLocalPK, jKit.LocalDelayPubKey[:])
|
||||
|
||||
// Determine if the breach transaction has a to-remote output and/or
|
||||
// to-local output to spend from. Note the seemingly-reversed
|
||||
// nomenclature.
|
||||
hasToRemote := test.breachInfo.LocalOutputSignDesc != nil
|
||||
hasToLocal := test.breachInfo.RemoteOutputSignDesc != nil
|
||||
|
||||
// If the to-remote output is present, assert that the to-remote public
|
||||
// key was included in the blob. Otherwise assert that a blank public
|
||||
// key was inserted.
|
||||
if hasToRemote {
|
||||
require.Equal(t, expToRemotePK, jKit.CommitToRemotePubKey[:])
|
||||
} else {
|
||||
require.Equal(t, zeroPK[:], jKit.CommitToRemotePubKey[:])
|
||||
breachInfo := &lnwallet.BreachRetribution{
|
||||
RemoteDelay: csvDelay,
|
||||
KeyRing: &lnwallet.CommitmentKeyRing{
|
||||
ToLocalKey: expToLocalPK,
|
||||
RevocationKey: expRevPK,
|
||||
ToRemoteKey: expToRemotePK,
|
||||
},
|
||||
}
|
||||
|
||||
// Assert that the CSV is encoded in the blob.
|
||||
require.Equal(t, test.breachInfo.RemoteDelay, jKit.CSVDelay)
|
||||
|
||||
// Assert that the sweep pkscript is included.
|
||||
require.Equal(t, test.expSweepScript, jKit.SweepAddress)
|
||||
|
||||
// Finally, verify that the signatures are encoded in the justice kit.
|
||||
// We don't validate the actual signatures produced here, since at the
|
||||
// moment, it is tested indirectly by other packages and integration
|
||||
// tests.
|
||||
// TODO(conner): include signature validation checks
|
||||
emptyToLocalSig := bytes.Equal(
|
||||
jKit.CommitToLocalSig.RawBytes(), zeroSig[:],
|
||||
expectedKit, err := test.commitType.NewJusticeKit(
|
||||
test.expSweepScript, breachInfo, test.expToRemoteInput != nil,
|
||||
)
|
||||
if hasToLocal {
|
||||
require.False(t, emptyToLocalSig, "to-local signature should "+
|
||||
"not be empty")
|
||||
} else {
|
||||
require.True(t, emptyToLocalSig, "to-local signature should "+
|
||||
"be empty")
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
emptyToRemoteSig := bytes.Equal(
|
||||
jKit.CommitToRemoteSig.RawBytes(), zeroSig[:],
|
||||
)
|
||||
if hasToRemote {
|
||||
require.False(t, emptyToRemoteSig, "to-remote signature "+
|
||||
"should not be empty")
|
||||
} else {
|
||||
require.True(t, emptyToRemoteSig, "to-remote signature "+
|
||||
"should be empty")
|
||||
}
|
||||
jKit.AddToLocalSig(zeroSig)
|
||||
jKit.AddToRemoteSig(zeroSig)
|
||||
|
||||
require.Equal(t, expectedKit, jKit)
|
||||
}
|
||||
|
||||
func makeSig(i int) lnwire.Sig {
|
||||
var sigBytes [64]byte
|
||||
binary.BigEndian.PutUint64(sigBytes[:8], uint64(i))
|
||||
|
||||
sig, _ := lnwire.NewSigFromWireECDSA(sigBytes[:])
|
||||
|
||||
return sig
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user