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