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 2019-07-31 20:10:45 -07:00
parent 21133e1856
commit b399203e71
No known key found for this signature in database
GPG Key ID: BC13F65E2DC84465
8 changed files with 394 additions and 275 deletions

@ -869,6 +869,14 @@ func (c *OpenChannel) ChanSyncMsg() (*lnwire.ChannelReestablish, error) {
// allowing us to sweep our funds. // allowing us to sweep our funds.
if c.hasChanStatus(ChanStatusRestored) { if c.hasChanStatus(ChanStatusRestored) {
currentCommitSecret[0] ^= 1 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{ return &lnwire.ChannelReestablish{

@ -257,9 +257,10 @@ func createTestChannel(alicePrivKey, bobPrivKey []byte,
} }
aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:]) aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(aliceAmount, aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(
bobAmount, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, aliceAmount, bobAmount, &aliceCfg, &bobCfg, aliceCommitPoint,
*fundingTxIn) bobCommitPoint, *fundingTxIn, true,
)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }

@ -863,6 +863,12 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
diskCommit *channeldb.ChannelCommitment, localCommitPoint, diskCommit *channeldb.ChannelCommitment, localCommitPoint,
remoteCommitPoint *btcec.PublicKey) (*commitment, error) { 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 // 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 // party used within this particular state. If this is a pending commit
// (we extended but weren't able to complete the commitment dance // (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 var localCommitKeys, remoteCommitKeys *CommitmentKeyRing
if localCommitPoint != nil { if localCommitPoint != nil {
localCommitKeys = deriveCommitmentKeys( localCommitKeys = deriveCommitmentKeys(
localCommitPoint, true, lc.localChanCfg, localCommitPoint, true, tweaklessCommit,
lc.remoteChanCfg, lc.localChanCfg, lc.remoteChanCfg,
) )
} }
if remoteCommitPoint != nil { if remoteCommitPoint != nil {
remoteCommitKeys = deriveCommitmentKeys( remoteCommitKeys = deriveCommitmentKeys(
remoteCommitPoint, false, lc.localChanCfg, remoteCommitPoint, false, tweaklessCommit,
lc.remoteChanCfg, lc.localChanCfg, lc.remoteChanCfg,
) )
} }
@ -978,7 +984,8 @@ type CommitmentKeyRing struct {
// deriveCommitmentKey generates a new commitment key set using the base points // deriveCommitmentKey generates a new commitment key set using the base points
// and commitment point. The keys are derived differently depending whether the // and commitment point. The keys are derived differently depending whether the
// commitment transaction is ours or the remote peer's. // 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 { localChanCfg, remoteChanCfg *channeldb.ChannelConfig) *CommitmentKeyRing {
// First, we'll derive all the keys that don't depend on the context of // 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 // With the base points assigned, we can now derive the actual keys
// using the base point, and the current commitment tweak. // using the base point, and the current commitment tweak.
keyRing.DelayKey = input.TweakPubKey(delayBasePoint, commitPoint) keyRing.DelayKey = input.TweakPubKey(delayBasePoint, commitPoint)
keyRing.NoDelayKey = input.TweakPubKey(noDelayBasePoint, commitPoint)
keyRing.RevocationKey = input.DeriveRevocationPubkey( keyRing.RevocationKey = input.DeriveRevocationPubkey(
revocationBasePoint, commitPoint, 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 return keyRing
} }
@ -1695,9 +1711,11 @@ func (lc *LightningChannel) restoreCommitState(
// We'll also re-create the set of commitment keys needed to // We'll also re-create the set of commitment keys needed to
// fully re-derive the state. // fully re-derive the state.
tweaklessCommit := (lc.channelState.ChanType ==
channeldb.SingleFunderTweakless)
pendingRemoteKeyChain = deriveCommitmentKeys( pendingRemoteKeyChain = deriveCommitmentKeys(
pendingCommitPoint, false, lc.localChanCfg, pendingCommitPoint, false, tweaklessCommit,
lc.remoteChanCfg, 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 // With the commitment point generated, we can now generate the four
// keys we'll need to reconstruct the commitment state, // keys we'll need to reconstruct the commitment state,
keyRing := deriveCommitmentKeys(commitmentPoint, false, tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless
&chanState.LocalChanCfg, &chanState.RemoteChanCfg) keyRing := deriveCommitmentKeys(
commitmentPoint, false, tweaklessCommit,
&chanState.LocalChanCfg, &chanState.RemoteChanCfg,
)
// Next, reconstruct the scripts as they were present at this state // Next, reconstruct the scripts as they were present at this state
// number so we can have the proper witness script to sign and include // number so we can have the proper witness script to sign and include
@ -3042,6 +3063,146 @@ func (lc *LightningChannel) createCommitDiff(
}, nil }, 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 // SignNextCommitment signs a new commitment which includes any previous
// unsettled HTLCs, any new HTLCs, and any modifications to prior HTLCs // unsettled HTLCs, any new HTLCs, and any modifications to prior HTLCs
// committed in previous commitment updates. Signing a new commitment // 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 // Grab the next commitment point for the remote party. This will be
// used within fetchCommitmentView to derive all the keys necessary to // used within fetchCommitmentView to derive all the keys necessary to
// construct the commitment state. // construct the commitment state.
tweaklessCommit := (lc.channelState.ChanType ==
channeldb.SingleFunderTweakless)
keyRing := deriveCommitmentKeys( 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 // Create a new commitment view which will calculate the evaluated
@ -3495,7 +3659,10 @@ func (lc *LightningChannel) ProcessChanSyncMsg(
commitPoint = lc.channelState.RemoteNextRevocation 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) { !commitPoint.IsEqual(msg.LocalUnrevokedCommitPoint) {
walletLog.Errorf("ChannelPoint(%v), sync failed: remote "+ walletLog.Errorf("ChannelPoint(%v), sync failed: remote "+
@ -3585,138 +3752,6 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool,
return ourBalance, theirBalance, totalCommitWeight, filteredHTLCView 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 // genHtlcSigValidationJobs generates a series of signatures verification jobs
// meant to verify all the signatures for HTLC's attached to a newly created // 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 // 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 return err
} }
commitPoint := input.ComputeCommitmentPoint(commitSecret[:]) commitPoint := input.ComputeCommitmentPoint(commitSecret[:])
tweaklessCommit := (lc.channelState.ChanType ==
channeldb.SingleFunderTweakless)
keyRing := deriveCommitmentKeys( 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 // 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 // First, we'll generate the commitment point and the revocation point
// so we can re-construct the HTLC state and also our payment key. // so we can re-construct the HTLC state and also our payment key.
tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless
keyRing := deriveCommitmentKeys( keyRing := deriveCommitmentKeys(
commitPoint, false, &chanState.LocalChanCfg, commitPoint, false, tweaklessCommit, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, &chanState.RemoteChanCfg,
) )
@ -5070,6 +5109,12 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
}, },
MaturityDelay: 0, 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{ closeSummary := channeldb.ChannelCloseSummary{
@ -5655,8 +5700,11 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
return nil, err return nil, err
} }
commitPoint := input.ComputeCommitmentPoint(revocation[:]) commitPoint := input.ComputeCommitmentPoint(revocation[:])
keyRing := deriveCommitmentKeys(commitPoint, true, &chanState.LocalChanCfg, tweaklessCommit := chanState.ChanType == channeldb.SingleFunderTweakless
&chanState.RemoteChanCfg) keyRing := deriveCommitmentKeys(
commitPoint, true, tweaklessCommit, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg,
)
selfScript, err := input.CommitScriptToSelf(csvTimeout, keyRing.DelayKey, selfScript, err := input.CommitScriptToSelf(csvTimeout, keyRing.DelayKey,
keyRing.RevocationKey) keyRing.RevocationKey)
if err != nil { if err != nil {

@ -52,22 +52,13 @@ func assertOutputExistsByValue(t *testing.T, commitTx *wire.MsgTx,
spew.Sdump(commitTx)) spew.Sdump(commitTx))
} }
// TestSimpleAddSettleWorkflow tests a simple channel scenario wherein the // testAddSettleWorkflow tests a simple channel scenario where Alice and Bob
// local node (Alice in this case) creates a new outgoing HTLC to bob, commits // add, the settle an HTLC between themselves.
// this change, then bob immediately commits a settlement of the HTLC after the func testAddSettleWorkflow(t *testing.T, tweakless bool) {
// 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()
// Create a test channel which will be used for the duration of this // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(tweakless)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -295,10 +286,10 @@ func TestSimpleAddSettleWorkflow(t *testing.T) {
"instead forwarding: %v", len(fwdPkg.SettleFails)) "instead forwarding: %v", len(fwdPkg.SettleFails))
} }
// At this point, Bob should have 6 BTC settled, with Alice still having // At this point, Bob should have 6 BTC settled, with Alice still
// 4 BTC. Alice's channel should show 1 BTC sent and Bob's channel // having 4 BTC. Alice's channel should show 1 BTC sent and Bob's
// should show 1 BTC received. They should also be at commitment height // channel should show 1 BTC received. They should also be at
// two, with the revocation window extended by 1 (5). // commitment height two, with the revocation window extended by 1 (5).
mSatTransferred := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin) mSatTransferred := lnwire.NewMSatFromSatoshis(btcutil.SatoshiPerBitcoin)
if aliceChannel.channelState.TotalMSatSent != mSatTransferred { if aliceChannel.channelState.TotalMSatSent != mSatTransferred {
t.Fatalf("alice satoshis sent incorrect %v vs %v expected", 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 // TestCheckCommitTxSize checks that estimation size of commitment
// transaction with some degree of error corresponds to the actual size. // transaction with some degree of error corresponds to the actual size.
func TestCheckCommitTxSize(t *testing.T) { 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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. // transaction is well formed, and the signatures verify.
aliceCloseTx, _, err := bobChannel.CompleteCooperativeClose( aliceCloseTx, _, err := bobChannel.CompleteCooperativeClose(
bobCloseSig, aliceCloseSig, bobDeliveryScript, bobCloseSig, aliceCloseSig, bobDeliveryScript,
aliceDeliveryScript, bobFee) aliceDeliveryScript, bobFee,
)
if err != nil { if err != nil {
t.Fatalf("unable to complete alice cooperative close: %v", err) t.Fatalf("unable to complete alice cooperative close: %v", err)
} }
@ -481,7 +493,8 @@ func TestCooperativeChannelClosure(t *testing.T) {
bobCloseTx, _, err := aliceChannel.CompleteCooperativeClose( bobCloseTx, _, err := aliceChannel.CompleteCooperativeClose(
aliceCloseSig, bobCloseSig, aliceDeliveryScript, aliceCloseSig, bobCloseSig, aliceDeliveryScript,
bobDeliveryScript, aliceFee) bobDeliveryScript, aliceFee,
)
if err != nil { if err != nil {
t.Fatalf("unable to complete bob cooperative close: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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, // Create a test channel funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. Alice's dustlimit is 200 sat, while // and Bob having 5 BTC. Alice's dustlimit is 200 sat, while
// Bob has 1300 sat. // Bob has 1300 sat.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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. // Also add a fee update to the update logs.
fee := SatPerKWeight(111) fee := SatPerKWeight(333)
if err := aliceChannel.UpdateFee(fee); err != nil { if err := aliceChannel.UpdateFee(fee); err != nil {
t.Fatalf("unable to send fee update") 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -1921,7 +1934,7 @@ func TestCooperativeCloseDustAdherence(t *testing.T) {
func TestUpdateFeeAdjustments(t *testing.T) { func TestUpdateFeeAdjustments(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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 // smaller than the initial base fee rate. The fee application and
// state transition should proceed without issue. // state transition should proceed without issue.
newFee = SatPerKWeight(baseFeeRate / 100) newFee = SatPerKWeight(baseFeeRate / 10)
if err := aliceChannel.UpdateFee(newFee); err != nil { if err := aliceChannel.UpdateFee(newFee); err != nil {
t.Fatalf("unable to alice update fee: %v", err) t.Fatalf("unable to alice update fee: %v", err)
} }
@ -1976,7 +1989,7 @@ func TestUpdateFeeAdjustments(t *testing.T) {
func TestUpdateFeeFail(t *testing.T) { func TestUpdateFeeFail(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // Bob receives the update, that will apply to his commitment
// transaction. // 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 // Alice sends signature for commitment that does not cover any fee
// update. // update.
@ -2008,7 +2023,7 @@ func TestUpdateFeeFail(t *testing.T) {
func TestUpdateFeeConcurrentSig(t *testing.T) { func TestUpdateFeeConcurrentSig(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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. // Simulate Alice sending update fee message to bob.
fee := SatPerKWeight(111) fee := SatPerKWeight(333)
if err := aliceChannel.UpdateFee(fee); err != nil { if err := aliceChannel.UpdateFee(fee); err != nil {
t.Fatalf("unable to send fee update") 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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. // Simulate Alice sending update fee message to bob.
fee := SatPerKWeight(111) fee := SatPerKWeight(333)
aliceChannel.UpdateFee(fee) aliceChannel.UpdateFee(fee)
bobChannel.ReceiveUpdateFee(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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // Simulate Alice sending update fee message to bob
fee := SatPerKWeight(111) fee := SatPerKWeight(333)
aliceChannel.UpdateFee(fee) aliceChannel.UpdateFee(fee)
bobChannel.ReceiveUpdateFee(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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // Since Alice is the channel initiator, she should fail when receiving
// fee update // fee update
fee := SatPerKWeight(111) fee := SatPerKWeight(333)
err = aliceChannel.ReceiveUpdateFee(fee) err = aliceChannel.ReceiveUpdateFee(fee)
if err == nil { if err == nil {
t.Fatalf("expected alice to fail receiving fee update") 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
defer cleanUp() defer cleanUp()
// Simulate Alice sending update fee message to bob. // Simulate Alice sending update fee message to bob.
fee1 := SatPerKWeight(111) fee1 := SatPerKWeight(333)
fee2 := SatPerKWeight(222) fee2 := SatPerKWeight(333)
fee := SatPerKWeight(333) fee := SatPerKWeight(333)
aliceChannel.UpdateFee(fee1) aliceChannel.UpdateFee(fee1)
aliceChannel.UpdateFee(fee2) 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 // We'll kick off the test by creating our channels which both are
// loaded with 5 BTC each. // loaded with 5 BTC each.
aliceChannel, _, cleanUp, err := CreateTestChannels() aliceChannel, _, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, _, cleanUp, err := CreateTestChannels() aliceChannel, _, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, _, cleanUp, err := CreateTestChannels() aliceChannel, _, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -4549,7 +4564,7 @@ func TestLockedInHtlcForwardingSkipAfterRestart(t *testing.T) {
t.Parallel() t.Parallel()
// First, we'll make a channel between Alice and Bob. // First, we'll make a channel between Alice and Bob.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -4863,7 +4878,7 @@ func TestInvalidCommitSigError(t *testing.T) {
t.Parallel() t.Parallel()
// First, we'll make a channel between Alice and Bob. // First, we'll make a channel between Alice and Bob.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // 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, // unittest. The channel will be funded evenly with Alice having 5 BTC,
// and Bob having 5 BTC. // and Bob having 5 BTC.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(
false,
)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -5166,7 +5183,7 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) {
}) })
aliceSignDesc.SigHashes = txscript.NewTxSigHashes(sweepTx) aliceSignDesc.SigHashes = txscript.NewTxSigHashes(sweepTx)
sweepTx.TxIn[0].Witness, err = input.CommitSpendNoDelay( sweepTx.TxIn[0].Witness, err = input.CommitSpendNoDelay(
aliceChannel.Signer, &aliceSignDesc, sweepTx, aliceChannel.Signer, &aliceSignDesc, sweepTx, false,
) )
if err != nil { if err != nil {
t.Fatalf("unable to generate sweep witness: %v", err) 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 // If we validate the signature on the new sweep transaction, it should
// be fully valid. // be fully valid.
vm, err := txscript.NewEngine( vm, err := txscript.NewEngine(
aliceSignDesc.Output.PkScript, aliceSignDesc.Output.PkScript, sweepTx, 0,
sweepTx, 0, txscript.StandardVerifyFlags, nil, txscript.StandardVerifyFlags, nil, nil,
nil, aliceSignDesc.Output.Value, aliceSignDesc.Output.Value,
) )
if err != nil { if err != nil {
t.Fatalf("unable to create engine: %v", err) 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 // We'll kick off the test by creating our channels which both are
// loaded with 5 BTC each. // loaded with 5 BTC each.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // We'll kick off the test by creating our channels which both are
// loaded with 5 BTC each. // loaded with 5 BTC each.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // We'll kick off the test by creating our channels which both are
// loaded with 5 BTC each. // loaded with 5 BTC each.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -5410,7 +5427,9 @@ func TestChanReserve(t *testing.T) {
setupChannels := func() (*LightningChannel, *LightningChannel, func()) { setupChannels := func() (*LightningChannel, *LightningChannel, func()) {
// We'll kick off the test by creating our channels which both // We'll kick off the test by creating our channels which both
// are loaded with 5 BTC each. // are loaded with 5 BTC each.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(
true,
)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // We'll kick off the test by creating our channels which both are
// loaded with 5 BTC each. // loaded with 5 BTC each.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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 // We'll kick off the test by creating our channels which both are
// loaded with 5 BTC each. // loaded with 5 BTC each.
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -5855,7 +5874,7 @@ func compareLogs(a, b *updateLog) error {
func TestChannelRestoreUpdateLogs(t *testing.T) { func TestChannelRestoreUpdateLogs(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) 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) { func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -6145,7 +6164,7 @@ func TestChannelRestoreUpdateLogsFailedHTLC(t *testing.T) {
func TestDuplicateFailRejection(t *testing.T) { func TestDuplicateFailRejection(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -6223,7 +6242,7 @@ func TestDuplicateFailRejection(t *testing.T) {
func TestDuplicateSettleRejection(t *testing.T) { func TestDuplicateSettleRejection(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -6304,7 +6323,7 @@ func TestDuplicateSettleRejection(t *testing.T) {
func TestChannelRestoreCommitHeight(t *testing.T) { func TestChannelRestoreCommitHeight(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(true)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -6491,7 +6510,7 @@ func TestChannelRestoreCommitHeight(t *testing.T) {
func TestForceCloseFailLocalDataLoss(t *testing.T) { func TestForceCloseFailLocalDataLoss(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, _, cleanUp, err := CreateTestChannels() aliceChannel, _, cleanUp, err := CreateTestChannels(false)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }
@ -6522,7 +6541,7 @@ func TestForceCloseFailLocalDataLoss(t *testing.T) {
func TestForceCloseBorkedState(t *testing.T) { func TestForceCloseBorkedState(t *testing.T) {
t.Parallel() t.Parallel()
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels() aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(false)
if err != nil { if err != nil {
t.Fatalf("unable to create test channels: %v", err) t.Fatalf("unable to create test channels: %v", err)
} }

@ -89,7 +89,7 @@ var (
// function also returns a "cleanup" function that is meant to be called once // 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 // the test has been finalized. The clean up function will remote all temporary
// files created // files created
func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error) { func CreateTestChannels(tweaklessCommits bool) (*LightningChannel, *LightningChannel, func(), error) {
channelCapacity, err := btcutil.NewAmount(10) channelCapacity, err := btcutil.NewAmount(10)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
@ -202,9 +202,10 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
} }
aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:]) aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns(channelBal, aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns(
channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint,
*fundingTxIn) bobCommitPoint, *fundingTxIn, tweaklessCommits,
)
if err != nil { if err != nil {
return nil, nil, nil, err return nil, nil, nil, err
} }

@ -370,7 +370,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
// Manually construct a new LightningChannel. // Manually construct a new LightningChannel.
channelState := channeldb.OpenChannel{ channelState := channeldb.OpenChannel{
ChanType: channeldb.SingleFunder, ChanType: channeldb.SingleFunderTweakless,
ChainHash: *tc.netParams.GenesisHash, ChainHash: *tc.netParams.GenesisHash,
FundingOutpoint: tc.fundingOutpoint, FundingOutpoint: tc.fundingOutpoint,
ShortChannelID: tc.shortChanID, ShortChannelID: tc.shortChanID,
@ -999,18 +999,9 @@ func TestCommitTxStateHint(t *testing.T) {
} }
} }
// TestCommitmentSpendValidation test the spendability of both outputs within // testSpendValidation ensures that we're able to spend all outputs in the
// the commitment transaction. // commitment transaction that we create.
// func testSpendValidation(t *testing.T, tweakless bool) {
// 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()
// We generate a fake output, and the corresponding txin. This output // 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 // doesn't need to exist, as we'll only be validating spending from the
// transaction that references this. // transaction that references this.
@ -1030,18 +1021,28 @@ func TestCommitmentSpendValidation(t *testing.T) {
// We also set up set some resources for the commitment transaction. // We also set up set some resources for the commitment transaction.
// Each side currently has 1 BTC within the channel, with a total // Each side currently has 1 BTC within the channel, with a total
// channel capacity of 2BTC. // channel capacity of 2BTC.
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(), aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
testWalletPrivKey) btcec.S256(), testWalletPrivKey,
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(), )
bobsPrivKey) bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(
btcec.S256(), bobsPrivKey,
)
revocationPreimage := testHdSeed.CloneBytes() revocationPreimage := testHdSeed.CloneBytes()
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(), commitSecret, commitPoint := btcec.PrivKeyFromBytes(
revocationPreimage) btcec.S256(), revocationPreimage,
)
revokePubKey := input.DeriveRevocationPubkey(bobKeyPub, commitPoint) revokePubKey := input.DeriveRevocationPubkey(bobKeyPub, commitPoint)
aliceDelayKey := input.TweakPubKey(aliceKeyPub, 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) bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint)
if tweakless {
bobPayKey = bobKeyPub
}
aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub) aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub)
bobCommitTweak := input.SingleTweakBytes(commitPoint, bobKeyPub) bobCommitTweak := input.SingleTweakBytes(commitPoint, bobKeyPub)
@ -1062,8 +1063,10 @@ func TestCommitmentSpendValidation(t *testing.T) {
RevocationKey: revokePubKey, RevocationKey: revokePubKey,
NoDelayKey: bobPayKey, NoDelayKey: bobPayKey,
} }
commitmentTx, err := CreateCommitTx(*fakeFundingTxIn, keyRing, csvTimeout, commitmentTx, err := CreateCommitTx(
channelBalance, channelBalance, DefaultDustLimit()) *fakeFundingTxIn, keyRing, csvTimeout, channelBalance,
channelBalance, DefaultDustLimit(),
)
if err != nil { if err != nil {
t.Fatalf("unable to create commitment transaction: %v", 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. // First, we'll test spending with Alice's key after the timeout.
delayScript, err := input.CommitScriptToSelf(csvTimeout, aliceDelayKey, delayScript, err := input.CommitScriptToSelf(
revokePubKey) csvTimeout, aliceDelayKey, revokePubKey,
)
if err != nil { if err != nil {
t.Fatalf("unable to generate alice delay script: %v", err) t.Fatalf("unable to generate alice delay script: %v", err)
} }
@ -1107,8 +1111,9 @@ func TestCommitmentSpendValidation(t *testing.T) {
HashType: txscript.SigHashAll, HashType: txscript.SigHashAll,
InputIndex: 0, InputIndex: 0,
} }
aliceWitnessSpend, err := input.CommitSpendTimeout(aliceSelfOutputSigner, aliceWitnessSpend, err := input.CommitSpendTimeout(
signDesc, sweepTx) aliceSelfOutputSigner, signDesc, sweepTx,
)
if err != nil { if err != nil {
t.Fatalf("unable to generate delay commit spend witness: %v", err) t.Fatalf("unable to generate delay commit spend witness: %v", err)
} }
@ -1177,7 +1182,6 @@ func TestCommitmentSpendValidation(t *testing.T) {
KeyDesc: keychain.KeyDescriptor{ KeyDesc: keychain.KeyDescriptor{
PubKey: bobKeyPub, PubKey: bobKeyPub,
}, },
SingleTweak: bobCommitTweak,
WitnessScript: bobScriptP2WKH, WitnessScript: bobScriptP2WKH,
SigHashes: txscript.NewTxSigHashes(sweepTx), SigHashes: txscript.NewTxSigHashes(sweepTx),
Output: &wire.TxOut{ Output: &wire.TxOut{
@ -1187,15 +1191,21 @@ func TestCommitmentSpendValidation(t *testing.T) {
HashType: txscript.SigHashAll, HashType: txscript.SigHashAll,
InputIndex: 0, InputIndex: 0,
} }
bobRegularSpend, err := input.CommitSpendNoDelay(bobSigner, signDesc, if !tweakless {
sweepTx) signDesc.SingleTweak = bobCommitTweak
}
bobRegularSpend, err := input.CommitSpendNoDelay(
bobSigner, signDesc, sweepTx, tweakless,
)
if err != nil { if err != nil {
t.Fatalf("unable to create bob regular spend: %v", err) t.Fatalf("unable to create bob regular spend: %v", err)
} }
sweepTx.TxIn[0].Witness = bobRegularSpend sweepTx.TxIn[0].Witness = bobRegularSpend
vm, err = txscript.NewEngine(regularOutput.PkScript, vm, err = txscript.NewEngine(
regularOutput.PkScript,
sweepTx, 0, txscript.StandardVerifyFlags, nil, sweepTx, 0, txscript.StandardVerifyFlags, nil,
nil, int64(channelBalance)) nil, int64(channelBalance),
)
if err != nil { if err != nil {
t.Fatalf("unable to create engine: %v", err) 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) 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)
})
}
}

@ -655,12 +655,17 @@ func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMs
func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount, func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
ourChanCfg, theirChanCfg *channeldb.ChannelConfig, ourChanCfg, theirChanCfg *channeldb.ChannelConfig,
localCommitPoint, remoteCommitPoint *btcec.PublicKey, 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, localCommitmentKeys := deriveCommitmentKeys(
ourChanCfg, theirChanCfg) localCommitPoint, true, tweaklessCommit, ourChanCfg,
remoteCommitmentKeys := deriveCommitmentKeys(remoteCommitPoint, false, theirChanCfg,
ourChanCfg, theirChanCfg) )
remoteCommitmentKeys := deriveCommitmentKeys(
remoteCommitPoint, false, tweaklessCommit, ourChanCfg,
theirChanCfg,
)
ourCommitTx, err := CreateCommitTx(fundingTxIn, localCommitmentKeys, ourCommitTx, err := CreateCommitTx(fundingTxIn, localCommitmentKeys,
uint32(ourChanCfg.CsvDelay), localBalance, remoteBalance, uint32(ourChanCfg.CsvDelay), localBalance, remoteBalance,
@ -827,11 +832,13 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
// With the funding tx complete, create both commitment transactions. // With the funding tx complete, create both commitment transactions.
localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis()
remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis()
tweaklessCommits := pendingReservation.partialState.ChanType.IsTweakless()
ourCommitTx, theirCommitTx, err := CreateCommitmentTxns( ourCommitTx, theirCommitTx, err := CreateCommitmentTxns(
localBalance, remoteBalance, ourContribution.ChannelConfig, localBalance, remoteBalance, ourContribution.ChannelConfig,
theirContribution.ChannelConfig, theirContribution.ChannelConfig,
ourContribution.FirstCommitmentPoint, ourContribution.FirstCommitmentPoint,
theirContribution.FirstCommitmentPoint, fundingTxIn, theirContribution.FirstCommitmentPoint, fundingTxIn,
tweaklessCommits,
) )
if err != nil { if err != nil {
req.err <- err req.err <- err
@ -1151,13 +1158,14 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
// remote node's commitment transactions. // remote node's commitment transactions.
localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis() localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis()
remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis() remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis()
tweaklessCommits := pendingReservation.partialState.ChanType.IsTweakless()
ourCommitTx, theirCommitTx, err := CreateCommitmentTxns( ourCommitTx, theirCommitTx, err := CreateCommitmentTxns(
localBalance, remoteBalance, localBalance, remoteBalance,
pendingReservation.ourContribution.ChannelConfig, pendingReservation.ourContribution.ChannelConfig,
pendingReservation.theirContribution.ChannelConfig, pendingReservation.theirContribution.ChannelConfig,
pendingReservation.ourContribution.FirstCommitmentPoint, pendingReservation.ourContribution.FirstCommitmentPoint,
pendingReservation.theirContribution.FirstCommitmentPoint, pendingReservation.theirContribution.FirstCommitmentPoint,
*fundingTxIn, *fundingTxIn, tweaklessCommits,
) )
if err != nil { if err != nil {
req.err <- err req.err <- err

@ -186,9 +186,10 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
} }
aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:]) aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(channelBal, aliceCommitTx, bobCommitTx, err := lnwallet.CreateCommitmentTxns(
channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint, channelBal, channelBal, &aliceCfg, &bobCfg, aliceCommitPoint,
*fundingTxIn) bobCommitPoint, *fundingTxIn, true,
)
if err != nil { if err != nil {
return nil, nil, nil, nil, err return nil, nil, nil, nil, err
} }