utxonursery: update NurseryReport with details of new output types

The utxo nursery is now responsible for two additional output types:
outgoing HTLC’s on the commitment transaction of the remote party, and
second-level claim transactions that we broadcast. In this commit,
we’ve updated the NurseryReport to now include details, so users are
able to properly keep track of the status of all their pending coins.
This commit is contained in:
Olaoluwa Osuntokun 2018-01-16 20:46:55 -08:00
parent 13b5019cc6
commit 12babb3cea
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

View File

@ -508,7 +508,7 @@ func (u *utxoNursery) NurseryReport(
// Each crib output represents a stage one htlc, and
// will contribute towards the limbo balance.
report.AddLimboStage1Htlc(&baby)
report.AddLimboStage1TimeoutHtlc(&baby)
case bytes.HasPrefix(k, psclPrefix),
bytes.HasPrefix(k, kndrPrefix),
@ -521,15 +521,24 @@ func (u *utxoNursery) NurseryReport(
return err
}
// Now, use the state prefixes to determine how the this
// output should be represented in the nursery report.
// An output's funds are always in limbo until reaching
// the graduate state.
// Now, use the state prefixes to determine how the
// this output should be represented in the nursery
// report. An output's funds are always in limbo until
// reaching the graduate state.
switch {
case bytes.HasPrefix(k, psclPrefix):
// Preschool outputs are awaiting the
// confirmation of the commitment transaction.
report.AddLimboCommitment(&kid)
switch kid.WitnessType() {
case lnwallet.CommitmentTimeLock:
report.AddLimboCommitment(&kid)
// An HTLC output on our commitment transaction
// where the second-layer transaction hasn't
// yet confirmed.
case lnwallet.HtlcAcceptedSuccessSecondLevel:
report.AddLimboStage1SuccessHtlc(&kid)
}
case bytes.HasPrefix(k, kndrPrefix):
// Kindergarten outputs may originate from
@ -543,10 +552,20 @@ func (u *utxoNursery) NurseryReport(
// delay to expire.
report.AddLimboCommitment(&kid)
case lnwallet.HtlcOfferedTimeout:
// The htlc timeout transaction has
// confirmed, and the CSV delay has
// begun ticking.
case lnwallet.HtlcOfferedRemoteTimeout:
// This is an HTLC output on the
// commitment transaction of the remote
// party. The CLTV timelock has
// expired, and we only need to sweep
// it.
report.AddLimboDirectHtlc(&kid)
case lnwallet.HtlcAcceptedSuccessSecondLevel:
fallthrough
case lnwallet.HtlcOfferedTimeoutSecondLevel:
// The htlc timeout or success
// transaction has confirmed, and the
// CSV delay has begun ticking.
report.AddLimboStage2Htlc(&kid)
}
@ -562,10 +581,14 @@ func (u *utxoNursery) NurseryReport(
// regular p2wkh output.
report.AddRecoveredCommitment(&kid)
case lnwallet.HtlcOfferedTimeout:
// This htlc output successfully resides
// in a p2wkh output belonging to the
// user.
case lnwallet.HtlcAcceptedSuccessSecondLevel:
fallthrough
case lnwallet.HtlcOfferedTimeoutSecondLevel:
fallthrough
case lnwallet.HtlcOfferedRemoteTimeout:
// This htlc output successfully
// resides in a p2wkh output belonging
// to the user.
report.AddRecoveredHtlc(&kid)
}
}
@ -600,11 +623,11 @@ func (u *utxoNursery) reloadPreschool(heightHint uint32) error {
}
// reloadClasses reinitializes any height-dependent state transitions for which
// the utxonursery has not recevied confirmation, and replays the graduation of
// the utxonursery has not received confirmation, and replays the graduation of
// all kindergarten and crib outputs for heights that have not been finalized.
// This allows the nursery to reinitialize all state to continue sweeping
// outputs, even in the event that we missed blocks while offline. reloadClasses
// is called during the startup of the UTXO Nursery.
// outputs, even in the event that we missed blocks while offline.
// reloadClasses is called during the startup of the UTXO Nursery.
func (u *utxoNursery) reloadClasses(lastGradHeight uint32) error {
// Begin by loading all of the still-active heights up to and including
// the last height we successfully graduated.
@ -672,11 +695,11 @@ func (u *utxoNursery) reloadClasses(lastGradHeight uint32) error {
// properly registered, so they can be driven by the chain notifier. No
// transactions or signing are done as a result of this step.
func (u *utxoNursery) regraduateClass(classHeight uint32) error {
// Fetch all information about the crib and kindergarten outputs at this
// height. In addition to the outputs, we also retrieve the finalized
// kindergarten sweep txn, which will be nil if we have not attempted
// this height before, or if no kindergarten outputs exist at this
// height.
// Fetch all information about the crib and kindergarten outputs at
// this height. In addition to the outputs, we also retrieve the
// finalized kindergarten sweep txn, which will be nil if we have not
// attempted this height before, or if no kindergarten outputs exist at
// this height.
finalTx, kgtnOutputs, cribOutputs, err := u.cfg.Store.FetchClass(
classHeight)
if err != nil {
@ -774,11 +797,11 @@ func (u *utxoNursery) graduateClass(classHeight uint32) error {
u.bestHeight = classHeight
// Fetch all information about the crib and kindergarten outputs at this
// height. In addition to the outputs, we also retrieve the finalized
// kindergarten sweep txn, which will be nil if we have not attempted
// this height before, or if no kindergarten outputs exist at this
// height.
// Fetch all information about the crib and kindergarten outputs at
// this height. In addition to the outputs, we also retrieve the
// finalized kindergarten sweep txn, which will be nil if we have not
// attempted this height before, or if no kindergarten outputs exist at
// this height.
finalTx, kgtnOutputs, cribOutputs, err := u.cfg.Store.FetchClass(
classHeight)
if err != nil {
@ -1344,11 +1367,12 @@ func (c *contractMaturityReport) AddRecoveredCommitment(kid *kidOutput) {
c.maturityHeight = kid.BlocksToMaturity() + kid.ConfHeight()
}
// AddLimboStage1Htlc adds an htlc crib output to the maturity report's
// AddLimboStage1TimeoutHtlc adds an htlc crib output to the maturity report's
// htlcs, and contributes its amount to the limbo balance.
func (c *contractMaturityReport) AddLimboStage1Htlc(baby *babyOutput) {
func (c *contractMaturityReport) AddLimboStage1TimeoutHtlc(baby *babyOutput) {
c.limboBalance += baby.Amount()
// TODO(roasbeef): bool to indicate stage 1 vs stage 2?
c.htlcs = append(c.htlcs, htlcMaturityReport{
outpoint: *baby.OutPoint(),
amount: baby.Amount(),
@ -1358,6 +1382,38 @@ func (c *contractMaturityReport) AddLimboStage1Htlc(baby *babyOutput) {
})
}
// AddLimboDirectHtlc adds a direct HTLC on the commitment transaction of the
// remote party to the maturity report. This a CLTV time-locked output that
// hasn't yet expired.
func (c *contractMaturityReport) AddLimboDirectHtlc(kid *kidOutput) {
c.limboBalance += kid.Amount()
htlcReport := htlcMaturityReport{
outpoint: *kid.OutPoint(),
amount: kid.Amount(),
confHeight: kid.ConfHeight(),
maturityHeight: kid.absoluteMaturity,
stage: 2,
}
c.htlcs = append(c.htlcs, htlcReport)
}
// AddLimboStage1SuccessHtlcHtlc adds an htlc crib output to the maturity
// report's set of HTLC's. We'll use this to report any incoming HTLC sweeps
// where the second level transaction hasn't yet confirmed.
func (c *contractMaturityReport) AddLimboStage1SuccessHtlc(kid *kidOutput) {
c.limboBalance += kid.Amount()
c.htlcs = append(c.htlcs, htlcMaturityReport{
outpoint: *kid.OutPoint(),
amount: kid.Amount(),
confHeight: kid.ConfHeight(),
maturityRequirement: kid.BlocksToMaturity(),
stage: 1,
})
}
// AddLimboStage2Htlc adds an htlc kindergarten output to the maturity report's
// htlcs, and contributes its amount to the limbo balance.
func (c *contractMaturityReport) AddLimboStage2Htlc(kid *kidOutput) {
@ -1469,33 +1525,43 @@ type CsvSpendableOutput interface {
// htlc outputs through incubation. The first stage requires broadcasting a
// presigned timeout txn that spends from the CLTV locked output on the
// commitment txn. A babyOutput is treated as a subset of CsvSpendableOutputs,
// with the additional constraint that a transaction must be broadcast before it
// can be spent. Each baby transaction embeds the kidOutput that can later be
// used to spend the CSV output contained in the timeout txn.
// with the additional constraint that a transaction must be broadcast before
// it can be spent. Each baby transaction embeds the kidOutput that can later
// be used to spend the CSV output contained in the timeout txn.
//
// TODO(roasbeef): re-rename to timeout tx
// * create CltvCsvSpendableOutput
type babyOutput struct {
// expiry is the absolute block height at which the timeoutTx should be
// broadcast to the network.
// expiry is the absolute block height at which the secondLevelTx
// should be broadcast to the network.
//
// NOTE: This value will be zero if this is a baby output for a prior
// incoming HTLC.
expiry uint32
// timeoutTx is a fully-signed transaction that, upon confirmation,
// transitions the htlc into the delay+claim stage.
timeoutTx *wire.MsgTx
// kidOutput represents the CSV output to be swept from the timeoutTx
// after it has been broadcast and confirmed.
// kidOutput represents the CSV output to be swept from the
// secondLevelTx after it has been broadcast and confirmed.
kidOutput
}
// makeBabyOutput constructs a baby output the wraps a future kidOutput. The
// makeBabyOutput constructs a baby output that wraps a future kidOutput. The
// provided sign descriptors and witness types will be used once the output
// reaches the delay and claim stage.
func makeBabyOutput(outpoint, originChanPoint *wire.OutPoint,
blocksToMaturity uint32, witnessType lnwallet.WitnessType,
func makeBabyOutput(chanPoint *wire.OutPoint,
htlcResolution *lnwallet.OutgoingHtlcResolution) babyOutput {
kid := makeKidOutput(outpoint, originChanPoint,
blocksToMaturity, witnessType,
&htlcResolution.SweepSignDesc)
htlcOutpoint := htlcResolution.ClaimOutpoint
blocksToMaturity := htlcResolution.CsvDelay
witnessType := lnwallet.HtlcOfferedTimeoutSecondLevel
kid := makeKidOutput(
&htlcOutpoint, chanPoint, blocksToMaturity, witnessType,
&htlcResolution.SweepSignDesc, 0,
)
return babyOutput{
kidOutput: kid,