Merge pull request #1180 from halseth/empty-commitsig-fix
Empty commitsig fix
This commit is contained in:
commit
355355b81e
@ -3912,3 +3912,347 @@ func restartLink(aliceChannel *lnwallet.LightningChannel, aliceSwitch *Switch,
|
||||
|
||||
return aliceLink, t, cleanUp, nil
|
||||
}
|
||||
|
||||
// gnerateHtlc generates a simple payment from Bob to Alice.
|
||||
func generateHtlc(t *testing.T, coreLink *channelLink,
|
||||
bobChannel *lnwallet.LightningChannel, id uint64) *lnwire.UpdateAddHTLC {
|
||||
htlcAmt := lnwire.NewMSatFromSatoshis(10000)
|
||||
hops := []ForwardingInfo{
|
||||
{
|
||||
Network: BitcoinHop,
|
||||
NextHop: exitHop,
|
||||
AmountToForward: htlcAmt,
|
||||
OutgoingCTLV: 144,
|
||||
},
|
||||
}
|
||||
blob, err := generateRoute(hops...)
|
||||
invoice, htlc, err := generatePayment(htlcAmt, htlcAmt, 144,
|
||||
blob)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create payment: %v", err)
|
||||
}
|
||||
|
||||
// We must add the invoice to the registry, such that Alice
|
||||
// expects this payment.
|
||||
err = coreLink.cfg.Registry.(*mockInvoiceRegistry).AddInvoice(
|
||||
*invoice)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to add invoice to registry: %v", err)
|
||||
}
|
||||
htlc.ID = id
|
||||
return htlc
|
||||
}
|
||||
|
||||
// sendHtlcBobToAlice sends an HTLC from Bob to Alice, that pays to a preimage
|
||||
// already in Alice's registry.
|
||||
func sendHtlcBobToAlice(t *testing.T, aliceLink ChannelLink,
|
||||
bobChannel *lnwallet.LightningChannel, htlc *lnwire.UpdateAddHTLC) {
|
||||
_, err := bobChannel.AddHTLC(htlc, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("bob failed adding htlc: %v", err)
|
||||
}
|
||||
|
||||
aliceLink.HandleChannelUpdate(htlc)
|
||||
}
|
||||
|
||||
// sendCommitSigBobToAlice makes Bob sign a new commitment and send it to
|
||||
// Alice, asserting that it signs expHtlcs number of HTLCs.
|
||||
func sendCommitSigBobToAlice(t *testing.T, aliceLink ChannelLink,
|
||||
bobChannel *lnwallet.LightningChannel, expHtlcs int) {
|
||||
sig, htlcSigs, err := bobChannel.SignNextCommitment()
|
||||
if err != nil {
|
||||
t.Fatalf("error signing commitment: %v", err)
|
||||
}
|
||||
|
||||
commitSig := &lnwire.CommitSig{
|
||||
CommitSig: sig,
|
||||
HtlcSigs: htlcSigs,
|
||||
}
|
||||
|
||||
if len(commitSig.HtlcSigs) != expHtlcs {
|
||||
t.Fatalf("Expected %d htlc sigs, got %d", expHtlcs,
|
||||
len(commitSig.HtlcSigs))
|
||||
}
|
||||
|
||||
aliceLink.HandleChannelUpdate(commitSig)
|
||||
}
|
||||
|
||||
// receiveRevAndAckAliceToBob waits for Alice to send a RevAndAck to Bob, then
|
||||
// hands this to Bob.
|
||||
func receiveRevAndAckAliceToBob(t *testing.T, aliceMsgs chan lnwire.Message,
|
||||
aliceLink ChannelLink,
|
||||
bobChannel *lnwallet.LightningChannel) {
|
||||
var msg lnwire.Message
|
||||
select {
|
||||
case msg = <-aliceMsgs:
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("did not receive message")
|
||||
}
|
||||
|
||||
rev, ok := msg.(*lnwire.RevokeAndAck)
|
||||
if !ok {
|
||||
t.Fatalf("expected RevokeAndAck, got %T", msg)
|
||||
}
|
||||
|
||||
_, _, _, err := bobChannel.ReceiveRevocation(rev)
|
||||
if err != nil {
|
||||
t.Fatalf("bob failed receiving revocation: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// receiveCommitSigAliceToBob waits for Alice to send a CommitSig to Bob,
|
||||
// signing expHtlcs numbers of HTLCs, then hands this to Bob.
|
||||
func receiveCommitSigAliceToBob(t *testing.T, aliceMsgs chan lnwire.Message,
|
||||
aliceLink ChannelLink, bobChannel *lnwallet.LightningChannel,
|
||||
expHtlcs int) {
|
||||
var msg lnwire.Message
|
||||
select {
|
||||
case msg = <-aliceMsgs:
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("did not receive message")
|
||||
}
|
||||
|
||||
comSig, ok := msg.(*lnwire.CommitSig)
|
||||
if !ok {
|
||||
t.Fatalf("expected CommitSig, got %T", msg)
|
||||
}
|
||||
|
||||
if len(comSig.HtlcSigs) != expHtlcs {
|
||||
t.Fatalf("expected %d htlc sigs, got %d", expHtlcs,
|
||||
len(comSig.HtlcSigs))
|
||||
}
|
||||
err := bobChannel.ReceiveNewCommitment(comSig.CommitSig,
|
||||
comSig.HtlcSigs)
|
||||
if err != nil {
|
||||
t.Fatalf("bob failed receiving commitment: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// sendRevAndAckBobToAlice make Bob revoke his current commitment, then hand
|
||||
// the RevokeAndAck to Alice.
|
||||
func sendRevAndAckBobToAlice(t *testing.T, aliceLink ChannelLink,
|
||||
bobChannel *lnwallet.LightningChannel) {
|
||||
rev, _, err := bobChannel.RevokeCurrentCommitment()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to revoke commitment: %v", err)
|
||||
}
|
||||
|
||||
aliceLink.HandleChannelUpdate(rev)
|
||||
}
|
||||
|
||||
// receiveSettleAliceToBob waits for Alice to send a HTLC settle message to
|
||||
// Bob, then hands this to Bob.
|
||||
func receiveSettleAliceToBob(t *testing.T, aliceMsgs chan lnwire.Message,
|
||||
aliceLink ChannelLink, bobChannel *lnwallet.LightningChannel) {
|
||||
var msg lnwire.Message
|
||||
select {
|
||||
case msg = <-aliceMsgs:
|
||||
case <-time.After(15 * time.Second):
|
||||
t.Fatalf("did not receive message")
|
||||
}
|
||||
|
||||
settleMsg, ok := msg.(*lnwire.UpdateFulfillHTLC)
|
||||
if !ok {
|
||||
t.Fatalf("expected UpdateFulfillHTLC, got %T", msg)
|
||||
}
|
||||
|
||||
err := bobChannel.ReceiveHTLCSettle(settleMsg.PaymentPreimage,
|
||||
settleMsg.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("failed settling htlc: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestChannelLinkNoMoreUpdates tests that we won't send a new commitment
|
||||
// when there are no new updates to sign.
|
||||
func TestChannelLinkNoMoreUpdates(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const chanAmt = btcutil.SatoshiPerBitcoin * 5
|
||||
const chanReserve = btcutil.SatoshiPerBitcoin * 1
|
||||
aliceLink, bobChannel, _, cleanUp, _, err :=
|
||||
newSingleLinkTestHarness(chanAmt, chanReserve)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create link: %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
var (
|
||||
coreLink = aliceLink.(*channelLink)
|
||||
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
|
||||
)
|
||||
|
||||
// Add two HTLCs to Alice's registry, that Bob can pay.
|
||||
htlc1 := generateHtlc(t, coreLink, bobChannel, 0)
|
||||
htlc2 := generateHtlc(t, coreLink, bobChannel, 1)
|
||||
|
||||
// We now play out the following scanario:
|
||||
//
|
||||
// (1) Alice receives htlc1 from Bob.
|
||||
// (2) Bob sends signature covering htlc1.
|
||||
// (3) Alice receives htlc2 from Bob.
|
||||
// (4) Since Bob has sent a new commitment signature, Alice should
|
||||
// first respond with a revocation.
|
||||
// (5) Alice should also send a commitment signature for the new state,
|
||||
// covering htlc1.
|
||||
// (6) Bob sends a new commitment signature, covering htlc2 that he sent
|
||||
// earlier. This signature should cover hltc1 + htlc2.
|
||||
// (7) Alice should revoke the old commitment. This ACKs htlc2.
|
||||
// (8) Bob can now revoke his old commitment in response to the
|
||||
// signature Alice sent covering htlc1.
|
||||
// (9) htlc1 is now locked in on Bob's commitment, and we expect Alice
|
||||
// to settle it.
|
||||
// (10) Alice should send a signature covering this settle to Bob. Only
|
||||
// htlc2 should now be covered by this signature.
|
||||
// (11) Bob can revoke his last state, which will also ACK the settle
|
||||
// of htlc1.
|
||||
// (12) Bob sends a new commitment signature. This signature should
|
||||
// cover htlc2.
|
||||
// (13) Alice will send a settle for htlc2.
|
||||
// (14) Alice will also send a signature covering the settle.
|
||||
// (15) Alice should send a revocation in response to the signature Bob
|
||||
// sent earlier.
|
||||
// (16) Bob will revoke his commitment in response to the commitment
|
||||
// Alice sent.
|
||||
// (17) Send a signature for the empty state. No HTLCs are left.
|
||||
// (18) Alice will revoke her previous state.
|
||||
// Alice Bob
|
||||
// | |
|
||||
// | ... |
|
||||
// | | <--- idle (no htlc on either side)
|
||||
// | |
|
||||
sendHtlcBobToAlice(t, aliceLink, bobChannel, htlc1) // |<----- add-1 ------| (1)
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, 1) // |<------ sig -------| (2)
|
||||
sendHtlcBobToAlice(t, aliceLink, bobChannel, htlc2) // |<----- add-2 ------| (3)
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (4) <--- Alice acks add-1
|
||||
receiveCommitSigAliceToBob(t, aliceMsgs, aliceLink, bobChannel, 1) // |------- sig ------>| (5) <--- Alice signs add-1
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, 2) // |<------ sig -------| (6)
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (7) <--- Alice acks add-2
|
||||
sendRevAndAckBobToAlice(t, aliceLink, bobChannel) // |<------ rev -------| (8)
|
||||
receiveSettleAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------ ful-1 ----->| (9)
|
||||
receiveCommitSigAliceToBob(t, aliceMsgs, aliceLink, bobChannel, 1) // |------- sig ------>| (10) <--- Alice signs add-1 + add-2 + ful-1 = add-2
|
||||
sendRevAndAckBobToAlice(t, aliceLink, bobChannel) // |<------ rev -------| (11)
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, 1) // |<------ sig -------| (12)
|
||||
receiveSettleAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------ ful-2 ----->| (13)
|
||||
receiveCommitSigAliceToBob(t, aliceMsgs, aliceLink, bobChannel, 0) // |------- sig ------>| (14) <--- Alice signs add-2 + ful-2 = no htlcs
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (15)
|
||||
sendRevAndAckBobToAlice(t, aliceLink, bobChannel) // |<------ rev -------| (16) <--- Bob acks that there are no more htlcs
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, 0) // |<------ sig -------| (17)
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (18) <--- Alice acks that there are no htlcs on Alice's side
|
||||
|
||||
// No there are no more changes to ACK or sign, make sure Alice doesn't
|
||||
// attempt to send any more messages.
|
||||
var msg lnwire.Message
|
||||
select {
|
||||
case msg = <-aliceMsgs:
|
||||
t.Fatalf("did not expect message %T", msg)
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
|
||||
// TestChannelLinkWaitForRevocation tests that we will keep accepting updates
|
||||
// to our commitment transaction, even when we are waiting for a revocation
|
||||
// from the remote node.
|
||||
func TestChannelLinkWaitForRevocation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
const chanAmt = btcutil.SatoshiPerBitcoin * 5
|
||||
const chanReserve = btcutil.SatoshiPerBitcoin * 1
|
||||
aliceLink, bobChannel, _, cleanUp, _, err :=
|
||||
newSingleLinkTestHarness(chanAmt, chanReserve)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create link: %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
var (
|
||||
coreLink = aliceLink.(*channelLink)
|
||||
aliceMsgs = coreLink.cfg.Peer.(*mockPeer).sentMsgs
|
||||
)
|
||||
|
||||
// We will send 10 HTLCs in total, from Bob to Alice.
|
||||
numHtlcs := 10
|
||||
var htlcs []*lnwire.UpdateAddHTLC
|
||||
for i := 0; i < numHtlcs; i++ {
|
||||
htlc := generateHtlc(t, coreLink, bobChannel, uint64(i))
|
||||
htlcs = append(htlcs, htlc)
|
||||
}
|
||||
|
||||
// We play out the following scenario:
|
||||
//
|
||||
// (1) Add the first HTLC.
|
||||
// (2) Bob sends signature covering the htlc.
|
||||
// (3) Since Bob has sent a new commitment signature, Alice should first
|
||||
// respond with a revocation. This revocation will ACK the first htlc.
|
||||
// (4) Alice should also send a commitment signature for the new state,
|
||||
// locking in the HTLC on Bob's commitment. Note that we don't
|
||||
// immediately let Bob respond with a revocation in this case.
|
||||
// (5.i) Now we send the rest of the HTLCs from Bob to Alice.
|
||||
// (6.i) Bob sends a new commitment signature, covering all HTLCs up
|
||||
// to this point.
|
||||
// (7.i) Alice should respond to Bob's state updates with revocations,
|
||||
// but cannot send any new signatures for Bob's state because her
|
||||
// revocation window is exhausted.
|
||||
// (8) Now let Bob finally send his revocation.
|
||||
// (9) We expect Alice to settle her first HTLC, since it was already
|
||||
// locked in.
|
||||
// (10) Now Alice should send a signature covering this settle + lock
|
||||
// in the rest of the HTLCs on Bob's commitment.
|
||||
// (11) Bob receives the new signature for his commitment, and can
|
||||
// revoke his old state, ACKing the settle.
|
||||
// (12.i) Now Alice can settle all the HTLCs, since they are locked in
|
||||
// on both parties' commitments.
|
||||
// (13) Bob can send a signature covering the first settle Alice sent.
|
||||
// Bob's signature should cover all the remaining HTLCs as well, since
|
||||
// he hasn't ACKed the last settles yet. Alice receives the signature
|
||||
// from Bob. Alice's commitment now has the first HTLC settled, and all
|
||||
// the other HTLCs locked in.
|
||||
// (14) Alice will send a signature for all the settles she just sent.
|
||||
// (15) Bob can revoke his previous state, in response to Alice's
|
||||
// signature.
|
||||
// (16) In response to the signature Bob sent, Alice can
|
||||
// revoke her previous state.
|
||||
// (17) Bob still hasn't sent a commitment covering all settles, so do
|
||||
// that now. Since Bob ACKed all settles, no HTLCs should be left on
|
||||
// the commitment.
|
||||
// (18) Alice will revoke her previous state.
|
||||
// Alice Bob
|
||||
// | |
|
||||
// | ... |
|
||||
// | | <--- idle (no htlc on either side)
|
||||
// | |
|
||||
sendHtlcBobToAlice(t, aliceLink, bobChannel, htlcs[0]) // |<----- add-1 ------| (1)
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, 1) // |<------ sig -------| (2)
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (3) <--- Alice acks add-1
|
||||
receiveCommitSigAliceToBob(t, aliceMsgs, aliceLink, bobChannel, 1) // |------- sig ------>| (4) <--- Alice signs add-1
|
||||
for i := 1; i < numHtlcs; i++ { // | |
|
||||
sendHtlcBobToAlice(t, aliceLink, bobChannel, htlcs[i]) // |<----- add-i ------| (5.i)
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, i+1) // |<------ sig -------| (6.i)
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (7.i) <--- Alice acks add-i
|
||||
select { // | |
|
||||
case <-aliceMsgs: // | | Alice should not send a sig for
|
||||
t.Fatalf("unexpectedly received msg from Alice") // | | Bob's last state, since she is
|
||||
default: // | | still waiting for a revocation
|
||||
} // | | for the previous one.
|
||||
} // | |
|
||||
sendRevAndAckBobToAlice(t, aliceLink, bobChannel) // |<------ rev -------| (8) Finally let Bob send rev
|
||||
receiveSettleAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------ ful-1 ----->| (9)
|
||||
receiveCommitSigAliceToBob(t, aliceMsgs, aliceLink, bobChannel, numHtlcs-1) // |------- sig ------>| (10) <--- Alice signs add-i
|
||||
sendRevAndAckBobToAlice(t, aliceLink, bobChannel) // |<------ rev -------| (11)
|
||||
for i := 1; i < numHtlcs; i++ { // | |
|
||||
receiveSettleAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------ ful-1 ----->| (12.i)
|
||||
} // | |
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, numHtlcs-1) // |<------ sig -------| (13)
|
||||
receiveCommitSigAliceToBob(t, aliceMsgs, aliceLink, bobChannel, 0) // |------- sig ------>| (14)
|
||||
sendRevAndAckBobToAlice(t, aliceLink, bobChannel) // |<------ rev -------| (15)
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (16)
|
||||
sendCommitSigBobToAlice(t, aliceLink, bobChannel, 0) // |<------ sig -------| (17)
|
||||
receiveRevAndAckAliceToBob(t, aliceMsgs, aliceLink, bobChannel) // |------- rev ------>| (18)
|
||||
|
||||
// Both side's state is now updated, no more messages should be sent.
|
||||
select {
|
||||
case <-aliceMsgs:
|
||||
t.Fatalf("did not expect message from Alice")
|
||||
case <-time.After(50 * time.Millisecond):
|
||||
}
|
||||
}
|
||||
|
@ -3924,15 +3924,27 @@ func (lc *LightningChannel) FullySynced() bool {
|
||||
lastLocalCommit := lc.localCommitChain.tip()
|
||||
lastRemoteCommit := lc.remoteCommitChain.tip()
|
||||
|
||||
oweCommitment := lastLocalCommit.height > lastRemoteCommit.height
|
||||
|
||||
localUpdatesSynced := (lastLocalCommit.ourMessageIndex ==
|
||||
lastRemoteCommit.ourMessageIndex)
|
||||
|
||||
remoteUpdatesSynced := (lastLocalCommit.theirMessageIndex ==
|
||||
lastRemoteCommit.theirMessageIndex)
|
||||
|
||||
return !oweCommitment && localUpdatesSynced && remoteUpdatesSynced
|
||||
pendingFeeAck := false
|
||||
|
||||
// If we have received a fee update which we haven't yet ACKed, then
|
||||
// we owe a commitment.
|
||||
if !lc.channelState.IsInitiator {
|
||||
pendingFeeAck = lc.pendingAckFeeUpdate != nil
|
||||
}
|
||||
|
||||
// If we have sent a fee update which we haven't yet signed, then
|
||||
// we owe a commitment.
|
||||
if lc.channelState.IsInitiator {
|
||||
pendingFeeAck = lc.pendingFeeUpdate != nil
|
||||
}
|
||||
|
||||
return localUpdatesSynced && remoteUpdatesSynced && !pendingFeeAck
|
||||
}
|
||||
|
||||
// RevokeCurrentCommitment revokes the next lowest unrevoked commitment
|
||||
|
Loading…
Reference in New Issue
Block a user