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:
Olaoluwa Osuntokun committed 2019-09-25 18:25:43 -07:00
1 parent 21133e1856
commit b399203e71
8 files changed
+394 -275

No files matched your search

+63 -30
View File
@@ -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)
})
}
}