31e92c4ff2
In this commit, we add a compatibility mode for older version of clightning to ensure that we're able to properly parse all their channel updates. An older version of c-lightning would send out encapsulated onion error message with an additional type byte. This would throw off our parsing as we didn't expect the type byte, and so we always 2 bytes off. In order to ensure that we're able to parse these messages and make adjustments to our path finding, we'll first check to see if the type byte is there, if so, then we'll snip off two bytes from the front and continue with parsing. if the bytes aren't found, then we can proceed as normal and parse the request.
132 lines
3.8 KiB
Go
132 lines
3.8 KiB
Go
package lnwire
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"encoding/binary"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
var (
|
|
testOnionHash = []byte{}
|
|
testAmount = MilliSatoshi(1)
|
|
testCtlvExpiry = uint32(2)
|
|
testFlags = uint16(2)
|
|
sig, _ = NewSigFromSignature(testSig)
|
|
testChannelUpdate = ChannelUpdate{
|
|
Signature: sig,
|
|
ShortChannelID: NewShortChanIDFromInt(1),
|
|
Timestamp: 1,
|
|
Flags: 1,
|
|
}
|
|
)
|
|
|
|
var onionFailures = []FailureMessage{
|
|
&FailInvalidRealm{},
|
|
&FailTemporaryNodeFailure{},
|
|
&FailPermanentNodeFailure{},
|
|
&FailRequiredNodeFeatureMissing{},
|
|
&FailPermanentChannelFailure{},
|
|
&FailRequiredChannelFeatureMissing{},
|
|
&FailUnknownNextPeer{},
|
|
&FailUnknownPaymentHash{},
|
|
&FailIncorrectPaymentAmount{},
|
|
&FailFinalExpiryTooSoon{},
|
|
|
|
NewInvalidOnionVersion(testOnionHash),
|
|
NewInvalidOnionHmac(testOnionHash),
|
|
NewInvalidOnionKey(testOnionHash),
|
|
NewTemporaryChannelFailure(&testChannelUpdate),
|
|
NewTemporaryChannelFailure(nil),
|
|
NewAmountBelowMinimum(testAmount, testChannelUpdate),
|
|
NewFeeInsufficient(testAmount, testChannelUpdate),
|
|
NewIncorrectCltvExpiry(testCtlvExpiry, testChannelUpdate),
|
|
NewExpiryTooSoon(testChannelUpdate),
|
|
NewChannelDisabled(testFlags, testChannelUpdate),
|
|
NewFinalIncorrectCltvExpiry(testCtlvExpiry),
|
|
NewFinalIncorrectHtlcAmount(testAmount),
|
|
}
|
|
|
|
// TestEncodeDecodeCode tests the ability of onion errors to be properly encoded
|
|
// and decoded.
|
|
func TestEncodeDecodeCode(t *testing.T) {
|
|
for _, failure1 := range onionFailures {
|
|
var b bytes.Buffer
|
|
|
|
if err := EncodeFailure(&b, failure1, 0); err != nil {
|
|
t.Fatalf("unable to encode failure code(%v): %v",
|
|
failure1.Code(), err)
|
|
}
|
|
|
|
failure2, err := DecodeFailure(&b, 0)
|
|
if err != nil {
|
|
t.Fatalf("unable to decode failure code(%v): %v",
|
|
failure1.Code(), err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(failure1, failure2) {
|
|
t.Fatalf("failure message are different, failure "+
|
|
"code(%v)", failure1.Code())
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestChannelUpdateCompatabilityParsing tests that we're able to properly read
|
|
// out channel update messages encoded in an onion error payload that was
|
|
// written in the legacy (type prefixed) format.
|
|
func TestChannelUpdateCompatabilityParsing(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
// We'll start by taking out test channel update, and encoding it into
|
|
// a set of raw bytes.
|
|
var b bytes.Buffer
|
|
if err := testChannelUpdate.Encode(&b, 0); err != nil {
|
|
t.Fatalf("unable to encode chan update: %v", err)
|
|
}
|
|
|
|
// Now that we have the set of bytes encoded, we'll ensure that we're
|
|
// able to decode it using our compatibility method, as it's a regular
|
|
// encoded channel update message.
|
|
var newChanUpdate ChannelUpdate
|
|
err := parseChannelUpdateCompatabilityMode(
|
|
bufio.NewReader(&b), &newChanUpdate, 0,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("unable to parse channel update: %v", err)
|
|
}
|
|
|
|
// At this point, we'll ensure that we get the exact same failure out
|
|
// on the other side.
|
|
if !reflect.DeepEqual(testChannelUpdate, newChanUpdate) {
|
|
t.Fatalf("mismatched channel updates: %v", err)
|
|
}
|
|
|
|
// We'll now reset then re-encoded the same channel update to try it in
|
|
// the proper compatible mode.
|
|
b.Reset()
|
|
|
|
// Before we encode the update itself, we'll also write out the 2-byte
|
|
// type in order to simulate the compat mode.
|
|
var tByte [2]byte
|
|
binary.BigEndian.PutUint16(tByte[:], MsgChannelUpdate)
|
|
b.Write(tByte[:])
|
|
if err := testChannelUpdate.Encode(&b, 0); err != nil {
|
|
t.Fatalf("unable to encode chan update: %v", err)
|
|
}
|
|
|
|
// We should be able to properly parse the encoded channel update
|
|
// message even with the extra two bytes.
|
|
var newChanUpdate2 ChannelUpdate
|
|
err = parseChannelUpdateCompatabilityMode(
|
|
bufio.NewReader(&b), &newChanUpdate2, 0,
|
|
)
|
|
if err != nil {
|
|
t.Fatalf("unable to parse channel update: %v", err)
|
|
}
|
|
|
|
if !reflect.DeepEqual(newChanUpdate2, newChanUpdate) {
|
|
t.Fatalf("mismatched channel updates: %v", err)
|
|
}
|
|
}
|