mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-03-28 10:41:57 +01:00
Merge pull request #8861 from lightningnetwork/custom-channels-breach
multi: hook up breach arb with new aux sweeper sub-system
This commit is contained in:
commit
4e968d9b52
@ -23,6 +23,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lntypes"
|
"github.com/lightningnetwork/lnd/lntypes"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||||
|
"github.com/lightningnetwork/lnd/sweep"
|
||||||
"github.com/lightningnetwork/lnd/tlv"
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ type BreachConfig struct {
|
|||||||
Estimator chainfee.Estimator
|
Estimator chainfee.Estimator
|
||||||
|
|
||||||
// GenSweepScript generates the receiving scripts for swept outputs.
|
// GenSweepScript generates the receiving scripts for swept outputs.
|
||||||
GenSweepScript func() ([]byte, error)
|
GenSweepScript func() fn.Result[lnwallet.AddrWithKey]
|
||||||
|
|
||||||
// Notifier provides a publish/subscribe interface for event driven
|
// Notifier provides a publish/subscribe interface for event driven
|
||||||
// notifications regarding the confirmation of txids.
|
// notifications regarding the confirmation of txids.
|
||||||
@ -174,6 +175,10 @@ type BreachConfig struct {
|
|||||||
// breached channels. This is used in conjunction with DB to recover
|
// breached channels. This is used in conjunction with DB to recover
|
||||||
// from crashes, restarts, or other failures.
|
// from crashes, restarts, or other failures.
|
||||||
Store RetributionStorer
|
Store RetributionStorer
|
||||||
|
|
||||||
|
// AuxSweeper is an optional interface that can be used to modify the
|
||||||
|
// way sweep transaction are generated.
|
||||||
|
AuxSweeper fn.Option[sweep.AuxSweeper]
|
||||||
}
|
}
|
||||||
|
|
||||||
// BreachArbitrator is a special subsystem which is responsible for watching and
|
// BreachArbitrator is a special subsystem which is responsible for watching and
|
||||||
@ -738,10 +743,28 @@ justiceTxBroadcast:
|
|||||||
return spew.Sdump(finalTx)
|
return spew.Sdump(finalTx)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// As we're about to broadcast our breach transaction, we'll notify the
|
||||||
|
// aux sweeper of our broadcast attempt first.
|
||||||
|
err = fn.MapOptionZ(b.cfg.AuxSweeper, func(aux sweep.AuxSweeper) error {
|
||||||
|
bumpReq := sweep.BumpRequest{
|
||||||
|
Inputs: finalTx.inputs,
|
||||||
|
DeliveryAddress: finalTx.sweepAddr,
|
||||||
|
ExtraTxOut: finalTx.extraTxOut,
|
||||||
|
}
|
||||||
|
|
||||||
|
return aux.NotifyBroadcast(
|
||||||
|
&bumpReq, finalTx.justiceTx, finalTx.fee,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
brarLog.Errorf("unable to notify broadcast: %w", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// We'll now attempt to broadcast the transaction which finalized the
|
// We'll now attempt to broadcast the transaction which finalized the
|
||||||
// channel's retribution against the cheating counter party.
|
// channel's retribution against the cheating counter party.
|
||||||
label := labels.MakeLabel(labels.LabelTypeJusticeTransaction, nil)
|
label := labels.MakeLabel(labels.LabelTypeJusticeTransaction, nil)
|
||||||
err = b.cfg.PublishTransaction(finalTx, label)
|
err = b.cfg.PublishTransaction(finalTx.justiceTx, label)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
brarLog.Errorf("Unable to broadcast justice tx: %v", err)
|
brarLog.Errorf("Unable to broadcast justice tx: %v", err)
|
||||||
}
|
}
|
||||||
@ -863,7 +886,9 @@ Loop:
|
|||||||
return spew.Sdump(tx)
|
return spew.Sdump(tx)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
err = b.cfg.PublishTransaction(tx, label)
|
err = b.cfg.PublishTransaction(
|
||||||
|
tx.justiceTx, label,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
brarLog.Warnf("Unable to broadcast "+
|
brarLog.Warnf("Unable to broadcast "+
|
||||||
"commit out spending justice "+
|
"commit out spending justice "+
|
||||||
@ -880,7 +905,9 @@ Loop:
|
|||||||
return spew.Sdump(tx)
|
return spew.Sdump(tx)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
err = b.cfg.PublishTransaction(tx, label)
|
err = b.cfg.PublishTransaction(
|
||||||
|
tx.justiceTx, label,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
brarLog.Warnf("Unable to broadcast "+
|
brarLog.Warnf("Unable to broadcast "+
|
||||||
"HTLC out spending justice "+
|
"HTLC out spending justice "+
|
||||||
@ -897,7 +924,9 @@ Loop:
|
|||||||
return spew.Sdump(tx)
|
return spew.Sdump(tx)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
err = b.cfg.PublishTransaction(tx, label)
|
err = b.cfg.PublishTransaction(
|
||||||
|
tx.justiceTx, label,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
brarLog.Warnf("Unable to broadcast "+
|
brarLog.Warnf("Unable to broadcast "+
|
||||||
"second-level HTLC out "+
|
"second-level HTLC out "+
|
||||||
@ -1085,10 +1114,9 @@ type breachedOutput struct {
|
|||||||
// makeBreachedOutput assembles a new breachedOutput that can be used by the
|
// makeBreachedOutput assembles a new breachedOutput that can be used by the
|
||||||
// breach arbiter to construct a justice or sweep transaction.
|
// breach arbiter to construct a justice or sweep transaction.
|
||||||
func makeBreachedOutput(outpoint *wire.OutPoint,
|
func makeBreachedOutput(outpoint *wire.OutPoint,
|
||||||
witnessType input.StandardWitnessType,
|
witnessType input.StandardWitnessType, secondLevelScript []byte,
|
||||||
secondLevelScript []byte,
|
signDescriptor *input.SignDescriptor, confHeight uint32,
|
||||||
signDescriptor *input.SignDescriptor,
|
resolutionBlob fn.Option[tlv.Blob]) breachedOutput {
|
||||||
confHeight uint32) breachedOutput {
|
|
||||||
|
|
||||||
amount := signDescriptor.Output.Value
|
amount := signDescriptor.Output.Value
|
||||||
|
|
||||||
@ -1099,6 +1127,7 @@ func makeBreachedOutput(outpoint *wire.OutPoint,
|
|||||||
witnessType: witnessType,
|
witnessType: witnessType,
|
||||||
signDesc: *signDescriptor,
|
signDesc: *signDescriptor,
|
||||||
confHeight: confHeight,
|
confHeight: confHeight,
|
||||||
|
resolutionBlob: resolutionBlob,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1276,6 +1305,7 @@ func newRetributionInfo(chanPoint *wire.OutPoint,
|
|||||||
nil,
|
nil,
|
||||||
breachInfo.LocalOutputSignDesc,
|
breachInfo.LocalOutputSignDesc,
|
||||||
breachInfo.BreachHeight,
|
breachInfo.BreachHeight,
|
||||||
|
breachInfo.LocalResolutionBlob,
|
||||||
)
|
)
|
||||||
|
|
||||||
breachedOutputs = append(breachedOutputs, localOutput)
|
breachedOutputs = append(breachedOutputs, localOutput)
|
||||||
@ -1302,6 +1332,7 @@ func newRetributionInfo(chanPoint *wire.OutPoint,
|
|||||||
nil,
|
nil,
|
||||||
breachInfo.RemoteOutputSignDesc,
|
breachInfo.RemoteOutputSignDesc,
|
||||||
breachInfo.BreachHeight,
|
breachInfo.BreachHeight,
|
||||||
|
breachInfo.RemoteResolutionBlob,
|
||||||
)
|
)
|
||||||
|
|
||||||
breachedOutputs = append(breachedOutputs, remoteOutput)
|
breachedOutputs = append(breachedOutputs, remoteOutput)
|
||||||
@ -1336,6 +1367,7 @@ func newRetributionInfo(chanPoint *wire.OutPoint,
|
|||||||
breachInfo.HtlcRetributions[i].SecondLevelWitnessScript,
|
breachInfo.HtlcRetributions[i].SecondLevelWitnessScript,
|
||||||
&breachInfo.HtlcRetributions[i].SignDesc,
|
&breachInfo.HtlcRetributions[i].SignDesc,
|
||||||
breachInfo.BreachHeight,
|
breachInfo.BreachHeight,
|
||||||
|
breachInfo.HtlcRetributions[i].ResolutionBlob,
|
||||||
)
|
)
|
||||||
|
|
||||||
// For taproot outputs, we also need to hold onto the second
|
// For taproot outputs, we also need to hold onto the second
|
||||||
@ -1375,10 +1407,10 @@ func newRetributionInfo(chanPoint *wire.OutPoint,
|
|||||||
// spend the to_local output and commitment level HTLC outputs separately,
|
// spend the to_local output and commitment level HTLC outputs separately,
|
||||||
// before the CSV locks expire.
|
// before the CSV locks expire.
|
||||||
type justiceTxVariants struct {
|
type justiceTxVariants struct {
|
||||||
spendAll *wire.MsgTx
|
spendAll *justiceTxCtx
|
||||||
spendCommitOuts *wire.MsgTx
|
spendCommitOuts *justiceTxCtx
|
||||||
spendHTLCs *wire.MsgTx
|
spendHTLCs *justiceTxCtx
|
||||||
spendSecondLevelHTLCs []*wire.MsgTx
|
spendSecondLevelHTLCs []*justiceTxCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
// createJusticeTx creates transactions which exacts "justice" by sweeping ALL
|
// createJusticeTx creates transactions which exacts "justice" by sweeping ALL
|
||||||
@ -1442,7 +1474,9 @@ func (b *BreachArbitrator) createJusticeTx(
|
|||||||
err)
|
err)
|
||||||
}
|
}
|
||||||
|
|
||||||
secondLevelSweeps := make([]*wire.MsgTx, 0, len(secondLevelInputs))
|
// TODO(roasbeef): only register one of them?
|
||||||
|
|
||||||
|
secondLevelSweeps := make([]*justiceTxCtx, 0, len(secondLevelInputs))
|
||||||
for _, input := range secondLevelInputs {
|
for _, input := range secondLevelInputs {
|
||||||
sweepTx, err := b.createSweepTx(input)
|
sweepTx, err := b.createSweepTx(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1459,9 +1493,23 @@ func (b *BreachArbitrator) createJusticeTx(
|
|||||||
return txs, nil
|
return txs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// justiceTxCtx contains the justice transaction along with other related meta
|
||||||
|
// data.
|
||||||
|
type justiceTxCtx struct {
|
||||||
|
justiceTx *wire.MsgTx
|
||||||
|
|
||||||
|
sweepAddr lnwallet.AddrWithKey
|
||||||
|
|
||||||
|
extraTxOut fn.Option[sweep.SweepOutput]
|
||||||
|
|
||||||
|
fee btcutil.Amount
|
||||||
|
|
||||||
|
inputs []input.Input
|
||||||
|
}
|
||||||
|
|
||||||
// createSweepTx creates a tx that sweeps the passed inputs back to our wallet.
|
// createSweepTx creates a tx that sweeps the passed inputs back to our wallet.
|
||||||
func (b *BreachArbitrator) createSweepTx(inputs ...input.Input) (*wire.MsgTx,
|
func (b *BreachArbitrator) createSweepTx(
|
||||||
error) {
|
inputs ...input.Input) (*justiceTxCtx, error) {
|
||||||
|
|
||||||
if len(inputs) == 0 {
|
if len(inputs) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -1484,6 +1532,15 @@ func (b *BreachArbitrator) createSweepTx(inputs ...input.Input) (*wire.MsgTx,
|
|||||||
// nLockTime, and output are already included in the TxWeightEstimator.
|
// nLockTime, and output are already included in the TxWeightEstimator.
|
||||||
weightEstimate.AddP2TROutput()
|
weightEstimate.AddP2TROutput()
|
||||||
|
|
||||||
|
// If any of our inputs has a resolution blob, then we'll add another
|
||||||
|
// P2TR output.
|
||||||
|
hasBlobs := fn.Any(func(i input.Input) bool {
|
||||||
|
return i.ResolutionBlob().IsSome()
|
||||||
|
}, inputs)
|
||||||
|
if hasBlobs {
|
||||||
|
weightEstimate.AddP2TROutput()
|
||||||
|
}
|
||||||
|
|
||||||
// Next, we iterate over the breached outputs contained in the
|
// Next, we iterate over the breached outputs contained in the
|
||||||
// retribution info. For each, we switch over the witness type such
|
// retribution info. For each, we switch over the witness type such
|
||||||
// that we contribute the appropriate weight for each input and
|
// that we contribute the appropriate weight for each input and
|
||||||
@ -1517,13 +1574,13 @@ func (b *BreachArbitrator) createSweepTx(inputs ...input.Input) (*wire.MsgTx,
|
|||||||
// sweepSpendableOutputsTxn creates a signed transaction from a sequence of
|
// sweepSpendableOutputsTxn creates a signed transaction from a sequence of
|
||||||
// spendable outputs by sweeping the funds into a single p2wkh output.
|
// spendable outputs by sweeping the funds into a single p2wkh output.
|
||||||
func (b *BreachArbitrator) sweepSpendableOutputsTxn(txWeight lntypes.WeightUnit,
|
func (b *BreachArbitrator) sweepSpendableOutputsTxn(txWeight lntypes.WeightUnit,
|
||||||
inputs ...input.Input) (*wire.MsgTx, error) {
|
inputs ...input.Input) (*justiceTxCtx, error) {
|
||||||
|
|
||||||
// First, we obtain a new public key script from the wallet which we'll
|
// First, we obtain a new public key script from the wallet which we'll
|
||||||
// sweep the funds to.
|
// sweep the funds to.
|
||||||
// TODO(roasbeef): possibly create many outputs to minimize change in
|
// TODO(roasbeef): possibly create many outputs to minimize change in
|
||||||
// the future?
|
// the future?
|
||||||
pkScript, err := b.cfg.GenSweepScript()
|
pkScript, err := b.cfg.GenSweepScript().Unpack()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1542,6 +1599,18 @@ func (b *BreachArbitrator) sweepSpendableOutputsTxn(txWeight lntypes.WeightUnit,
|
|||||||
}
|
}
|
||||||
txFee := feePerKw.FeeForWeight(txWeight)
|
txFee := feePerKw.FeeForWeight(txWeight)
|
||||||
|
|
||||||
|
// At this point, we'll check to see if we have any extra outputs to
|
||||||
|
// add from the aux sweeper.
|
||||||
|
extraChangeOut := fn.MapOptionZ(
|
||||||
|
b.cfg.AuxSweeper,
|
||||||
|
func(aux sweep.AuxSweeper) fn.Result[sweep.SweepOutput] {
|
||||||
|
return aux.DeriveSweepAddr(inputs, pkScript)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err := extraChangeOut.Err(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): already start to siphon their funds into fees
|
// TODO(roasbeef): already start to siphon their funds into fees
|
||||||
sweepAmt := int64(totalAmt - txFee)
|
sweepAmt := int64(totalAmt - txFee)
|
||||||
|
|
||||||
@ -1549,12 +1618,22 @@ func (b *BreachArbitrator) sweepSpendableOutputsTxn(txWeight lntypes.WeightUnit,
|
|||||||
// information gathered above and the provided retribution information.
|
// information gathered above and the provided retribution information.
|
||||||
txn := wire.NewMsgTx(2)
|
txn := wire.NewMsgTx(2)
|
||||||
|
|
||||||
// We begin by adding the output to which our funds will be deposited.
|
// First, we'll add the extra swep output if it exists, subtracting the
|
||||||
|
// amount from the sweep amt.
|
||||||
|
extraChangeOut.WhenResult(func(o sweep.SweepOutput) {
|
||||||
|
sweepAmt -= o.Value
|
||||||
|
|
||||||
|
txn.AddTxOut(&o.TxOut)
|
||||||
|
})
|
||||||
|
|
||||||
|
// Next, we'll add the output to which our funds will be deposited.
|
||||||
txn.AddTxOut(&wire.TxOut{
|
txn.AddTxOut(&wire.TxOut{
|
||||||
PkScript: pkScript,
|
PkScript: pkScript.DeliveryAddress,
|
||||||
Value: sweepAmt,
|
Value: sweepAmt,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// TODO(roasbeef): add other output change modify sweep amt
|
||||||
|
|
||||||
// Next, we add all of the spendable outputs as inputs to the
|
// Next, we add all of the spendable outputs as inputs to the
|
||||||
// transaction.
|
// transaction.
|
||||||
for _, inp := range inputs {
|
for _, inp := range inputs {
|
||||||
@ -1610,7 +1689,13 @@ func (b *BreachArbitrator) sweepSpendableOutputsTxn(txWeight lntypes.WeightUnit,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return txn, nil
|
return &justiceTxCtx{
|
||||||
|
justiceTx: txn,
|
||||||
|
sweepAddr: pkScript,
|
||||||
|
extraTxOut: extraChangeOut.Option(),
|
||||||
|
fee: txFee,
|
||||||
|
inputs: inputs,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// RetributionStore handles persistence of retribution states to disk and is
|
// RetributionStore handles persistence of retribution states to disk and is
|
||||||
@ -1642,12 +1727,28 @@ func taprootBriefcaseFromRetInfo(retInfo *retributionInfo) *taprootBriefcase {
|
|||||||
//nolint:lll
|
//nolint:lll
|
||||||
tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock = bo.signDesc.ControlBlock
|
tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock = bo.signDesc.ControlBlock
|
||||||
|
|
||||||
|
bo.resolutionBlob.WhenSome(func(blob tlv.Blob) {
|
||||||
|
tapCase.SettledCommitBlob = tlv.SomeRecordT(
|
||||||
|
tlv.NewPrimitiveRecord[tlv.TlvType2](
|
||||||
|
blob,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// To spend the revoked output again, we'll store the same
|
// To spend the revoked output again, we'll store the same
|
||||||
// control block value as above, but in a different place.
|
// control block value as above, but in a different place.
|
||||||
case input.TaprootCommitmentRevoke:
|
case input.TaprootCommitmentRevoke:
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
tapCase.CtrlBlocks.Val.RevokeSweepCtrlBlock = bo.signDesc.ControlBlock
|
tapCase.CtrlBlocks.Val.RevokeSweepCtrlBlock = bo.signDesc.ControlBlock
|
||||||
|
|
||||||
|
bo.resolutionBlob.WhenSome(func(blob tlv.Blob) {
|
||||||
|
tapCase.BreachedCommitBlob = tlv.SomeRecordT(
|
||||||
|
tlv.NewPrimitiveRecord[tlv.TlvType3](
|
||||||
|
blob,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// For spending the HTLC outputs, we'll store the first and
|
// For spending the HTLC outputs, we'll store the first and
|
||||||
// second level tweak values.
|
// second level tweak values.
|
||||||
case input.TaprootHtlcAcceptedRevoke:
|
case input.TaprootHtlcAcceptedRevoke:
|
||||||
@ -1685,12 +1786,22 @@ func applyTaprootRetInfo(tapCase *taprootBriefcase,
|
|||||||
//nolint:lll
|
//nolint:lll
|
||||||
bo.signDesc.ControlBlock = tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock
|
bo.signDesc.ControlBlock = tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock
|
||||||
|
|
||||||
|
tapCase.SettledCommitBlob.WhenSomeV(func(blob tlv.Blob) { //nolint:lll
|
||||||
|
bo.resolutionBlob = fn.Some(blob)
|
||||||
|
})
|
||||||
|
|
||||||
// To spend the revoked output again, we'll apply the same
|
// To spend the revoked output again, we'll apply the same
|
||||||
// control block value as above, but to a different place.
|
// control block value as above, but to a different place.
|
||||||
case input.TaprootCommitmentRevoke:
|
case input.TaprootCommitmentRevoke:
|
||||||
//nolint:lll
|
//nolint:lll
|
||||||
bo.signDesc.ControlBlock = tapCase.CtrlBlocks.Val.RevokeSweepCtrlBlock
|
bo.signDesc.ControlBlock = tapCase.CtrlBlocks.Val.RevokeSweepCtrlBlock
|
||||||
|
|
||||||
|
tapCase.BreachedCommitBlob.WhenSomeV(
|
||||||
|
func(blob tlv.Blob) {
|
||||||
|
bo.resolutionBlob = fn.Some(blob)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
// For spending the HTLC outputs, we'll apply the first and
|
// For spending the HTLC outputs, we'll apply the first and
|
||||||
// second level tweak values.
|
// second level tweak values.
|
||||||
case input.TaprootHtlcAcceptedRevoke:
|
case input.TaprootHtlcAcceptedRevoke:
|
||||||
|
@ -1199,6 +1199,8 @@ func TestBreachCreateJusticeTx(t *testing.T) {
|
|||||||
input.HtlcSecondLevelRevoke,
|
input.HtlcSecondLevelRevoke,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rBlob := fn.Some([]byte{0x01})
|
||||||
|
|
||||||
breachedOutputs := make([]breachedOutput, len(outputTypes))
|
breachedOutputs := make([]breachedOutput, len(outputTypes))
|
||||||
for i, wt := range outputTypes {
|
for i, wt := range outputTypes {
|
||||||
// Create a fake breached output for each type, ensuring they
|
// Create a fake breached output for each type, ensuring they
|
||||||
@ -1217,6 +1219,7 @@ func TestBreachCreateJusticeTx(t *testing.T) {
|
|||||||
nil,
|
nil,
|
||||||
signDesc,
|
signDesc,
|
||||||
1,
|
1,
|
||||||
|
rBlob,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1227,16 +1230,16 @@ func TestBreachCreateJusticeTx(t *testing.T) {
|
|||||||
|
|
||||||
// The spendAll tx should be spending all the outputs. This is the
|
// The spendAll tx should be spending all the outputs. This is the
|
||||||
// "regular" justice transaction type.
|
// "regular" justice transaction type.
|
||||||
require.Len(t, justiceTxs.spendAll.TxIn, len(breachedOutputs))
|
require.Len(t, justiceTxs.spendAll.justiceTx.TxIn, len(breachedOutputs))
|
||||||
|
|
||||||
// The spendCommitOuts tx should be spending the 4 types of commit outs
|
// The spendCommitOuts tx should be spending the 4 types of commit outs
|
||||||
// (note that in practice there will be at most two commit outputs per
|
// (note that in practice there will be at most two commit outputs per
|
||||||
// commit, but we test all 4 types here).
|
// commit, but we test all 4 types here).
|
||||||
require.Len(t, justiceTxs.spendCommitOuts.TxIn, 4)
|
require.Len(t, justiceTxs.spendCommitOuts.justiceTx.TxIn, 4)
|
||||||
|
|
||||||
// Check that the spendHTLCs tx is spending the two revoked commitment
|
// Check that the spendHTLCs tx is spending the two revoked commitment
|
||||||
// level HTLC output types.
|
// level HTLC output types.
|
||||||
require.Len(t, justiceTxs.spendHTLCs.TxIn, 2)
|
require.Len(t, justiceTxs.spendHTLCs.justiceTx.TxIn, 2)
|
||||||
|
|
||||||
// Finally, check that the spendSecondLevelHTLCs txs are spending the
|
// Finally, check that the spendSecondLevelHTLCs txs are spending the
|
||||||
// second level type.
|
// second level type.
|
||||||
@ -2131,15 +2134,19 @@ func createTestArbiter(t *testing.T, contractBreaches chan *ContractBreachEvent,
|
|||||||
// Assemble our test arbiter.
|
// Assemble our test arbiter.
|
||||||
notifier := mock.MakeMockSpendNotifier()
|
notifier := mock.MakeMockSpendNotifier()
|
||||||
ba := NewBreachArbitrator(&BreachConfig{
|
ba := NewBreachArbitrator(&BreachConfig{
|
||||||
CloseLink: func(_ *wire.OutPoint, _ ChannelCloseType) {},
|
CloseLink: func(_ *wire.OutPoint, _ ChannelCloseType) {},
|
||||||
DB: db.ChannelStateDB(),
|
DB: db.ChannelStateDB(),
|
||||||
Estimator: chainfee.NewStaticEstimator(12500, 0),
|
Estimator: chainfee.NewStaticEstimator(12500, 0),
|
||||||
GenSweepScript: func() ([]byte, error) { return nil, nil },
|
GenSweepScript: func() fn.Result[lnwallet.AddrWithKey] {
|
||||||
ContractBreaches: contractBreaches,
|
return fn.Ok(lnwallet.AddrWithKey{})
|
||||||
Signer: signer,
|
},
|
||||||
Notifier: notifier,
|
ContractBreaches: contractBreaches,
|
||||||
PublishTransaction: func(_ *wire.MsgTx, _ string) error { return nil },
|
Signer: signer,
|
||||||
Store: store,
|
Notifier: notifier,
|
||||||
|
PublishTransaction: func(_ *wire.MsgTx, _ string) error {
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
Store: store,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := ba.Start(); err != nil {
|
if err := ba.Start(); err != nil {
|
||||||
|
@ -1558,7 +1558,7 @@ func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
|
|||||||
tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock = commitSignDesc.ControlBlock
|
tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock = commitSignDesc.ControlBlock
|
||||||
|
|
||||||
c.CommitResolution.ResolutionBlob.WhenSome(func(b []byte) {
|
c.CommitResolution.ResolutionBlob.WhenSome(func(b []byte) {
|
||||||
tapCase.CommitBlob = tlv.SomeRecordT(
|
tapCase.SettledCommitBlob = tlv.SomeRecordT(
|
||||||
tlv.NewPrimitiveRecord[tlv.TlvType2](b),
|
tlv.NewPrimitiveRecord[tlv.TlvType2](b),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1649,7 +1649,7 @@ func decodeTapRootAuxData(r io.Reader, c *ContractResolutions) error {
|
|||||||
c.CommitResolution.SelfOutputSignDesc.ControlBlock =
|
c.CommitResolution.SelfOutputSignDesc.ControlBlock =
|
||||||
tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock
|
tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock
|
||||||
|
|
||||||
tapCase.CommitBlob.WhenSomeV(func(b []byte) {
|
tapCase.SettledCommitBlob.WhenSomeV(func(b []byte) {
|
||||||
c.CommitResolution.ResolutionBlob = fn.Some(b)
|
c.CommitResolution.ResolutionBlob = fn.Some(b)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -30,10 +30,16 @@ type taprootBriefcase struct {
|
|||||||
// revocation paths.
|
// revocation paths.
|
||||||
TapTweaks tlv.RecordT[tlv.TlvType1, tapTweaks]
|
TapTweaks tlv.RecordT[tlv.TlvType1, tapTweaks]
|
||||||
|
|
||||||
// CommitBlob is an optional record that contains an opaque blob that
|
// SettledCommitBlob is an optional record that contains an opaque blob
|
||||||
// may be used to properly sweep commitment outputs on a force close
|
// that may be used to properly sweep commitment outputs on a force
|
||||||
// transaction.
|
// close transaction.
|
||||||
CommitBlob tlv.OptionalRecordT[tlv.TlvType2, tlv.Blob]
|
SettledCommitBlob tlv.OptionalRecordT[tlv.TlvType2, tlv.Blob]
|
||||||
|
|
||||||
|
// BreachCommitBlob is an optional record that contains an opaque blob
|
||||||
|
// used to sweep a remote party's breached output.
|
||||||
|
BreachedCommitBlob tlv.OptionalRecordT[tlv.TlvType3, tlv.Blob]
|
||||||
|
|
||||||
|
// TODO(roasbeef): htlc blobs
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(roasbeef): morph into new tlv record
|
// TODO(roasbeef): morph into new tlv record
|
||||||
@ -53,9 +59,16 @@ func (t *taprootBriefcase) EncodeRecords() []tlv.Record {
|
|||||||
t.CtrlBlocks.Record(), t.TapTweaks.Record(),
|
t.CtrlBlocks.Record(), t.TapTweaks.Record(),
|
||||||
}
|
}
|
||||||
|
|
||||||
t.CommitBlob.WhenSome(func(r tlv.RecordT[tlv.TlvType2, tlv.Blob]) {
|
t.SettledCommitBlob.WhenSome(
|
||||||
records = append(records, r.Record())
|
func(r tlv.RecordT[tlv.TlvType2, tlv.Blob]) {
|
||||||
})
|
records = append(records, r.Record())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
t.BreachedCommitBlob.WhenSome(
|
||||||
|
func(r tlv.RecordT[tlv.TlvType3, tlv.Blob]) {
|
||||||
|
records = append(records, r.Record())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
return records
|
return records
|
||||||
}
|
}
|
||||||
@ -79,8 +92,12 @@ func (t *taprootBriefcase) Encode(w io.Writer) error {
|
|||||||
|
|
||||||
// Decode decodes the given reader into the target struct.
|
// Decode decodes the given reader into the target struct.
|
||||||
func (t *taprootBriefcase) Decode(r io.Reader) error {
|
func (t *taprootBriefcase) Decode(r io.Reader) error {
|
||||||
commitBlob := t.CommitBlob.Zero()
|
settledCommitBlob := t.SettledCommitBlob.Zero()
|
||||||
records := append(t.DecodeRecords(), commitBlob.Record())
|
breachedCommitBlob := t.BreachedCommitBlob.Zero()
|
||||||
|
records := append(
|
||||||
|
t.DecodeRecords(), settledCommitBlob.Record(),
|
||||||
|
breachedCommitBlob.Record(),
|
||||||
|
)
|
||||||
stream, err := tlv.NewStream(records...)
|
stream, err := tlv.NewStream(records...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -91,8 +108,11 @@ func (t *taprootBriefcase) Decode(r io.Reader) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if val, ok := typeMap[t.CommitBlob.TlvType()]; ok && val == nil {
|
if val, ok := typeMap[t.SettledCommitBlob.TlvType()]; ok && val == nil {
|
||||||
t.CommitBlob = tlv.SomeRecordT(commitBlob)
|
t.SettledCommitBlob = tlv.SomeRecordT(settledCommitBlob)
|
||||||
|
}
|
||||||
|
if v, ok := typeMap[t.BreachedCommitBlob.TlvType()]; ok && v == nil {
|
||||||
|
t.BreachedCommitBlob = tlv.SomeRecordT(breachedCommitBlob)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -87,9 +87,12 @@ func TestTaprootBriefcase(t *testing.T) {
|
|||||||
BreachedHtlcTweaks: randHtlcTweaks(t),
|
BreachedHtlcTweaks: randHtlcTweaks(t),
|
||||||
BreachedSecondLevelHltcTweaks: randHtlcTweaks(t),
|
BreachedSecondLevelHltcTweaks: randHtlcTweaks(t),
|
||||||
}),
|
}),
|
||||||
CommitBlob: tlv.SomeRecordT(
|
SettledCommitBlob: tlv.SomeRecordT(
|
||||||
tlv.NewPrimitiveRecord[tlv.TlvType2](commitBlob[:]),
|
tlv.NewPrimitiveRecord[tlv.TlvType2](commitBlob[:]),
|
||||||
),
|
),
|
||||||
|
BreachedCommitBlob: tlv.SomeRecordT(
|
||||||
|
tlv.NewPrimitiveRecord[tlv.TlvType3](commitBlob[:]),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/labels"
|
"github.com/lightningnetwork/lnd/labels"
|
||||||
"github.com/lightningnetwork/lnd/lnwallet"
|
"github.com/lightningnetwork/lnd/lnwallet"
|
||||||
"github.com/lightningnetwork/lnd/sweep"
|
"github.com/lightningnetwork/lnd/sweep"
|
||||||
|
"github.com/lightningnetwork/lnd/tlv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SUMMARY OF OUTPUT STATES
|
// SUMMARY OF OUTPUT STATES
|
||||||
@ -1425,6 +1426,7 @@ func makeKidOutput(outpoint, originChanPoint *wire.OutPoint,
|
|||||||
return kidOutput{
|
return kidOutput{
|
||||||
breachedOutput: makeBreachedOutput(
|
breachedOutput: makeBreachedOutput(
|
||||||
outpoint, witnessType, nil, signDescriptor, heightHint,
|
outpoint, witnessType, nil, signDescriptor, heightHint,
|
||||||
|
fn.None[tlv.Blob](),
|
||||||
),
|
),
|
||||||
isHtlc: isHtlc,
|
isHtlc: isHtlc,
|
||||||
originChanPoint: *originChanPoint,
|
originChanPoint: *originChanPoint,
|
||||||
|
@ -69,6 +69,12 @@ type ResolutionReq struct {
|
|||||||
// CsvDelay is the CSV delay for the local output for this commitment.
|
// CsvDelay is the CSV delay for the local output for this commitment.
|
||||||
CsvDelay uint32
|
CsvDelay uint32
|
||||||
|
|
||||||
|
// BreachCsvDelay is the CSV delay for the remote output. This is only
|
||||||
|
// set when the CloseType is Breach. This indicates the CSV delay to
|
||||||
|
// use for the remote party's to_local delayed output, that is now
|
||||||
|
// rightfully ours in a breach situation.
|
||||||
|
BreachCsvDelay fn.Option[uint32]
|
||||||
|
|
||||||
// CltvDelay is the CLTV delay for the outpoint.
|
// CltvDelay is the CLTV delay for the outpoint.
|
||||||
CltvDelay fn.Option[uint32]
|
CltvDelay fn.Option[uint32]
|
||||||
}
|
}
|
||||||
|
@ -2466,6 +2466,10 @@ type HtlcRetribution struct {
|
|||||||
// this HTLC was offered by us. This flag is used determine the exact
|
// this HTLC was offered by us. This flag is used determine the exact
|
||||||
// witness type should be used to sweep the output.
|
// witness type should be used to sweep the output.
|
||||||
IsIncoming bool
|
IsIncoming bool
|
||||||
|
|
||||||
|
// ResolutionBlob is a blob used for aux channels that permits a
|
||||||
|
// spender of this output to claim all funds.
|
||||||
|
ResolutionBlob fn.Option[tlv.Blob]
|
||||||
}
|
}
|
||||||
|
|
||||||
// BreachRetribution contains all the data necessary to bring a channel
|
// BreachRetribution contains all the data necessary to bring a channel
|
||||||
@ -2536,10 +2540,13 @@ type BreachRetribution struct {
|
|||||||
// have access to the public keys used in the scripts.
|
// have access to the public keys used in the scripts.
|
||||||
KeyRing *CommitmentKeyRing
|
KeyRing *CommitmentKeyRing
|
||||||
|
|
||||||
// ResolutionBlob is a blob used for aux channels that permits a
|
// LocalResolutionBlob is a blob used for aux channels that permits an
|
||||||
// spender of the output to properly resolve it in the case of a force
|
// honest party to sweep the local commitment output.
|
||||||
// close.
|
LocalResolutionBlob fn.Option[tlv.Blob]
|
||||||
ResolutionBlob fn.Option[tlv.Blob]
|
|
||||||
|
// RemoteResolutionBlob is a blob used for aux channels that permits an
|
||||||
|
// honest party to sweep the remote commitment output.
|
||||||
|
RemoteResolutionBlob fn.Option[tlv.Blob]
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBreachRetribution creates a new fully populated BreachRetribution for the
|
// NewBreachRetribution creates a new fully populated BreachRetribution for the
|
||||||
@ -2552,7 +2559,8 @@ type BreachRetribution struct {
|
|||||||
func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||||
breachHeight uint32, spendTx *wire.MsgTx,
|
breachHeight uint32, spendTx *wire.MsgTx,
|
||||||
leafStore fn.Option[AuxLeafStore],
|
leafStore fn.Option[AuxLeafStore],
|
||||||
auxResolver fn.Option[AuxContractResolver]) (*BreachRetribution, error) { //nolint:lll
|
auxResolver fn.Option[AuxContractResolver]) (*BreachRetribution,
|
||||||
|
error) {
|
||||||
|
|
||||||
// Query the on-disk revocation log for the snapshot which was recorded
|
// Query the on-disk revocation log for the snapshot which was recorded
|
||||||
// at this particular state num. Based on whether a legacy revocation
|
// at this particular state num. Based on whether a legacy revocation
|
||||||
@ -2604,26 +2612,26 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
|
|
||||||
// Since it is the remote breach we are reconstructing, the output
|
// Since it is the remote breach we are reconstructing, the output
|
||||||
// going to us will be a to-remote script with our local params.
|
// going to us will be a to-remote script with our local params.
|
||||||
localAuxLeaf := fn.MapOption(func(l CommitAuxLeaves) input.AuxTapLeaf {
|
remoteAuxLeaf := fn.MapOption(func(l CommitAuxLeaves) input.AuxTapLeaf {
|
||||||
return l.LocalAuxLeaf
|
return l.RemoteAuxLeaf
|
||||||
})(auxLeaves)
|
})(auxLeaves)
|
||||||
isRemoteInitiator := !chanState.IsInitiator
|
isRemoteInitiator := !chanState.IsInitiator
|
||||||
ourScript, ourDelay, err := CommitScriptToRemote(
|
ourScript, ourDelay, err := CommitScriptToRemote(
|
||||||
chanState.ChanType, isRemoteInitiator, keyRing.ToRemoteKey,
|
chanState.ChanType, isRemoteInitiator, keyRing.ToRemoteKey,
|
||||||
leaseExpiry, fn.FlattenOption(localAuxLeaf),
|
leaseExpiry, fn.FlattenOption(remoteAuxLeaf),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteAuxLeaf := fn.MapOption(func(l CommitAuxLeaves) input.AuxTapLeaf {
|
localAuxLeaf := fn.MapOption(func(l CommitAuxLeaves) input.AuxTapLeaf {
|
||||||
return l.RemoteAuxLeaf
|
return l.LocalAuxLeaf
|
||||||
})(auxLeaves)
|
})(auxLeaves)
|
||||||
theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
||||||
theirScript, err := CommitScriptToSelf(
|
theirScript, err := CommitScriptToSelf(
|
||||||
chanState.ChanType, isRemoteInitiator, keyRing.ToLocalKey,
|
chanState.ChanType, isRemoteInitiator, keyRing.ToLocalKey,
|
||||||
keyRing.RevocationKey, theirDelay, leaseExpiry,
|
keyRing.RevocationKey, theirDelay, leaseExpiry,
|
||||||
fn.FlattenOption(remoteAuxLeaf),
|
fn.FlattenOption(localAuxLeaf),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -2716,19 +2724,21 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
resolveBlob := fn.MapOptionZ(
|
resolveBlob := fn.MapOptionZ(
|
||||||
auxResolver,
|
auxResolver,
|
||||||
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
||||||
|
//nolint:lll
|
||||||
return a.ResolveContract(ResolutionReq{
|
return a.ResolveContract(ResolutionReq{
|
||||||
ChanPoint: chanState.FundingOutpoint,
|
ChanPoint: chanState.FundingOutpoint,
|
||||||
ShortChanID: chanState.ShortChanID(),
|
ShortChanID: chanState.ShortChanID(),
|
||||||
Initiator: chanState.IsInitiator,
|
Initiator: chanState.IsInitiator,
|
||||||
CommitBlob: chanState.RemoteCommitment.CustomBlob, //nolint:lll
|
CommitBlob: revokedLog.CustomBlob.ValOpt(),
|
||||||
FundingBlob: chanState.CustomBlob,
|
FundingBlob: chanState.CustomBlob,
|
||||||
Type: input.TaprootRemoteCommitSpend, //nolint:lll
|
Type: input.TaprootRemoteCommitSpend,
|
||||||
CloseType: Breach,
|
CloseType: Breach,
|
||||||
CommitTx: spendTx,
|
CommitTx: spendTx,
|
||||||
SignDesc: *br.LocalOutputSignDesc,
|
SignDesc: *br.LocalOutputSignDesc,
|
||||||
KeyRing: keyRing,
|
KeyRing: keyRing,
|
||||||
CsvDelay: theirDelay,
|
CsvDelay: ourDelay,
|
||||||
CommitFee: chanState.RemoteCommitment.CommitFee, //nolint:lll
|
BreachCsvDelay: fn.Some(theirDelay),
|
||||||
|
CommitFee: chanState.RemoteCommitment.CommitFee,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -2736,7 +2746,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
br.ResolutionBlob = resolveBlob.Option()
|
br.LocalResolutionBlob = resolveBlob.Option()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Similarly, if their balance exceeds the remote party's dust limit,
|
// Similarly, if their balance exceeds the remote party's dust limit,
|
||||||
@ -2790,19 +2800,21 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
resolveBlob := fn.MapOptionZ(
|
resolveBlob := fn.MapOptionZ(
|
||||||
auxResolver,
|
auxResolver,
|
||||||
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
func(a AuxContractResolver) fn.Result[tlv.Blob] {
|
||||||
|
//nolint:lll
|
||||||
return a.ResolveContract(ResolutionReq{
|
return a.ResolveContract(ResolutionReq{
|
||||||
ChanPoint: chanState.FundingOutpoint,
|
ChanPoint: chanState.FundingOutpoint,
|
||||||
ShortChanID: chanState.ShortChanID(),
|
ShortChanID: chanState.ShortChanID(),
|
||||||
Initiator: chanState.IsInitiator,
|
Initiator: chanState.IsInitiator,
|
||||||
CommitBlob: chanState.RemoteCommitment.CustomBlob, //nolint:lll
|
CommitBlob: revokedLog.CustomBlob.ValOpt(),
|
||||||
FundingBlob: chanState.CustomBlob,
|
FundingBlob: chanState.CustomBlob,
|
||||||
Type: input.TaprootCommitmentRevoke, //nolint:lll
|
Type: input.TaprootCommitmentRevoke,
|
||||||
CloseType: Breach,
|
CloseType: Breach,
|
||||||
CommitTx: spendTx,
|
CommitTx: spendTx,
|
||||||
SignDesc: *br.RemoteOutputSignDesc,
|
SignDesc: *br.RemoteOutputSignDesc,
|
||||||
KeyRing: keyRing,
|
KeyRing: keyRing,
|
||||||
CsvDelay: theirDelay,
|
CsvDelay: theirDelay,
|
||||||
CommitFee: chanState.RemoteCommitment.CommitFee, //nolint:lll
|
BreachCsvDelay: fn.Some(theirDelay),
|
||||||
|
CommitFee: chanState.RemoteCommitment.CommitFee,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -2810,7 +2822,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
|||||||
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
return nil, fmt.Errorf("unable to aux resolve: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
br.ResolutionBlob = resolveBlob.Option()
|
br.RemoteResolutionBlob = resolveBlob.Option()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, with all the necessary data constructed, we can pad the
|
// Finally, with all the necessary data constructed, we can pad the
|
||||||
|
14
server.go
14
server.go
@ -1152,16 +1152,9 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
CloseLink: closeLink,
|
CloseLink: closeLink,
|
||||||
DB: s.chanStateDB,
|
DB: s.chanStateDB,
|
||||||
Estimator: s.cc.FeeEstimator,
|
Estimator: s.cc.FeeEstimator,
|
||||||
GenSweepScript: func() ([]byte, error) {
|
GenSweepScript: newSweepPkScriptGen(
|
||||||
addr, err := newSweepPkScriptGen(
|
cc.Wallet, s.cfg.ActiveNetParams.Params,
|
||||||
cc.Wallet, netParams,
|
),
|
||||||
)().Unpack()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr.DeliveryAddress, nil
|
|
||||||
},
|
|
||||||
Notifier: cc.ChainNotifier,
|
Notifier: cc.ChainNotifier,
|
||||||
PublishTransaction: cc.Wallet.PublishTransaction,
|
PublishTransaction: cc.Wallet.PublishTransaction,
|
||||||
ContractBreaches: contractBreaches,
|
ContractBreaches: contractBreaches,
|
||||||
@ -1169,6 +1162,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||||||
Store: contractcourt.NewRetributionStore(
|
Store: contractcourt.NewRetributionStore(
|
||||||
dbs.ChanStateDB,
|
dbs.ChanStateDB,
|
||||||
),
|
),
|
||||||
|
AuxSweeper: s.implCfg.AuxSweeper,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user