github.com/decred/dcrlnd@v0.7.6/contractcourt/utxonursery.go (about) 1 package contractcourt 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 "io" 8 "sync" 9 "sync/atomic" 10 11 "github.com/davecgh/go-spew/spew" 12 "github.com/decred/dcrd/dcrutil/v4" 13 "github.com/decred/dcrd/wire" 14 "github.com/decred/dcrlnd/chainntnfs" 15 "github.com/decred/dcrlnd/channeldb" 16 "github.com/decred/dcrlnd/input" 17 "github.com/decred/dcrlnd/labels" 18 "github.com/decred/dcrlnd/lnwallet" 19 "github.com/decred/dcrlnd/sweep" 20 ) 21 22 // SUMMARY OF OUTPUT STATES 23 // 24 // - CRIB 25 // - SerializedType: babyOutput 26 // - OriginalOutputType: HTLC 27 // - Awaiting: First-stage HTLC CLTV expiry 28 // - HeightIndexEntry: Absolute block height of CLTV expiry. 29 // - NextState: KNDR 30 // - PSCL 31 // - SerializedType: kidOutput 32 // - OriginalOutputType: Commitment 33 // - Awaiting: Confirmation of commitment txn 34 // - HeightIndexEntry: None. 35 // - NextState: KNDR 36 // - KNDR 37 // - SerializedType: kidOutput 38 // - OriginalOutputType: Commitment or HTLC 39 // - Awaiting: Commitment CSV expiry or second-stage HTLC CSV expiry. 40 // - HeightIndexEntry: Input confirmation height + relative CSV delay 41 // - NextState: GRAD 42 // - GRAD: 43 // - SerializedType: kidOutput 44 // - OriginalOutputType: Commitment or HTLC 45 // - Awaiting: All other outputs in channel to become GRAD. 46 // - NextState: Mark channel fully closed in channeldb and remove. 47 // 48 // DESCRIPTION OF OUTPUT STATES 49 // 50 // TODO(roasbeef): update comment with both new output types 51 // 52 // - CRIB (babyOutput) outputs are two-stage htlc outputs that are initially 53 // locked using a CLTV delay, followed by a CSV delay. The first stage of a 54 // crib output requires broadcasting a presigned htlc timeout txn generated 55 // by the wallet after an absolute expiry height. Since the timeout txns are 56 // predetermined, they cannot be batched after-the-fact, meaning that all 57 // CRIB outputs are broadcast and confirmed independently. After the first 58 // stage is complete, a CRIB output is moved to the KNDR state, which will 59 // finishing sweeping the second-layer CSV delay. 60 // 61 // - PSCL (kidOutput) outputs are commitment outputs locked under a CSV delay. 62 // These outputs are stored temporarily in this state until the commitment 63 // transaction confirms, as this solidifies an absolute height that the 64 // relative time lock will expire. Once this maturity height is determined, 65 // the PSCL output is moved into KNDR. 66 // 67 // - KNDR (kidOutput) outputs are CSV delayed outputs for which the maturity 68 // height has been fully determined. This results from having received 69 // confirmation of the UTXO we are trying to spend, contained in either the 70 // commitment txn or htlc timeout txn. Once the maturity height is reached, 71 // the utxo nursery will sweep all KNDR outputs scheduled for that height 72 // using a single txn. 73 // 74 // - GRAD (kidOutput) outputs are KNDR outputs that have successfully been 75 // swept into the user's wallet. A channel is considered mature once all of 76 // its outputs, including two-stage htlcs, have entered the GRAD state, 77 // indicating that it safe to mark the channel as fully closed. 78 // 79 // 80 // OUTPUT STATE TRANSITIONS IN UTXO NURSERY 81 // 82 // ┌────────────────┐ ┌──────────────┐ 83 // │ Commit Outputs │ │ HTLC Outputs │ 84 // └────────────────┘ └──────────────┘ 85 // │ │ 86 // │ │ 87 // │ │ UTXO NURSERY 88 // ┌───────────┼────────────────┬───────────┼───────────────────────────────┐ 89 // │ │ │ │ 90 // │ │ │ │ │ 91 // │ │ │ CLTV-Delayed │ 92 // │ │ │ V babyOutputs │ 93 // │ │ ┌──────┐ │ 94 // │ │ │ │ CRIB │ │ 95 // │ │ └──────┘ │ 96 // │ │ │ │ │ 97 // │ │ │ │ 98 // │ │ │ | │ 99 // │ │ V Wait CLTV │ 100 // │ │ │ [ ] + │ 101 // │ │ | Publish Txn │ 102 // │ │ │ │ │ 103 // │ │ │ │ 104 // │ │ │ V ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┐ │ 105 // │ │ ( ) waitForTimeoutConf │ 106 // │ │ │ | └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘ │ 107 // │ │ │ │ 108 // │ │ │ │ │ 109 // │ │ │ │ 110 // │ V │ │ │ 111 // │ ┌──────┐ │ │ 112 // │ │ PSCL │ └ ── ── ─┼ ── ── ── ── ── ── ── ─┤ 113 // │ └──────┘ │ │ 114 // │ │ │ │ 115 // │ │ │ │ 116 // │ V ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┐ │ CSV-Delayed │ 117 // │ ( ) waitForCommitConf │ kidOutputs │ 118 // │ | └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─┘ │ │ 119 // │ │ │ │ 120 // │ │ │ │ 121 // │ │ V │ 122 // │ │ ┌──────┐ │ 123 // │ └─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─▶│ KNDR │ │ 124 // │ └──────┘ │ 125 // │ │ │ 126 // │ │ │ 127 // │ | │ 128 // │ V Wait CSV │ 129 // │ [ ] + │ 130 // │ | Publish Txn │ 131 // │ │ │ 132 // │ │ │ 133 // │ V ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ 134 // │ ( ) waitForSweepConf │ 135 // │ | └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ 136 // │ │ │ 137 // │ │ │ 138 // │ V │ 139 // │ ┌──────┐ │ 140 // │ │ GRAD │ │ 141 // │ └──────┘ │ 142 // │ │ │ 143 // │ │ │ 144 // │ │ │ 145 // └────────────────────────────────────────┼───────────────────────────────┘ 146 // │ 147 // │ 148 // │ 149 // │ 150 // V 151 // ┌────────────────┐ 152 // │ Wallet Outputs │ 153 // └────────────────┘ 154 155 var byteOrder = binary.BigEndian 156 157 const ( 158 // kgtnOutputConfTarget is the default confirmation target we'll use for 159 // sweeps of CSV delayed outputs. 160 kgtnOutputConfTarget = 6 161 ) 162 163 var ( 164 // ErrContractNotFound is returned when the nursery is unable to 165 // retrieve information about a queried contract. 166 ErrContractNotFound = fmt.Errorf("unable to locate contract") 167 ) 168 169 // NurseryConfig abstracts the required subsystems used by the utxo nursery. An 170 // instance of NurseryConfig is passed to newUtxoNursery during instantiation. 171 type NurseryConfig struct { 172 // ChainIO is used by the utxo nursery to determine the current block 173 // height, which drives the incubation of the nursery's outputs. 174 ChainIO lnwallet.BlockChainIO 175 176 // ConfDepth is the number of blocks the nursery store waits before 177 // determining outputs in the chain as confirmed. 178 ConfDepth uint32 179 180 // FetchClosedChannels provides access to a user's channels, such that 181 // they can be marked fully closed after incubation has concluded. 182 FetchClosedChannels func(pendingOnly bool) ( 183 []*channeldb.ChannelCloseSummary, error) 184 185 // FetchClosedChannel provides access to the close summary to extract a 186 // height hint from. 187 FetchClosedChannel func(chanID *wire.OutPoint) ( 188 *channeldb.ChannelCloseSummary, error) 189 190 // Notifier provides the utxo nursery the ability to subscribe to 191 // transaction confirmation events, which advance outputs through their 192 // persistence state transitions. 193 Notifier chainntnfs.ChainNotifier 194 195 // PublishTransaction facilitates the process of broadcasting a signed 196 // transaction to the appropriate network. 197 PublishTransaction func(*wire.MsgTx, string) error 198 199 // Store provides access to and modification of the persistent state 200 // maintained about the utxo nursery's incubating outputs. 201 Store NurseryStorer 202 203 // Sweep sweeps an input back to the wallet. 204 SweepInput func(input.Input, sweep.Params) (chan sweep.Result, error) 205 } 206 207 // UtxoNursery is a system dedicated to incubating time-locked outputs created 208 // by the broadcast of a commitment transaction either by us, or the remote 209 // peer. The nursery accepts outputs and "incubates" them until they've reached 210 // maturity, then sweep the outputs into the source wallet. An output is 211 // considered mature after the relative time-lock within the pkScript has 212 // passed. As outputs reach their maturity age, they're swept in batches into 213 // the source wallet, returning the outputs so they can be used within future 214 // channels, or regular Decred transactions. 215 type UtxoNursery struct { 216 started uint32 // To be used atomically. 217 stopped uint32 // To be used atomically. 218 219 cfg *NurseryConfig 220 221 mu sync.Mutex 222 bestHeight uint32 223 224 quit chan struct{} 225 wg sync.WaitGroup 226 } 227 228 // NewUtxoNursery creates a new instance of the UtxoNursery from a 229 // ChainNotifier and LightningWallet instance. 230 func NewUtxoNursery(cfg *NurseryConfig) *UtxoNursery { 231 return &UtxoNursery{ 232 cfg: cfg, 233 quit: make(chan struct{}), 234 } 235 } 236 237 // Start launches all goroutines the UtxoNursery needs to properly carry out 238 // its duties. 239 func (u *UtxoNursery) Start() error { 240 if !atomic.CompareAndSwapUint32(&u.started, 0, 1) { 241 return nil 242 } 243 244 utxnLog.Tracef("Starting UTXO nursery") 245 246 // Retrieve the currently best known block. This is needed to have the 247 // state machine catch up with the blocks we missed when we were down. 248 bestHash, bestHeight, err := u.cfg.ChainIO.GetBestBlock() 249 if err != nil { 250 return err 251 } 252 253 // Set best known height to schedule late registrations properly. 254 atomic.StoreUint32(&u.bestHeight, uint32(bestHeight)) 255 256 // 2. Flush all fully-graduated channels from the pipeline. 257 258 // Load any pending close channels, which represents the super set of 259 // all channels that may still be incubating. 260 pendingCloseChans, err := u.cfg.FetchClosedChannels(true) 261 if err != nil { 262 return err 263 } 264 265 // Ensure that all mature channels have been marked as fully closed in 266 // the channeldb. 267 for _, pendingClose := range pendingCloseChans { 268 err := u.closeAndRemoveIfMature(&pendingClose.ChanPoint) 269 if err != nil { 270 return err 271 } 272 } 273 274 // TODO(conner): check if any fully closed channels can be removed from 275 // utxn. 276 277 // 2. Restart spend ntfns for any preschool outputs, which are waiting 278 // for the force closed commitment txn to confirm, or any second-layer 279 // HTLC success transactions. 280 // 281 // NOTE: The next two steps *may* spawn go routines, thus from this 282 // point forward, we must close the nursery's quit channel if we detect 283 // any failures during startup to ensure they terminate. 284 if err := u.reloadPreschool(); err != nil { 285 close(u.quit) 286 return err 287 } 288 289 // 3. Replay all crib and kindergarten outputs up to the current best 290 // height. 291 if err := u.reloadClasses(uint32(bestHeight)); err != nil { 292 close(u.quit) 293 return err 294 } 295 296 // Start watching for new blocks, as this will drive the nursery store's 297 // state machine. 298 newBlockChan, err := u.cfg.Notifier.RegisterBlockEpochNtfn(&chainntnfs.BlockEpoch{ 299 Height: bestHeight, 300 Hash: bestHash, 301 }) 302 if err != nil { 303 close(u.quit) 304 return err 305 } 306 307 u.wg.Add(1) 308 go u.incubator(newBlockChan) 309 310 return nil 311 } 312 313 // Stop gracefully shuts down any lingering goroutines launched during normal 314 // operation of the UtxoNursery. 315 func (u *UtxoNursery) Stop() error { 316 if !atomic.CompareAndSwapUint32(&u.stopped, 0, 1) { 317 return nil 318 } 319 320 utxnLog.Infof("UTXO nursery shutting down") 321 322 close(u.quit) 323 u.wg.Wait() 324 325 return nil 326 } 327 328 // IncubateOutputs sends a request to the UtxoNursery to incubate a set of 329 // outputs from an existing commitment transaction. Outputs need to incubate if 330 // they're CLTV absolute time locked, or if they're CSV relative time locked. 331 // Once all outputs reach maturity, they'll be swept back into the wallet. 332 func (u *UtxoNursery) IncubateOutputs(chanPoint wire.OutPoint, 333 outgoingHtlcs []lnwallet.OutgoingHtlcResolution, 334 incomingHtlcs []lnwallet.IncomingHtlcResolution, 335 broadcastHeight uint32) error { 336 337 // Add to wait group because nursery might shut down during execution of 338 // this function. Otherwise it could happen that nursery thinks it is 339 // shut down, but in this function new goroutines were started and stay 340 // around. 341 u.wg.Add(1) 342 defer u.wg.Done() 343 344 // Check quit channel for the case where the waitgroup wait was finished 345 // right before this function's add call was made. 346 select { 347 case <-u.quit: 348 return fmt.Errorf("nursery shutting down") 349 default: 350 } 351 352 numHtlcs := len(incomingHtlcs) + len(outgoingHtlcs) 353 var ( 354 // Kid outputs can be swept after an initial confirmation 355 // followed by a maturity period.Baby outputs are two stage and 356 // will need to wait for an absolute time out to reach a 357 // confirmation, then require a relative confirmation delay. 358 kidOutputs = make([]kidOutput, 0, 1+len(incomingHtlcs)) 359 babyOutputs = make([]babyOutput, 0, len(outgoingHtlcs)) 360 ) 361 362 // 1. Build all the spendable outputs that we will try to incubate. 363 364 // TODO(roasbeef): query and see if we already have, if so don't add? 365 366 // For each incoming HTLC, we'll register a kid output marked as a 367 // second-layer HTLC output. We effectively skip the baby stage (as the 368 // timelock is zero), and enter the kid stage. 369 for _, htlcRes := range incomingHtlcs { 370 htlcOutput := makeKidOutput( 371 &htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay, 372 input.HtlcAcceptedSuccessSecondLevel, 373 &htlcRes.SweepSignDesc, 0, 374 ) 375 376 if htlcOutput.Amount() > 0 { 377 kidOutputs = append(kidOutputs, htlcOutput) 378 } 379 } 380 381 // For each outgoing HTLC, we'll create a baby output. If this is our 382 // commitment transaction, then we'll broadcast a second-layer 383 // transaction to transition to a kid output. Otherwise, we'll directly 384 // spend once the CLTV delay us up. 385 for _, htlcRes := range outgoingHtlcs { 386 // If this HTLC is on our commitment transaction, then it'll be 387 // a baby output as we need to go to the second level to sweep 388 // it. 389 if htlcRes.SignedTimeoutTx != nil { 390 htlcOutput := makeBabyOutput(&chanPoint, &htlcRes) 391 392 if htlcOutput.Amount() > 0 { 393 babyOutputs = append(babyOutputs, htlcOutput) 394 } 395 continue 396 } 397 398 // Otherwise, this is actually a kid output as we can sweep it 399 // once the commitment transaction confirms, and the absolute 400 // CLTV lock has expired. We set the CSV delay what the 401 // resolution encodes, since the sequence number must be set 402 // accordingly. 403 htlcOutput := makeKidOutput( 404 &htlcRes.ClaimOutpoint, &chanPoint, htlcRes.CsvDelay, 405 input.HtlcOfferedRemoteTimeout, 406 &htlcRes.SweepSignDesc, htlcRes.Expiry, 407 ) 408 kidOutputs = append(kidOutputs, htlcOutput) 409 } 410 411 // TODO(roasbeef): if want to handle outgoing on remote commit 412 // * need ability to cancel in the case that we learn of pre-image or 413 // remote party pulls 414 415 utxnLog.Infof("Incubating Channel(%s) num-htlcs=%d", 416 chanPoint, numHtlcs) 417 418 u.mu.Lock() 419 defer u.mu.Unlock() 420 421 // 2. Persist the outputs we intended to sweep in the nursery store 422 if err := u.cfg.Store.Incubate(kidOutputs, babyOutputs); err != nil { 423 utxnLog.Errorf("unable to begin incubation of Channel(%s): %v", 424 chanPoint, err) 425 return err 426 } 427 428 // As an intermediate step, we'll now check to see if any of the baby 429 // outputs has actually _already_ expired. This may be the case if 430 // blocks were mined while we processed this message. 431 _, bestHeight, err := u.cfg.ChainIO.GetBestBlock() 432 if err != nil { 433 return err 434 } 435 436 // We'll examine all the baby outputs just inserted into the database, 437 // if the output has already expired, then we'll *immediately* sweep 438 // it. This may happen if the caller raced a block to call this method. 439 for i, babyOutput := range babyOutputs { 440 if uint32(bestHeight) >= babyOutput.expiry { 441 err = u.sweepCribOutput( 442 babyOutput.expiry, &babyOutputs[i], 443 ) 444 if err != nil { 445 return err 446 } 447 } 448 } 449 450 // 3. If we are incubating any preschool outputs, register for a 451 // confirmation notification that will transition it to the 452 // kindergarten bucket. 453 if len(kidOutputs) != 0 { 454 for i := range kidOutputs { 455 err := u.registerPreschoolConf( 456 &kidOutputs[i], broadcastHeight, 457 ) 458 if err != nil { 459 return err 460 } 461 } 462 } 463 464 return nil 465 } 466 467 // NurseryReport attempts to return a nursery report stored for the target 468 // outpoint. A nursery report details the maturity/sweeping progress for a 469 // contract that was previously force closed. If a report entry for the target 470 // chanPoint is unable to be constructed, then an error will be returned. 471 func (u *UtxoNursery) NurseryReport( 472 chanPoint *wire.OutPoint) (*ContractMaturityReport, error) { 473 474 u.mu.Lock() 475 defer u.mu.Unlock() 476 477 utxnLog.Debugf("NurseryReport: building nursery report for channel %v", 478 chanPoint) 479 480 var report *ContractMaturityReport 481 482 if err := u.cfg.Store.ForChanOutputs(chanPoint, func(k, v []byte) error { 483 switch { 484 case bytes.HasPrefix(k, cribPrefix): 485 // Cribs outputs are the only kind currently stored as 486 // baby outputs. 487 var baby babyOutput 488 err := baby.Decode(bytes.NewReader(v)) 489 if err != nil { 490 return err 491 } 492 493 // Each crib output represents a stage one htlc, and 494 // will contribute towards the limbo balance. 495 report.AddLimboStage1TimeoutHtlc(&baby) 496 497 case bytes.HasPrefix(k, psclPrefix), 498 bytes.HasPrefix(k, kndrPrefix), 499 bytes.HasPrefix(k, gradPrefix): 500 501 // All others states can be deserialized as kid outputs. 502 var kid kidOutput 503 err := kid.Decode(bytes.NewReader(v)) 504 if err != nil { 505 return err 506 } 507 508 // Now, use the state prefixes to determine how the 509 // this output should be represented in the nursery 510 // report. An output's funds are always in limbo until 511 // reaching the graduate state. 512 switch { 513 case bytes.HasPrefix(k, psclPrefix): 514 // Preschool outputs are awaiting the 515 // confirmation of the commitment transaction. 516 switch kid.WitnessType() { 517 518 case input.HtlcAcceptedSuccessSecondLevel: 519 // An HTLC output on our commitment transaction 520 // where the second-layer transaction hasn't 521 // yet confirmed. 522 report.AddLimboStage1SuccessHtlc(&kid) 523 524 case input.HtlcOfferedRemoteTimeout: 525 // This is an HTLC output on the 526 // commitment transaction of the remote 527 // party. We are waiting for the CLTV 528 // timelock expire. 529 report.AddLimboDirectHtlc(&kid) 530 } 531 532 case bytes.HasPrefix(k, kndrPrefix): 533 // Kindergarten outputs may originate from 534 // either the commitment transaction or an htlc. 535 // We can distinguish them via their witness 536 // types. 537 switch kid.WitnessType() { 538 539 case input.HtlcOfferedRemoteTimeout: 540 // This is an HTLC output on the 541 // commitment transaction of the remote 542 // party. The CLTV timelock has 543 // expired, and we only need to sweep 544 // it. 545 report.AddLimboDirectHtlc(&kid) 546 547 case input.HtlcAcceptedSuccessSecondLevel: 548 fallthrough 549 case input.HtlcOfferedTimeoutSecondLevel: 550 // The htlc timeout or success 551 // transaction has confirmed, and the 552 // CSV delay has begun ticking. 553 report.AddLimboStage2Htlc(&kid) 554 } 555 556 case bytes.HasPrefix(k, gradPrefix): 557 // Graduate outputs are those whose funds have 558 // been swept back into the wallet. Each output 559 // will contribute towards the recovered 560 // balance. 561 switch kid.WitnessType() { 562 563 case input.HtlcAcceptedSuccessSecondLevel: 564 fallthrough 565 case input.HtlcOfferedTimeoutSecondLevel: 566 fallthrough 567 case input.HtlcOfferedRemoteTimeout: 568 // This htlc output successfully 569 // resides in a p2wkh output belonging 570 // to the user. 571 report.AddRecoveredHtlc(&kid) 572 } 573 } 574 575 default: 576 } 577 578 return nil 579 }, func() { 580 report = &ContractMaturityReport{} 581 }); err != nil { 582 return nil, err 583 } 584 585 return report, nil 586 } 587 588 // reloadPreschool re-initializes the chain notifier with all of the outputs 589 // that had been saved to the "preschool" database bucket prior to shutdown. 590 func (u *UtxoNursery) reloadPreschool() error { 591 psclOutputs, err := u.cfg.Store.FetchPreschools() 592 if err != nil { 593 return err 594 } 595 596 // For each of the preschool outputs stored in the nursery store, load 597 // its close summary from disk so that we can get an accurate height 598 // hint from which to start our range for spend notifications. 599 for i := range psclOutputs { 600 kid := &psclOutputs[i] 601 chanPoint := kid.OriginChanPoint() 602 603 // Load the close summary for this output's channel point. 604 closeSummary, err := u.cfg.FetchClosedChannel(chanPoint) 605 if err == channeldb.ErrClosedChannelNotFound { 606 // This should never happen since the close summary 607 // should only be removed after the channel has been 608 // swept completely. 609 utxnLog.Warnf("Close summary not found for "+ 610 "chan_point=%v, can't determine height hint"+ 611 "to sweep commit txn", chanPoint) 612 continue 613 614 } else if err != nil { 615 return err 616 } 617 618 // Use the close height from the channel summary as our height 619 // hint to drive our spend notifications, with our confirmation 620 // depth as a buffer for reorgs. 621 heightHint := closeSummary.CloseHeight - u.cfg.ConfDepth 622 err = u.registerPreschoolConf(kid, heightHint) 623 if err != nil { 624 return err 625 } 626 } 627 628 return nil 629 } 630 631 // reloadClasses reinitializes any height-dependent state transitions for which 632 // the utxonursery has not received confirmation, and replays the graduation of 633 // all kindergarten and crib outputs for all heights up to the current block. 634 // This allows the nursery to reinitialize all state to continue sweeping 635 // outputs, even in the event that we missed blocks while offline. reloadClasses 636 // is called during the startup of the UTXO Nursery. 637 func (u *UtxoNursery) reloadClasses(bestHeight uint32) error { 638 // Loading all active heights up to and including the current block. 639 activeHeights, err := u.cfg.Store.HeightsBelowOrEqual(bestHeight) 640 if err != nil { 641 return err 642 } 643 644 // Return early if nothing to sweep. 645 if len(activeHeights) == 0 { 646 return nil 647 } 648 649 utxnLog.Infof("(Re)-sweeping %d heights below height=%d", 650 len(activeHeights), bestHeight) 651 652 // Attempt to re-register notifications for any outputs still at these 653 // heights. 654 for _, classHeight := range activeHeights { 655 utxnLog.Debugf("Attempting to sweep outputs at height=%v", 656 classHeight) 657 658 if err = u.graduateClass(classHeight); err != nil { 659 utxnLog.Errorf("Failed to sweep outputs at "+ 660 "height=%v: %v", classHeight, err) 661 return err 662 } 663 } 664 665 utxnLog.Infof("UTXO Nursery is now fully synced") 666 667 return nil 668 } 669 670 // incubator is tasked with driving all state transitions that are dependent on 671 // the current height of the blockchain. As new blocks arrive, the incubator 672 // will attempt spend outputs at the latest height. The asynchronous 673 // confirmation of these spends will either 1) move a crib output into the 674 // kindergarten bucket or 2) move a kindergarten output into the graduated 675 // bucket. 676 func (u *UtxoNursery) incubator(newBlockChan *chainntnfs.BlockEpochEvent) { 677 defer u.wg.Done() 678 defer newBlockChan.Cancel() 679 680 for { 681 select { 682 case epoch, ok := <-newBlockChan.Epochs: 683 // If the epoch channel has been closed, then the 684 // ChainNotifier is exiting which means the daemon is 685 // as well. Therefore, we exit early also in order to 686 // ensure the daemon shuts down gracefully, yet 687 // swiftly. 688 if !ok { 689 return 690 } 691 692 // TODO(roasbeef): if the BlockChainIO is rescanning 693 // will give stale data 694 695 // A new block has just been connected to the main 696 // chain, which means we might be able to graduate crib 697 // or kindergarten outputs at this height. This involves 698 // broadcasting any presigned htlc timeout txns, as well 699 // as signing and broadcasting a sweep txn that spends 700 // from all kindergarten outputs at this height. 701 height := uint32(epoch.Height) 702 703 // Update best known block height for late registrations 704 // to be scheduled properly. 705 atomic.StoreUint32(&u.bestHeight, height) 706 707 if err := u.graduateClass(height); err != nil { 708 utxnLog.Errorf("error while graduating "+ 709 "class at height=%d: %v", height, err) 710 711 // TODO(conner): signal fatal error to daemon 712 } 713 714 case <-u.quit: 715 return 716 } 717 } 718 } 719 720 // graduateClass handles the steps involved in spending outputs whose CSV or 721 // CLTV delay expires at the nursery's current height. This method is called 722 // each time a new block arrives, or during startup to catch up on heights we 723 // may have missed while the nursery was offline. 724 func (u *UtxoNursery) graduateClass(classHeight uint32) error { 725 // Record this height as the nursery's current best height. 726 u.mu.Lock() 727 defer u.mu.Unlock() 728 729 // Fetch all information about the crib and kindergarten outputs at 730 // this height. 731 kgtnOutputs, cribOutputs, err := u.cfg.Store.FetchClass( 732 classHeight) 733 if err != nil { 734 return err 735 } 736 737 utxnLog.Infof("Attempting to graduate height=%v: num_kids=%v, "+ 738 "num_babies=%v", classHeight, len(kgtnOutputs), len(cribOutputs)) 739 740 // Offer the outputs to the sweeper and set up notifications that will 741 // transition the swept kindergarten outputs and cltvCrib into graduated 742 // outputs. 743 if len(kgtnOutputs) > 0 { 744 if err := u.sweepMatureOutputs(classHeight, kgtnOutputs); err != nil { 745 utxnLog.Errorf("Failed to sweep %d kindergarten "+ 746 "outputs at height=%d: %v", 747 len(kgtnOutputs), classHeight, err) 748 return err 749 } 750 } 751 752 // Now, we broadcast all pre-signed htlc txns from the csv crib outputs 753 // at this height. 754 for i := range cribOutputs { 755 err := u.sweepCribOutput(classHeight, &cribOutputs[i]) 756 if err != nil { 757 utxnLog.Errorf("Failed to sweep first-stage HTLC "+ 758 "(CLTV-delayed) output %v", 759 cribOutputs[i].OutPoint()) 760 return err 761 } 762 } 763 764 return nil 765 } 766 767 // sweepMatureOutputs generates and broadcasts the transaction that transfers 768 // control of funds from a prior channel commitment transaction to the user's 769 // wallet. The outputs swept were previously time locked (either absolute or 770 // relative), but are not mature enough to sweep into the wallet. 771 func (u *UtxoNursery) sweepMatureOutputs(classHeight uint32, 772 kgtnOutputs []kidOutput) error { 773 774 utxnLog.Infof("Sweeping %v CSV-delayed outputs with sweep tx for "+ 775 "height %v", len(kgtnOutputs), classHeight) 776 777 feePref := sweep.FeePreference{ConfTarget: kgtnOutputConfTarget} 778 for _, output := range kgtnOutputs { 779 // Create local copy to prevent pointer to loop variable to be 780 // passed in with disastrous consequences. 781 local := output 782 783 resultChan, err := u.cfg.SweepInput( 784 &local, sweep.Params{Fee: feePref}, 785 ) 786 if err != nil { 787 return err 788 } 789 u.wg.Add(1) 790 go u.waitForSweepConf(classHeight, &local, resultChan) 791 } 792 793 return nil 794 } 795 796 // waitForSweepConf watches for the confirmation of a sweep transaction 797 // containing a batch of kindergarten outputs. Once confirmation has been 798 // received, the nursery will mark those outputs as fully graduated, and proceed 799 // to mark any mature channels as fully closed in channeldb. 800 // NOTE(conner): this method MUST be called as a go routine. 801 func (u *UtxoNursery) waitForSweepConf(classHeight uint32, 802 output *kidOutput, resultChan chan sweep.Result) { 803 804 defer u.wg.Done() 805 806 select { 807 case result, ok := <-resultChan: 808 if !ok { 809 utxnLog.Errorf("Notification chan closed, can't" + 810 " advance graduating output") 811 return 812 } 813 814 // In case of a remote spend, still graduate the output. There 815 // is no way to sweep it anymore. 816 if result.Err == sweep.ErrRemoteSpend { 817 utxnLog.Infof("Output %v was spend by remote party", 818 output.OutPoint()) 819 break 820 } 821 822 if result.Err != nil { 823 utxnLog.Errorf("Failed to sweep %v at "+ 824 "height=%d", output.OutPoint(), 825 classHeight) 826 return 827 } 828 829 case <-u.quit: 830 return 831 } 832 833 u.mu.Lock() 834 defer u.mu.Unlock() 835 836 // TODO(conner): add retry logic? 837 838 // Mark the confirmed kindergarten output as graduated. 839 if err := u.cfg.Store.GraduateKinder(classHeight, output); err != nil { 840 utxnLog.Errorf("Unable to graduate kindergarten output %v: %v", 841 output.OutPoint(), err) 842 return 843 } 844 845 utxnLog.Infof("Graduated kindergarten output from height=%d", 846 classHeight) 847 848 // Attempt to close the channel, only doing so if all of the channel's 849 // outputs have been graduated. 850 chanPoint := output.OriginChanPoint() 851 if err := u.closeAndRemoveIfMature(chanPoint); err != nil { 852 utxnLog.Errorf("Failed to close and remove channel %v", 853 *chanPoint) 854 return 855 } 856 } 857 858 // sweepCribOutput broadcasts the crib output's htlc timeout txn, and sets up a 859 // notification that will advance it to the kindergarten bucket upon 860 // confirmation. 861 func (u *UtxoNursery) sweepCribOutput(classHeight uint32, baby *babyOutput) error { 862 utxnLog.Infof("Publishing CLTV-delayed HTLC output using timeout tx "+ 863 "(txid=%v): %v", baby.timeoutTx.TxHash(), 864 newLogClosure(func() string { 865 return spew.Sdump(baby.timeoutTx) 866 }), 867 ) 868 869 // We'll now broadcast the HTLC transaction, then wait for it to be 870 // confirmed before transitioning it to kindergarten. 871 label := labels.MakeLabel(labels.LabelTypeSweepTransaction, nil) 872 err := u.cfg.PublishTransaction(baby.timeoutTx, label) 873 if err != nil && err != lnwallet.ErrDoubleSpend { 874 utxnLog.Errorf("Unable to broadcast baby tx: "+ 875 "%v, %v", err, spew.Sdump(baby.timeoutTx)) 876 return err 877 } 878 879 return u.registerTimeoutConf(baby, classHeight) 880 } 881 882 // registerTimeoutConf is responsible for subscribing to confirmation 883 // notification for an htlc timeout transaction. If successful, a goroutine 884 // will be spawned that will transition the provided baby output into the 885 // kindergarten state within the nursery store. 886 func (u *UtxoNursery) registerTimeoutConf(baby *babyOutput, heightHint uint32) error { 887 888 birthTxID := baby.timeoutTx.TxHash() 889 890 // Register for the confirmation of presigned htlc txn. 891 confChan, err := u.cfg.Notifier.RegisterConfirmationsNtfn( 892 &birthTxID, baby.timeoutTx.TxOut[0].PkScript, u.cfg.ConfDepth, 893 heightHint, 894 ) 895 if err != nil { 896 return err 897 } 898 899 utxnLog.Infof("Htlc output %v registered for promotion "+ 900 "notification.", baby.OutPoint()) 901 902 u.wg.Add(1) 903 go u.waitForTimeoutConf(baby, confChan) 904 905 return nil 906 } 907 908 // waitForTimeoutConf watches for the confirmation of an htlc timeout 909 // transaction, and attempts to move the htlc output from the crib bucket to the 910 // kindergarten bucket upon success. 911 func (u *UtxoNursery) waitForTimeoutConf(baby *babyOutput, 912 confChan *chainntnfs.ConfirmationEvent) { 913 914 defer u.wg.Done() 915 916 select { 917 case txConfirmation, ok := <-confChan.Confirmed: 918 if !ok { 919 utxnLog.Debugf("Notification chan "+ 920 "closed, can't advance baby output %v", 921 baby.OutPoint()) 922 return 923 } 924 925 baby.SetConfHeight(txConfirmation.BlockHeight) 926 927 case <-u.quit: 928 return 929 } 930 931 u.mu.Lock() 932 defer u.mu.Unlock() 933 934 // TODO(conner): add retry logic? 935 936 err := u.cfg.Store.CribToKinder(baby) 937 if err != nil { 938 utxnLog.Errorf("Unable to move htlc output from "+ 939 "crib to kindergarten bucket: %v", err) 940 return 941 } 942 943 utxnLog.Infof("Htlc output %v promoted to "+ 944 "kindergarten", baby.OutPoint()) 945 } 946 947 // registerPreschoolConf is responsible for subscribing to the confirmation of 948 // a commitment transaction, or an htlc success transaction for an incoming 949 // HTLC on our commitment transaction.. If successful, the provided preschool 950 // output will be moved persistently into the kindergarten state within the 951 // nursery store. 952 func (u *UtxoNursery) registerPreschoolConf(kid *kidOutput, heightHint uint32) error { 953 txID := kid.OutPoint().Hash 954 955 // TODO(roasbeef): ensure we don't already have one waiting, need to 956 // de-duplicate 957 // * need to do above? 958 959 pkScript := kid.signDesc.Output.PkScript 960 confChan, err := u.cfg.Notifier.RegisterConfirmationsNtfn( 961 &txID, pkScript, u.cfg.ConfDepth, heightHint, 962 ) 963 if err != nil { 964 return err 965 } 966 967 var outputType string 968 if kid.isHtlc { 969 outputType = "HTLC" 970 } else { 971 outputType = "Commitment" 972 } 973 974 utxnLog.Infof("%v outpoint %v registered for "+ 975 "confirmation notification.", outputType, kid.OutPoint()) 976 977 u.wg.Add(1) 978 go u.waitForPreschoolConf(kid, confChan) 979 980 return nil 981 } 982 983 // waitForPreschoolConf is intended to be run as a goroutine that will wait until 984 // a channel force close commitment transaction, or a second layer HTLC success 985 // transaction has been included in a confirmed block. Once the transaction has 986 // been confirmed (as reported by the Chain Notifier), waitForPreschoolConf 987 // will delete the output from the "preschool" database bucket and atomically 988 // add it to the "kindergarten" database bucket. This is the second step in 989 // the output incubation process. 990 func (u *UtxoNursery) waitForPreschoolConf(kid *kidOutput, 991 confChan *chainntnfs.ConfirmationEvent) { 992 993 defer u.wg.Done() 994 995 select { 996 case txConfirmation, ok := <-confChan.Confirmed: 997 if !ok { 998 utxnLog.Errorf("Notification chan "+ 999 "closed, can't advance output %v", 1000 kid.OutPoint()) 1001 return 1002 } 1003 1004 kid.SetConfHeight(txConfirmation.BlockHeight) 1005 1006 case <-u.quit: 1007 return 1008 } 1009 1010 u.mu.Lock() 1011 defer u.mu.Unlock() 1012 1013 // TODO(conner): add retry logic? 1014 1015 var outputType string 1016 if kid.isHtlc { 1017 outputType = "HTLC" 1018 } else { 1019 outputType = "Commitment" 1020 } 1021 1022 bestHeight := atomic.LoadUint32(&u.bestHeight) 1023 err := u.cfg.Store.PreschoolToKinder(kid, bestHeight) 1024 if err != nil { 1025 utxnLog.Errorf("Unable to move %v output "+ 1026 "from preschool to kindergarten bucket: %v", 1027 outputType, err) 1028 return 1029 } 1030 } 1031 1032 // RemoveChannel channel erases all entries from the channel bucket for the 1033 // provided channel point. 1034 func (u *UtxoNursery) RemoveChannel(op *wire.OutPoint) error { 1035 return u.cfg.Store.RemoveChannel(op) 1036 1037 } 1038 1039 // ContractMaturityReport is a report that details the maturity progress of a 1040 // particular force closed contract. 1041 type ContractMaturityReport struct { 1042 // LimboBalance is the total number of frozen coins within this 1043 // contract. 1044 LimboBalance dcrutil.Amount 1045 1046 // RecoveredBalance is the total value that has been successfully swept 1047 // back to the user's wallet. 1048 RecoveredBalance dcrutil.Amount 1049 1050 // htlcs records a maturity report for each htlc output in this channel. 1051 Htlcs []HtlcMaturityReport 1052 } 1053 1054 // HtlcMaturityReport provides a summary of a single htlc output, and is 1055 // embedded as party of the overarching ContractMaturityReport 1056 type HtlcMaturityReport struct { 1057 // Outpoint is the final output that will be swept back to the wallet. 1058 Outpoint wire.OutPoint 1059 1060 // amount is the final value that will be swept in back to the wallet. 1061 Amount dcrutil.Amount 1062 1063 // MaturityHeight is the absolute block height that this output will 1064 // mature at. 1065 MaturityHeight uint32 1066 1067 // Stage indicates whether the htlc is in the CLTV-timeout stage (1) or 1068 // the CSV-delay stage (2). A stage 1 htlc's maturity height will be set 1069 // to its expiry height, while a stage 2 htlc's maturity height will be 1070 // set to its confirmation height plus the maturity requirement. 1071 Stage uint32 1072 } 1073 1074 // AddLimboStage1TimeoutHtlc adds an htlc crib output to the maturity report's 1075 // htlcs, and contributes its amount to the limbo balance. 1076 func (c *ContractMaturityReport) AddLimboStage1TimeoutHtlc(baby *babyOutput) { 1077 c.LimboBalance += baby.Amount() 1078 1079 // TODO(roasbeef): bool to indicate stage 1 vs stage 2? 1080 c.Htlcs = append(c.Htlcs, HtlcMaturityReport{ 1081 Outpoint: *baby.OutPoint(), 1082 Amount: baby.Amount(), 1083 MaturityHeight: baby.expiry, 1084 Stage: 1, 1085 }) 1086 } 1087 1088 // AddLimboDirectHtlc adds a direct HTLC on the commitment transaction of the 1089 // remote party to the maturity report. This a CLTV time-locked output that 1090 // has or hasn't expired yet. 1091 func (c *ContractMaturityReport) AddLimboDirectHtlc(kid *kidOutput) { 1092 c.LimboBalance += kid.Amount() 1093 1094 htlcReport := HtlcMaturityReport{ 1095 Outpoint: *kid.OutPoint(), 1096 Amount: kid.Amount(), 1097 MaturityHeight: kid.absoluteMaturity, 1098 Stage: 2, 1099 } 1100 1101 c.Htlcs = append(c.Htlcs, htlcReport) 1102 } 1103 1104 // AddLimboStage1SuccessHtlcHtlc adds an htlc crib output to the maturity 1105 // report's set of HTLC's. We'll use this to report any incoming HTLC sweeps 1106 // where the second level transaction hasn't yet confirmed. 1107 func (c *ContractMaturityReport) AddLimboStage1SuccessHtlc(kid *kidOutput) { 1108 c.LimboBalance += kid.Amount() 1109 1110 c.Htlcs = append(c.Htlcs, HtlcMaturityReport{ 1111 Outpoint: *kid.OutPoint(), 1112 Amount: kid.Amount(), 1113 Stage: 1, 1114 }) 1115 } 1116 1117 // AddLimboStage2Htlc adds an htlc kindergarten output to the maturity report's 1118 // htlcs, and contributes its amount to the limbo balance. 1119 func (c *ContractMaturityReport) AddLimboStage2Htlc(kid *kidOutput) { 1120 c.LimboBalance += kid.Amount() 1121 1122 htlcReport := HtlcMaturityReport{ 1123 Outpoint: *kid.OutPoint(), 1124 Amount: kid.Amount(), 1125 Stage: 2, 1126 } 1127 1128 // If the confirmation height is set, then this means the first stage 1129 // has been confirmed, and we know the final maturity height of the CSV 1130 // delay. 1131 if kid.ConfHeight() != 0 { 1132 htlcReport.MaturityHeight = kid.ConfHeight() + kid.BlocksToMaturity() 1133 } 1134 1135 c.Htlcs = append(c.Htlcs, htlcReport) 1136 } 1137 1138 // AddRecoveredHtlc adds a graduate output to the maturity report's htlcs, and 1139 // contributes its amount to the recovered balance. 1140 func (c *ContractMaturityReport) AddRecoveredHtlc(kid *kidOutput) { 1141 c.RecoveredBalance += kid.Amount() 1142 1143 c.Htlcs = append(c.Htlcs, HtlcMaturityReport{ 1144 Outpoint: *kid.OutPoint(), 1145 Amount: kid.Amount(), 1146 MaturityHeight: kid.ConfHeight() + kid.BlocksToMaturity(), 1147 }) 1148 } 1149 1150 // closeAndRemoveIfMature removes a particular channel from the channel index 1151 // if and only if all of its outputs have been marked graduated. If the channel 1152 // still has ungraduated outputs, the method will succeed without altering the 1153 // database state. 1154 func (u *UtxoNursery) closeAndRemoveIfMature(chanPoint *wire.OutPoint) error { 1155 isMature, err := u.cfg.Store.IsMatureChannel(chanPoint) 1156 if err == ErrContractNotFound { 1157 return nil 1158 } else if err != nil { 1159 utxnLog.Errorf("Unable to determine maturity of "+ 1160 "channel=%s", chanPoint) 1161 return err 1162 } 1163 1164 // Nothing to do if we are still incubating. 1165 if !isMature { 1166 return nil 1167 } 1168 1169 // Now that the channel is fully closed, we remove the channel from the 1170 // nursery store here. This preserves the invariant that we never remove 1171 // a channel unless it is mature, as this is the only place the utxo 1172 // nursery removes a channel. 1173 if err := u.cfg.Store.RemoveChannel(chanPoint); err != nil { 1174 utxnLog.Errorf("Unable to remove channel=%s from "+ 1175 "nursery store: %v", chanPoint, err) 1176 return err 1177 } 1178 1179 utxnLog.Infof("Removed channel %v from nursery store", chanPoint) 1180 1181 return nil 1182 } 1183 1184 // babyOutput represents a two-stage CSV locked output, and is used to track 1185 // htlc outputs through incubation. The first stage requires broadcasting a 1186 // presigned timeout txn that spends from the CLTV locked output on the 1187 // commitment txn. A babyOutput is treated as a subset of CsvSpendableOutputs, 1188 // with the additional constraint that a transaction must be broadcast before 1189 // it can be spent. Each baby transaction embeds the kidOutput that can later 1190 // be used to spend the CSV output contained in the timeout txn. 1191 // 1192 // TODO(roasbeef): re-rename to timeout tx 1193 // - create CltvCsvSpendableOutput 1194 type babyOutput struct { 1195 // expiry is the absolute block height at which the secondLevelTx 1196 // should be broadcast to the network. 1197 // 1198 // NOTE: This value will be zero if this is a baby output for a prior 1199 // incoming HTLC. 1200 expiry uint32 1201 1202 // timeoutTx is a fully-signed transaction that, upon confirmation, 1203 // transitions the htlc into the delay+claim stage. 1204 timeoutTx *wire.MsgTx 1205 1206 // kidOutput represents the CSV output to be swept from the 1207 // secondLevelTx after it has been broadcast and confirmed. 1208 kidOutput 1209 } 1210 1211 // makeBabyOutput constructs a baby output that wraps a future kidOutput. The 1212 // provided sign descriptors and witness types will be used once the output 1213 // reaches the delay and claim stage. 1214 func makeBabyOutput(chanPoint *wire.OutPoint, 1215 htlcResolution *lnwallet.OutgoingHtlcResolution) babyOutput { 1216 1217 htlcOutpoint := htlcResolution.ClaimOutpoint 1218 blocksToMaturity := htlcResolution.CsvDelay 1219 witnessType := input.HtlcOfferedTimeoutSecondLevel 1220 1221 kid := makeKidOutput( 1222 &htlcOutpoint, chanPoint, blocksToMaturity, witnessType, 1223 &htlcResolution.SweepSignDesc, 0, 1224 ) 1225 1226 return babyOutput{ 1227 kidOutput: kid, 1228 expiry: htlcResolution.Expiry, 1229 timeoutTx: htlcResolution.SignedTimeoutTx, 1230 } 1231 } 1232 1233 // Encode writes the baby output to the given io.Writer. 1234 func (bo *babyOutput) Encode(w io.Writer) error { 1235 var scratch [4]byte 1236 byteOrder.PutUint32(scratch[:], bo.expiry) 1237 if _, err := w.Write(scratch[:]); err != nil { 1238 return err 1239 } 1240 1241 if err := bo.timeoutTx.Serialize(w); err != nil { 1242 return err 1243 } 1244 1245 return bo.kidOutput.Encode(w) 1246 } 1247 1248 // Decode reconstructs a baby output using the provided io.Reader. 1249 func (bo *babyOutput) Decode(r io.Reader) error { 1250 var scratch [4]byte 1251 if _, err := r.Read(scratch[:]); err != nil { 1252 return err 1253 } 1254 bo.expiry = byteOrder.Uint32(scratch[:]) 1255 1256 bo.timeoutTx = new(wire.MsgTx) 1257 if err := bo.timeoutTx.Deserialize(r); err != nil { 1258 return err 1259 } 1260 1261 return bo.kidOutput.Decode(r) 1262 } 1263 1264 // kidOutput represents an output that's waiting for a required blockheight 1265 // before its funds will be available to be moved into the user's wallet. The 1266 // struct includes a WitnessGenerator closure which will be used to generate 1267 // the witness required to sweep the output once it's mature. 1268 // 1269 // TODO(roasbeef): rename to immatureOutput? 1270 type kidOutput struct { 1271 breachedOutput 1272 1273 originChanPoint wire.OutPoint 1274 1275 // isHtlc denotes if this kid output is an HTLC output or not. This 1276 // value will be used to determine how to report this output within the 1277 // nursery report. 1278 isHtlc bool 1279 1280 // blocksToMaturity is the relative CSV delay required after initial 1281 // confirmation of the commitment transaction before we can sweep this 1282 // output. 1283 // 1284 // NOTE: This will be set for: commitment outputs, and incoming HTLC's. 1285 // Otherwise, this will be zero. It will also be non-zero for 1286 // commitment types which requires confirmed spends. 1287 blocksToMaturity uint32 1288 1289 // absoluteMaturity is the absolute height that this output will be 1290 // mature at. In order to sweep the output after this height, the 1291 // locktime of sweep transaction will need to be set to this value. 1292 // 1293 // NOTE: This will only be set for: outgoing HTLC's on the commitment 1294 // transaction of the remote party. 1295 absoluteMaturity uint32 1296 } 1297 1298 func makeKidOutput(outpoint, originChanPoint *wire.OutPoint, 1299 blocksToMaturity uint32, witnessType input.StandardWitnessType, 1300 signDescriptor *input.SignDescriptor, 1301 absoluteMaturity uint32) kidOutput { 1302 1303 // This is an HTLC either if it's an incoming HTLC on our commitment 1304 // transaction, or is an outgoing HTLC on the commitment transaction of 1305 // the remote peer. 1306 isHtlc := (witnessType == input.HtlcAcceptedSuccessSecondLevel || 1307 witnessType == input.HtlcOfferedRemoteTimeout) 1308 1309 // heightHint can be safely set to zero here, because after this 1310 // function returns, nursery will set a proper confirmation height in 1311 // waitForTimeoutConf or waitForPreschoolConf. 1312 heightHint := uint32(0) 1313 1314 return kidOutput{ 1315 breachedOutput: makeBreachedOutput( 1316 outpoint, witnessType, nil, signDescriptor, heightHint, 1317 ), 1318 isHtlc: isHtlc, 1319 originChanPoint: *originChanPoint, 1320 blocksToMaturity: blocksToMaturity, 1321 absoluteMaturity: absoluteMaturity, 1322 } 1323 } 1324 1325 func (k *kidOutput) OriginChanPoint() *wire.OutPoint { 1326 return &k.originChanPoint 1327 } 1328 1329 func (k *kidOutput) BlocksToMaturity() uint32 { 1330 return k.blocksToMaturity 1331 } 1332 1333 func (k *kidOutput) SetConfHeight(height uint32) { 1334 k.confHeight = height 1335 } 1336 1337 func (k *kidOutput) ConfHeight() uint32 { 1338 return k.confHeight 1339 } 1340 1341 // Encode converts a KidOutput struct into a form suitable for on-disk database 1342 // storage. Note that the signDescriptor struct field is included so that the 1343 // output's witness can be generated by createSweepTx() when the output becomes 1344 // spendable. 1345 func (k *kidOutput) Encode(w io.Writer) error { 1346 var scratch [8]byte 1347 byteOrder.PutUint64(scratch[:], uint64(k.Amount())) 1348 if _, err := w.Write(scratch[:]); err != nil { 1349 return err 1350 } 1351 1352 if err := writeOutpoint(w, k.OutPoint()); err != nil { 1353 return err 1354 } 1355 if err := writeOutpoint(w, k.OriginChanPoint()); err != nil { 1356 return err 1357 } 1358 1359 if err := binary.Write(w, byteOrder, k.isHtlc); err != nil { 1360 return err 1361 } 1362 1363 byteOrder.PutUint32(scratch[:4], k.BlocksToMaturity()) 1364 if _, err := w.Write(scratch[:4]); err != nil { 1365 return err 1366 } 1367 1368 byteOrder.PutUint32(scratch[:4], k.absoluteMaturity) 1369 if _, err := w.Write(scratch[:4]); err != nil { 1370 return err 1371 } 1372 1373 byteOrder.PutUint32(scratch[:4], k.ConfHeight()) 1374 if _, err := w.Write(scratch[:4]); err != nil { 1375 return err 1376 } 1377 1378 byteOrder.PutUint16(scratch[:2], uint16(k.witnessType)) 1379 if _, err := w.Write(scratch[:2]); err != nil { 1380 return err 1381 } 1382 1383 return input.WriteSignDescriptor(w, k.SignDesc()) 1384 } 1385 1386 // Decode takes a byte array representation of a kidOutput and converts it to an 1387 // struct. Note that the witnessFunc method isn't added during deserialization 1388 // and must be added later based on the value of the witnessType field. 1389 func (k *kidOutput) Decode(r io.Reader) error { 1390 var scratch [8]byte 1391 1392 if _, err := r.Read(scratch[:]); err != nil { 1393 return err 1394 } 1395 k.amt = dcrutil.Amount(byteOrder.Uint64(scratch[:])) 1396 1397 if err := readOutpoint(io.LimitReader(r, 40), &k.outpoint); err != nil { 1398 return err 1399 } 1400 1401 err := readOutpoint(io.LimitReader(r, 40), &k.originChanPoint) 1402 if err != nil { 1403 return err 1404 } 1405 1406 if err := binary.Read(r, byteOrder, &k.isHtlc); err != nil { 1407 return err 1408 } 1409 1410 if _, err := r.Read(scratch[:4]); err != nil { 1411 return err 1412 } 1413 k.blocksToMaturity = byteOrder.Uint32(scratch[:4]) 1414 1415 if _, err := r.Read(scratch[:4]); err != nil { 1416 return err 1417 } 1418 k.absoluteMaturity = byteOrder.Uint32(scratch[:4]) 1419 1420 if _, err := r.Read(scratch[:4]); err != nil { 1421 return err 1422 } 1423 k.confHeight = byteOrder.Uint32(scratch[:4]) 1424 1425 if _, err := r.Read(scratch[:2]); err != nil { 1426 return err 1427 } 1428 k.witnessType = input.StandardWitnessType(byteOrder.Uint16(scratch[:2])) 1429 1430 return input.ReadSignDescriptor(r, &k.signDesc) 1431 } 1432 1433 // TODO(bvu): copied from channeldb, remove repetition 1434 // 1435 // Note(decred): this cannot be moved to use the channeldb version because it 1436 // does not include the outpoint's tree field. 1437 func writeOutpoint(w io.Writer, o *wire.OutPoint) error { 1438 // TODO(roasbeef): make all scratch buffers on the stack 1439 scratch := make([]byte, 4) 1440 1441 // TODO(roasbeef): write raw 32 bytes instead of wasting the extra 1442 // byte. 1443 if err := wire.WriteVarBytes(w, 0, o.Hash[:]); err != nil { 1444 return err 1445 } 1446 1447 byteOrder.PutUint32(scratch, o.Index) 1448 _, err := w.Write(scratch) 1449 1450 // Note(decred): this does not include the Tree field 1451 return err 1452 } 1453 1454 // TODO(bvu): copied from channeldb, remove repetition 1455 // 1456 // Note(decred): this cannot be moved to use the channeldb version because it 1457 // does not include the outpoint's tree field. 1458 func readOutpoint(r io.Reader, o *wire.OutPoint) error { 1459 scratch := make([]byte, 4) 1460 1461 txid, err := wire.ReadVarBytes(r, 0, 32, "prevout") 1462 if err != nil { 1463 return err 1464 } 1465 copy(o.Hash[:], txid) 1466 1467 if _, err := r.Read(scratch); err != nil { 1468 return err 1469 } 1470 o.Index = byteOrder.Uint32(scratch) 1471 1472 // Note(decred): this does not include the Tree field 1473 return nil 1474 } 1475 1476 // Compile-time constraint to ensure kidOutput implements the 1477 // Input interface. 1478 1479 var _ input.Input = (*kidOutput)(nil)