Merge pull request #6810 from Roasbeef/taproot-errwhere
multi: use taproot errwhere applicable for change/delivery/tower addresses
This commit is contained in:
18 files changed
+136
-66
No files matched your search
@@ -1347,9 +1347,9 @@ func (b *BreachArbiter) createSweepTx(inputs []input.Input) (*wire.MsgTx,
|
|||||||
spendableOutputs = make([]input.Input, 0, len(inputs))
|
spendableOutputs = make([]input.Input, 0, len(inputs))
|
||||||
|
|
||||||
// The justice transaction we construct will be a segwit transaction
|
// The justice transaction we construct will be a segwit transaction
|
||||||
// that pays to a p2wkh output. Components such as the version,
|
// that pays to a p2tr output. Components such as the version,
|
||||||
// nLockTime, and output are already included in the TxWeightEstimator.
|
// nLockTime, and output are already included in the TxWeightEstimator.
|
||||||
weightEstimate.AddP2WKHOutput()
|
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
|
||||||
|
|||||||
@@ -21,12 +21,15 @@
|
|||||||
|
|
||||||
## Taproot
|
## Taproot
|
||||||
|
|
||||||
[`lnd` will now refuse to start if it detects the full node backned does not
|
[`lnd` will now refuse to start if it detects the full node backend does not
|
||||||
support Tapoot](https://github.com/lightningnetwork/lnd/pull/6798).
|
support Tapoot](https://github.com/lightningnetwork/lnd/pull/6798).
|
||||||
|
|
||||||
[`lnd` will now use taproot addresses for co-op closes if the remote peer
|
[`lnd` will now use taproot addresses for co-op closes if the remote peer
|
||||||
supports the feature.](https://github.com/lightningnetwork/lnd/pull/6633)
|
supports the feature.](https://github.com/lightningnetwork/lnd/pull/6633)
|
||||||
|
|
||||||
|
The [wallet also creates P2TR change addresses by
|
||||||
|
default](https://github.com/lightningnetwork/lnd/pull/6810) in most cases.
|
||||||
|
|
||||||
## `lncli`
|
## `lncli`
|
||||||
|
|
||||||
* [Add `payment_addr` flag to
|
* [Add `payment_addr` flag to
|
||||||
|
|||||||
@@ -458,7 +458,7 @@ func Main(cfg *Config, lisCfg ListenerCfg, implCfg *ImplementationCfg,
|
|||||||
Net: cfg.net,
|
Net: cfg.net,
|
||||||
NewAddress: func() (btcutil.Address, error) {
|
NewAddress: func() (btcutil.Address, error) {
|
||||||
return activeChainControl.Wallet.NewAddress(
|
return activeChainControl.Wallet.NewAddress(
|
||||||
lnwallet.WitnessPubKey, false,
|
lnwallet.TaprootPubkey, false,
|
||||||
lnwallet.DefaultAccountName,
|
lnwallet.DefaultAccountName,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -98,8 +98,8 @@ func calculateFees(utxos []Coin, feeRate chainfee.SatPerKWeight) (btcutil.Amount
|
|||||||
requiredFeeNoChange := feeRate.FeeForWeight(totalWeight)
|
requiredFeeNoChange := feeRate.FeeForWeight(totalWeight)
|
||||||
|
|
||||||
// Estimate the fee required for a transaction with a change output.
|
// Estimate the fee required for a transaction with a change output.
|
||||||
// Assume that change output is a P2WKH output.
|
// Assume that change output is a P2TR output.
|
||||||
weightEstimate.AddP2WKHOutput()
|
weightEstimate.AddP2TROutput()
|
||||||
|
|
||||||
// Now that we have added the change output, redo the fee
|
// Now that we have added the change output, redo the fee
|
||||||
// estimate.
|
// estimate.
|
||||||
@@ -209,7 +209,8 @@ func CoinSelectSubtractFees(feeRate chainfee.SatPerKWeight, amt,
|
|||||||
// Obtain fee estimates both with and without using a change
|
// Obtain fee estimates both with and without using a change
|
||||||
// output.
|
// output.
|
||||||
requiredFeeNoChange, requiredFeeWithChange, err := calculateFees(
|
requiredFeeNoChange, requiredFeeWithChange, err := calculateFees(
|
||||||
selectedUtxos, feeRate)
|
selectedUtxos, feeRate,
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, 0, err
|
return nil, 0, 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ func fundingFee(feeRate chainfee.SatPerKWeight, numInput int, // nolint:unparam
|
|||||||
|
|
||||||
// Optionally count a change output.
|
// Optionally count a change output.
|
||||||
if change {
|
if change {
|
||||||
weightEstimate.AddP2WKHOutput()
|
weightEstimate.AddP2TROutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
totalWeight := int64(weightEstimate.Weight())
|
totalWeight := int64(weightEstimate.Weight())
|
||||||
@@ -81,7 +81,7 @@ func TestCalculateFees(t *testing.T) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
expectedFeeNoChange: 487,
|
expectedFeeNoChange: 487,
|
||||||
expectedFeeWithChange: 611,
|
expectedFeeWithChange: 659,
|
||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ func TestCalculateFees(t *testing.T) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
expectedFeeNoChange: 579,
|
expectedFeeNoChange: 579,
|
||||||
expectedFeeWithChange: 703,
|
expectedFeeWithChange: 751,
|
||||||
expectedErr: nil,
|
expectedErr: nil,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import (
|
|||||||
//
|
//
|
||||||
// Steps to final channel provisioning:
|
// Steps to final channel provisioning:
|
||||||
// 1. Call BindKeys to notify the intent which keys to use when constructing
|
// 1. Call BindKeys to notify the intent which keys to use when constructing
|
||||||
// the multi-sig output.
|
// the multi-sig output.
|
||||||
// 2. Call CompileFundingTx afterwards to obtain the funding transaction.
|
// 2. Call CompileFundingTx afterwards to obtain the funding transaction.
|
||||||
//
|
//
|
||||||
// If either of these steps fail, then the Cancel method MUST be called.
|
// If either of these steps fail, then the Cancel method MUST be called.
|
||||||
|
|||||||
@@ -2708,6 +2708,14 @@ var walletTests = []walletTestCase{
|
|||||||
name: "change output spend confirmation",
|
name: "change output spend confirmation",
|
||||||
test: testChangeOutputSpendConfirmation,
|
test: testChangeOutputSpendConfirmation,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// TODO(guggero): this test should remain second until dual
|
||||||
|
// funding can properly exchange full UTXO information and we
|
||||||
|
// can use P2TR change outputs as the funding inputs for a dual
|
||||||
|
// funded channel.
|
||||||
|
name: "dual funder workflow",
|
||||||
|
test: testDualFundingReservationWorkflow,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "spend unconfirmed outputs",
|
name: "spend unconfirmed outputs",
|
||||||
test: testSpendUnconfirmed,
|
test: testSpendUnconfirmed,
|
||||||
@@ -2744,10 +2752,6 @@ var walletTests = []walletTestCase{
|
|||||||
name: "single funding workflow external funding tx",
|
name: "single funding workflow external funding tx",
|
||||||
test: testSingleFunderExternalFundingTx,
|
test: testSingleFunderExternalFundingTx,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: "dual funder workflow",
|
|
||||||
test: testDualFundingReservationWorkflow,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "output locking",
|
name: "output locking",
|
||||||
test: testFundingTransactionLockedOutputs,
|
test: testFundingTransactionLockedOutputs,
|
||||||
|
|||||||
+1
-1
@@ -775,7 +775,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
|
|||||||
FeeRate: req.FundingFeePerKw,
|
FeeRate: req.FundingFeePerKw,
|
||||||
ChangeAddr: func() (btcutil.Address, error) {
|
ChangeAddr: func() (btcutil.Address, error) {
|
||||||
return l.NewAddress(
|
return l.NewAddress(
|
||||||
WitnessPubKey, true, DefaultAccountName,
|
TaprootPubkey, true, DefaultAccountName,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1330,7 +1330,7 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||||||
// ensures this is an address the wallet knows about,
|
// ensures this is an address the wallet knows about,
|
||||||
// allowing us to pass the reserved value check.
|
// allowing us to pass the reserved value check.
|
||||||
changeAddr, err := r.server.cc.Wallet.NewAddress(
|
changeAddr, err := r.server.cc.Wallet.NewAddress(
|
||||||
lnwallet.WitnessPubKey, true,
|
lnwallet.TaprootPubkey, true,
|
||||||
lnwallet.DefaultAccountName,
|
lnwallet.DefaultAccountName,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -4534,7 +4534,8 @@ func newSweepPkScriptGen(
|
|||||||
|
|
||||||
return func() ([]byte, error) {
|
return func() ([]byte, error) {
|
||||||
sweepAddr, err := wallet.NewAddress(
|
sweepAddr, err := wallet.NewAddress(
|
||||||
lnwallet.WitnessPubKey, false, lnwallet.DefaultAccountName,
|
lnwallet.TaprootPubkey, false,
|
||||||
|
lnwallet.DefaultAccountName,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ func newTxInputSet(wallet Wallet, feePerKW chainfee.SatPerKWeight,
|
|||||||
func (t *txInputSet) enoughInput() bool {
|
func (t *txInputSet) enoughInput() bool {
|
||||||
// If we have a change output above dust, then we certainly have enough
|
// If we have a change output above dust, then we certainly have enough
|
||||||
// inputs to the transaction.
|
// inputs to the transaction.
|
||||||
if t.changeOutput >= lnwallet.DustLimitForSize(input.P2WPKHSize) {
|
if t.changeOutput >= lnwallet.DustLimitForSize(input.P2TRSize) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ func generateInputPartitionings(sweepableInputs []txInput,
|
|||||||
// continuing with the remaining inputs will only lead to sets
|
// continuing with the remaining inputs will only lead to sets
|
||||||
// with an even lower output value.
|
// with an even lower output value.
|
||||||
if !txInputs.enoughInput() {
|
if !txInputs.enoughInput() {
|
||||||
// The change output is always a p2wpkh here.
|
// The change output is always a p2tr here.
|
||||||
dl := lnwallet.DustLimitForSize(input.P2WPKHSize)
|
dl := lnwallet.DustLimitForSize(input.P2TRSize)
|
||||||
log.Debugf("Set value %v (r=%v, c=%v) below dust "+
|
log.Debugf("Set value %v (r=%v, c=%v) below dust "+
|
||||||
"limit of %v", txInputs.totalOutput(),
|
"limit of %v", txInputs.totalOutput(),
|
||||||
txInputs.requiredOutput, txInputs.changeOutput,
|
txInputs.requiredOutput, txInputs.changeOutput,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcutil/txsort"
|
"github.com/btcsuite/btcd/btcutil/txsort"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
"github.com/lightningnetwork/lnd/watchtower/wtdb"
|
||||||
@@ -228,8 +229,8 @@ func (p *JusticeDescriptor) assembleJusticeTxn(txWeight int64,
|
|||||||
i := inputIndex[inp.outPoint]
|
i := inputIndex[inp.outPoint]
|
||||||
justiceTxn.TxIn[i].Witness = inp.witness
|
justiceTxn.TxIn[i].Witness = inp.witness
|
||||||
|
|
||||||
// Validate the reconstructed witnesses to ensure they are valid
|
// Validate the reconstructed witnesses to ensure they are
|
||||||
// for the breached inputs.
|
// valid for the breached inputs.
|
||||||
vm, err := txscript.NewEngine(
|
vm, err := txscript.NewEngine(
|
||||||
inp.txOut.PkScript, justiceTxn, i,
|
inp.txOut.PkScript, justiceTxn, i,
|
||||||
txscript.StandardVerifyFlags,
|
txscript.StandardVerifyFlags,
|
||||||
@@ -239,7 +240,9 @@ func (p *JusticeDescriptor) assembleJusticeTxn(txWeight int64,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := vm.Execute(); err != nil {
|
if err := vm.Execute(); err != nil {
|
||||||
return nil, err
|
log.Debugf("Failed to validate justice transaction: %s",
|
||||||
|
spew.Sdump(justiceTxn))
|
||||||
|
return nil, fmt.Errorf("error validating TX: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +303,9 @@ func (p *JusticeDescriptor) CreateJusticeTxn() (*wire.MsgTx, error) {
|
|||||||
|
|
||||||
sweepInputs = append(sweepInputs, toLocalInput)
|
sweepInputs = append(sweepInputs, toLocalInput)
|
||||||
|
|
||||||
|
log.Debugf("Found to local witness output=%#v, stack=%v",
|
||||||
|
toLocalInput.txOut, toLocalInput.witness)
|
||||||
|
|
||||||
// If the justice kit specifies that we have to sweep the to-remote
|
// If the justice kit specifies that we have to sweep the to-remote
|
||||||
// output, we'll also try to assemble the output and add it to weight
|
// output, we'll also try to assemble the output and add it to weight
|
||||||
// estimate if successful.
|
// estimate if successful.
|
||||||
@@ -310,6 +316,9 @@ func (p *JusticeDescriptor) CreateJusticeTxn() (*wire.MsgTx, error) {
|
|||||||
}
|
}
|
||||||
sweepInputs = append(sweepInputs, toRemoteInput)
|
sweepInputs = append(sweepInputs, toRemoteInput)
|
||||||
|
|
||||||
|
log.Debugf("Found to remote witness output=%#v, stack=%v",
|
||||||
|
toRemoteInput.txOut, toRemoteInput.witness)
|
||||||
|
|
||||||
if p.JusticeKit.BlobType.IsAnchorChannel() {
|
if p.JusticeKit.BlobType.IsAnchorChannel() {
|
||||||
weightEstimate.AddWitnessInput(input.ToRemoteConfirmedWitnessSize)
|
weightEstimate.AddWitnessInput(input.ToRemoteConfirmedWitnessSize)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/btcutil/txsort"
|
"github.com/btcsuite/btcd/btcutil/txsort"
|
||||||
|
"github.com/btcsuite/btcd/chaincfg"
|
||||||
"github.com/btcsuite/btcd/txscript"
|
"github.com/btcsuite/btcd/txscript"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/channeldb"
|
"github.com/lightningnetwork/lnd/channeldb"
|
||||||
@@ -151,6 +152,42 @@ func (t *backupTask) inputs() map[wire.OutPoint]input.Input {
|
|||||||
return inputs
|
return inputs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addrType returns the type of an address after parsing it and matching it to
|
||||||
|
// the set of known script templates.
|
||||||
|
func addrType(pkScript []byte) txscript.ScriptClass {
|
||||||
|
// We pass in a set of dummy chain params here as they're only needed
|
||||||
|
// to make the address struct, which we're ignoring anyway (scripts are
|
||||||
|
// always the same, it's addresses that change across chains).
|
||||||
|
scriptClass, _, _, _ := txscript.ExtractPkScriptAddrs(
|
||||||
|
pkScript, &chaincfg.MainNetParams,
|
||||||
|
)
|
||||||
|
|
||||||
|
return scriptClass
|
||||||
|
}
|
||||||
|
|
||||||
|
// addScriptWeight parses the passed pkScript and adds the computed weight cost
|
||||||
|
// were the script to be added to the justice transaction.
|
||||||
|
func addScriptWeight(weightEstimate *input.TxWeightEstimator,
|
||||||
|
pkScript []byte) error {
|
||||||
|
|
||||||
|
switch addrType(pkScript) { //nolint: whitespace
|
||||||
|
|
||||||
|
case txscript.WitnessV0PubKeyHashTy:
|
||||||
|
weightEstimate.AddP2WKHOutput()
|
||||||
|
|
||||||
|
case txscript.WitnessV0ScriptHashTy:
|
||||||
|
weightEstimate.AddP2WSHOutput()
|
||||||
|
|
||||||
|
case txscript.WitnessV1TaprootTy:
|
||||||
|
weightEstimate.AddP2TROutput()
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid addr type: %v", addrType(pkScript))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// bindSession determines if the backupTask is compatible with the passed
|
// bindSession determines if the backupTask is compatible with the passed
|
||||||
// SessionInfo's policy. If no error is returned, the task has been bound to the
|
// SessionInfo's policy. If no error is returned, the task has been bound to the
|
||||||
// session and can be queued to upload to the tower. Otherwise, the bind failed
|
// session and can be queued to upload to the tower. Otherwise, the bind failed
|
||||||
@@ -192,13 +229,19 @@ func (t *backupTask) bindSession(session *wtdb.ClientSessionBody) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// All justice transactions have a p2wkh output paying to the victim.
|
// All justice transactions will either use segwit v0 (p2wkh + p2wsh)
|
||||||
weightEstimate.AddP2WKHOutput()
|
// or segwit v1 (p2tr).
|
||||||
|
if err := addScriptWeight(&weightEstimate, t.sweepPkScript); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// If the justice transaction has a reward output, add the output's
|
// If the justice transaction has a reward output, add the output's
|
||||||
// contribution to the weight estimate.
|
// contribution to the weight estimate.
|
||||||
if session.Policy.BlobType.Has(blob.FlagReward) {
|
if session.Policy.BlobType.Has(blob.FlagReward) {
|
||||||
weightEstimate.AddP2WKHOutput()
|
err := addScriptWeight(&weightEstimate, session.RewardPkScript)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if t.chanType.HasAnchors() != session.Policy.IsAnchorChannel() {
|
if t.chanType.HasAnchors() != session.Policy.IsAnchorChannel() {
|
||||||
|
|||||||
@@ -247,7 +247,7 @@ func genTaskTest(
|
|||||||
RewardPkScript: rewardScript,
|
RewardPkScript: rewardScript,
|
||||||
},
|
},
|
||||||
bindErr: bindErr,
|
bindErr: bindErr,
|
||||||
expSweepScript: makeAddrSlice(22),
|
expSweepScript: sweepAddr,
|
||||||
signer: signer,
|
signer: signer,
|
||||||
chanType: chanType,
|
chanType: chanType,
|
||||||
}
|
}
|
||||||
@@ -259,10 +259,18 @@ var (
|
|||||||
blobTypeCommitReward = (blob.FlagCommitOutputs | blob.FlagReward).Type()
|
blobTypeCommitReward = (blob.FlagCommitOutputs | blob.FlagReward).Type()
|
||||||
|
|
||||||
addr, _ = btcutil.DecodeAddress(
|
addr, _ = btcutil.DecodeAddress(
|
||||||
"mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz", &chaincfg.TestNet3Params,
|
"tb1pw8gzj8clt3v5lxykpgacpju5n8xteskt7gxhmudu6pa70nwfhe6s3unsyk",
|
||||||
|
&chaincfg.TestNet3Params,
|
||||||
)
|
)
|
||||||
|
|
||||||
addrScript, _ = txscript.PayToAddrScript(addr)
|
addrScript, _ = txscript.PayToAddrScript(addr)
|
||||||
|
|
||||||
|
sweepAddrScript, _ = btcutil.DecodeAddress(
|
||||||
|
"tb1qs3jyc9sf5kak3x0w99cav9u605aeu3t600xxx0",
|
||||||
|
&chaincfg.TestNet3Params,
|
||||||
|
)
|
||||||
|
|
||||||
|
sweepAddr, _ = txscript.PayToAddrScript(sweepAddrScript)
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestBackupTaskBind tests the initialization and binding of a backupTask to a
|
// TestBackupTaskBind tests the initialization and binding of a backupTask to a
|
||||||
@@ -297,9 +305,9 @@ func TestBackupTask(t *testing.T) {
|
|||||||
expSweepCommitNoRewardBoth int64 = 299241
|
expSweepCommitNoRewardBoth int64 = 299241
|
||||||
expSweepCommitNoRewardLocal int64 = 199514
|
expSweepCommitNoRewardLocal int64 = 199514
|
||||||
expSweepCommitNoRewardRemote int64 = 99561
|
expSweepCommitNoRewardRemote int64 = 99561
|
||||||
expSweepCommitRewardBoth int64 = 296117
|
expSweepCommitRewardBoth int64 = 296069
|
||||||
expSweepCommitRewardLocal int64 = 197390
|
expSweepCommitRewardLocal int64 = 197342
|
||||||
expSweepCommitRewardRemote int64 = 98437
|
expSweepCommitRewardRemote int64 = 98389
|
||||||
sweepFeeRateNoRewardRemoteDust chainfee.SatPerKWeight = 227500
|
sweepFeeRateNoRewardRemoteDust chainfee.SatPerKWeight = 227500
|
||||||
sweepFeeRateRewardRemoteDust chainfee.SatPerKWeight = 175350
|
sweepFeeRateRewardRemoteDust chainfee.SatPerKWeight = 175350
|
||||||
)
|
)
|
||||||
@@ -307,9 +315,9 @@ func TestBackupTask(t *testing.T) {
|
|||||||
expSweepCommitNoRewardBoth = 299236
|
expSweepCommitNoRewardBoth = 299236
|
||||||
expSweepCommitNoRewardLocal = 199513
|
expSweepCommitNoRewardLocal = 199513
|
||||||
expSweepCommitNoRewardRemote = 99557
|
expSweepCommitNoRewardRemote = 99557
|
||||||
expSweepCommitRewardBoth = 296112
|
expSweepCommitRewardBoth = 296064
|
||||||
expSweepCommitRewardLocal = 197389
|
expSweepCommitRewardLocal = 197341
|
||||||
expSweepCommitRewardRemote = 98433
|
expSweepCommitRewardRemote = 98385
|
||||||
sweepFeeRateNoRewardRemoteDust = 225400
|
sweepFeeRateNoRewardRemoteDust = 225400
|
||||||
sweepFeeRateRewardRemoteDust = 174100
|
sweepFeeRateRewardRemoteDust = 174100
|
||||||
}
|
}
|
||||||
@@ -436,7 +444,7 @@ func TestBackupTask(t *testing.T) {
|
|||||||
"commit reward, to-remote output only, creates dust",
|
"commit reward, to-remote output only, creates dust",
|
||||||
1, // stateNum
|
1, // stateNum
|
||||||
0, // toLocalAmt
|
0, // toLocalAmt
|
||||||
100000, // toRemoteAmt
|
108221, // toRemoteAmt
|
||||||
blobTypeCommitReward, // blobType
|
blobTypeCommitReward, // blobType
|
||||||
sweepFeeRateRewardRemoteDust, // sweepFeeRate
|
sweepFeeRateRewardRemoteDust, // sweepFeeRate
|
||||||
addrScript, // rewardScript
|
addrScript, // rewardScript
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ var (
|
|||||||
|
|
||||||
// addr is the server's reward address given to watchtower clients.
|
// addr is the server's reward address given to watchtower clients.
|
||||||
addr, _ = btcutil.DecodeAddress(
|
addr, _ = btcutil.DecodeAddress(
|
||||||
"mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz", &chaincfg.TestNet3Params,
|
"tb1pw8gzj8clt3v5lxykpgacpju5n8xteskt7gxhmudu6pa70nwfhe6s3unsyk",
|
||||||
|
&chaincfg.TestNet3Params,
|
||||||
)
|
)
|
||||||
|
|
||||||
addrScript, _ = txscript.PayToAddrScript(addr)
|
addrScript, _ = txscript.PayToAddrScript(addr)
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
|
|
||||||
"github.com/btcsuite/btcd/btcutil"
|
"github.com/btcsuite/btcd/btcutil"
|
||||||
"github.com/btcsuite/btcd/wire"
|
"github.com/btcsuite/btcd/wire"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
|
||||||
"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/watchtower/blob"
|
"github.com/lightningnetwork/lnd/watchtower/blob"
|
||||||
@@ -156,7 +155,7 @@ func (p Policy) Validate() error {
|
|||||||
// of the justice transaction and subtracting an amount that satisfies the
|
// of the justice transaction and subtracting an amount that satisfies the
|
||||||
// policy's fee rate.
|
// policy's fee rate.
|
||||||
func (p *Policy) ComputeAltruistOutput(totalAmt btcutil.Amount,
|
func (p *Policy) ComputeAltruistOutput(totalAmt btcutil.Amount,
|
||||||
txWeight int64) (btcutil.Amount, error) {
|
txWeight int64, sweepScript []byte) (btcutil.Amount, error) {
|
||||||
|
|
||||||
txFee := p.SweepFeeRate.FeeForWeight(txWeight)
|
txFee := p.SweepFeeRate.FeeForWeight(txWeight)
|
||||||
if txFee > totalAmt {
|
if txFee > totalAmt {
|
||||||
@@ -165,10 +164,9 @@ func (p *Policy) ComputeAltruistOutput(totalAmt btcutil.Amount,
|
|||||||
|
|
||||||
sweepAmt := totalAmt - txFee
|
sweepAmt := totalAmt - txFee
|
||||||
|
|
||||||
// TODO(conner): replace w/ configurable dust limit
|
// Check that the created outputs won't be dusty. We'll base the dust
|
||||||
// Check that the created outputs won't be dusty. The sweep pkscript is
|
// computation on the type of the script itself.
|
||||||
// currently a p2wpkh, so we'll use that script's dust limit.
|
if sweepAmt < lnwallet.DustLimitForSize(len(sweepScript)) {
|
||||||
if sweepAmt < lnwallet.DustLimitForSize(input.P2WPKHSize) {
|
|
||||||
return 0, ErrCreatesDust
|
return 0, ErrCreatesDust
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +178,8 @@ func (p *Policy) ComputeAltruistOutput(totalAmt btcutil.Amount,
|
|||||||
// and reward rate. The reward to he tower is subtracted first, before
|
// and reward rate. The reward to he tower is subtracted first, before
|
||||||
// splitting the remaining balance amongst the victim and fees.
|
// splitting the remaining balance amongst the victim and fees.
|
||||||
func (p *Policy) ComputeRewardOutputs(totalAmt btcutil.Amount,
|
func (p *Policy) ComputeRewardOutputs(totalAmt btcutil.Amount,
|
||||||
txWeight int64) (btcutil.Amount, btcutil.Amount, error) {
|
txWeight int64,
|
||||||
|
rewardScript []byte) (btcutil.Amount, btcutil.Amount, error) {
|
||||||
|
|
||||||
txFee := p.SweepFeeRate.FeeForWeight(txWeight)
|
txFee := p.SweepFeeRate.FeeForWeight(txWeight)
|
||||||
if txFee > totalAmt {
|
if txFee > totalAmt {
|
||||||
@@ -198,10 +197,9 @@ func (p *Policy) ComputeRewardOutputs(totalAmt btcutil.Amount,
|
|||||||
// input value.
|
// input value.
|
||||||
sweepAmt := totalAmt - rewardAmt - txFee
|
sweepAmt := totalAmt - rewardAmt - txFee
|
||||||
|
|
||||||
// TODO(conner): replace w/ configurable dust limit
|
// Check that the created outputs won't be dusty. We'll base the dust
|
||||||
// Check that the created outputs won't be dusty. The sweep pkscript is
|
// computation on the type of the script itself.
|
||||||
// currently a p2wpkh, so we'll use that script's dust limit.
|
if sweepAmt < lnwallet.DustLimitForSize(len(rewardScript)) {
|
||||||
if sweepAmt < lnwallet.DustLimitForSize(input.P2WPKHSize) {
|
|
||||||
return 0, 0, ErrCreatesDust
|
return 0, 0, ErrCreatesDust
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,15 +229,16 @@ func ComputeRewardAmount(total btcutil.Amount, base, rate uint32) btcutil.Amount
|
|||||||
return rewardBase + proportional
|
return rewardBase + proportional
|
||||||
}
|
}
|
||||||
|
|
||||||
// ComputeJusticeTxOuts constructs the justice transaction outputs for the given
|
// ComputeJusticeTxOuts constructs the justice transaction outputs for the
|
||||||
// policy. If the policy specifies a reward for the tower, there will be two
|
// given policy. If the policy specifies a reward for the tower, there will be
|
||||||
// outputs paying to the victim and the tower. Otherwise there will be a single
|
// two outputs paying to the victim and the tower. Otherwise there will be a
|
||||||
// output sweeping funds back to the victim. The totalAmt should be the sum of
|
// single output sweeping funds back to the victim. The totalAmt should be the
|
||||||
// any inputs used in the transaction. The passed txWeight should include the
|
// sum of any inputs used in the transaction. The passed txWeight should
|
||||||
// weight of the outputs for the justice transaction, which is dependent on
|
// include the weight of the outputs for the justice transaction, which is
|
||||||
// whether the justice transaction has a reward. The sweepPkScript should be the
|
// dependent on whether the justice transaction has a reward. The sweepPkScript
|
||||||
// pkScript of the victim to which funds will be recovered. The rewardPkScript
|
// should be the pkScript of the victim to which funds will be recovered. The
|
||||||
// is the pkScript of the tower where its reward will be deposited, and will be
|
// rewardPkScript is the pkScript of the tower where its reward will be
|
||||||
|
// deposited, and will be
|
||||||
// ignored if the blob type does not specify a reward.
|
// ignored if the blob type does not specify a reward.
|
||||||
func (p *Policy) ComputeJusticeTxOuts(totalAmt btcutil.Amount, txWeight int64,
|
func (p *Policy) ComputeJusticeTxOuts(totalAmt btcutil.Amount, txWeight int64,
|
||||||
sweepPkScript, rewardPkScript []byte) ([]*wire.TxOut, error) {
|
sweepPkScript, rewardPkScript []byte) ([]*wire.TxOut, error) {
|
||||||
@@ -247,19 +246,19 @@ func (p *Policy) ComputeJusticeTxOuts(totalAmt btcutil.Amount, txWeight int64,
|
|||||||
var outputs []*wire.TxOut
|
var outputs []*wire.TxOut
|
||||||
|
|
||||||
// If the policy specifies a reward for the tower, compute a split of
|
// If the policy specifies a reward for the tower, compute a split of
|
||||||
// the funds based on the policy's parameters. Otherwise, we will use an
|
// the funds based on the policy's parameters. Otherwise, we will use
|
||||||
// the altruist output computation and sweep as much of the funds back
|
// the altruist output computation and sweep as much of the funds
|
||||||
// to the victim as possible.
|
// back to the victim as possible.
|
||||||
if p.BlobType.Has(blob.FlagReward) {
|
if p.BlobType.Has(blob.FlagReward) {
|
||||||
// Using the total input amount and the transaction's weight,
|
// Using the total input amount and the transaction's weight,
|
||||||
// compute the sweep and reward amounts. This corresponds to the
|
// compute the sweep and reward amounts. This corresponds to
|
||||||
// amount returned to the victim and the amount paid to the
|
// the amount returned to the victim and the amount paid to the
|
||||||
// tower, respectively. To do so, the required transaction fee
|
// tower, respectively. To do so, the required transaction fee
|
||||||
// is subtracted from the total, and the remaining amount is
|
// is subtracted from the total, and the remaining amount is
|
||||||
// divided according to the prenegotiated reward rate from the
|
// divided according to the pre negotiated reward rate from the
|
||||||
// client's session info.
|
// client's session info.
|
||||||
sweepAmt, rewardAmt, err := p.ComputeRewardOutputs(
|
sweepAmt, rewardAmt, err := p.ComputeRewardOutputs(
|
||||||
totalAmt, txWeight,
|
totalAmt, txWeight, rewardPkScript,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -280,7 +279,7 @@ func (p *Policy) ComputeJusticeTxOuts(totalAmt btcutil.Amount, txWeight int64,
|
|||||||
// returned to the victim. To do so, the required transaction
|
// returned to the victim. To do so, the required transaction
|
||||||
// fee is subtracted from the total input amount.
|
// fee is subtracted from the total input amount.
|
||||||
sweepAmt, err := p.ComputeAltruistOutput(
|
sweepAmt, err := p.ComputeAltruistOutput(
|
||||||
totalAmt, txWeight,
|
totalAmt, txWeight, sweepPkScript,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ import (
|
|||||||
var (
|
var (
|
||||||
// addr is the server's reward address given to watchtower clients.
|
// addr is the server's reward address given to watchtower clients.
|
||||||
addr, _ = btcutil.DecodeAddress(
|
addr, _ = btcutil.DecodeAddress(
|
||||||
"mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz", &chaincfg.TestNet3Params,
|
"tb1pw8gzj8clt3v5lxykpgacpju5n8xteskt7gxhmudu6pa70nwfhe6s3unsyk",
|
||||||
|
&chaincfg.TestNet3Params,
|
||||||
)
|
)
|
||||||
|
|
||||||
addrScript, _ = txscript.PayToAddrScript(addr)
|
addrScript, _ = txscript.PayToAddrScript(addr)
|
||||||
|
|||||||
Reference in new issue
Block a user