From b399203e717e6f9fd628e7a7fa763f0f2af60c18 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Wed, 31 Jul 2019 20:10:45 -0700 Subject: [PATCH] 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. --- channeldb/channel.go | 8 + htlcswitch/test_utils.go | 7 +- lnwallet/channel.go | 344 +++++++++++++++++++--------------- lnwallet/channel_test.go | 181 ++++++++++-------- lnwallet/test_utils.go | 9 +- lnwallet/transactions_test.go | 93 ++++++--- lnwallet/wallet.go | 20 +- test_utils.go | 7 +- 8 files changed, 394 insertions(+), 275 deletions(-) diff --git a/channeldb/channel.go b/channeldb/channel.go index fefd2740..7bc9e480 100644 --- a/channeldb/channel.go +++ b/channeldb/channel.go @@ -869,6 +869,14 @@ func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) { // allowing us to sweep our funds. if c.hasChanStatus(ChanStatusRestored) { currentCommitSecret[0] ^= 1 + + // If this is a tweakless channel, then we'll purposefully send + // a next local height taht's invalid to trigger a force close + // on their end. We do this as tweakless channels don't require + // that the commitment point is valid, only that it's present. + if c.ChanType.IsTweakless() { + nextLocalCommitHeight = 0 + } } return &lnwire.ChannelReestablish{ diff --git a/htlcswitch/test_utils.go b/htlcswitch/test_utils.go index a908afb3..4f48c4f6 100644 --- a/htlcswitch/test_utils.go +++ b/htlcswitch/test_utils.go @@ -257,9 +257,10 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte, } aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:]) - aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(aliceAmount, - bobAmount, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, - *fundingTxIn) + aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns( + aliceAmount, bobAmount, &aliceCfg, &bobCfg, aliceCommitPoint, + bobCommitPoint, *fundingTxIn, true, + ) if err != nil { return nil, nil, nil, err } diff --git a/lnwallet/channel.go b/lnwallet/channel.go index 90871498..bf8cdadb 100644 --- a/lnwallet/channel.go +++ b/lnwallet/channel.go @@ -863,6 +863,12 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool, diskCommit *channeldb.ChannelCommitment, localCommitPoint, remoteCommitPoint *btcec.PublicKey) (*commitment, error) { + // If this commit is tweakless, then it'll affect the way we derive our + // keys, which will affect the commitment transaction reconstruction. + // So we'll determine this first, before we do anything else. + tweaklessCommit := (lc.channelState.ChanType == + channeldb.SingleFunderTweakless) + // First, we'll need to re-derive the commitment key ring for each // party used within this particular state. If this is a pending commit // (we extended but weren't able to complete the commitment dance @@ -871,14 +877,14 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool, var localCommitKeys, remoteCommitKeys *CommitmentKeyRing if localCommitPoint != nil { localCommitKeys = deriveCommitmentKeys( - localCommitPoint, true, lc.localChanCfg, - lc.remoteChanCfg, + localCommitPoint, true, tweaklessCommit, + lc.localChanCfg, lc.remoteChanCfg, ) } if remoteCommitPoint != nil { remoteCommitKeys = deriveCommitmentKeys( - remoteCommitPoint, false, lc.localChanCfg, - lc.remoteChanCfg, + remoteCommitPoint, false, tweaklessCommit, + lc.localChanCfg, lc.remoteChanCfg, ) } @@ -978,7 +984,8 @@ type CommitmentKeyRing struct { // deriveCommitmentKey generates a new commitment key set using the base points // and commitment point. The keys are derived differently depending whether the // commitment transaction is ours or the remote peer's. -func deriveCommitmentKeys(commitPoint *btcec.PublicKey, isOurCommit bool, +func deriveCommitmentKeys(commitPoint *btcec.PublicKey, + isOurCommit, tweaklessCommit bool, localChanCfg, remoteChanCfg *channeldb.ChannelConfig) *CommitmentKeyRing { // First, we'll derive all the keys that don't depend on the context of @@ -1023,11 +1030,20 @@ func deriveCommitmentKeys(commitPoint *btcec.PublicKey, isOurCommit bool, // With the base points assigned, we can now derive the actual keys // using the base point, and the current commitment tweak. keyRing.DelayKey = input.TweakPubKey(delayBasePoint, commitPoint) - keyRing.NoDelayKey = input.TweakPubKey(noDelayBasePoint, commitPoint) keyRing.RevocationKey = input.DeriveRevocationPubkey( revocationBasePoint, commitPoint, ) + // If this commitment should omit the tweak for the remote point, then + // we'll use that directly, and ignore the commitPoint tweak. + if tweaklessCommit { + keyRing.NoDelayKey = noDelayBasePoint + } else { + keyRing.NoDelayKey = input.TweakPubKey( + noDelayBasePoint, commitPoint, + ) + } + return keyRing } @@ -1695,9 +1711,11 @@ func (lc *LightningChannel) restoreCommitState( // We'll also re-create the set of commitment keys needed to // fully re-derive the state. + tweaklessCommit := (lc.channelState.ChanType == + channeldb.SingleFunderTweakless) pendingRemoteKeyChain = deriveCommitmentKeys( - pendingCommitPoint, false, lc.localChanCfg, - lc.remoteChanCfg, + pendingCommitPoint, false, tweaklessCommit, + lc.localChanCfg, lc.remoteChanCfg, ) } @@ -1981,8 +1999,11 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64, // With the commitment point generated, we can now generate the four // keys we'll need to reconstruct the commitment state, - keyRing := deriveCommitmentKeys(commitmentPoint, false, - &chanState.LocalChanCfg, &chanState.RemoteChanCfg) + tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless + keyRing := deriveCommitmentKeys( + commitmentPoint, false, tweaklessCommit, + &chanState.LocalChanCfg, &chanState.RemoteChanCfg, + ) // Next, reconstruct the scripts as they were present at this state // number so we can have the proper witness script to sign and include @@ -3042,6 +3063,146 @@ func (lc *LightningChannel) createCommitDiff( }, nil } +// validateCommitmentSanity is used to validate the current state of the +// commitment transaction in terms of the ChannelConstraints that we and our +// remote peer agreed upon during the funding workflow. The predictAdded +// parameter should be set to a valid PaymentDescriptor if we are validating +// in the state when adding a new HTLC, or nil otherwise. +func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter, + ourLogCounter uint64, remoteChain bool, + predictAdded *PaymentDescriptor) error { + + // Fetch all updates not committed. + view := lc.fetchHTLCView(theirLogCounter, ourLogCounter) + + // If we are checking if we can add a new HTLC, we add this to the + // update log, in order to validate the sanity of the commitment + // resulting from _actually adding_ this HTLC to the state. + if predictAdded != nil { + // If we are adding an HTLC, this will be an Add to the local + // update log. + view.ourUpdates = append(view.ourUpdates, predictAdded) + } + + commitChain := lc.localCommitChain + if remoteChain { + commitChain = lc.remoteCommitChain + } + ourInitialBalance := commitChain.tip().ourBalance + theirInitialBalance := commitChain.tip().theirBalance + + ourBalance, theirBalance, commitWeight, filteredView := lc.computeView( + view, remoteChain, false, + ) + feePerKw := filteredView.feePerKw + + // Calculate the commitment fee, and subtract it from the initiator's + // balance. + commitFee := feePerKw.FeeForWeight(commitWeight) + commitFeeMsat := lnwire.NewMSatFromSatoshis(commitFee) + if lc.channelState.IsInitiator { + ourBalance -= commitFeeMsat + } else { + theirBalance -= commitFeeMsat + } + + // As a quick sanity check, we'll ensure that if we interpret the + // balances as signed integers, they haven't dipped down below zero. If + // they have, then this indicates that a party doesn't have sufficient + // balance to satisfy the final evaluated HTLC's. + switch { + case int64(ourBalance) < 0: + return ErrBelowChanReserve + case int64(theirBalance) < 0: + return ErrBelowChanReserve + } + + // Ensure that the fee being applied is enough to be relayed across the + // network in a reasonable time frame. + if feePerKw < FeePerKwFloor { + return fmt.Errorf("commitment fee per kw %v below fee floor %v", + feePerKw, FeePerKwFloor) + } + + // If the added HTLCs will decrease the balance, make sure they won't + // dip the local and remote balances below the channel reserves. + switch { + case ourBalance < ourInitialBalance && + ourBalance < lnwire.NewMSatFromSatoshis( + lc.localChanCfg.ChanReserve): + + return ErrBelowChanReserve + case theirBalance < theirInitialBalance && + theirBalance < lnwire.NewMSatFromSatoshis( + lc.remoteChanCfg.ChanReserve): + + return ErrBelowChanReserve + } + + // validateUpdates take a set of updates, and validates them against + // the passed channel constraints. + validateUpdates := func(updates []*PaymentDescriptor, + constraints *channeldb.ChannelConfig) error { + + // We keep track of the number of HTLCs in flight for the + // commitment, and the amount in flight. + var numInFlight uint16 + var amtInFlight lnwire.MilliSatoshi + + // Go through all updates, checking that they don't violate the + // channel constraints. + for _, entry := range updates { + if entry.EntryType == Add { + // An HTLC is being added, this will add to the + // number and amount in flight. + amtInFlight += entry.Amount + numInFlight++ + + // Check that the value of the HTLC they added + // is above our minimum. + if entry.Amount < constraints.MinHTLC { + return ErrBelowMinHTLC + } + } + } + + // Now that we know the total value of added HTLCs, we check + // that this satisfy the MaxPendingAmont contraint. + if amtInFlight > constraints.MaxPendingAmount { + return ErrMaxPendingAmount + } + + // In this step, we verify that the total number of active + // HTLCs does not exceed the constraint of the maximum number + // of HTLCs in flight. + if numInFlight > constraints.MaxAcceptedHtlcs { + return ErrMaxHTLCNumber + } + + return nil + } + + // First check that the remote updates won't violate it's channel + // constraints. + err := validateUpdates( + filteredView.theirUpdates, lc.remoteChanCfg, + ) + if err != nil { + return err + } + + // Secondly check that our updates won't violate our channel + // constraints. + err = validateUpdates( + filteredView.ourUpdates, lc.localChanCfg, + ) + if err != nil { + return err + } + + return nil +} + // SignNextCommitment signs a new commitment which includes any previous // unsettled HTLCs, any new HTLCs, and any modifications to prior HTLCs // committed in previous commitment updates. Signing a new commitment @@ -3091,8 +3252,11 @@ func (lc *LightningChannel) SignNextCommitment() (lnwire.Sig, []lnwire.Sig, []ch // Grab the next commitment point for the remote party. This will be // used within fetchCommitmentView to derive all the keys necessary to // construct the commitment state. + tweaklessCommit := (lc.channelState.ChanType == + channeldb.SingleFunderTweakless) keyRing := deriveCommitmentKeys( - commitPoint, false, lc.localChanCfg, lc.remoteChanCfg, + commitPoint, false, tweaklessCommit, lc.localChanCfg, + lc.remoteChanCfg, ) // Create a new commitment view which will calculate the evaluated @@ -3495,7 +3659,10 @@ func (lc *LightningChannel) ProcessChanSyncMsg( commitPoint = lc.channelState.RemoteNextRevocation } - if commitPoint != nil && + // Only if this is a tweakless channel will we attempt to verify the + // commitment point, as otherwise it has no validity requirements. + tweakless := lc.channelState.ChanType.IsTweakless() + if !tweakless && commitPoint != nil && !commitPoint.IsEqual(msg.LocalUnrevokedCommitPoint) { walletLog.Errorf("ChannelPoint(%v), sync failed: remote "+ @@ -3585,138 +3752,6 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool, return ourBalance, theirBalance, totalCommitWeight, filteredHTLCView } -// validateCommitmentSanity is used to validate the current state of the -// commitment transaction in terms of the ChannelConstraints that we and our -// remote peer agreed upon during the funding workflow. The predictAdded -// parameter should be set to a valid PaymentDescriptor if we are validating -// in the state when adding a new HTLC, or nil otherwise. -func (lc *LightningChannel) validateCommitmentSanity(theirLogCounter, - ourLogCounter uint64, remoteChain bool, - predictAdded *PaymentDescriptor) error { - - // Fetch all updates not committed. - view := lc.fetchHTLCView(theirLogCounter, ourLogCounter) - - // If we are checking if we can add a new HTLC, we add this to the - // update log, in order to validate the sanity of the commitment - // resulting from _actually adding_ this HTLC to the state. - if predictAdded != nil { - // If we are adding an HTLC, this will be an Add to the local - // update log. - view.ourUpdates = append(view.ourUpdates, predictAdded) - } - - commitChain := lc.localCommitChain - if remoteChain { - commitChain = lc.remoteCommitChain - } - ourInitialBalance := commitChain.tip().ourBalance - theirInitialBalance := commitChain.tip().theirBalance - - ourBalance, theirBalance, commitWeight, filteredView := lc.computeView( - view, remoteChain, false, - ) - feePerKw := filteredView.feePerKw - - // Calculate the commitment fee, and subtract it from the initiator's - // balance. - commitFee := feePerKw.FeeForWeight(commitWeight) - commitFeeMsat := lnwire.NewMSatFromSatoshis(commitFee) - if lc.channelState.IsInitiator { - ourBalance -= commitFeeMsat - } else { - theirBalance -= commitFeeMsat - } - - // As a quick sanity check, we'll ensure that if we interpret the - // balances as signed integers, they haven't dipped down below zero. If - // they have, then this indicates that a party doesn't have sufficient - // balance to satisfy the final evaluated HTLC's. - switch { - case int64(ourBalance) < 0: - return ErrBelowChanReserve - case int64(theirBalance) < 0: - return ErrBelowChanReserve - } - - // If the added HTLCs will decrease the balance, make sure they won't - // dip the local and remote balances below the channel reserves. - if ourBalance < ourInitialBalance && - ourBalance < lnwire.NewMSatFromSatoshis( - lc.localChanCfg.ChanReserve) { - return ErrBelowChanReserve - } - - if theirBalance < theirInitialBalance && - theirBalance < lnwire.NewMSatFromSatoshis( - lc.remoteChanCfg.ChanReserve) { - return ErrBelowChanReserve - } - - // validateUpdates take a set of updates, and validates them against - // the passed channel constraints. - validateUpdates := func(updates []*PaymentDescriptor, - constraints *channeldb.ChannelConfig) error { - - // We keep track of the number of HTLCs in flight for the - // commitment, and the amount in flight. - var numInFlight uint16 - var amtInFlight lnwire.MilliSatoshi - - // Go through all updates, checking that they don't violate the - // channel constraints. - for _, entry := range updates { - if entry.EntryType == Add { - // An HTLC is being added, this will add to the - // number and amount in flight. - amtInFlight += entry.Amount - numInFlight++ - - // Check that the value of the HTLC they added - // is above our minimum. - if entry.Amount < constraints.MinHTLC { - return ErrBelowMinHTLC - } - } - } - - // Now that we know the total value of added HTLCs, we check - // that this satisfy the MaxPendingAmont contraint. - if amtInFlight > constraints.MaxPendingAmount { - return ErrMaxPendingAmount - } - - // In this step, we verify that the total number of active - // HTLCs does not exceed the constraint of the maximum number - // of HTLCs in flight. - if numInFlight > constraints.MaxAcceptedHtlcs { - return ErrMaxHTLCNumber - } - - return nil - } - - // First check that the remote updates won't violate it's channel - // constraints. - err := validateUpdates( - filteredView.theirUpdates, lc.remoteChanCfg, - ) - if err != nil { - return err - } - - // Secondly check that our updates won't violate our channel - // constraints. - err = validateUpdates( - filteredView.ourUpdates, lc.localChanCfg, - ) - if err != nil { - return err - } - - return nil -} - // genHtlcSigValidationJobs generates a series of signatures verification jobs // meant to verify all the signatures for HTLC's attached to a newly created // commitment state. The jobs generated are fully populated, and can be sent @@ -3976,8 +4011,11 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig lnwire.Sig, return err } commitPoint := input.ComputeCommitmentPoint(commitSecret[:]) + tweaklessCommit := (lc.channelState.ChanType == + channeldb.SingleFunderTweakless) keyRing := deriveCommitmentKeys( - commitPoint, true, lc.localChanCfg, lc.remoteChanCfg, + commitPoint, true, tweaklessCommit, lc.localChanCfg, + lc.remoteChanCfg, ) // With the current commitment point re-calculated, construct the new @@ -5006,8 +5044,9 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si // First, we'll generate the commitment point and the revocation point // so we can re-construct the HTLC state and also our payment key. + tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless keyRing := deriveCommitmentKeys( - commitPoint, false, &chanState.LocalChanCfg, + commitPoint, false, tweaklessCommit, &chanState.LocalChanCfg, &chanState.RemoteChanCfg, ) @@ -5070,6 +5109,12 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si }, MaturityDelay: 0, } + + // If this is a tweakless commitment, then we can safely blank + // out the SingleTweak value as it isn't needed. + if tweaklessCommit { + commitResolution.SelfOutputSignDesc.SingleTweak = nil + } } closeSummary := channeldb.ChannelCloseSummary{ @@ -5655,8 +5700,11 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Si return nil, err } commitPoint := input.ComputeCommitmentPoint(revocation[:]) - keyRing := deriveCommitmentKeys(commitPoint, true, &chanState.LocalChanCfg, - &chanState.RemoteChanCfg) + tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless + keyRing := deriveCommitmentKeys( + commitPoint, true, tweaklessCommit, &chanState.LocalChanCfg, + &chanState.RemoteChanCfg, + ) selfScript, err := input.CommitScriptToSelf(csvTimeout, keyRing.DelayKey, keyRing.RevocationKey) if err != nil { diff --git a/lnwallet/channel_test.go b/lnwallet/channel_test.go index ca686d34..91e5e17d 100644 --- a/lnwallet/channel_test.go +++ b/lnwallet/channel_test.go @@ -52,22 +52,13 @@ func assertOutputExistsByValue(t *testing.T, commitTx *wire.MsgTx, spew.Sdump(commitTx)) } -// TestSimpleAddSettleWorkflow tests a simple channel scenario wherein the -// local node (Alice in this case) creates a new outgoing HTLC to bob, commits -// this change, then bob immediately commits a settlement of the HTLC after the -// initial add is fully committed in both commit chains. -// -// TODO(roasbeef): write higher level framework to exercise various states of -// the state machine -// * DSL language perhaps? -// * constructed via input/output files -func TestSimpleAddSettleWorkflow(t *testing.T) { - t.Parallel() - +// testAddSettleWorkflow tests a simple channel scenario where Alice and Bob +// add, the settle an HTLC between themselves. +func testAddSettleWorkflow(t *testing.T, tweakless bool) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(tweakless) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -295,10 +286,10 @@ func TestSimpleAddSettleWorkflow(t *testing.T) { "instead forwarding: %v", len(fwdPkg.SettleFails)) } - // At this point, Bob should have 6 BTC settled, with Alice still having - // 4 BTC. Alice's channel should show 1 BTC sent and Bob's channel - // should show 1 BTC received. They should also be at commitment height - // two, with the revocation window extended by 1 (5). + // At this point, Bob should have 6 BTC settled, with Alice still + // having 4 BTC. Alice's channel should show 1 BTC sent and Bob's + // channel should show 1 BTC received. They should also be at + // commitment height two, with the revocation window extended by 1 (5). mSatTransferred := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) if aliceChannel.channelState.TotalMSatSent != mSatTransferred { t.Fatalf("alice satoshis sent incorrect %v vs %v expected", @@ -348,6 +339,26 @@ func TestSimpleAddSettleWorkflow(t *testing.T) { } } +// TestSimpleAddSettleWorkflow tests a simple channel scenario wherein the +// local node (Alice in this case) creates a new outgoing HTLC to bob, commits +// this change, then bob immediately commits a settlement of the HTLC after the +// initial add is fully committed in both commit chains. +// +// TODO(roasbeef): write higher level framework to exercise various states of +// the state machine +// * DSL language perhaps? +// * constructed via input/output files +func TestSimpleAddSettleWorkflow(t *testing.T) { + t.Parallel() + + for _, tweakless := range []bool{true, false} { + tweakless := tweakless + t.Run(fmt.Sprintf("tweakless=%v", tweakless), func(t *testing.T) { + testAddSettleWorkflow(t, tweakless) + }) + } +} + // TestCheckCommitTxSize checks that estimation size of commitment // transaction with some degree of error corresponds to the actual size. func TestCheckCommitTxSize(t *testing.T) { @@ -377,7 +388,7 @@ func TestCheckCommitTxSize(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -436,7 +447,7 @@ func TestCooperativeChannelClosure(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -473,7 +484,8 @@ func TestCooperativeChannelClosure(t *testing.T) { // transaction is well formed, and the signatures verify. aliceCloseTx, _, err := bobChannel.CompleteCooperativeClose( bobCloseSig, aliceCloseSig, bobDeliveryScript, - aliceDeliveryScript, bobFee) + aliceDeliveryScript, bobFee, + ) if err != nil { t.Fatalf("unable to complete alice cooperative close: %v", err) } @@ -481,7 +493,8 @@ func TestCooperativeChannelClosure(t *testing.T) { bobCloseTx, _, err := aliceChannel.CompleteCooperativeClose( aliceCloseSig, bobCloseSig, aliceDeliveryScript, - bobDeliveryScript, aliceFee) + bobDeliveryScript, aliceFee, + ) if err != nil { t.Fatalf("unable to complete bob cooperative close: %v", err) } @@ -503,7 +516,7 @@ func TestForceClose(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -787,7 +800,7 @@ func TestForceCloseDustOutput(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -905,7 +918,7 @@ func TestDustHTLCFees(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -982,7 +995,7 @@ func TestHTLCDustLimit(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1067,7 +1080,7 @@ func TestHTLCSigNumber(t *testing.T) { // Create a test channel funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. Alice's dustlimit is 200 sat, while // Bob has 1300 sat. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1237,7 +1250,7 @@ func TestChannelBalanceDustLimit(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1305,7 +1318,7 @@ func TestStateUpdatePersistence(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1353,7 +1366,7 @@ func TestStateUpdatePersistence(t *testing.T) { } // Also add a fee update to the update logs. - fee := SatPerKWeight(111) + fee := SatPerKWeight(333) if err := aliceChannel.UpdateFee(fee); err != nil { t.Fatalf("unable to send fee update") } @@ -1646,7 +1659,7 @@ func TestCancelHTLC(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1760,7 +1773,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1921,7 +1934,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) { func TestUpdateFeeAdjustments(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1959,7 +1972,7 @@ func TestUpdateFeeAdjustments(t *testing.T) { // Finally, we'll attempt to adjust the fee down and use a fee which is // smaller than the initial base fee rate. The fee application and // state transition should proceed without issue. - newFee = SatPerKWeight(baseFeeRate / 100) + newFee = SatPerKWeight(baseFeeRate / 10) if err := aliceChannel.UpdateFee(newFee); err != nil { t.Fatalf("unable to alice update fee: %v", err) } @@ -1976,7 +1989,7 @@ func TestUpdateFeeAdjustments(t *testing.T) { func TestUpdateFeeFail(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -1984,7 +1997,9 @@ func TestUpdateFeeFail(t *testing.T) { // Bob receives the update, that will apply to his commitment // transaction. - bobChannel.ReceiveUpdateFee(111) + if err := bobChannel.ReceiveUpdateFee(333); err != nil { + t.Fatalf("unable to apply fee update: %v", err) + } // Alice sends signature for commitment that does not cover any fee // update. @@ -2008,7 +2023,7 @@ func TestUpdateFeeFail(t *testing.T) { func TestUpdateFeeConcurrentSig(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -2033,7 +2048,7 @@ func TestUpdateFeeConcurrentSig(t *testing.T) { } // Simulate Alice sending update fee message to bob. - fee := SatPerKWeight(111) + fee := SatPerKWeight(333) if err := aliceChannel.UpdateFee(fee); err != nil { t.Fatalf("unable to send fee update") } @@ -2094,7 +2109,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -2119,7 +2134,7 @@ func TestUpdateFeeSenderCommits(t *testing.T) { } // Simulate Alice sending update fee message to bob. - fee := SatPerKWeight(111) + fee := SatPerKWeight(333) aliceChannel.UpdateFee(fee) bobChannel.ReceiveUpdateFee(fee) @@ -2208,7 +2223,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -2233,7 +2248,7 @@ func TestUpdateFeeReceiverCommits(t *testing.T) { } // Simulate Alice sending update fee message to bob - fee := SatPerKWeight(111) + fee := SatPerKWeight(333) aliceChannel.UpdateFee(fee) bobChannel.ReceiveUpdateFee(fee) @@ -2349,7 +2364,7 @@ func TestUpdateFeeReceiverSendsUpdate(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -2357,7 +2372,7 @@ func TestUpdateFeeReceiverSendsUpdate(t *testing.T) { // Since Alice is the channel initiator, she should fail when receiving // fee update - fee := SatPerKWeight(111) + fee := SatPerKWeight(333) err = aliceChannel.ReceiveUpdateFee(fee) if err == nil { t.Fatalf("expected alice to fail receiving fee update") @@ -2378,15 +2393,15 @@ func TestUpdateFeeMultipleUpdates(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } defer cleanUp() // Simulate Alice sending update fee message to bob. - fee1 := SatPerKWeight(111) - fee2 := SatPerKWeight(222) + fee1 := SatPerKWeight(333) + fee2 := SatPerKWeight(333) fee := SatPerKWeight(333) aliceChannel.UpdateFee(fee1) aliceChannel.UpdateFee(fee2) @@ -2490,7 +2505,7 @@ func TestAddHTLCNegativeBalance(t *testing.T) { // We'll kick off the test by creating our channels which both are // loaded with 5 BTC each. - aliceChannel, _, cleanUp, err := CreateTestChannels() + aliceChannel, _, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -2571,7 +2586,7 @@ func TestChanSyncFullySynced(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -2691,7 +2706,7 @@ func TestChanSyncOweCommitment(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -3005,7 +3020,7 @@ func TestChanSyncOweRevocation(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -3195,7 +3210,7 @@ func TestChanSyncOweRevocationAndCommit(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -3364,7 +3379,7 @@ func TestChanSyncOweRevocationAndCommitForceTransition(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -3593,7 +3608,7 @@ func TestChanSyncFailure(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -3846,7 +3861,7 @@ func TestFeeUpdateRejectInsaneFee(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, _, cleanUp, err := CreateTestChannels() + aliceChannel, _, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -3872,7 +3887,7 @@ func TestChannelRetransmissionFeeUpdate(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4055,7 +4070,7 @@ func TestFeeUpdateOldDiskFormat(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4274,7 +4289,7 @@ func TestChanSyncUnableToSync(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4311,7 +4326,7 @@ func TestChanSyncInvalidLastSecret(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4401,7 +4416,7 @@ func TestChanAvailableBandwidth(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4524,7 +4539,7 @@ func TestSignCommitmentFailNotLockedIn(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, _, cleanUp, err := CreateTestChannels() + aliceChannel, _, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4549,7 +4564,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) { t.Parallel() // First, we'll make a channel between Alice and Bob. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4863,7 +4878,7 @@ func TestInvalidCommitSigError(t *testing.T) { t.Parallel() // First, we'll make a channel between Alice and Bob. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -4910,7 +4925,7 @@ func TestChannelUnilateralCloseHtlcResolution(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5068,7 +5083,9 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) { // Create a test channel which will be used for the duration of this // unittest. The channel will be funded evenly with Alice having 5 BTC, // and Bob having 5 BTC. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels( + false, + ) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5166,7 +5183,7 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) { }) aliceSignDesc.SigHashes = txscript.NewTxSigHashes(sweepTx) sweepTx.TxIn[0].Witness, err = input.CommitSpendNoDelay( - aliceChannel.Signer, &aliceSignDesc, sweepTx, + aliceChannel.Signer, &aliceSignDesc, sweepTx, false, ) if err != nil { t.Fatalf("unable to generate sweep witness: %v", err) @@ -5175,9 +5192,9 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) { // If we validate the signature on the new sweep transaction, it should // be fully valid. vm, err := txscript.NewEngine( - aliceSignDesc.Output.PkScript, - sweepTx, 0, txscript.StandardVerifyFlags, nil, - nil, aliceSignDesc.Output.Value, + aliceSignDesc.Output.PkScript, sweepTx, 0, + txscript.StandardVerifyFlags, nil, nil, + aliceSignDesc.Output.Value, ) if err != nil { t.Fatalf("unable to create engine: %v", err) @@ -5194,7 +5211,7 @@ func TestDesyncHTLCs(t *testing.T) { // We'll kick off the test by creating our channels which both are // loaded with 5 BTC each. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5261,7 +5278,7 @@ func TestMaxAcceptedHTLCs(t *testing.T) { // We'll kick off the test by creating our channels which both are // loaded with 5 BTC each. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5322,7 +5339,7 @@ func TestMaxPendingAmount(t *testing.T) { // We'll kick off the test by creating our channels which both are // loaded with 5 BTC each. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5410,7 +5427,9 @@ func TestChanReserve(t *testing.T) { setupChannels := func() (*LightningChannel, *LightningChannel, func()) { // We'll kick off the test by creating our channels which both // are loaded with 5 BTC each. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels( + true, + ) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5626,7 +5645,7 @@ func TestMinHTLC(t *testing.T) { // We'll kick off the test by creating our channels which both are // loaded with 5 BTC each. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5683,7 +5702,7 @@ func TestNewBreachRetributionSkipsDustHtlcs(t *testing.T) { // We'll kick off the test by creating our channels which both are // loaded with 5 BTC each. - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -5855,7 +5874,7 @@ func compareLogs(a, b *updateLog) error { func TestChannelRestoreUpdateLogs(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -6024,7 +6043,7 @@ func restoreAndAssert(t *testing.T, channel *LightningChannel, numAddsLocal, func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -6145,7 +6164,7 @@ func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) { func TestDuplicateFailRejection(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -6223,7 +6242,7 @@ func TestDuplicateFailRejection(t *testing.T) { func TestDuplicateSettleRejection(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -6304,7 +6323,7 @@ func TestDuplicateSettleRejection(t *testing.T) { func TestChannelRestoreCommitHeight(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -6491,7 +6510,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) { func TestForceCloseFailLocalDataLoss(t *testing.T) { t.Parallel() - aliceChannel, _, cleanUp, err := CreateTestChannels() + aliceChannel, _, cleanUp, err := CreateTestChannels(false) if err != nil { t.Fatalf("unable to create test channels: %v", err) } @@ -6522,7 +6541,7 @@ func TestForceCloseFailLocalDataLoss(t *testing.T) { func TestForceCloseBorkedState(t *testing.T) { t.Parallel() - aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() + aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false) if err != nil { t.Fatalf("unable to create test channels: %v", err) } diff --git a/lnwallet/test_utils.go b/lnwallet/test_utils.go index 32c6db95..579622fa 100644 --- a/lnwallet/test_utils.go +++ b/lnwallet/test_utils.go @@ -89,7 +89,7 @@ var ( // function also returns a "cleanup" function that is meant to be called once // the test has been finalized. The clean up function will remote all temporary // files created -func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error) { +func CreateTestChannels(tweaklessCommits bool) (*LightningChannel, *LightningChannel, func(), error) { channelCapacity, err := btcutil.NewAmount(10) if err != nil { return nil, nil, nil, err @@ -202,9 +202,10 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error) } aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:]) - aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns(channelBal, - channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, - *fundingTxIn) + aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns( + channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, + bobCommitPoint, *fundingTxIn, tweaklessCommits, + ) if err != nil { return nil, nil, nil, err } diff --git a/lnwallet/transactions_test.go b/lnwallet/transactions_test.go index 50a3bdf4..ed4c533d 100644 --- a/lnwallet/transactions_test.go +++ b/lnwallet/transactions_test.go @@ -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) + }) + } +} diff --git a/lnwallet/wallet.go b/lnwallet/wallet.go index c3ac2638..f86afb61 100644 --- a/lnwallet/wallet.go +++ b/lnwallet/wallet.go @@ -655,12 +655,17 @@ func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMs func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount, ourChanCfg, theirChanCfg *channeldb.ChannelConfig, localCommitPoint, remoteCommitPoint *btcec.PublicKey, - fundingTxIn wire.TxIn) (*wire.MsgTx, *wire.MsgTx, error) { + fundingTxIn wire.TxIn, + tweaklessCommit bool) (*wire.MsgTx, *wire.MsgTx, error) { - localCommitmentKeys := deriveCommitmentKeys(localCommitPoint, true, - ourChanCfg, theirChanCfg) - remoteCommitmentKeys := deriveCommitmentKeys(remoteCommitPoint, false, - ourChanCfg, theirChanCfg) + localCommitmentKeys := deriveCommitmentKeys( + localCommitPoint, true, tweaklessCommit, ourChanCfg, + theirChanCfg, + ) + remoteCommitmentKeys := deriveCommitmentKeys( + remoteCommitPoint, false, tweaklessCommit, ourChanCfg, + theirChanCfg, + ) ourCommitTx, err := CreateCommitTx(fundingTxIn, localCommitmentKeys, uint32(ourChanCfg.CsvDelay), localBalance, remoteBalance, @@ -827,11 +832,13 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) { // With the funding tx complete, create both commitment transactions. localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() + tweaklessCommits := pendingReservation.partialState.ChanType.IsTweakless() ourCommitTx, theirCommitTx, err := CreateCommitmentTxns( localBalance, remoteBalance, ourContribution.ChannelConfig, theirContribution.ChannelConfig, ourContribution.FirstCommitmentPoint, theirContribution.FirstCommitmentPoint, fundingTxIn, + tweaklessCommits, ) if err != nil { req.err <- err @@ -1151,13 +1158,14 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) { // remote node's commitment transactions. localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() + tweaklessCommits := pendingReservation.partialState.ChanType.IsTweakless() ourCommitTx, theirCommitTx, err := CreateCommitmentTxns( localBalance, remoteBalance, pendingReservation.ourContribution.ChannelConfig, pendingReservation.theirContribution.ChannelConfig, pendingReservation.ourContribution.FirstCommitmentPoint, pendingReservation.theirContribution.FirstCommitmentPoint, - *fundingTxIn, + *fundingTxIn, tweaklessCommits, ) if err != nil { req.err <- err diff --git a/test_utils.go b/test_utils.go index 7a5a1c34..cce87d54 100644 --- a/test_utils.go +++ b/test_utils.go @@ -186,9 +186,10 @@ func createTestPeer(notifier chainntnfs.ChainNotifier, } aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:]) - aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(channelBal, - channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, - *fundingTxIn) + aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns( + channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, + bobCommitPoint, *fundingTxIn, true, + ) if err != nil { return nil, nil, nil, nil, err }