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 }