github.com/decred/dcrlnd@v0.7.6/contractcourt/htlc_success_resolver.go (about) 1 package contractcourt 2 3 import ( 4 "encoding/binary" 5 "io" 6 "sync" 7 8 "github.com/davecgh/go-spew/spew" 9 "github.com/decred/dcrd/chaincfg/chainhash" 10 "github.com/decred/dcrd/dcrutil/v4" 11 "github.com/decred/dcrd/wire" 12 13 "github.com/decred/dcrlnd/chainntnfs" 14 "github.com/decred/dcrlnd/channeldb" 15 "github.com/decred/dcrlnd/input" 16 "github.com/decred/dcrlnd/labels" 17 "github.com/decred/dcrlnd/lnwallet" 18 "github.com/decred/dcrlnd/sweep" 19 ) 20 21 // htlcSuccessResolver is a resolver that's capable of sweeping an incoming 22 // HTLC output on-chain. If this is the remote party's commitment, we'll sweep 23 // it directly from the commitment output *immediately*. If this is our 24 // commitment, we'll first broadcast the success transaction, then send it to 25 // the incubator for sweeping. That's it, no need to send any clean up 26 // messages. 27 // 28 // TODO(roasbeef): don't need to broadcast? 29 type htlcSuccessResolver struct { 30 // htlcResolution is the incoming HTLC resolution for this HTLC. It 31 // contains everything we need to properly resolve this HTLC. 32 htlcResolution lnwallet.IncomingHtlcResolution 33 34 // outputIncubating returns true if we've sent the output to the output 35 // incubator (utxo nursery). In case the htlcResolution has non-nil 36 // SignDetails, it means we will let the Sweeper handle broadcasting 37 // the secondd-level transaction, and sweeping its output. In this case 38 // we let this field indicate whether we need to broadcast the 39 // second-level tx (false) or if it has confirmed and we must sweep the 40 // second-level output (true). 41 outputIncubating bool 42 43 // resolved reflects if the contract has been fully resolved or not. 44 resolved bool 45 46 // broadcastHeight is the height that the original contract was 47 // broadcast to the main-chain at. We'll use this value to bound any 48 // historical queries to the chain for spends/confirmations. 49 broadcastHeight uint32 50 51 // sweepTx will be non-nil if we've already crafted a transaction to 52 // sweep a direct HTLC output. This is only a concern if we're sweeping 53 // from the commitment transaction of the remote party. 54 // 55 // TODO(roasbeef): send off to utxobundler 56 sweepTx *wire.MsgTx 57 58 // htlc contains information on the htlc that we are resolving 59 // on-chain. 60 htlc channeldb.HTLC 61 62 // currentReport stores the current state of the resolver for reporting 63 // over the rpc interface. This should only be reported in case we have 64 // a non-nil SignDetails on the htlcResolution, otherwise the nursery 65 // will produce reports. 66 currentReport ContractReport 67 68 // reportLock prevents concurrent access to the resolver report. 69 reportLock sync.Mutex 70 71 contractResolverKit 72 } 73 74 // newSuccessResolver instanties a new htlc success resolver. 75 func newSuccessResolver(res lnwallet.IncomingHtlcResolution, 76 broadcastHeight uint32, htlc channeldb.HTLC, 77 resCfg ResolverConfig) *htlcSuccessResolver { 78 79 h := &htlcSuccessResolver{ 80 contractResolverKit: *newContractResolverKit(resCfg), 81 htlcResolution: res, 82 broadcastHeight: broadcastHeight, 83 htlc: htlc, 84 } 85 86 h.initReport() 87 88 return h 89 } 90 91 // ResolverKey returns an identifier which should be globally unique for this 92 // particular resolver within the chain the original contract resides within. 93 // 94 // NOTE: Part of the ContractResolver interface. 95 func (h *htlcSuccessResolver) ResolverKey() []byte { 96 // The primary key for this resolver will be the outpoint of the HTLC 97 // on the commitment transaction itself. If this is our commitment, 98 // then the output can be found within the signed success tx, 99 // otherwise, it's just the ClaimOutpoint. 100 var op wire.OutPoint 101 if h.htlcResolution.SignedSuccessTx != nil { 102 op = h.htlcResolution.SignedSuccessTx.TxIn[0].PreviousOutPoint 103 } else { 104 op = h.htlcResolution.ClaimOutpoint 105 } 106 107 key := newResolverID(op) 108 return key[:] 109 } 110 111 // Resolve attempts to resolve an unresolved incoming HTLC that we know the 112 // preimage to. If the HTLC is on the commitment of the remote party, then we'll 113 // simply sweep it directly. Otherwise, we'll hand this off to the utxo nursery 114 // to do its duty. There is no need to make a call to the invoice registry 115 // anymore. Every HTLC has already passed through the incoming contest resolver 116 // and in there the invoice was already marked as settled. 117 // 118 // TODO(roasbeef): create multi to batch 119 // 120 // NOTE: Part of the ContractResolver interface. 121 func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { 122 // If we're already resolved, then we can exit early. 123 if h.resolved { 124 return nil, nil 125 } 126 127 // If we don't have a success transaction, then this means that this is 128 // an output on the remote party's commitment transaction. 129 if h.htlcResolution.SignedSuccessTx == nil { 130 return h.resolveRemoteCommitOutput() 131 } 132 133 // Otherwise this an output on our own commitment, and we must start by 134 // broadcasting the second-level success transaction. 135 secondLevelOutpoint, err := h.broadcastSuccessTx() 136 if err != nil { 137 return nil, err 138 } 139 140 // To wrap this up, we'll wait until the second-level transaction has 141 // been spent, then fully resolve the contract. 142 log.Infof("%T(%x): waiting for second-level HTLC output to be spent "+ 143 "after csv_delay=%v", h, h.htlc.RHash[:], h.htlcResolution.CsvDelay) 144 145 spend, err := waitForSpend( 146 secondLevelOutpoint, 147 h.htlcResolution.SweepSignDesc.Output.PkScript, 148 h.broadcastHeight, h.Notifier, h.quit, 149 ) 150 if err != nil { 151 return nil, err 152 } 153 154 h.reportLock.Lock() 155 h.currentReport.RecoveredBalance = h.currentReport.LimboBalance 156 h.currentReport.LimboBalance = 0 157 h.reportLock.Unlock() 158 159 h.resolved = true 160 return nil, h.checkpointClaim( 161 spend.SpenderTxHash, channeldb.ResolverOutcomeClaimed, 162 ) 163 } 164 165 // broadcastSuccessTx handles an HTLC output on our local commitment by 166 // broadcasting the second-level success transaction. It returns the ultimate 167 // outpoint of the second-level tx, that we must wait to be spent for the 168 // resolver to be fully resolved. 169 func (h *htlcSuccessResolver) broadcastSuccessTx() (*wire.OutPoint, error) { 170 // If we have non-nil SignDetails, this means that have a 2nd level 171 // HTLC transaction that is signed using sighash SINGLE|ANYONECANPAY 172 // (the case for anchor type channels). In this case we can re-sign it 173 // and attach fees at will. We let the sweeper handle this job. 174 // We use the checkpointed outputIncubating field to determine if we 175 // already swept the HTLC output into the second level transaction. 176 if h.htlcResolution.SignDetails != nil { 177 return h.broadcastReSignedSuccessTx() 178 } 179 180 // Otherwise we'll publish the second-level transaction directly and 181 // offer the resolution to the nursery to handle. 182 log.Infof("%T(%x): broadcasting second-layer transition tx: %v", 183 h, h.htlc.RHash[:], spew.Sdump(h.htlcResolution.SignedSuccessTx)) 184 185 // We'll now broadcast the second layer transaction so we can kick off 186 // the claiming process. 187 // 188 // TODO(roasbeef): after changing sighashes send to tx bundler 189 label := labels.MakeLabel( 190 labels.LabelTypeChannelClose, &h.ShortChanID, 191 ) 192 err := h.PublishTx(h.htlcResolution.SignedSuccessTx, label) 193 if err != nil { 194 return nil, err 195 } 196 197 // Otherwise, this is an output on our commitment transaction. In this 198 // case, we'll send it to the incubator, but only if we haven't already 199 // done so. 200 if !h.outputIncubating { 201 log.Infof("%T(%x): incubating incoming htlc output", 202 h, h.htlc.RHash[:]) 203 204 err := h.IncubateOutputs( 205 h.ChanPoint, nil, &h.htlcResolution, 206 h.broadcastHeight, 207 ) 208 if err != nil { 209 return nil, err 210 } 211 212 h.outputIncubating = true 213 214 if err := h.Checkpoint(h); err != nil { 215 log.Errorf("unable to Checkpoint: %v", err) 216 return nil, err 217 } 218 } 219 220 return &h.htlcResolution.ClaimOutpoint, nil 221 } 222 223 // broadcastReSignedSuccessTx handles the case where we have non-nil 224 // SignDetails, and offers the second level transaction to the Sweeper, that 225 // will re-sign it and attach fees at will. 226 func (h *htlcSuccessResolver) broadcastReSignedSuccessTx() ( 227 *wire.OutPoint, error) { 228 229 // Keep track of the tx spending the HTLC output on the commitment, as 230 // this will be the confirmed second-level tx we'll ultimately sweep. 231 var commitSpend *chainntnfs.SpendDetail 232 233 // We will have to let the sweeper re-sign the success tx and wait for 234 // it to confirm, if we haven't already. 235 if !h.outputIncubating { 236 log.Infof("%T(%x): offering second-layer transition tx to "+ 237 "sweeper: %v", h, h.htlc.RHash[:], 238 spew.Sdump(h.htlcResolution.SignedSuccessTx)) 239 240 secondLevelInput := input.MakeHtlcSecondLevelSuccessAnchorInput( 241 h.htlcResolution.SignedSuccessTx, 242 h.htlcResolution.SignDetails, h.htlcResolution.Preimage, 243 h.broadcastHeight, 244 ) 245 _, err := h.Sweeper.SweepInput( 246 &secondLevelInput, 247 sweep.Params{ 248 Fee: sweep.FeePreference{ 249 ConfTarget: secondLevelConfTarget, 250 }, 251 }, 252 ) 253 if err != nil { 254 return nil, err 255 } 256 257 log.Infof("%T(%x): waiting for second-level HTLC success "+ 258 "transaction to confirm", h, h.htlc.RHash[:]) 259 260 // Wait for the second level transaction to confirm. 261 commitSpend, err = waitForSpend( 262 &h.htlcResolution.SignedSuccessTx.TxIn[0].PreviousOutPoint, 263 h.htlcResolution.SignDetails.SignDesc.Output.PkScript, 264 h.broadcastHeight, h.Notifier, h.quit, 265 ) 266 if err != nil { 267 return nil, err 268 } 269 270 // Now that the second-level transaction has confirmed, we 271 // checkpoint the state so we'll go to the next stage in case 272 // of restarts. 273 h.outputIncubating = true 274 if err := h.Checkpoint(h); err != nil { 275 log.Errorf("unable to Checkpoint: %v", err) 276 return nil, err 277 } 278 279 log.Infof("%T(%x): second-level HTLC success transaction "+ 280 "confirmed!", h, h.htlc.RHash[:]) 281 } 282 283 // If we ended up here after a restart, we must again get the 284 // spend notification. 285 if commitSpend == nil { 286 var err error 287 commitSpend, err = waitForSpend( 288 &h.htlcResolution.SignedSuccessTx.TxIn[0].PreviousOutPoint, 289 h.htlcResolution.SignDetails.SignDesc.Output.PkScript, 290 h.broadcastHeight, h.Notifier, h.quit, 291 ) 292 if err != nil { 293 return nil, err 294 } 295 } 296 297 // The HTLC success tx has a CSV lock that we must wait for. 298 waitHeight := uint32(commitSpend.SpendingHeight) + 299 h.htlcResolution.CsvDelay - 1 300 301 // Now that the sweeper has broadcasted the second-level transaction, 302 // it has confirmed, and we have checkpointed our state, we'll sweep 303 // the second level output. We report the resolver has moved the next 304 // stage. 305 h.reportLock.Lock() 306 h.currentReport.Stage = 2 307 h.currentReport.MaturityHeight = waitHeight 308 h.reportLock.Unlock() 309 310 log.Infof("%T(%x): waiting for CSV lock to expire at height %v", 311 h, h.htlc.RHash[:], waitHeight) 312 313 err := waitForHeight(waitHeight, h.Notifier, h.quit) 314 if err != nil { 315 return nil, err 316 } 317 318 // We'll use this input index to determine the second-level output 319 // index on the transaction, as the signatures requires the indexes to 320 // be the same. We don't look for the second-level output script 321 // directly, as there might be more than one HTLC output to the same 322 // pkScript. 323 op := &wire.OutPoint{ 324 Hash: *commitSpend.SpenderTxHash, 325 Index: commitSpend.SpenderInputIndex, 326 } 327 328 // Finally, let the sweeper sweep the second-level output. 329 log.Infof("%T(%x): CSV lock expired, offering second-layer "+ 330 "output to sweeper: %v", h, h.htlc.RHash[:], op) 331 332 inp := input.NewCsvInput( 333 op, input.HtlcAcceptedSuccessSecondLevel, 334 &h.htlcResolution.SweepSignDesc, h.broadcastHeight, 335 h.htlcResolution.CsvDelay, 336 ) 337 _, err = h.Sweeper.SweepInput( 338 inp, 339 sweep.Params{ 340 Fee: sweep.FeePreference{ 341 ConfTarget: sweepConfTarget, 342 }, 343 }, 344 ) 345 if err != nil { 346 return nil, err 347 } 348 349 // Will return this outpoint, when this is spent the resolver is fully 350 // resolved. 351 return op, nil 352 } 353 354 // resolveRemoteCommitOutput handles sweeping an HTLC output on the remote 355 // commitment with the preimage. In this case we can sweep the output directly, 356 // and don't have to broadcast a second-level transaction. 357 func (h *htlcSuccessResolver) resolveRemoteCommitOutput() ( 358 ContractResolver, error) { 359 360 // If we don't already have the sweep transaction constructed, we'll do 361 // so and broadcast it. 362 if h.sweepTx == nil { 363 log.Infof("%T(%x): crafting sweep tx for incoming+remote "+ 364 "htlc confirmed", h, h.htlc.RHash[:]) 365 366 // Before we can craft out sweeping transaction, we need to 367 // create an input which contains all the items required to add 368 // this input to a sweeping transaction, and generate a 369 // witness. 370 inp := input.MakeHtlcSucceedInput( 371 &h.htlcResolution.ClaimOutpoint, 372 &h.htlcResolution.SweepSignDesc, 373 h.htlcResolution.Preimage[:], 374 h.broadcastHeight, 375 h.htlcResolution.CsvDelay, 376 ) 377 378 // With the input created, we can now generate the full sweep 379 // transaction, that we'll use to move these coins back into 380 // the backing wallet. 381 // 382 // TODO: Set tx lock time to current block height instead of 383 // zero. Will be taken care of once sweeper implementation is 384 // complete. 385 // 386 // TODO: Use time-based sweeper and result chan. 387 var err error 388 h.sweepTx, err = h.Sweeper.CreateSweepTx( 389 []input.Input{&inp}, 390 sweep.FeePreference{ 391 ConfTarget: sweepConfTarget, 392 }, 0, 393 ) 394 if err != nil { 395 return nil, err 396 } 397 398 log.Infof("%T(%x): crafted sweep tx=%v", h, 399 h.htlc.RHash[:], spew.Sdump(h.sweepTx)) 400 401 // TODO(halseth): should checkpoint sweep tx to DB? Since after 402 // a restart we might create a different tx, that will conflict 403 // with the published one. 404 } 405 406 // Regardless of whether an existing transaction was found or newly 407 // constructed, we'll broadcast the sweep transaction to the network. 408 label := labels.MakeLabel( 409 labels.LabelTypeChannelClose, &h.ShortChanID, 410 ) 411 err := h.PublishTx(h.sweepTx, label) 412 if err != nil { 413 log.Infof("%T(%x): unable to publish tx: %v", 414 h, h.htlc.RHash[:], err) 415 return nil, err 416 } 417 418 // With the sweep transaction broadcast, we'll wait for its 419 // confirmation. 420 sweepTXID := h.sweepTx.TxHash() 421 sweepScript := h.sweepTx.TxOut[0].PkScript 422 confNtfn, err := h.Notifier.RegisterConfirmationsNtfn( 423 &sweepTXID, sweepScript, 1, h.broadcastHeight, 424 ) 425 if err != nil { 426 return nil, err 427 } 428 429 log.Infof("%T(%x): waiting for sweep tx (txid=%v) to be "+ 430 "confirmed", h, h.htlc.RHash[:], sweepTXID) 431 432 select { 433 case _, ok := <-confNtfn.Confirmed: 434 if !ok { 435 return nil, errResolverShuttingDown 436 } 437 438 case <-h.quit: 439 return nil, errResolverShuttingDown 440 } 441 442 // Once the transaction has received a sufficient number of 443 // confirmations, we'll mark ourselves as fully resolved and exit. 444 h.resolved = true 445 446 // Checkpoint the resolver, and write the outcome to disk. 447 return nil, h.checkpointClaim( 448 &sweepTXID, 449 channeldb.ResolverOutcomeClaimed, 450 ) 451 } 452 453 // checkpointClaim checkpoints the success resolver with the reports it needs. 454 // If this htlc was claimed two stages, it will write reports for both stages, 455 // otherwise it will just write for the single htlc claim. 456 func (h *htlcSuccessResolver) checkpointClaim(spendTx *chainhash.Hash, 457 outcome channeldb.ResolverOutcome) error { 458 459 // Create a resolver report for claiming of the htlc itself. 460 amt := dcrutil.Amount(h.htlcResolution.SweepSignDesc.Output.Value) 461 reports := []*channeldb.ResolverReport{ 462 { 463 OutPoint: h.htlcResolution.ClaimOutpoint, 464 Amount: amt, 465 ResolverType: channeldb.ResolverTypeIncomingHtlc, 466 ResolverOutcome: outcome, 467 SpendTxID: spendTx, 468 }, 469 } 470 471 // If we have a success tx, we append a report to represent our first 472 // stage claim. 473 if h.htlcResolution.SignedSuccessTx != nil { 474 // If the SignedSuccessTx is not nil, we are claiming the htlc 475 // in two stages, so we need to create a report for the first 476 // stage transaction as well. 477 spendTx := h.htlcResolution.SignedSuccessTx 478 spendTxID := spendTx.TxHash() 479 480 report := &channeldb.ResolverReport{ 481 OutPoint: spendTx.TxIn[0].PreviousOutPoint, 482 Amount: h.htlc.Amt.ToAtoms(), 483 ResolverType: channeldb.ResolverTypeIncomingHtlc, 484 ResolverOutcome: channeldb.ResolverOutcomeFirstStage, 485 SpendTxID: &spendTxID, 486 } 487 reports = append(reports, report) 488 } 489 490 // Finally, we checkpoint the resolver with our report(s). 491 return h.Checkpoint(h, reports...) 492 } 493 494 // Stop signals the resolver to cancel any current resolution processes, and 495 // suspend. 496 // 497 // NOTE: Part of the ContractResolver interface. 498 func (h *htlcSuccessResolver) Stop() { 499 close(h.quit) 500 } 501 502 // IsResolved returns true if the stored state in the resolve is fully 503 // resolved. In this case the target output can be forgotten. 504 // 505 // NOTE: Part of the ContractResolver interface. 506 func (h *htlcSuccessResolver) IsResolved() bool { 507 return h.resolved 508 } 509 510 // report returns a report on the resolution state of the contract. 511 func (h *htlcSuccessResolver) report() *ContractReport { 512 // If the sign details are nil, the report will be created by handled 513 // by the nursery. 514 if h.htlcResolution.SignDetails == nil { 515 return nil 516 } 517 518 h.reportLock.Lock() 519 defer h.reportLock.Unlock() 520 copy := h.currentReport 521 return © 522 } 523 524 func (h *htlcSuccessResolver) initReport() { 525 // We create the initial report. This will only be reported for 526 // resolvers not handled by the nursery. 527 finalAmt := h.htlc.Amt.ToAtoms() 528 if h.htlcResolution.SignedSuccessTx != nil { 529 finalAmt = dcrutil.Amount( 530 h.htlcResolution.SignedSuccessTx.TxOut[0].Value, 531 ) 532 } 533 534 h.currentReport = ContractReport{ 535 Outpoint: h.htlcResolution.ClaimOutpoint, 536 Type: ReportOutputIncomingHtlc, 537 Amount: finalAmt, 538 MaturityHeight: h.htlcResolution.CsvDelay, 539 LimboBalance: finalAmt, 540 Stage: 1, 541 } 542 } 543 544 // Encode writes an encoded version of the ContractResolver into the passed 545 // Writer. 546 // 547 // NOTE: Part of the ContractResolver interface. 548 func (h *htlcSuccessResolver) Encode(w io.Writer) error { 549 // First we'll encode our inner HTLC resolution. 550 if err := encodeIncomingResolution(w, &h.htlcResolution); err != nil { 551 return err 552 } 553 554 // Next, we'll write out the fields that are specified to the contract 555 // resolver. 556 if err := binary.Write(w, endian, h.outputIncubating); err != nil { 557 return err 558 } 559 if err := binary.Write(w, endian, h.resolved); err != nil { 560 return err 561 } 562 if err := binary.Write(w, endian, h.broadcastHeight); err != nil { 563 return err 564 } 565 if _, err := w.Write(h.htlc.RHash[:]); err != nil { 566 return err 567 } 568 569 // We encode the sign details last for backwards compatibility. 570 err := encodeSignDetails(w, h.htlcResolution.SignDetails) 571 if err != nil { 572 return err 573 } 574 575 return nil 576 } 577 578 // newSuccessResolverFromReader attempts to decode an encoded ContractResolver 579 // from the passed Reader instance, returning an active ContractResolver 580 // instance. 581 func newSuccessResolverFromReader(r io.Reader, resCfg ResolverConfig) ( 582 *htlcSuccessResolver, error) { 583 584 h := &htlcSuccessResolver{ 585 contractResolverKit: *newContractResolverKit(resCfg), 586 } 587 588 // First we'll decode our inner HTLC resolution. 589 if err := decodeIncomingResolution(r, &h.htlcResolution); err != nil { 590 return nil, err 591 } 592 593 // Next, we'll read all the fields that are specified to the contract 594 // resolver. 595 if err := binary.Read(r, endian, &h.outputIncubating); err != nil { 596 return nil, err 597 } 598 if err := binary.Read(r, endian, &h.resolved); err != nil { 599 return nil, err 600 } 601 if err := binary.Read(r, endian, &h.broadcastHeight); err != nil { 602 return nil, err 603 } 604 if _, err := io.ReadFull(r, h.htlc.RHash[:]); err != nil { 605 return nil, err 606 } 607 608 // Sign details is a new field that was added to the htlc resolution, 609 // so it is serialized last for backwards compatibility. We try to read 610 // it, but don't error out if there are not bytes left. 611 signDetails, err := decodeSignDetails(r) 612 if err == nil { 613 h.htlcResolution.SignDetails = signDetails 614 } else if err != io.EOF && err != io.ErrUnexpectedEOF { 615 return nil, err 616 } 617 618 h.initReport() 619 620 return h, nil 621 } 622 623 // Supplement adds additional information to the resolver that is required 624 // before Resolve() is called. 625 // 626 // NOTE: Part of the htlcContractResolver interface. 627 func (h *htlcSuccessResolver) Supplement(htlc channeldb.HTLC) { 628 h.htlc = htlc 629 } 630 631 // SupplementState allows the user of a ContractResolver to supplement it with 632 // state required for the proper resolution of a contract. 633 // 634 // NOTE: Part of the ContractResolver interface. 635 func (h *htlcSuccessResolver) SupplementState(_ *channeldb.OpenChannel) { 636 } 637 638 // HtlcPoint returns the htlc's outpoint on the commitment tx. 639 // 640 // NOTE: Part of the htlcContractResolver interface. 641 func (h *htlcSuccessResolver) HtlcPoint() wire.OutPoint { 642 return h.htlcResolution.HtlcPoint() 643 } 644 645 // A compile time assertion to ensure htlcSuccessResolver meets the 646 // ContractResolver interface. 647 var _ htlcContractResolver = (*htlcSuccessResolver)(nil)