github.com/decred/dcrlnd@v0.7.6/contractcourt/briefcase_test.go (about) 1 package contractcourt 2 3 import ( 4 "crypto/rand" 5 "io/ioutil" 6 "os" 7 "reflect" 8 "testing" 9 "time" 10 11 prand "math/rand" 12 13 "github.com/davecgh/go-spew/spew" 14 "github.com/decred/dcrd/chaincfg/chainhash" 15 "github.com/decred/dcrd/dcrec/secp256k1/v4" 16 "github.com/decred/dcrd/dcrec/secp256k1/v4/ecdsa" 17 "github.com/decred/dcrd/txscript/v4" 18 "github.com/decred/dcrd/wire" 19 "github.com/decred/dcrlnd/channeldb" 20 "github.com/decred/dcrlnd/input" 21 "github.com/decred/dcrlnd/kvdb" 22 "github.com/decred/dcrlnd/lntest/channels" 23 "github.com/decred/dcrlnd/lnwallet" 24 ) 25 26 var ( 27 testChainHash = [chainhash.HashSize]byte{ 28 0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda, 29 0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17, 30 0x2d, 0xe7, 0x93, 0xe4, 31 } 32 33 testChanPoint1 = wire.OutPoint{ 34 Hash: chainhash.Hash{ 35 0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda, 36 0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17, 37 0x2d, 0xe7, 0x93, 0xe4, 38 }, 39 Index: 1, 40 } 41 42 testChanPoint2 = wire.OutPoint{ 43 Hash: chainhash.Hash{ 44 0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17, 45 0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda, 46 0x2d, 0xe7, 0x93, 0xe4, 47 }, 48 Index: 2, 49 } 50 51 testChanPoint3 = wire.OutPoint{ 52 Hash: chainhash.Hash{ 53 0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17, 54 0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda, 55 0x2d, 0xe7, 0x93, 0xe4, 56 }, 57 Index: 3, 58 } 59 60 testPreimage = [32]byte{ 61 0x52, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda, 62 0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17, 63 0x2d, 0xe7, 0x93, 0xe4, 64 } 65 66 key1 = []byte{ 67 0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a, 68 0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e, 69 0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca, 70 0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0, 71 0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64, 72 0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9, 73 0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56, 74 0xb4, 0x12, 0xa3, 75 } 76 77 testSignDesc = input.SignDescriptor{ 78 SingleTweak: []byte{ 79 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 80 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 81 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 82 0x02, 0x02, 0x02, 0x02, 0x02, 83 }, 84 WitnessScript: []byte{ 85 0x00, 0x14, 0xee, 0x91, 0x41, 0x7e, 0x85, 0x6c, 0xde, 86 0x10, 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 0xbd, 0x69, 0xe2, 87 0xef, 0xb5, 0x71, 0x48, 88 }, 89 Output: &wire.TxOut{ 90 Value: 5000000000, 91 PkScript: []byte{ 92 0x41, // OP_DATA_65 93 0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5, 94 0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42, 95 0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1, 96 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24, 97 0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97, 98 0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, 99 0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20, 100 0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63, 101 0xa6, // 65-byte signature 102 0xac, // OP_CHECKSIG 103 }, 104 }, 105 HashType: txscript.SigHashAll, 106 } 107 108 testTx = &wire.MsgTx{ 109 Version: 2, 110 TxIn: []*wire.TxIn{ 111 { 112 PreviousOutPoint: testChanPoint2, 113 SignatureScript: []byte{ 114 0x14, 0xee, 0x91, 0x41, 115 0x7e, 0x85, 0x6c, 0xde, 0x10, 116 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 117 0xbd, 0x69, 0xe2, 0xef, 0xb5, 118 0x71, 0x48, 119 }, 120 Sequence: 1, 121 }, 122 }, 123 TxOut: []*wire.TxOut{ 124 { 125 Value: 5000000000, 126 PkScript: []byte{ 127 0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 128 0x86, 0x24, 0xe1, 0x81, 0x75, 0xe8, 129 0x51, 0xc9, 0x6b, 0x97, 0x3d, 0x81, 130 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78, 131 }, 132 }, 133 }, 134 LockTime: 123, 135 } 136 137 testSig, _ = ecdsa.ParseDERSignature(channels.TestSigBytes) 138 139 testSignDetails = &input.SignDetails{ 140 SignDesc: testSignDesc, 141 SigHashType: txscript.SigHashSingle, 142 PeerSig: testSig, 143 } 144 ) 145 146 func makeTestDB() (kvdb.Backend, func(), error) { 147 // First, create a temporary directory to be used for the duration of 148 // this test. 149 tempDirName, err := ioutil.TempDir("", "arblog") 150 if err != nil { 151 return nil, nil, err 152 } 153 154 db, err := kvdb.Create( 155 kvdb.BoltBackendName, tempDirName+"/test.db", true, 156 kvdb.DefaultDBTimeout, 157 ) 158 if err != nil { 159 return nil, nil, err 160 } 161 162 cleanUp := func() { 163 db.Close() 164 os.RemoveAll(tempDirName) 165 } 166 167 return db, cleanUp, nil 168 } 169 170 func newTestBoltArbLog(chainhash chainhash.Hash, 171 op wire.OutPoint) (ArbitratorLog, func(), error) { 172 173 testDB, cleanUp, err := makeTestDB() 174 if err != nil { 175 return nil, nil, err 176 } 177 178 testArbCfg := ChannelArbitratorConfig{ 179 PutResolverReport: func(_ kvdb.RwTx, 180 _ *channeldb.ResolverReport) error { 181 return nil 182 }, 183 } 184 testLog, err := newBoltArbitratorLog(testDB, testArbCfg, chainhash, op) 185 if err != nil { 186 return nil, nil, err 187 } 188 189 return testLog, cleanUp, err 190 } 191 192 func randOutPoint() wire.OutPoint { 193 var op wire.OutPoint 194 rand.Read(op.Hash[:]) 195 op.Index = prand.Uint32() 196 197 return op 198 } 199 200 func assertResolversEqual(t *testing.T, originalResolver ContractResolver, 201 diskResolver ContractResolver) { 202 203 assertTimeoutResEqual := func(ogRes, diskRes *htlcTimeoutResolver) { 204 if !reflect.DeepEqual(ogRes.htlcResolution, diskRes.htlcResolution) { 205 t.Fatalf("resolution mismatch: expected %#v, got %v#", 206 ogRes.htlcResolution, diskRes.htlcResolution) 207 } 208 if ogRes.outputIncubating != diskRes.outputIncubating { 209 t.Fatalf("expected %v, got %v", 210 ogRes.outputIncubating, diskRes.outputIncubating) 211 } 212 if ogRes.resolved != diskRes.resolved { 213 t.Fatalf("expected %v, got %v", ogRes.resolved, 214 diskRes.resolved) 215 } 216 if ogRes.broadcastHeight != diskRes.broadcastHeight { 217 t.Fatalf("expected %v, got %v", 218 ogRes.broadcastHeight, diskRes.broadcastHeight) 219 } 220 if ogRes.htlc.HtlcIndex != diskRes.htlc.HtlcIndex { 221 t.Fatalf("expected %v, got %v", ogRes.htlc.HtlcIndex, 222 diskRes.htlc.HtlcIndex) 223 } 224 } 225 226 assertSuccessResEqual := func(ogRes, diskRes *htlcSuccessResolver) { 227 if !reflect.DeepEqual(ogRes.htlcResolution, diskRes.htlcResolution) { 228 t.Fatalf("resolution mismatch: expected %#v, got %v#", 229 ogRes.htlcResolution, diskRes.htlcResolution) 230 } 231 if ogRes.outputIncubating != diskRes.outputIncubating { 232 t.Fatalf("expected %v, got %v", 233 ogRes.outputIncubating, diskRes.outputIncubating) 234 } 235 if ogRes.resolved != diskRes.resolved { 236 t.Fatalf("expected %v, got %v", ogRes.resolved, 237 diskRes.resolved) 238 } 239 if ogRes.broadcastHeight != diskRes.broadcastHeight { 240 t.Fatalf("expected %v, got %v", 241 ogRes.broadcastHeight, diskRes.broadcastHeight) 242 } 243 if ogRes.htlc.RHash != diskRes.htlc.RHash { 244 t.Fatalf("expected %v, got %v", ogRes.htlc.RHash, 245 diskRes.htlc.RHash) 246 } 247 } 248 249 switch ogRes := originalResolver.(type) { 250 case *htlcTimeoutResolver: 251 diskRes := diskResolver.(*htlcTimeoutResolver) 252 assertTimeoutResEqual(ogRes, diskRes) 253 254 case *htlcSuccessResolver: 255 diskRes := diskResolver.(*htlcSuccessResolver) 256 assertSuccessResEqual(ogRes, diskRes) 257 258 case *htlcOutgoingContestResolver: 259 diskRes := diskResolver.(*htlcOutgoingContestResolver) 260 assertTimeoutResEqual( 261 ogRes.htlcTimeoutResolver, diskRes.htlcTimeoutResolver, 262 ) 263 264 case *htlcIncomingContestResolver: 265 diskRes := diskResolver.(*htlcIncomingContestResolver) 266 assertSuccessResEqual( 267 ogRes.htlcSuccessResolver, diskRes.htlcSuccessResolver, 268 ) 269 270 if ogRes.htlcExpiry != diskRes.htlcExpiry { 271 t.Fatalf("expected %v, got %v", ogRes.htlcExpiry, 272 diskRes.htlcExpiry) 273 } 274 275 case *commitSweepResolver: 276 diskRes := diskResolver.(*commitSweepResolver) 277 if !reflect.DeepEqual(ogRes.commitResolution, diskRes.commitResolution) { 278 t.Fatalf("resolution mismatch: expected %v, got %v", 279 ogRes.commitResolution, diskRes.commitResolution) 280 } 281 if ogRes.resolved != diskRes.resolved { 282 t.Fatalf("expected %v, got %v", ogRes.resolved, 283 diskRes.resolved) 284 } 285 if ogRes.broadcastHeight != diskRes.broadcastHeight { 286 t.Fatalf("expected %v, got %v", 287 ogRes.broadcastHeight, diskRes.broadcastHeight) 288 } 289 if ogRes.chanPoint != diskRes.chanPoint { 290 t.Fatalf("expected %v, got %v", ogRes.chanPoint, 291 diskRes.chanPoint) 292 } 293 } 294 } 295 296 // TestContractInsertionRetrieval tests that were able to insert a set of 297 // unresolved contracts into the log, and retrieve the same set properly. 298 // 299 // We disable govet in this case to avoid the complaint about a copied lock. 300 // 301 //nolint:govet 302 func TestContractInsertionRetrieval(t *testing.T) { 303 t.Parallel() 304 305 // First, we'll create a test instance of the ArbitratorLog 306 // implementation backed by bboltdb. 307 testLog, cleanUp, err := newTestBoltArbLog( 308 testChainHash, testChanPoint1, 309 ) 310 if err != nil { 311 t.Fatalf("unable to create test log: %v", err) 312 } 313 defer cleanUp() 314 315 // The log created, we'll create a series of resolvers, each properly 316 // implementing the ContractResolver interface. 317 timeoutResolver := htlcTimeoutResolver{ 318 htlcResolution: lnwallet.OutgoingHtlcResolution{ 319 Expiry: 99, 320 SignedTimeoutTx: nil, 321 CsvDelay: 99, 322 ClaimOutpoint: randOutPoint(), 323 SweepSignDesc: testSignDesc, 324 }, 325 outputIncubating: true, 326 resolved: true, 327 broadcastHeight: 102, 328 htlc: channeldb.HTLC{ 329 HtlcIndex: 12, 330 }, 331 } 332 successResolver := htlcSuccessResolver{ 333 htlcResolution: lnwallet.IncomingHtlcResolution{ 334 Preimage: testPreimage, 335 SignedSuccessTx: nil, 336 CsvDelay: 900, 337 ClaimOutpoint: randOutPoint(), 338 SweepSignDesc: testSignDesc, 339 }, 340 outputIncubating: true, 341 resolved: true, 342 broadcastHeight: 109, 343 htlc: channeldb.HTLC{ 344 RHash: testPreimage, 345 }, 346 sweepTx: nil, 347 } 348 resolvers := []ContractResolver{ 349 &timeoutResolver, 350 &successResolver, 351 &commitSweepResolver{ 352 commitResolution: lnwallet.CommitOutputResolution{ 353 SelfOutPoint: testChanPoint2, 354 SelfOutputSignDesc: testSignDesc, 355 MaturityDelay: 99, 356 }, 357 resolved: false, 358 broadcastHeight: 109, 359 chanPoint: testChanPoint1, 360 }, 361 } 362 363 // All resolvers require a unique ResolverKey() output. To achieve this 364 // for the composite resolvers, we'll mutate the underlying resolver 365 // with a new outpoint. 366 contestTimeout := timeoutResolver 367 contestTimeout.htlcResolution.ClaimOutpoint = randOutPoint() 368 resolvers = append(resolvers, &htlcOutgoingContestResolver{ 369 htlcTimeoutResolver: &contestTimeout, 370 }) 371 contestSuccess := successResolver 372 contestSuccess.htlcResolution.ClaimOutpoint = randOutPoint() 373 resolvers = append(resolvers, &htlcIncomingContestResolver{ 374 htlcExpiry: 100, 375 htlcSuccessResolver: &contestSuccess, 376 }) 377 378 // For quick lookup during the test, we'll create this map which allow 379 // us to lookup a resolver according to its unique resolver key. 380 resolverMap := make(map[string]ContractResolver) 381 resolverMap[string(timeoutResolver.ResolverKey())] = resolvers[0] 382 resolverMap[string(successResolver.ResolverKey())] = resolvers[1] 383 resolverMap[string(resolvers[2].ResolverKey())] = resolvers[2] 384 resolverMap[string(resolvers[3].ResolverKey())] = resolvers[3] 385 resolverMap[string(resolvers[4].ResolverKey())] = resolvers[4] 386 387 // Now, we'll insert the resolver into the log, we do not need to apply 388 // any closures, so we will pass in nil. 389 err = testLog.InsertUnresolvedContracts(nil, resolvers...) 390 if err != nil { 391 t.Fatalf("unable to insert resolvers: %v", err) 392 } 393 394 // With the resolvers inserted, we'll now attempt to retrieve them from 395 // the database, so we can compare them to the versions we created 396 // above. 397 diskResolvers, err := testLog.FetchUnresolvedContracts() 398 if err != nil { 399 t.Fatalf("unable to retrieve resolvers: %v", err) 400 } 401 402 if len(diskResolvers) != len(resolvers) { 403 t.Fatalf("expected %v got resolvers, instead got %v: %#v", 404 len(resolvers), len(diskResolvers), 405 diskResolvers) 406 } 407 408 // Now we'll run through each of the resolvers, and ensure that it maps 409 // to a resolver perfectly that we inserted previously. 410 for _, diskResolver := range diskResolvers { 411 resKey := string(diskResolver.ResolverKey()) 412 originalResolver, ok := resolverMap[resKey] 413 if !ok { 414 t.Fatalf("unable to find resolver match for %T: %v", 415 diskResolver, resKey) 416 } 417 418 assertResolversEqual(t, originalResolver, diskResolver) 419 } 420 421 // We'll now delete the state, then attempt to retrieve the set of 422 // resolvers, no resolvers should be found. 423 if err := testLog.WipeHistory(); err != nil { 424 t.Fatalf("unable to wipe log: %v", err) 425 } 426 diskResolvers, err = testLog.FetchUnresolvedContracts() 427 if err != nil { 428 t.Fatalf("unable to fetch unresolved contracts: %v", err) 429 } 430 if len(diskResolvers) != 0 { 431 t.Fatalf("no resolvers should be found, instead %v were", 432 len(diskResolvers)) 433 } 434 } 435 436 // TestContractResolution tests that once we mark a contract as resolved, it's 437 // properly removed from the database. 438 func TestContractResolution(t *testing.T) { 439 t.Parallel() 440 441 // First, we'll create a test instance of the ArbitratorLog 442 // implementation backed by bboltdb. 443 testLog, cleanUp, err := newTestBoltArbLog( 444 testChainHash, testChanPoint1, 445 ) 446 if err != nil { 447 t.Fatalf("unable to create test log: %v", err) 448 } 449 defer cleanUp() 450 451 // We'll now create a timeout resolver that we'll be using for the 452 // duration of this test. 453 timeoutResolver := &htlcTimeoutResolver{ 454 htlcResolution: lnwallet.OutgoingHtlcResolution{ 455 Expiry: 991, 456 SignedTimeoutTx: nil, 457 CsvDelay: 992, 458 ClaimOutpoint: randOutPoint(), 459 SweepSignDesc: testSignDesc, 460 }, 461 outputIncubating: true, 462 resolved: true, 463 broadcastHeight: 192, 464 htlc: channeldb.HTLC{ 465 HtlcIndex: 9912, 466 }, 467 } 468 469 // First, we'll insert the resolver into the database and ensure that 470 // we get the same resolver out the other side. We do not need to apply 471 // any closures. 472 err = testLog.InsertUnresolvedContracts(nil, timeoutResolver) 473 if err != nil { 474 t.Fatalf("unable to insert contract into db: %v", err) 475 } 476 dbContracts, err := testLog.FetchUnresolvedContracts() 477 if err != nil { 478 t.Fatalf("unable to fetch contracts from db: %v", err) 479 } 480 assertResolversEqual(t, timeoutResolver, dbContracts[0]) 481 482 // Now, we'll mark the contract as resolved within the database. 483 if err := testLog.ResolveContract(timeoutResolver); err != nil { 484 t.Fatalf("unable to resolve contract: %v", err) 485 } 486 487 // At this point, no contracts should exist within the log. 488 dbContracts, err = testLog.FetchUnresolvedContracts() 489 if err != nil { 490 t.Fatalf("unable to fetch contracts from db: %v", err) 491 } 492 if len(dbContracts) != 0 { 493 t.Fatalf("no contract should be from in the db, instead %v "+ 494 "were", len(dbContracts)) 495 } 496 } 497 498 // TestContractSwapping ensures that callers are able to atomically swap to 499 // distinct contracts for one another. 500 func TestContractSwapping(t *testing.T) { 501 t.Parallel() 502 503 // First, we'll create a test instance of the ArbitratorLog 504 // implementation backed by bboltdb. 505 testLog, cleanUp, err := newTestBoltArbLog( 506 testChainHash, testChanPoint1, 507 ) 508 if err != nil { 509 t.Fatalf("unable to create test log: %v", err) 510 } 511 defer cleanUp() 512 513 // We'll create two resolvers, a regular timeout resolver, and the 514 // contest resolver that eventually turns into the timeout resolver. 515 timeoutResolver := &htlcTimeoutResolver{ 516 htlcResolution: lnwallet.OutgoingHtlcResolution{ 517 Expiry: 99, 518 SignedTimeoutTx: nil, 519 CsvDelay: 99, 520 ClaimOutpoint: randOutPoint(), 521 SweepSignDesc: testSignDesc, 522 }, 523 outputIncubating: true, 524 resolved: true, 525 broadcastHeight: 102, 526 htlc: channeldb.HTLC{ 527 HtlcIndex: 12, 528 }, 529 } 530 contestResolver := &htlcOutgoingContestResolver{ 531 htlcTimeoutResolver: timeoutResolver, 532 } 533 534 // We'll first insert the contest resolver into the log with no 535 // additional updates. 536 err = testLog.InsertUnresolvedContracts(nil, contestResolver) 537 if err != nil { 538 t.Fatalf("unable to insert contract into db: %v", err) 539 } 540 541 // With the resolver inserted, we'll now attempt to atomically swap it 542 // for its underlying timeout resolver. 543 err = testLog.SwapContract(contestResolver, timeoutResolver) 544 if err != nil { 545 t.Fatalf("unable to swap contracts: %v", err) 546 } 547 548 // At this point, there should now only be a single contract in the 549 // database. 550 dbContracts, err := testLog.FetchUnresolvedContracts() 551 if err != nil { 552 t.Fatalf("unable to fetch contracts from db: %v", err) 553 } 554 if len(dbContracts) != 1 { 555 t.Fatalf("one contract should be from in the db, instead %v "+ 556 "were", len(dbContracts)) 557 } 558 559 // That single contract should be the underlying timeout resolver. 560 assertResolversEqual(t, timeoutResolver, dbContracts[0]) 561 } 562 563 // TestContractResolutionsStorage tests that we're able to properly store and 564 // retrieve contract resolutions written to disk. 565 func TestContractResolutionsStorage(t *testing.T) { 566 t.Parallel() 567 568 // First, we'll create a test instance of the ArbitratorLog 569 // implementation backed by bboltdb. 570 testLog, cleanUp, err := newTestBoltArbLog( 571 testChainHash, testChanPoint1, 572 ) 573 if err != nil { 574 t.Fatalf("unable to create test log: %v", err) 575 } 576 defer cleanUp() 577 578 // With the test log created, we'll now craft a contact resolution that 579 // will be using for the duration of this test. 580 res := ContractResolutions{ 581 CommitHash: testChainHash, 582 CommitResolution: &lnwallet.CommitOutputResolution{ 583 SelfOutPoint: testChanPoint2, 584 SelfOutputSignDesc: testSignDesc, 585 MaturityDelay: 101, 586 }, 587 HtlcResolutions: lnwallet.HtlcResolutions{ 588 IncomingHTLCs: []lnwallet.IncomingHtlcResolution{ 589 { 590 Preimage: testPreimage, 591 SignedSuccessTx: nil, 592 CsvDelay: 900, 593 ClaimOutpoint: randOutPoint(), 594 SweepSignDesc: testSignDesc, 595 }, 596 597 // We add a resolution with SignDetails. 598 { 599 Preimage: testPreimage, 600 SignedSuccessTx: testTx, 601 SignDetails: testSignDetails, 602 CsvDelay: 900, 603 ClaimOutpoint: randOutPoint(), 604 SweepSignDesc: testSignDesc, 605 }, 606 607 // We add a resolution with a signed tx, but no 608 // SignDetails. 609 { 610 Preimage: testPreimage, 611 SignedSuccessTx: testTx, 612 CsvDelay: 900, 613 ClaimOutpoint: randOutPoint(), 614 SweepSignDesc: testSignDesc, 615 }, 616 }, 617 OutgoingHTLCs: []lnwallet.OutgoingHtlcResolution{ 618 // We add a resolution with a signed tx, but no 619 // SignDetails. 620 { 621 Expiry: 103, 622 SignedTimeoutTx: testTx, 623 CsvDelay: 923923, 624 ClaimOutpoint: randOutPoint(), 625 SweepSignDesc: testSignDesc, 626 }, 627 // Resolution without signed tx. 628 { 629 Expiry: 103, 630 SignedTimeoutTx: nil, 631 CsvDelay: 923923, 632 ClaimOutpoint: randOutPoint(), 633 SweepSignDesc: testSignDesc, 634 }, 635 // Resolution with SignDetails. 636 { 637 Expiry: 103, 638 SignedTimeoutTx: testTx, 639 SignDetails: testSignDetails, 640 CsvDelay: 923923, 641 ClaimOutpoint: randOutPoint(), 642 SweepSignDesc: testSignDesc, 643 }, 644 }, 645 }, 646 AnchorResolution: &lnwallet.AnchorResolution{ 647 CommitAnchor: testChanPoint3, 648 AnchorSignDescriptor: testSignDesc, 649 }, 650 } 651 652 // First make sure that fetching unlogged contract resolutions will 653 // fail. 654 _, err = testLog.FetchContractResolutions() 655 if err == nil { 656 t.Fatalf("expected reading unlogged resolution from db to fail") 657 } 658 659 // Insert the resolution into the database, then immediately retrieve 660 // them so we can compare equality against the original version. 661 if err := testLog.LogContractResolutions(&res); err != nil { 662 t.Fatalf("unable to insert resolutions into db: %v", err) 663 } 664 diskRes, err := testLog.FetchContractResolutions() 665 if err != nil { 666 t.Fatalf("unable to read resolution from db: %v", err) 667 } 668 669 if !reflect.DeepEqual(&res, diskRes) { 670 t.Fatalf("resolution mismatch: expected %v\n, got %v", 671 spew.Sdump(&res), spew.Sdump(diskRes)) 672 } 673 674 // We'll now delete the state, then attempt to retrieve the set of 675 // resolvers, no resolutions should be found. 676 if err := testLog.WipeHistory(); err != nil { 677 t.Fatalf("unable to wipe log: %v", err) 678 } 679 _, err = testLog.FetchContractResolutions() 680 if err != errScopeBucketNoExist { 681 t.Fatalf("unexpected error: %v", err) 682 } 683 } 684 685 // TestStateMutation tests that we're able to properly mutate the state of the 686 // log, then retrieve that same mutated state from disk. 687 func TestStateMutation(t *testing.T) { 688 t.Parallel() 689 690 testLog, cleanUp, err := newTestBoltArbLog( 691 testChainHash, testChanPoint1, 692 ) 693 if err != nil { 694 t.Fatalf("unable to create test log: %v", err) 695 } 696 defer cleanUp() 697 698 // The default state of an arbitrator should be StateDefault. 699 arbState, err := testLog.CurrentState(nil) 700 if err != nil { 701 t.Fatalf("unable to read arb state: %v", err) 702 } 703 if arbState != StateDefault { 704 t.Fatalf("state mismatch: expected %v, got %v", StateDefault, 705 arbState) 706 } 707 708 // We should now be able to mutate the state to an arbitrary one of our 709 // choosing, then read that same state back from disk. 710 if err := testLog.CommitState(StateFullyResolved); err != nil { 711 t.Fatalf("unable to write state: %v", err) 712 } 713 arbState, err = testLog.CurrentState(nil) 714 if err != nil { 715 t.Fatalf("unable to read arb state: %v", err) 716 } 717 if arbState != StateFullyResolved { 718 t.Fatalf("state mismatch: expected %v, got %v", StateFullyResolved, 719 arbState) 720 } 721 722 // Next, we'll wipe our state and ensure that if we try to query for 723 // the current state, we get the proper error. 724 err = testLog.WipeHistory() 725 if err != nil { 726 t.Fatalf("unable to wipe history: %v", err) 727 } 728 729 // If we try to query for the state again, we should get the default 730 // state again. 731 arbState, err = testLog.CurrentState(nil) 732 if err != nil { 733 t.Fatalf("unable to fetch current arbitrator state: %v", err) 734 } 735 if arbState != StateDefault { 736 t.Fatalf("state mismatch: expected %v, got %v", StateDefault, 737 arbState) 738 } 739 } 740 741 // TestScopeIsolation tests the two distinct ArbitratorLog instances with two 742 // distinct scopes, don't over write the state of one another. 743 func TestScopeIsolation(t *testing.T) { 744 t.Parallel() 745 746 // We'll create two distinct test logs. Each log will have a unique 747 // scope key, and therefore should be isolated from the other on disk. 748 testLog1, cleanUp1, err := newTestBoltArbLog( 749 testChainHash, testChanPoint1, 750 ) 751 if err != nil { 752 t.Fatalf("unable to create test log: %v", err) 753 } 754 defer cleanUp1() 755 756 testLog2, cleanUp2, err := newTestBoltArbLog( 757 testChainHash, testChanPoint2, 758 ) 759 if err != nil { 760 t.Fatalf("unable to create test log: %v", err) 761 } 762 defer cleanUp2() 763 764 // We'll now update the current state of both the logs to a unique 765 // state. 766 if err := testLog1.CommitState(StateWaitingFullResolution); err != nil { 767 t.Fatalf("unable to write state: %v", err) 768 } 769 if err := testLog2.CommitState(StateContractClosed); err != nil { 770 t.Fatalf("unable to write state: %v", err) 771 } 772 773 // Querying each log, the states should be the prior one we set, and be 774 // disjoint. 775 log1State, err := testLog1.CurrentState(nil) 776 if err != nil { 777 t.Fatalf("unable to read arb state: %v", err) 778 } 779 log2State, err := testLog2.CurrentState(nil) 780 if err != nil { 781 t.Fatalf("unable to read arb state: %v", err) 782 } 783 784 if log1State == log2State { 785 t.Fatalf("log states are the same: %v", log1State) 786 } 787 788 if log1State != StateWaitingFullResolution { 789 t.Fatalf("state mismatch: expected %v, got %v", 790 StateWaitingFullResolution, log1State) 791 } 792 if log2State != StateContractClosed { 793 t.Fatalf("state mismatch: expected %v, got %v", 794 StateContractClosed, log2State) 795 } 796 } 797 798 // TestCommitSetStorage tests that we're able to properly read/write active 799 // commitment sets. 800 func TestCommitSetStorage(t *testing.T) { 801 t.Parallel() 802 803 testLog, cleanUp, err := newTestBoltArbLog( 804 testChainHash, testChanPoint1, 805 ) 806 if err != nil { 807 t.Fatalf("unable to create test log: %v", err) 808 } 809 defer cleanUp() 810 811 activeHTLCs := []channeldb.HTLC{ 812 { 813 Amt: 1000, 814 OnionBlob: make([]byte, 0), 815 Signature: make([]byte, 0), 816 }, 817 } 818 819 confTypes := []HtlcSetKey{ 820 LocalHtlcSet, RemoteHtlcSet, RemotePendingHtlcSet, 821 } 822 for _, pendingRemote := range []bool{true, false} { 823 for _, confType := range confTypes { 824 commitSet := &CommitSet{ 825 ConfCommitKey: &confType, 826 HtlcSets: make(map[HtlcSetKey][]channeldb.HTLC), 827 } 828 commitSet.HtlcSets[LocalHtlcSet] = activeHTLCs 829 commitSet.HtlcSets[RemoteHtlcSet] = activeHTLCs 830 831 if pendingRemote { 832 commitSet.HtlcSets[RemotePendingHtlcSet] = activeHTLCs 833 } 834 835 err := testLog.InsertConfirmedCommitSet(commitSet) 836 if err != nil { 837 t.Fatalf("unable to write commit set: %v", err) 838 } 839 840 diskCommitSet, err := testLog.FetchConfirmedCommitSet(nil) 841 if err != nil { 842 t.Fatalf("unable to read commit set: %v", err) 843 } 844 845 if !reflect.DeepEqual(commitSet, diskCommitSet) { 846 t.Fatalf("commit set mismatch: expected %v, got %v", 847 spew.Sdump(commitSet), spew.Sdump(diskCommitSet)) 848 } 849 } 850 } 851 852 } 853 854 func init() { 855 testSignDesc.KeyDesc.PubKey, _ = secp256k1.ParsePubKey(key1) 856 857 prand.Seed(time.Now().Unix()) 858 }