github.com/decred/dcrlnd@v0.7.6/channeldb/migration/lnwire21/onion_error_test.go (about)

     1  package lnwire
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/binary"
     7  	"io"
     8  	"reflect"
     9  	"testing"
    10  
    11  	"github.com/davecgh/go-spew/spew"
    12  )
    13  
    14  var (
    15  	testOnionHash     = []byte{}
    16  	testAmount        = MilliAtom(1)
    17  	testCtlvExpiry    = uint32(2)
    18  	testFlags         = uint16(2)
    19  	testType          = uint64(3)
    20  	testOffset        = uint16(24)
    21  	sig, _            = NewSigFromSignature(testSig)
    22  	testChannelUpdate = ChannelUpdate{
    23  		Signature:      sig,
    24  		ShortChannelID: NewShortChanIDFromInt(1),
    25  		Timestamp:      1,
    26  		MessageFlags:   0,
    27  		ChannelFlags:   1,
    28  	}
    29  )
    30  
    31  var onionFailures = []FailureMessage{
    32  	&FailInvalidRealm{},
    33  	&FailTemporaryNodeFailure{},
    34  	&FailPermanentNodeFailure{},
    35  	&FailRequiredNodeFeatureMissing{},
    36  	&FailPermanentChannelFailure{},
    37  	&FailRequiredChannelFeatureMissing{},
    38  	&FailUnknownNextPeer{},
    39  	&FailIncorrectPaymentAmount{},
    40  	&FailFinalExpiryTooSoon{},
    41  	&FailMPPTimeout{},
    42  
    43  	NewFailIncorrectDetails(99, 100),
    44  	NewInvalidOnionVersion(testOnionHash),
    45  	NewInvalidOnionHmac(testOnionHash),
    46  	NewInvalidOnionKey(testOnionHash),
    47  	NewTemporaryChannelFailure(&testChannelUpdate),
    48  	NewTemporaryChannelFailure(nil),
    49  	NewAmountBelowMinimum(testAmount, testChannelUpdate),
    50  	NewFeeInsufficient(testAmount, testChannelUpdate),
    51  	NewIncorrectCltvExpiry(testCtlvExpiry, testChannelUpdate),
    52  	NewExpiryTooSoon(testChannelUpdate),
    53  	NewChannelDisabled(testFlags, testChannelUpdate),
    54  	NewFinalIncorrectCltvExpiry(testCtlvExpiry),
    55  	NewFinalIncorrectHtlcAmount(testAmount),
    56  	NewInvalidOnionPayload(testType, testOffset),
    57  }
    58  
    59  // TestEncodeDecodeCode tests the ability of onion errors to be properly encoded
    60  // and decoded.
    61  func TestEncodeDecodeCode(t *testing.T) {
    62  	for _, failure1 := range onionFailures {
    63  		var b bytes.Buffer
    64  
    65  		if err := EncodeFailure(&b, failure1, 0); err != nil {
    66  			t.Fatalf("unable to encode failure code(%v): %v",
    67  				failure1.Code(), err)
    68  		}
    69  
    70  		failure2, err := DecodeFailure(&b, 0)
    71  		if err != nil {
    72  			t.Fatalf("unable to decode failure code(%v): %v",
    73  				failure1.Code(), err)
    74  		}
    75  
    76  		if !reflect.DeepEqual(failure1, failure2) {
    77  			t.Fatalf("expected %v, got %v", spew.Sdump(failure1),
    78  				spew.Sdump(failure2))
    79  		}
    80  	}
    81  }
    82  
    83  // TestChannelUpdateCompatabilityParsing tests that we're able to properly read
    84  // out channel update messages encoded in an onion error payload that was
    85  // written in the legacy (type prefixed) format.
    86  func TestChannelUpdateCompatabilityParsing(t *testing.T) {
    87  	t.Parallel()
    88  
    89  	// We'll start by taking out test channel update, and encoding it into
    90  	// a set of raw bytes.
    91  	var b bytes.Buffer
    92  	if err := testChannelUpdate.Encode(&b, 0); err != nil {
    93  		t.Fatalf("unable to encode chan update: %v", err)
    94  	}
    95  
    96  	// Now that we have the set of bytes encoded, we'll ensure that we're
    97  	// able to decode it using our compatibility method, as it's a regular
    98  	// encoded channel update message.
    99  	var newChanUpdate ChannelUpdate
   100  	err := parseChannelUpdateCompatabilityMode(
   101  		bufio.NewReader(&b), &newChanUpdate, 0,
   102  	)
   103  	if err != nil {
   104  		t.Fatalf("unable to parse channel update: %v", err)
   105  	}
   106  
   107  	// At this point, we'll ensure that we get the exact same failure out
   108  	// on the other side.
   109  	if !reflect.DeepEqual(testChannelUpdate, newChanUpdate) {
   110  		t.Fatalf("mismatched channel updates: %v", err)
   111  	}
   112  
   113  	// We'll now reset then re-encoded the same channel update to try it in
   114  	// the proper compatible mode.
   115  	b.Reset()
   116  
   117  	// Before we encode the update itself, we'll also write out the 2-byte
   118  	// type in order to simulate the compat mode.
   119  	var tByte [2]byte
   120  	binary.BigEndian.PutUint16(tByte[:], MsgChannelUpdate)
   121  	b.Write(tByte[:])
   122  	if err := testChannelUpdate.Encode(&b, 0); err != nil {
   123  		t.Fatalf("unable to encode chan update: %v", err)
   124  	}
   125  
   126  	// We should be able to properly parse the encoded channel update
   127  	// message even with the extra two bytes.
   128  	var newChanUpdate2 ChannelUpdate
   129  	err = parseChannelUpdateCompatabilityMode(
   130  		bufio.NewReader(&b), &newChanUpdate2, 0,
   131  	)
   132  	if err != nil {
   133  		t.Fatalf("unable to parse channel update: %v", err)
   134  	}
   135  
   136  	if !reflect.DeepEqual(newChanUpdate2, newChanUpdate) {
   137  		t.Fatalf("mismatched channel updates: %v", err)
   138  	}
   139  }
   140  
   141  // TestWriteOnionErrorChanUpdate tests that we write an exact size for the
   142  // channel update in order to be more compliant with the parsers of other
   143  // implementations.
   144  func TestWriteOnionErrorChanUpdate(t *testing.T) {
   145  	t.Parallel()
   146  
   147  	// First, we'll write out the raw channel update so we can obtain the
   148  	// raw serialized length.
   149  	var b bytes.Buffer
   150  	update := testChannelUpdate
   151  	if err := update.Encode(&b, 0); err != nil {
   152  		t.Fatalf("unable to write update: %v", err)
   153  	}
   154  	trueUpdateLength := b.Len()
   155  
   156  	// Next, we'll use the function to encode the update as we would in a
   157  	// onion error message.
   158  	var errorBuf bytes.Buffer
   159  	err := writeOnionErrorChanUpdate(&errorBuf, &update, 0)
   160  	if err != nil {
   161  		t.Fatalf("unable to encode onion error: %v", err)
   162  	}
   163  
   164  	// Finally, read the length encoded and ensure that it matches the raw
   165  	// length.
   166  	var encodedLen uint16
   167  	if err := ReadElement(&errorBuf, &encodedLen); err != nil {
   168  		t.Fatalf("unable to read len: %v", err)
   169  	}
   170  	if uint16(trueUpdateLength) != encodedLen {
   171  		t.Fatalf("wrong length written: expected %v, got %v",
   172  			trueUpdateLength, encodedLen)
   173  	}
   174  }
   175  
   176  // TestFailIncorrectDetailsOptionalAmount tests that we're able to decode an
   177  // FailIncorrectDetails error that doesn't have the optional amount. This
   178  // ensures we're able to decode FailIncorrectDetails messages from older nodes.
   179  func TestFailIncorrectDetailsOptionalAmount(t *testing.T) {
   180  	t.Parallel()
   181  
   182  	onionError := &mockFailIncorrectDetailsNoAmt{}
   183  
   184  	var b bytes.Buffer
   185  	if err := EncodeFailure(&b, onionError, 0); err != nil {
   186  		t.Fatalf("unable to encode failure: %v", err)
   187  	}
   188  
   189  	onionError2, err := DecodeFailure(bytes.NewReader(b.Bytes()), 0)
   190  	if err != nil {
   191  		t.Fatalf("unable to decode error: %v", err)
   192  	}
   193  
   194  	invalidDetailsErr, ok := onionError2.(*FailIncorrectDetails)
   195  	if !ok {
   196  		t.Fatalf("expected FailIncorrectDetails, but got %T",
   197  			onionError2)
   198  	}
   199  
   200  	if invalidDetailsErr.amount != 0 {
   201  		t.Fatalf("expected amount to be zero")
   202  	}
   203  	if invalidDetailsErr.height != 0 {
   204  		t.Fatalf("height incorrect")
   205  	}
   206  }
   207  
   208  type mockFailIncorrectDetailsNoAmt struct {
   209  }
   210  
   211  func (f *mockFailIncorrectDetailsNoAmt) Code() FailCode {
   212  	return CodeIncorrectOrUnknownPaymentDetails
   213  }
   214  
   215  func (f *mockFailIncorrectDetailsNoAmt) Error() string {
   216  	return ""
   217  }
   218  
   219  func (f *mockFailIncorrectDetailsNoAmt) Decode(r io.Reader, pver uint32) error {
   220  	return nil
   221  }
   222  
   223  func (f *mockFailIncorrectDetailsNoAmt) Encode(w io.Writer, pver uint32) error {
   224  	return nil
   225  }
   226  
   227  // TestFailIncorrectDetailsOptionalHeight tests that we're able to decode an
   228  // FailIncorrectDetails error that doesn't have the optional height. This
   229  // ensures we're able to decode FailIncorrectDetails messages from older nodes.
   230  func TestFailIncorrectDetailsOptionalHeight(t *testing.T) {
   231  	t.Parallel()
   232  
   233  	onionError := &mockFailIncorrectDetailsNoHeight{
   234  		amount: uint64(123),
   235  	}
   236  
   237  	var b bytes.Buffer
   238  	if err := EncodeFailure(&b, onionError, 0); err != nil {
   239  		t.Fatalf("unable to encode failure: %v", err)
   240  	}
   241  
   242  	onionError2, err := DecodeFailure(bytes.NewReader(b.Bytes()), 0)
   243  	if err != nil {
   244  		t.Fatalf("unable to decode error: %v", err)
   245  	}
   246  
   247  	invalidDetailsErr, ok := onionError2.(*FailIncorrectDetails)
   248  	if !ok {
   249  		t.Fatalf("expected FailIncorrectDetails, but got %T",
   250  			onionError2)
   251  	}
   252  
   253  	if invalidDetailsErr.amount != 123 {
   254  		t.Fatalf("amount incorrect")
   255  	}
   256  	if invalidDetailsErr.height != 0 {
   257  		t.Fatalf("height incorrect")
   258  	}
   259  }
   260  
   261  type mockFailIncorrectDetailsNoHeight struct {
   262  	amount uint64
   263  }
   264  
   265  func (f *mockFailIncorrectDetailsNoHeight) Code() FailCode {
   266  	return CodeIncorrectOrUnknownPaymentDetails
   267  }
   268  
   269  func (f *mockFailIncorrectDetailsNoHeight) Error() string {
   270  	return ""
   271  }
   272  
   273  func (f *mockFailIncorrectDetailsNoHeight) Decode(r io.Reader, pver uint32) error {
   274  	return nil
   275  }
   276  
   277  func (f *mockFailIncorrectDetailsNoHeight) Encode(w io.Writer, pver uint32) error {
   278  	return WriteElement(w, f.amount)
   279  }