lnwallet: update channel state machine to be aware of tweakless commits
In this commit, we update the channel state machine to be aware of tweakless commits. In several areas, we'll now check the channel's type to see if it's `SingleFunderTweakless`. If so, then we'll opt to use the remote party's non-delay based point directly in the script, skipping any additional cryptographic operations. Along the way we move the `validateCommitmentSanity` method to be defined _before_ it's used as is cutomary within the codebase. Notably, within the `NewUnilateralCloseSummary` method, we'll now _blank out_ the `SingleTweak` value if the commitment is tweakless. This indicates to callers the witness type they should map to, as the value isn't needed at all any longer when sweeping a non-delay output. We also update the signing+verification tests to also test that we're able to properly generate a valid witness for the new tweakless commitment format.
This commit is contained in:
8 files changed
+394
-275
No files matched your search
@@ -370,7 +370,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
|
||||
|
||||
// Manually construct a new LightningChannel.
|
||||
channelState := channeldb.OpenChannel{
|
||||
ChanType: channeldb.SingleFunder,
|
||||
ChanType: channeldb.SingleFunderTweakless,
|
||||
ChainHash: *tc.netParams.GenesisHash,
|
||||
FundingOutpoint: tc.fundingOutpoint,
|
||||
ShortChannelID: tc.shortChanID,
|
||||
@@ -999,18 +999,9 @@ func TestCommitTxStateHint(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCommitmentSpendValidation test the spendability of both outputs within
|
||||
// the commitment transaction.
|
||||
//
|
||||
// The following spending cases are covered by this test:
|
||||
// * Alice's spend from the delayed output on her commitment transaction.
|
||||
// * Bob's spend from Alice's delayed output when she broadcasts a revoked
|
||||
// commitment transaction.
|
||||
// * Bob's spend from his unencumbered output within Alice's commitment
|
||||
// transaction.
|
||||
func TestCommitmentSpendValidation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// testSpendValidation ensures that we're able to spend all outputs in the
|
||||
// commitment transaction that we create.
|
||||
func testSpendValidation(t *testing.T, tweakless bool) {
|
||||
// We generate a fake output, and the corresponding txin. This output
|
||||
// doesn't need to exist, as we'll only be validating spending from the
|
||||
// transaction that references this.
|
||||
@@ -1030,18 +1021,28 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
// We also set up set some resources for the commitment transaction.
|
||||
// Each side currently has 1 BTC within the channel, with a total
|
||||
// channel capacity of 2BTC.
|
||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
testWalletPrivKey)
|
||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
bobsPrivKey)
|
||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
|
||||
btcec.S256(), testWalletPrivKey,
|
||||
)
|
||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(
|
||||
btcec.S256(), bobsPrivKey,
|
||||
)
|
||||
|
||||
revocationPreimage := testHdSeed.CloneBytes()
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
revocationPreimage)
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(
|
||||
btcec.S256(), revocationPreimage,
|
||||
)
|
||||
revokePubKey := input.DeriveRevocationPubkey(bobKeyPub, commitPoint)
|
||||
|
||||
aliceDelayKey := input.TweakPubKey(aliceKeyPub, commitPoint)
|
||||
|
||||
// Bob will have the channel "force closed" on him, so for the sake of
|
||||
// our commitments, if it's tweakless, his key will just be his regular
|
||||
// pubkey.
|
||||
bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint)
|
||||
if tweakless {
|
||||
bobPayKey = bobKeyPub
|
||||
}
|
||||
|
||||
aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub)
|
||||
bobCommitTweak := input.SingleTweakBytes(commitPoint, bobKeyPub)
|
||||
@@ -1062,8 +1063,10 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
RevocationKey: revokePubKey,
|
||||
NoDelayKey: bobPayKey,
|
||||
}
|
||||
commitmentTx, err := CreateCommitTx(*fakeFundingTxIn, keyRing, csvTimeout,
|
||||
channelBalance, channelBalance, DefaultDustLimit())
|
||||
commitmentTx, err := CreateCommitTx(
|
||||
*fakeFundingTxIn, keyRing, csvTimeout, channelBalance,
|
||||
channelBalance, DefaultDustLimit(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create commitment transaction: %v", nil)
|
||||
}
|
||||
@@ -1088,8 +1091,9 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
})
|
||||
|
||||
// First, we'll test spending with Alice's key after the timeout.
|
||||
delayScript, err := input.CommitScriptToSelf(csvTimeout, aliceDelayKey,
|
||||
revokePubKey)
|
||||
delayScript, err := input.CommitScriptToSelf(
|
||||
csvTimeout, aliceDelayKey, revokePubKey,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate alice delay script: %v", err)
|
||||
}
|
||||
@@ -1107,8 +1111,9 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
HashType: txscript.SigHashAll,
|
||||
InputIndex: 0,
|
||||
}
|
||||
aliceWitnessSpend, err := input.CommitSpendTimeout(aliceSelfOutputSigner,
|
||||
signDesc, sweepTx)
|
||||
aliceWitnessSpend, err := input.CommitSpendTimeout(
|
||||
aliceSelfOutputSigner, signDesc, sweepTx,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate delay commit spend witness: %v", err)
|
||||
}
|
||||
@@ -1177,7 +1182,6 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: bobCommitTweak,
|
||||
WitnessScript: bobScriptP2WKH,
|
||||
SigHashes: txscript.NewTxSigHashes(sweepTx),
|
||||
Output: &wire.TxOut{
|
||||
@@ -1187,15 +1191,21 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
HashType: txscript.SigHashAll,
|
||||
InputIndex: 0,
|
||||
}
|
||||
bobRegularSpend, err := input.CommitSpendNoDelay(bobSigner, signDesc,
|
||||
sweepTx)
|
||||
if !tweakless {
|
||||
signDesc.SingleTweak = bobCommitTweak
|
||||
}
|
||||
bobRegularSpend, err := input.CommitSpendNoDelay(
|
||||
bobSigner, signDesc, sweepTx, tweakless,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create bob regular spend: %v", err)
|
||||
}
|
||||
sweepTx.TxIn[0].Witness = bobRegularSpend
|
||||
vm, err = txscript.NewEngine(regularOutput.PkScript,
|
||||
vm, err = txscript.NewEngine(
|
||||
regularOutput.PkScript,
|
||||
sweepTx, 0, txscript.StandardVerifyFlags, nil,
|
||||
nil, int64(channelBalance))
|
||||
nil, int64(channelBalance),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create engine: %v", err)
|
||||
}
|
||||
@@ -1203,3 +1213,26 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
t.Fatalf("bob p2wkh spend is invalid: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestCommitmentSpendValidation test the spendability of both outputs within
|
||||
// the commitment transaction.
|
||||
//
|
||||
// The following spending cases are covered by this test:
|
||||
// * Alice's spend from the delayed output on her commitment transaction.
|
||||
// * Bob's spend from Alice's delayed output when she broadcasts a revoked
|
||||
// commitment transaction.
|
||||
// * Bob's spend from his unencumbered output within Alice's commitment
|
||||
// transaction.
|
||||
func TestCommitmentSpendValidation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// In the modern network, all channels use the new tweakless format,
|
||||
// but we also need to support older nodes that want to open channels
|
||||
// with the legacy format, so we'll test spending in both scenarios.
|
||||
for _, tweakless := range []bool{true, false} {
|
||||
tweakless := tweakless
|
||||
t.Run(fmt.Sprintf("tweak=%v", tweakless), func(t *testing.T) {
|
||||
testSpendValidation(t, tweakless)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user