discovery+routing: validate msg flags and max htlc in ChannelUpdates
In this commit, we alter the ValidateChannelUpdateAnn function in ann_validation to validate a remote ChannelUpdate's message flags and max HTLC field. If the message flag is set but the max HTLC field is not set or vice versa, the ChannelUpdate fails validation. Co-authored-by: Johan T. Halseth <johanth@gmail.com>
This commit is contained in:
1 parent
f316cc6c7e
commit
15168c391e
4 files changed
+150
-18
No files matched your search
+105
-8
@@ -10,6 +10,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -474,14 +475,7 @@ func createUpdateAnnouncement(blockHeight uint32,
|
||||
a.ExtraOpaqueData = extraBytes[0]
|
||||
}
|
||||
|
||||
pub := nodeKey.PubKey()
|
||||
signer := mockSigner{nodeKey}
|
||||
sig, err := SignAnnouncement(&signer, pub, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
a.Signature, err = lnwire.NewSigFromSignature(sig)
|
||||
err = signUpdate(nodeKey, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -489,6 +483,22 @@ func createUpdateAnnouncement(blockHeight uint32,
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error {
|
||||
pub := nodeKey.PubKey()
|
||||
signer := mockSigner{nodeKey}
|
||||
sig, err := SignAnnouncement(&signer, pub, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.Signature, err = lnwire.NewSigFromSignature(sig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func createAnnouncementWithoutProof(blockHeight uint32,
|
||||
extraBytes ...[]byte) *lnwire.ChannelAnnouncement {
|
||||
|
||||
@@ -2765,6 +2775,93 @@ func TestNodeAnnouncementNoChannels(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestOptionalFieldsChannelUpdateValidation tests that we're able to properly
|
||||
// validate the msg flags and optional max HTLC field of a ChannelUpdate.
|
||||
func TestOptionalFieldsChannelUpdateValidation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
ctx, cleanup, err := createTestCtx(0)
|
||||
if err != nil {
|
||||
t.Fatalf("can't create context: %v", err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
chanUpdateHeight := uint32(0)
|
||||
timestamp := uint32(123456)
|
||||
nodePeer := &mockPeer{nodeKeyPriv1.PubKey(), nil, nil}
|
||||
|
||||
// In this scenario, we'll test whether the message flags field in a channel
|
||||
// update is properly handled.
|
||||
chanAnn, err := createRemoteChannelAnnouncement(chanUpdateHeight)
|
||||
if err != nil {
|
||||
t.Fatalf("can't create channel announcement: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(chanAnn, nodePeer):
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("did not process remote announcement")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unable to process announcement: %v", err)
|
||||
}
|
||||
|
||||
// The first update should fail from an invalid max HTLC field, which is
|
||||
// less than the min HTLC.
|
||||
chanUpdAnn, err := createUpdateAnnouncement(0, 0, nodeKeyPriv1, timestamp)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create channel update: %v", err)
|
||||
}
|
||||
|
||||
chanUpdAnn.HtlcMinimumMsat = 5000
|
||||
chanUpdAnn.HtlcMaximumMsat = 4000
|
||||
if err := signUpdate(nodeKeyPriv1, chanUpdAnn); err != nil {
|
||||
t.Fatalf("unable to sign channel update: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(chanUpdAnn, nodePeer):
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("did not process remote announcement")
|
||||
}
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid max htlc") {
|
||||
t.Fatalf("expected chan update to error, instead got %v", err)
|
||||
}
|
||||
|
||||
// The second update should fail because the message flag is set but
|
||||
// the max HTLC field is 0.
|
||||
chanUpdAnn.HtlcMinimumMsat = 0
|
||||
chanUpdAnn.HtlcMaximumMsat = 0
|
||||
if err := signUpdate(nodeKeyPriv1, chanUpdAnn); err != nil {
|
||||
t.Fatalf("unable to sign channel update: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(chanUpdAnn, nodePeer):
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("did not process remote announcement")
|
||||
}
|
||||
if err == nil || !strings.Contains(err.Error(), "invalid max htlc") {
|
||||
t.Fatalf("expected chan update to error, instead got %v", err)
|
||||
}
|
||||
|
||||
// The final update should succeed, since setting the flag 0 means the
|
||||
// nonsense max_htlc field will just be ignored.
|
||||
chanUpdAnn.MessageFlags = 0
|
||||
if err := signUpdate(nodeKeyPriv1, chanUpdAnn); err != nil {
|
||||
t.Fatalf("unable to sign channel update: %v", err)
|
||||
}
|
||||
|
||||
select {
|
||||
case err = <-ctx.gossiper.ProcessRemoteAnnouncement(chanUpdAnn, nodePeer):
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatal("did not process remote announcement")
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("unable to process announcement: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// mockPeer implements the lnpeer.Peer interface and is used to test the
|
||||
// gossiper's interaction with peers.
|
||||
type mockPeer struct {
|
||||
|
||||
Reference in new issue
Block a user