lnwallet/channel_test: assert commit sorting of commit diff htlcs
This commit adds a test to exercise that HTLC signatures are sent in the correct order, i.e. they match the sorting of the HTLC outputs on the commitment after applying BOLT 3's BIP69+CLTV sort.
This commit is contained in:
parent
3ea3b1d0b5
commit
b0c3072ff7
@ -450,6 +450,139 @@ func TestCheckCommitTxSize(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCommitHTLCSigTieBreak asserts that HTLC signatures are sent the proper
|
||||
// BIP69+CLTV sorting expected by BOLT 3 when multiple HTLCs have identical
|
||||
// payment hashes and amounts, but differing CLTVs. This is exercised by adding
|
||||
// the HTLCs in the descending order of their CLTVs, and asserting that their
|
||||
// order is reversed when signing.
|
||||
func TestCommitHTLCSigTieBreak(t *testing.T) {
|
||||
t.Run("no restart", func(t *testing.T) {
|
||||
testCommitHTLCSigTieBreak(t, false)
|
||||
})
|
||||
t.Run("restart", func(t *testing.T) {
|
||||
testCommitHTLCSigTieBreak(t, true)
|
||||
})
|
||||
}
|
||||
|
||||
func testCommitHTLCSigTieBreak(t *testing.T, restart bool) {
|
||||
aliceChannel, bobChannel, cleanUp, err := CreateTestChannels(
|
||||
channeldb.SingleFunderTweaklessBit,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create test channels; %v", err)
|
||||
}
|
||||
defer cleanUp()
|
||||
|
||||
const (
|
||||
htlcAmt = lnwire.MilliSatoshi(20000000)
|
||||
numHtlcs = 2
|
||||
)
|
||||
|
||||
// Add HTLCs with identical payment hashes and amounts, but descending
|
||||
// CLTV values. We will expect the signatures to appear in the reverse
|
||||
// order that the HTLCs are added due to the commitment sorting.
|
||||
for i := 0; i < numHtlcs; i++ {
|
||||
var (
|
||||
preimage lntypes.Preimage
|
||||
hash = preimage.Hash()
|
||||
)
|
||||
|
||||
htlc := &lnwire.UpdateAddHTLC{
|
||||
ID: uint64(i),
|
||||
PaymentHash: hash,
|
||||
Amount: htlcAmt,
|
||||
Expiry: uint32(numHtlcs - i),
|
||||
}
|
||||
|
||||
if _, err := aliceChannel.AddHTLC(htlc, nil); err != nil {
|
||||
t.Fatalf("alice unable to add htlc: %v", err)
|
||||
}
|
||||
if _, err := bobChannel.ReceiveHTLC(htlc); err != nil {
|
||||
t.Fatalf("bob unable to receive htlc: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Have Alice initiate the first half of the commitment dance. The
|
||||
// tie-breaking for commitment sorting won't affect the commitment
|
||||
// signed by Alice because received HTLC scripts commit to the CLTV
|
||||
// directly, so the outputs will have different scriptPubkeys.
|
||||
aliceSig, aliceHtlcSigs, _, err := aliceChannel.SignNextCommitment()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to sign alice's commitment: %v", err)
|
||||
}
|
||||
|
||||
err = bobChannel.ReceiveNewCommitment(aliceSig, aliceHtlcSigs)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to receive alice's commitment: %v", err)
|
||||
}
|
||||
|
||||
bobRevocation, _, err := bobChannel.RevokeCurrentCommitment()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to revoke bob's commitment: %v", err)
|
||||
}
|
||||
_, _, _, _, err = aliceChannel.ReceiveRevocation(bobRevocation)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to receive bob's revocation: %v", err)
|
||||
}
|
||||
|
||||
// Now have Bob initiate the second half of the commitment dance. Here
|
||||
// the offered HTLC scripts he adds for Alice will need to have the
|
||||
// tie-breaking applied because the CLTV is not committed, but instead
|
||||
// implicit via the construction of the second-level transactions.
|
||||
bobSig, bobHtlcSigs, bobHtlcs, err := bobChannel.SignNextCommitment()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to sign bob's commitment: %v", err)
|
||||
}
|
||||
|
||||
if len(bobHtlcs) != numHtlcs {
|
||||
t.Fatalf("expected %d htlcs, got: %v", numHtlcs, len(bobHtlcs))
|
||||
}
|
||||
|
||||
// Ensure that our HTLCs appear in the reverse order from which they
|
||||
// were added by inspecting each's outpoint index. We expect the output
|
||||
// indexes to be in descending order, i.e. the first HTLC added had the
|
||||
// highest CLTV and should end up last.
|
||||
lastIndex := bobHtlcs[0].OutputIndex
|
||||
for i, htlc := range bobHtlcs[1:] {
|
||||
if htlc.OutputIndex >= lastIndex {
|
||||
t.Fatalf("htlc %d output index %d is not descending",
|
||||
i, htlc.OutputIndex)
|
||||
}
|
||||
|
||||
lastIndex = htlc.OutputIndex
|
||||
}
|
||||
|
||||
// If requsted, restart Alice so that we can test that the necessary
|
||||
// indexes can be reconstructed before needing to validate the
|
||||
// signatures from Bob.
|
||||
if restart {
|
||||
aliceState := aliceChannel.channelState
|
||||
aliceChannels, err := aliceState.Db.FetchOpenChannels(
|
||||
aliceState.IdentityPub,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to fetch channel: %v", err)
|
||||
}
|
||||
|
||||
aliceChannelNew, err := NewLightningChannel(
|
||||
aliceChannel.Signer, aliceChannels[0],
|
||||
aliceChannel.sigPool,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create new channel: %v", err)
|
||||
}
|
||||
|
||||
aliceChannel = aliceChannelNew
|
||||
}
|
||||
|
||||
// Finally, have Alice validate the signatures to ensure that she is
|
||||
// expecting the signatures in the proper order.
|
||||
err = aliceChannel.ReceiveNewCommitment(bobSig, bobHtlcSigs)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to receive bob's commitment: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCooperativeChannelClosure(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user