github.com/decred/dcrlnd@v0.7.6/channeldb/forwarding_package_test.go (about) 1 package channeldb_test 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "path/filepath" 7 "runtime" 8 "testing" 9 10 "github.com/decred/dcrd/wire" 11 "github.com/decred/dcrlnd/channeldb" 12 "github.com/decred/dcrlnd/kvdb" 13 "github.com/decred/dcrlnd/lnwire" 14 "github.com/stretchr/testify/require" 15 ) 16 17 // TestPkgFilterBruteForce tests the behavior of a pkg filter up to size 1000, 18 // which is greater than the number of HTLCs we permit on a commitment txn. 19 // This should encapsulate every potential filter used in practice. 20 func TestPkgFilterBruteForce(t *testing.T) { 21 t.Parallel() 22 23 checkPkgFilterRange(t, 1000) 24 } 25 26 // checkPkgFilterRange verifies the behavior of a pkg filter when doing a linear 27 // insertion of `high` elements. This is primarily to test that IsFull functions 28 // properly for all relevant sizes of `high`. 29 func checkPkgFilterRange(t *testing.T, high int) { 30 for i := uint16(0); i < uint16(high); i++ { 31 f := channeldb.NewPkgFilter(i) 32 33 if f.Count() != i { 34 t.Fatalf("pkg filter count=%d is actually %d", 35 i, f.Count()) 36 } 37 checkPkgFilterEncodeDecode(t, i, f) 38 39 for j := uint16(0); j < i; j++ { 40 if f.Contains(j) { 41 t.Fatalf("pkg filter count=%d contains %d "+ 42 "before being added", i, j) 43 } 44 45 f.Set(j) 46 checkPkgFilterEncodeDecode(t, i, f) 47 48 if !f.Contains(j) { 49 t.Fatalf("pkg filter count=%d missing %d "+ 50 "after being added", i, j) 51 } 52 53 if j < i-1 && f.IsFull() { 54 t.Fatalf("pkg filter count=%d already full", i) 55 } 56 } 57 58 if !f.IsFull() { 59 t.Fatalf("pkg filter count=%d not full", i) 60 } 61 checkPkgFilterEncodeDecode(t, i, f) 62 } 63 } 64 65 // TestPkgFilterRand uses a random permutation to verify the proper behavior of 66 // the pkg filter if the entries are not inserted in-order. 67 func TestPkgFilterRand(t *testing.T) { 68 t.Parallel() 69 70 checkPkgFilterRand(t, 3, 17) 71 } 72 73 // checkPkgFilterRand checks the behavior of a pkg filter by randomly inserting 74 // indices and asserting the invariants. The order in which indices are inserted 75 // is parameterized by a base `b` coprime to `p`, and using modular 76 // exponentiation to generate all elements in [1,p). 77 func checkPkgFilterRand(t *testing.T, b, p uint16) { 78 f := channeldb.NewPkgFilter(p) 79 var j = b 80 for i := uint16(1); i < p; i++ { 81 if f.Contains(j) { 82 t.Fatalf("pkg filter contains %d-%d "+ 83 "before being added", i, j) 84 } 85 86 f.Set(j) 87 checkPkgFilterEncodeDecode(t, i, f) 88 89 if !f.Contains(j) { 90 t.Fatalf("pkg filter missing %d-%d "+ 91 "after being added", i, j) 92 } 93 94 if i < p-1 && f.IsFull() { 95 t.Fatalf("pkg filter %d already full", i) 96 } 97 checkPkgFilterEncodeDecode(t, i, f) 98 99 j = (b * j) % p 100 } 101 102 // Set 0 independently, since it will never be emitted by the generator. 103 f.Set(0) 104 checkPkgFilterEncodeDecode(t, p, f) 105 106 if !f.IsFull() { 107 t.Fatalf("pkg filter count=%d not full", p) 108 } 109 checkPkgFilterEncodeDecode(t, p, f) 110 } 111 112 // checkPkgFilterEncodeDecode tests the serialization of a pkg filter by: 113 // 1. writing it to a buffer 114 // 2. verifying the number of bytes written matches the filter's Size() 115 // 3. reconstructing the filter decoding the bytes 116 // 4. checking that the two filters are the same according to Equal 117 func checkPkgFilterEncodeDecode(t *testing.T, i uint16, f *channeldb.PkgFilter) { 118 var b bytes.Buffer 119 if err := f.Encode(&b); err != nil { 120 t.Fatalf("unable to serialize pkg filter: %v", err) 121 } 122 123 // +2 for uint16 length 124 size := uint16(len(b.Bytes())) 125 if size != f.Size() { 126 t.Fatalf("pkg filter count=%d serialized size differs, "+ 127 "Size(): %d, len(bytes): %v", i, f.Size(), size) 128 } 129 130 reader := bytes.NewReader(b.Bytes()) 131 132 f2 := &channeldb.PkgFilter{} 133 if err := f2.Decode(reader); err != nil { 134 t.Fatalf("unable to deserialize pkg filter: %v", err) 135 } 136 137 if !f.Equal(f2) { 138 t.Fatalf("pkg filter count=%v does is not equal "+ 139 "after deserialization, want: %v, got %v", 140 i, f, f2) 141 } 142 } 143 144 var ( 145 chanID = lnwire.NewChanIDFromOutPoint(&wire.OutPoint{}) 146 147 adds = []channeldb.LogUpdate{ 148 { 149 LogIndex: 0, 150 UpdateMsg: &lnwire.UpdateAddHTLC{ 151 ChanID: chanID, 152 ID: 1, 153 Amount: 100, 154 Expiry: 1000, 155 PaymentHash: [32]byte{0}, 156 }, 157 }, 158 { 159 LogIndex: 1, 160 UpdateMsg: &lnwire.UpdateAddHTLC{ 161 ChanID: chanID, 162 ID: 1, 163 Amount: 101, 164 Expiry: 1001, 165 PaymentHash: [32]byte{1}, 166 }, 167 }, 168 } 169 170 settleFails = []channeldb.LogUpdate{ 171 { 172 LogIndex: 2, 173 UpdateMsg: &lnwire.UpdateFulfillHTLC{ 174 ChanID: chanID, 175 ID: 0, 176 PaymentPreimage: [32]byte{0}, 177 }, 178 }, 179 { 180 LogIndex: 3, 181 UpdateMsg: &lnwire.UpdateFailHTLC{ 182 ChanID: chanID, 183 ID: 1, 184 Reason: []byte{}, 185 }, 186 }, 187 } 188 ) 189 190 // TestPackagerEmptyFwdPkg checks that the state transitions exhibited by a 191 // forwarding package that contains no adds, fails or settles. We expect that 192 // the fwdpkg reaches FwdStateCompleted immediately after writing the forwarding 193 // decision via SetFwdFilter. 194 func TestPackagerEmptyFwdPkg(t *testing.T) { 195 t.Parallel() 196 197 db := makeFwdPkgDB(t, "") 198 199 shortChanID := lnwire.NewShortChanIDFromInt(1) 200 packager := channeldb.NewChannelPackager(shortChanID) 201 202 // To begin, there should be no forwarding packages on disk. 203 fwdPkgs := loadFwdPkgs(t, db, packager) 204 if len(fwdPkgs) != 0 { 205 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 206 } 207 208 // Next, create and write a new forwarding package with no htlcs. 209 fwdPkg := channeldb.NewFwdPkg(shortChanID, 0, nil, nil) 210 211 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 212 return packager.AddFwdPkg(tx, fwdPkg) 213 }, func() {}); err != nil { 214 t.Fatalf("unable to add fwd pkg: %v", err) 215 } 216 217 // There should now be one fwdpkg on disk. Since no forwarding decision 218 // has been written, we expect it to be FwdStateLockedIn. With no HTLCs, 219 // the ack filter will have no elements, and should always return true. 220 fwdPkgs = loadFwdPkgs(t, db, packager) 221 if len(fwdPkgs) != 1 { 222 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 223 } 224 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateLockedIn) 225 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], 0, 0) 226 assertAckFilterIsFull(t, fwdPkgs[0], true) 227 228 // Now, write the forwarding decision. In this case, its just an empty 229 // fwd filter. 230 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 231 return packager.SetFwdFilter(tx, fwdPkg.Height, fwdPkg.FwdFilter) 232 }, func() {}); err != nil { 233 t.Fatalf("unable to set fwdfiter: %v", err) 234 } 235 236 // We should still have one package on disk. Since the forwarding 237 // decision has been written, it will minimally be in FwdStateProcessed. 238 // However with no htlcs, it should leap frog to FwdStateCompleted. 239 fwdPkgs = loadFwdPkgs(t, db, packager) 240 if len(fwdPkgs) != 1 { 241 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 242 } 243 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateCompleted) 244 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], 0, 0) 245 assertAckFilterIsFull(t, fwdPkgs[0], true) 246 247 // Lastly, remove the completed forwarding package from disk. 248 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 249 return packager.RemovePkg(tx, fwdPkg.Height) 250 }, func() {}); err != nil { 251 t.Fatalf("unable to remove fwdpkg: %v", err) 252 } 253 254 // Check that the fwd package was actually removed. 255 fwdPkgs = loadFwdPkgs(t, db, packager) 256 if len(fwdPkgs) != 0 { 257 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 258 } 259 } 260 261 // TestPackagerOnlyAdds checks that the fwdpkg does not reach FwdStateCompleted 262 // as soon as all the adds in the package have been acked using AckAddHtlcs. 263 func TestPackagerOnlyAdds(t *testing.T) { 264 t.Parallel() 265 266 db := makeFwdPkgDB(t, "") 267 268 shortChanID := lnwire.NewShortChanIDFromInt(1) 269 packager := channeldb.NewChannelPackager(shortChanID) 270 271 // To begin, there should be no forwarding packages on disk. 272 fwdPkgs := loadFwdPkgs(t, db, packager) 273 if len(fwdPkgs) != 0 { 274 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 275 } 276 277 // Next, create and write a new forwarding package that only has add 278 // htlcs. 279 fwdPkg := channeldb.NewFwdPkg(shortChanID, 0, adds, nil) 280 281 nAdds := len(adds) 282 283 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 284 return packager.AddFwdPkg(tx, fwdPkg) 285 }, func() {}); err != nil { 286 t.Fatalf("unable to add fwd pkg: %v", err) 287 } 288 289 // There should now be one fwdpkg on disk. Since no forwarding decision 290 // has been written, we expect it to be FwdStateLockedIn. The package 291 // has unacked add HTLCs, so the ack filter should not be full. 292 fwdPkgs = loadFwdPkgs(t, db, packager) 293 if len(fwdPkgs) != 1 { 294 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 295 } 296 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateLockedIn) 297 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, 0) 298 assertAckFilterIsFull(t, fwdPkgs[0], false) 299 300 // Now, write the forwarding decision. Since we have not explicitly 301 // added any adds to the fwdfilter, this would indicate that all of the 302 // adds were 1) settled locally by this link (exit hop), or 2) the htlc 303 // was failed locally. 304 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 305 return packager.SetFwdFilter(tx, fwdPkg.Height, fwdPkg.FwdFilter) 306 }, func() {}); err != nil { 307 t.Fatalf("unable to set fwdfiter: %v", err) 308 } 309 310 for i := range adds { 311 // We should still have one package on disk. Since the forwarding 312 // decision has been written, it will minimally be in FwdStateProcessed. 313 // However not allf of the HTLCs have been acked, so should not 314 // have advanced further. 315 fwdPkgs = loadFwdPkgs(t, db, packager) 316 if len(fwdPkgs) != 1 { 317 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 318 } 319 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateProcessed) 320 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, 0) 321 assertAckFilterIsFull(t, fwdPkgs[0], false) 322 323 addRef := channeldb.AddRef{ 324 Height: fwdPkg.Height, 325 Index: uint16(i), 326 } 327 328 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 329 return packager.AckAddHtlcs(tx, addRef) 330 }, func() {}); err != nil { 331 t.Fatalf("unable to ack add htlc: %v", err) 332 } 333 } 334 335 // We should still have one package on disk. Now that all adds have been 336 // acked, the ack filter should return true and the package should be 337 // FwdStateCompleted since there are no other settle/fail packets. 338 fwdPkgs = loadFwdPkgs(t, db, packager) 339 if len(fwdPkgs) != 1 { 340 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 341 } 342 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateCompleted) 343 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, 0) 344 assertAckFilterIsFull(t, fwdPkgs[0], true) 345 346 // Lastly, remove the completed forwarding package from disk. 347 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 348 return packager.RemovePkg(tx, fwdPkg.Height) 349 }, func() {}); err != nil { 350 t.Fatalf("unable to remove fwdpkg: %v", err) 351 } 352 353 // Check that the fwd package was actually removed. 354 fwdPkgs = loadFwdPkgs(t, db, packager) 355 if len(fwdPkgs) != 0 { 356 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 357 } 358 } 359 360 // TestPackagerOnlySettleFails asserts that the fwdpkg remains in 361 // FwdStateProcessed after writing the forwarding decision when there are no 362 // adds in the fwdpkg. We expect this because an empty FwdFilter will always 363 // return true, but we are still waiting for the remaining fails and settles to 364 // be deleted. 365 func TestPackagerOnlySettleFails(t *testing.T) { 366 t.Parallel() 367 368 db := makeFwdPkgDB(t, "") 369 370 shortChanID := lnwire.NewShortChanIDFromInt(1) 371 packager := channeldb.NewChannelPackager(shortChanID) 372 373 // To begin, there should be no forwarding packages on disk. 374 fwdPkgs := loadFwdPkgs(t, db, packager) 375 if len(fwdPkgs) != 0 { 376 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 377 } 378 379 // Next, create and write a new forwarding package that only has add 380 // htlcs. 381 fwdPkg := channeldb.NewFwdPkg(shortChanID, 0, nil, settleFails) 382 383 nSettleFails := len(settleFails) 384 385 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 386 return packager.AddFwdPkg(tx, fwdPkg) 387 }, func() {}); err != nil { 388 t.Fatalf("unable to add fwd pkg: %v", err) 389 } 390 391 // There should now be one fwdpkg on disk. Since no forwarding decision 392 // has been written, we expect it to be FwdStateLockedIn. The package 393 // has unacked add HTLCs, so the ack filter should not be full. 394 fwdPkgs = loadFwdPkgs(t, db, packager) 395 if len(fwdPkgs) != 1 { 396 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 397 } 398 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateLockedIn) 399 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], 0, nSettleFails) 400 assertAckFilterIsFull(t, fwdPkgs[0], true) 401 402 // Now, write the forwarding decision. Since we have not explicitly 403 // added any adds to the fwdfilter, this would indicate that all of the 404 // adds were 1) settled locally by this link (exit hop), or 2) the htlc 405 // was failed locally. 406 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 407 return packager.SetFwdFilter(tx, fwdPkg.Height, fwdPkg.FwdFilter) 408 }, func() {}); err != nil { 409 t.Fatalf("unable to set fwdfiter: %v", err) 410 } 411 412 for i := range settleFails { 413 // We should still have one package on disk. Since the 414 // forwarding decision has been written, it will minimally be in 415 // FwdStateProcessed. However, not all of the HTLCs have been 416 // acked, so should not have advanced further. 417 fwdPkgs = loadFwdPkgs(t, db, packager) 418 if len(fwdPkgs) != 1 { 419 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 420 } 421 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateProcessed) 422 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], 0, nSettleFails) 423 assertSettleFailFilterIsFull(t, fwdPkgs[0], false) 424 assertAckFilterIsFull(t, fwdPkgs[0], true) 425 426 failSettleRef := channeldb.SettleFailRef{ 427 Source: shortChanID, 428 Height: fwdPkg.Height, 429 Index: uint16(i), 430 } 431 432 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 433 return packager.AckSettleFails(tx, failSettleRef) 434 }, func() {}); err != nil { 435 t.Fatalf("unable to ack add htlc: %v", err) 436 } 437 } 438 439 // We should still have one package on disk. Now that all settles and 440 // fails have been removed, package should be FwdStateCompleted since 441 // there are no other add packets. 442 fwdPkgs = loadFwdPkgs(t, db, packager) 443 if len(fwdPkgs) != 1 { 444 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 445 } 446 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateCompleted) 447 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], 0, nSettleFails) 448 assertSettleFailFilterIsFull(t, fwdPkgs[0], true) 449 assertAckFilterIsFull(t, fwdPkgs[0], true) 450 451 // Lastly, remove the completed forwarding package from disk. 452 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 453 return packager.RemovePkg(tx, fwdPkg.Height) 454 }, func() {}); err != nil { 455 t.Fatalf("unable to remove fwdpkg: %v", err) 456 } 457 458 // Check that the fwd package was actually removed. 459 fwdPkgs = loadFwdPkgs(t, db, packager) 460 if len(fwdPkgs) != 0 { 461 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 462 } 463 } 464 465 // TestPackagerAddsThenSettleFails writes a fwdpkg containing both adds and 466 // settle/fails, then checks the behavior when the adds are acked before any of 467 // the settle fails. Here we expect pkg to remain in FwdStateProcessed while the 468 // remainder of the fail/settles are being deleted. 469 func TestPackagerAddsThenSettleFails(t *testing.T) { 470 t.Parallel() 471 472 db := makeFwdPkgDB(t, "") 473 474 shortChanID := lnwire.NewShortChanIDFromInt(1) 475 packager := channeldb.NewChannelPackager(shortChanID) 476 477 // To begin, there should be no forwarding packages on disk. 478 fwdPkgs := loadFwdPkgs(t, db, packager) 479 if len(fwdPkgs) != 0 { 480 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 481 } 482 483 // Next, create and write a new forwarding package that only has add 484 // htlcs. 485 fwdPkg := channeldb.NewFwdPkg(shortChanID, 0, adds, settleFails) 486 487 nAdds := len(adds) 488 nSettleFails := len(settleFails) 489 490 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 491 return packager.AddFwdPkg(tx, fwdPkg) 492 }, func() {}); err != nil { 493 t.Fatalf("unable to add fwd pkg: %v", err) 494 } 495 496 // There should now be one fwdpkg on disk. Since no forwarding decision 497 // has been written, we expect it to be FwdStateLockedIn. The package 498 // has unacked add HTLCs, so the ack filter should not be full. 499 fwdPkgs = loadFwdPkgs(t, db, packager) 500 if len(fwdPkgs) != 1 { 501 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 502 } 503 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateLockedIn) 504 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 505 assertAckFilterIsFull(t, fwdPkgs[0], false) 506 507 // Now, write the forwarding decision. Since we have not explicitly 508 // added any adds to the fwdfilter, this would indicate that all of the 509 // adds were 1) settled locally by this link (exit hop), or 2) the htlc 510 // was failed locally. 511 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 512 return packager.SetFwdFilter(tx, fwdPkg.Height, fwdPkg.FwdFilter) 513 }, func() {}); err != nil { 514 t.Fatalf("unable to set fwdfiter: %v", err) 515 } 516 517 for i := range adds { 518 // We should still have one package on disk. Since the forwarding 519 // decision has been written, it will minimally be in FwdStateProcessed. 520 // However not allf of the HTLCs have been acked, so should not 521 // have advanced further. 522 fwdPkgs = loadFwdPkgs(t, db, packager) 523 if len(fwdPkgs) != 1 { 524 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 525 } 526 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateProcessed) 527 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 528 assertSettleFailFilterIsFull(t, fwdPkgs[0], false) 529 assertAckFilterIsFull(t, fwdPkgs[0], false) 530 531 addRef := channeldb.AddRef{ 532 Height: fwdPkg.Height, 533 Index: uint16(i), 534 } 535 536 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 537 return packager.AckAddHtlcs(tx, addRef) 538 }, func() {}); err != nil { 539 t.Fatalf("unable to ack add htlc: %v", err) 540 } 541 } 542 543 for i := range settleFails { 544 // We should still have one package on disk. Since the 545 // forwarding decision has been written, it will minimally be in 546 // FwdStateProcessed. However not allf of the HTLCs have been 547 // acked, so should not have advanced further. 548 fwdPkgs = loadFwdPkgs(t, db, packager) 549 if len(fwdPkgs) != 1 { 550 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 551 } 552 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateProcessed) 553 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 554 assertSettleFailFilterIsFull(t, fwdPkgs[0], false) 555 assertAckFilterIsFull(t, fwdPkgs[0], true) 556 557 failSettleRef := channeldb.SettleFailRef{ 558 Source: shortChanID, 559 Height: fwdPkg.Height, 560 Index: uint16(i), 561 } 562 563 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 564 return packager.AckSettleFails(tx, failSettleRef) 565 }, func() {}); err != nil { 566 t.Fatalf("unable to remove settle/fail htlc: %v", err) 567 } 568 } 569 570 // We should still have one package on disk. Now that all settles and 571 // fails have been removed, package should be FwdStateCompleted since 572 // there are no other add packets. 573 fwdPkgs = loadFwdPkgs(t, db, packager) 574 if len(fwdPkgs) != 1 { 575 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 576 } 577 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateCompleted) 578 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 579 assertSettleFailFilterIsFull(t, fwdPkgs[0], true) 580 assertAckFilterIsFull(t, fwdPkgs[0], true) 581 582 // Lastly, remove the completed forwarding package from disk. 583 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 584 return packager.RemovePkg(tx, fwdPkg.Height) 585 }, func() {}); err != nil { 586 t.Fatalf("unable to remove fwdpkg: %v", err) 587 } 588 589 // Check that the fwd package was actually removed. 590 fwdPkgs = loadFwdPkgs(t, db, packager) 591 if len(fwdPkgs) != 0 { 592 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 593 } 594 } 595 596 // TestPackagerSettleFailsThenAdds writes a fwdpkg with both adds and 597 // settle/fails, then checks the behavior when the settle/fails are removed 598 // before any of the adds have been acked. This should cause the fwdpkg to 599 // remain in FwdStateProcessed until the final ack is recorded, at which point 600 // it should be promoted directly to FwdStateCompleted.since all adds have been 601 // removed. 602 func TestPackagerSettleFailsThenAdds(t *testing.T) { 603 t.Parallel() 604 605 db := makeFwdPkgDB(t, "") 606 607 shortChanID := lnwire.NewShortChanIDFromInt(1) 608 packager := channeldb.NewChannelPackager(shortChanID) 609 610 // To begin, there should be no forwarding packages on disk. 611 fwdPkgs := loadFwdPkgs(t, db, packager) 612 if len(fwdPkgs) != 0 { 613 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 614 } 615 616 // Next, create and write a new forwarding package that has both add 617 // and settle/fail htlcs. 618 fwdPkg := channeldb.NewFwdPkg(shortChanID, 0, adds, settleFails) 619 620 nAdds := len(adds) 621 nSettleFails := len(settleFails) 622 623 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 624 return packager.AddFwdPkg(tx, fwdPkg) 625 }, func() {}); err != nil { 626 t.Fatalf("unable to add fwd pkg: %v", err) 627 } 628 629 // There should now be one fwdpkg on disk. Since no forwarding decision 630 // has been written, we expect it to be FwdStateLockedIn. The package 631 // has unacked add HTLCs, so the ack filter should not be full. 632 fwdPkgs = loadFwdPkgs(t, db, packager) 633 if len(fwdPkgs) != 1 { 634 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 635 } 636 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateLockedIn) 637 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 638 assertAckFilterIsFull(t, fwdPkgs[0], false) 639 640 // Now, write the forwarding decision. Since we have not explicitly 641 // added any adds to the fwdfilter, this would indicate that all of the 642 // adds were 1) settled locally by this link (exit hop), or 2) the htlc 643 // was failed locally. 644 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 645 return packager.SetFwdFilter(tx, fwdPkg.Height, fwdPkg.FwdFilter) 646 }, func() {}); err != nil { 647 t.Fatalf("unable to set fwdfiter: %v", err) 648 } 649 650 // Simulate another channel deleting the settle/fails it received from 651 // the original fwd pkg. 652 // TODO(conner): use different packager/s? 653 for i := range settleFails { 654 // We should still have one package on disk. Since the 655 // forwarding decision has been written, it will minimally be in 656 // FwdStateProcessed. However none all of the add HTLCs have 657 // been acked, so should not have advanced further. 658 fwdPkgs = loadFwdPkgs(t, db, packager) 659 if len(fwdPkgs) != 1 { 660 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 661 } 662 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateProcessed) 663 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 664 assertSettleFailFilterIsFull(t, fwdPkgs[0], false) 665 assertAckFilterIsFull(t, fwdPkgs[0], false) 666 667 failSettleRef := channeldb.SettleFailRef{ 668 Source: shortChanID, 669 Height: fwdPkg.Height, 670 Index: uint16(i), 671 } 672 673 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 674 return packager.AckSettleFails(tx, failSettleRef) 675 }, func() {}); err != nil { 676 t.Fatalf("unable to remove settle/fail htlc: %v", err) 677 } 678 } 679 680 // Now simulate this channel receiving a fail/settle for the adds in the 681 // fwdpkg. 682 for i := range adds { 683 // Again, we should still have one package on disk and be in 684 // FwdStateProcessed. This should not change until all of the 685 // add htlcs have been acked. 686 fwdPkgs = loadFwdPkgs(t, db, packager) 687 if len(fwdPkgs) != 1 { 688 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 689 } 690 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateProcessed) 691 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 692 assertSettleFailFilterIsFull(t, fwdPkgs[0], true) 693 assertAckFilterIsFull(t, fwdPkgs[0], false) 694 695 addRef := channeldb.AddRef{ 696 Height: fwdPkg.Height, 697 Index: uint16(i), 698 } 699 700 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 701 return packager.AckAddHtlcs(tx, addRef) 702 }, func() {}); err != nil { 703 t.Fatalf("unable to ack add htlc: %v", err) 704 } 705 } 706 707 // We should still have one package on disk. Now that all settles and 708 // fails have been removed, package should be FwdStateCompleted since 709 // there are no other add packets. 710 fwdPkgs = loadFwdPkgs(t, db, packager) 711 if len(fwdPkgs) != 1 { 712 t.Fatalf("expected 1 fwdpkg, instead found %d", len(fwdPkgs)) 713 } 714 assertFwdPkgState(t, fwdPkgs[0], channeldb.FwdStateCompleted) 715 assertFwdPkgNumAddsSettleFails(t, fwdPkgs[0], nAdds, nSettleFails) 716 assertSettleFailFilterIsFull(t, fwdPkgs[0], true) 717 assertAckFilterIsFull(t, fwdPkgs[0], true) 718 719 // Lastly, remove the completed forwarding package from disk. 720 if err := kvdb.Update(db, func(tx kvdb.RwTx) error { 721 return packager.RemovePkg(tx, fwdPkg.Height) 722 }, func() {}); err != nil { 723 t.Fatalf("unable to remove fwdpkg: %v", err) 724 } 725 726 // Check that the fwd package was actually removed. 727 fwdPkgs = loadFwdPkgs(t, db, packager) 728 if len(fwdPkgs) != 0 { 729 t.Fatalf("no forwarding packages should exist, found %d", len(fwdPkgs)) 730 } 731 } 732 733 // TestPackagerWipeAll checks that when the method is called, all the related 734 // forwarding packages will be removed. 735 func TestPackagerWipeAll(t *testing.T) { 736 t.Parallel() 737 738 db := makeFwdPkgDB(t, "") 739 740 shortChanID := lnwire.NewShortChanIDFromInt(1) 741 packager := channeldb.NewChannelPackager(shortChanID) 742 743 // To begin, there should be no forwarding packages on disk. 744 fwdPkgs := loadFwdPkgs(t, db, packager) 745 require.Empty(t, fwdPkgs, "no forwarding packages should exist") 746 747 // Now, check we can wipe without error since it's a noop. 748 err := kvdb.Update(db, packager.Wipe, func() {}) 749 require.NoError(t, err, "unable to wipe fwdpkg") 750 751 // Next, create and write two forwarding packages with no htlcs. 752 fwdPkg1 := channeldb.NewFwdPkg(shortChanID, 0, nil, nil) 753 fwdPkg2 := channeldb.NewFwdPkg(shortChanID, 1, nil, nil) 754 755 err = kvdb.Update(db, func(tx kvdb.RwTx) error { 756 if err := packager.AddFwdPkg(tx, fwdPkg2); err != nil { 757 return err 758 } 759 return packager.AddFwdPkg(tx, fwdPkg1) 760 }, func() {}) 761 require.NoError(t, err, "unable to add fwd pkg") 762 763 // There should now be two fwdpkgs on disk. 764 fwdPkgs = loadFwdPkgs(t, db, packager) 765 require.Equal(t, 2, len(fwdPkgs), "expected 2 fwdpkg") 766 767 // Now, wipe all forwarding packages from disk. 768 err = kvdb.Update(db, packager.Wipe, func() {}) 769 require.NoError(t, err, "unable to wipe fwdpkg") 770 771 // Check that the packages were actually removed. 772 fwdPkgs = loadFwdPkgs(t, db, packager) 773 require.Empty(t, fwdPkgs, "no forwarding packages should exist") 774 } 775 776 // assertFwdPkgState checks the current state of a fwdpkg meets our 777 // expectations. 778 func assertFwdPkgState(t *testing.T, fwdPkg *channeldb.FwdPkg, 779 state channeldb.FwdState) { 780 _, _, line, _ := runtime.Caller(1) 781 if fwdPkg.State != state { 782 t.Fatalf("line %d: expected fwdpkg in state %v, found %v", 783 line, state, fwdPkg.State) 784 } 785 } 786 787 // assertFwdPkgNumAddsSettleFails checks that the number of adds and 788 // settle/fail log updates are correct. 789 func assertFwdPkgNumAddsSettleFails(t *testing.T, fwdPkg *channeldb.FwdPkg, 790 expectedNumAdds, expectedNumSettleFails int) { 791 _, _, line, _ := runtime.Caller(1) 792 if len(fwdPkg.Adds) != expectedNumAdds { 793 t.Fatalf("line %d: expected fwdpkg to have %d adds, found %d", 794 line, expectedNumAdds, len(fwdPkg.Adds)) 795 } 796 797 if len(fwdPkg.SettleFails) != expectedNumSettleFails { 798 t.Fatalf("line %d: expected fwdpkg to have %d settle/fails, found %d", 799 line, expectedNumSettleFails, len(fwdPkg.SettleFails)) 800 } 801 } 802 803 // assertAckFilterIsFull checks whether or not a fwdpkg's ack filter matches our 804 // expected full-ness. 805 func assertAckFilterIsFull(t *testing.T, fwdPkg *channeldb.FwdPkg, expected bool) { 806 _, _, line, _ := runtime.Caller(1) 807 if fwdPkg.AckFilter.IsFull() != expected { 808 t.Fatalf("line %d: expected fwdpkg ack filter IsFull to be %v, "+ 809 "found %v", line, expected, fwdPkg.AckFilter.IsFull()) 810 } 811 } 812 813 // assertSettleFailFilterIsFull checks whether or not a fwdpkg's settle fail 814 // filter matches our expected full-ness. 815 func assertSettleFailFilterIsFull(t *testing.T, fwdPkg *channeldb.FwdPkg, expected bool) { 816 _, _, line, _ := runtime.Caller(1) 817 if fwdPkg.SettleFailFilter.IsFull() != expected { 818 t.Fatalf("line %d: expected fwdpkg settle/fail filter IsFull to be %v, "+ 819 "found %v", line, expected, fwdPkg.SettleFailFilter.IsFull()) 820 } 821 } 822 823 // loadFwdPkgs is a helper method that reads all forwarding packages for a 824 // particular packager. 825 func loadFwdPkgs(t *testing.T, db kvdb.Backend, 826 packager channeldb.FwdPackager) []*channeldb.FwdPkg { 827 828 var fwdPkgs []*channeldb.FwdPkg 829 if err := kvdb.View(db, func(tx kvdb.RTx) error { 830 var err error 831 fwdPkgs, err = packager.LoadFwdPkgs(tx) 832 return err 833 }, func() { 834 fwdPkgs = nil 835 }); err != nil { 836 t.Fatalf("unable to load fwd pkgs: %v", err) 837 } 838 839 return fwdPkgs 840 } 841 842 // makeFwdPkgDB initializes a test database for forwarding packages. If the 843 // provided path is an empty, it will create a temp dir/file to use. 844 func makeFwdPkgDB(t *testing.T, path string) kvdb.Backend { 845 if path == "" { 846 var err error 847 path, err = ioutil.TempDir("", "fwdpkgdb") 848 if err != nil { 849 t.Fatalf("unable to create temp path: %v", err) 850 } 851 852 path = filepath.Join(path, "fwdpkg.db") 853 } 854 855 bdb, err := kvdb.Create( 856 kvdb.BoltBackendName, path, true, kvdb.DefaultDBTimeout, 857 ) 858 if err != nil { 859 t.Fatalf("unable to open bboltdb: %v", err) 860 } 861 862 return bdb 863 }