diff --git a/breacharbiter.go b/breacharbiter.go index c7786791a..45c4bafc1 100644 --- a/breacharbiter.go +++ b/breacharbiter.go @@ -757,6 +757,7 @@ type breachedOutput struct { outpoint wire.OutPoint witnessType lnwallet.WitnessType signDesc lnwallet.SignDescriptor + confHeight uint32 secondLevelWitnessScript []byte @@ -768,7 +769,8 @@ type breachedOutput struct { func makeBreachedOutput(outpoint *wire.OutPoint, witnessType lnwallet.WitnessType, secondLevelScript []byte, - signDescriptor *lnwallet.SignDescriptor) breachedOutput { + signDescriptor *lnwallet.SignDescriptor, + confHeight uint32) breachedOutput { amount := signDescriptor.Output.Value @@ -778,6 +780,7 @@ func makeBreachedOutput(outpoint *wire.OutPoint, secondLevelWitnessScript: secondLevelScript, witnessType: witnessType, signDesc: *signDescriptor, + confHeight: confHeight, } } @@ -831,6 +834,12 @@ func (bo *breachedOutput) BlocksToMaturity() uint32 { return 0 } +// HeightHint returns the minimum height at which a confirmed spending tx can +// occur. +func (bo *breachedOutput) HeightHint() uint32 { + return bo.confHeight +} + // Add compile-time constraint ensuring breachedOutput implements the Input // interface. var _ sweep.Input = (*breachedOutput)(nil) @@ -878,7 +887,8 @@ func newRetributionInfo(chanPoint *wire.OutPoint, // No second level script as this is a commitment // output. nil, - breachInfo.LocalOutputSignDesc) + breachInfo.LocalOutputSignDesc, + breachInfo.BreachHeight) breachedOutputs = append(breachedOutputs, localOutput) } @@ -895,7 +905,8 @@ func newRetributionInfo(chanPoint *wire.OutPoint, // No second level script as this is a commitment // output. nil, - breachInfo.RemoteOutputSignDesc) + breachInfo.RemoteOutputSignDesc, + breachInfo.BreachHeight) breachedOutputs = append(breachedOutputs, remoteOutput) } @@ -919,7 +930,8 @@ func newRetributionInfo(chanPoint *wire.OutPoint, &breachInfo.HtlcRetributions[i].OutPoint, htlcWitnessType, breachInfo.HtlcRetributions[i].SecondLevelWitnessScript, - &breachInfo.HtlcRetributions[i].SignDesc) + &breachInfo.HtlcRetributions[i].SignDesc, + breachInfo.BreachHeight) breachedOutputs = append(breachedOutputs, htlcOutput) } diff --git a/contractcourt/contract_resolvers.go b/contractcourt/contract_resolvers.go index 71ea72dc1..74cb396cf 100644 --- a/contractcourt/contract_resolvers.go +++ b/contractcourt/contract_resolvers.go @@ -462,6 +462,7 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) { &h.htlcResolution.ClaimOutpoint, &h.htlcResolution.SweepSignDesc, h.htlcResolution.Preimage[:], + h.broadcastHeight, ) // With the input created, we can now generate the full @@ -1254,6 +1255,7 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) { &c.commitResolution.SelfOutPoint, lnwallet.CommitmentNoDelay, &c.commitResolution.SelfOutputSignDesc, + c.broadcastHeight, ) // With out input constructed, we'll now request that the diff --git a/sweep/input.go b/sweep/input.go index 6cf09760d..57ee79393 100644 --- a/sweep/input.go +++ b/sweep/input.go @@ -33,12 +33,17 @@ type Input interface { // the output can be spent. For non-CSV locked inputs this is always // zero. BlocksToMaturity() uint32 + + // HeightHint returns the minimum height at which a confirmed spending + // tx can occur. + HeightHint() uint32 } type inputKit struct { outpoint wire.OutPoint witnessType lnwallet.WitnessType signDesc lnwallet.SignDescriptor + heightHint uint32 } // OutPoint returns the breached output's identifier that is to be included as @@ -59,6 +64,12 @@ func (i *inputKit) SignDesc() *lnwallet.SignDescriptor { return &i.signDesc } +// HeightHint returns the minimum height at which a confirmed spending +// tx can occur. +func (i *inputKit) HeightHint() uint32 { + return i.heightHint +} + // BaseInput contains all the information needed to sweep a basic output // (CSV/CLTV/no time lock) type BaseInput struct { @@ -68,13 +79,14 @@ type BaseInput struct { // MakeBaseInput assembles a new BaseInput that can be used to construct a // sweep transaction. func MakeBaseInput(outpoint *wire.OutPoint, witnessType lnwallet.WitnessType, - signDescriptor *lnwallet.SignDescriptor) BaseInput { + signDescriptor *lnwallet.SignDescriptor, heightHint uint32) BaseInput { return BaseInput{ inputKit{ outpoint: *outpoint, witnessType: witnessType, signDesc: *signDescriptor, + heightHint: heightHint, }, } } @@ -113,13 +125,14 @@ type HtlcSucceedInput struct { // construct a sweep transaction. func MakeHtlcSucceedInput(outpoint *wire.OutPoint, signDescriptor *lnwallet.SignDescriptor, - preimage []byte) HtlcSucceedInput { + preimage []byte, heightHint uint32) HtlcSucceedInput { return HtlcSucceedInput{ inputKit: inputKit{ outpoint: *outpoint, witnessType: lnwallet.HtlcAcceptedRemoteSuccess, signDesc: *signDescriptor, + heightHint: heightHint, }, preimage: preimage, } diff --git a/utxonursery.go b/utxonursery.go index 3f8cc2f34..0849c3094 100644 --- a/utxonursery.go +++ b/utxonursery.go @@ -1554,8 +1554,6 @@ type kidOutput struct { // NOTE: This will only be set for: outgoing HTLC's on the commitment // transaction of the remote party. absoluteMaturity uint32 - - confHeight uint32 } func makeKidOutput(outpoint, originChanPoint *wire.OutPoint, @@ -1569,9 +1567,14 @@ func makeKidOutput(outpoint, originChanPoint *wire.OutPoint, isHtlc := (witnessType == lnwallet.HtlcAcceptedSuccessSecondLevel || witnessType == lnwallet.HtlcOfferedRemoteTimeout) + // heightHint can be safely set to zero here, because after this + // function returns, nursery will set a proper confirmation height in + // waitForTimeoutConf or waitForPreschoolConf. + heightHint := uint32(0) + return kidOutput{ breachedOutput: makeBreachedOutput( - outpoint, witnessType, nil, signDescriptor, + outpoint, witnessType, nil, signDescriptor, heightHint, ), isHtlc: isHtlc, originChanPoint: *originChanPoint, diff --git a/utxonursery_test.go b/utxonursery_test.go index db0ebd9a3..32cde4cf6 100644 --- a/utxonursery_test.go +++ b/utxonursery_test.go @@ -206,10 +206,10 @@ var ( amt: btcutil.Amount(13e7), outpoint: outPoints[1], witnessType: lnwallet.CommitmentTimeLock, + confHeight: uint32(1000), }, originChanPoint: outPoints[0], blocksToMaturity: uint32(42), - confHeight: uint32(1000), }, { @@ -217,10 +217,10 @@ var ( amt: btcutil.Amount(24e7), outpoint: outPoints[2], witnessType: lnwallet.CommitmentTimeLock, + confHeight: uint32(1000), }, originChanPoint: outPoints[0], blocksToMaturity: uint32(42), - confHeight: uint32(1000), }, { @@ -228,10 +228,10 @@ var ( amt: btcutil.Amount(2e5), outpoint: outPoints[3], witnessType: lnwallet.CommitmentTimeLock, + confHeight: uint32(500), }, originChanPoint: outPoints[0], blocksToMaturity: uint32(28), - confHeight: uint32(500), }, { @@ -239,10 +239,10 @@ var ( amt: btcutil.Amount(10e6), outpoint: outPoints[4], witnessType: lnwallet.CommitmentTimeLock, + confHeight: uint32(500), }, originChanPoint: outPoints[0], blocksToMaturity: uint32(28), - confHeight: uint32(500), }, }