Merge pull request #3821 from halseth/pluggable-anchors-lnwallet

[anchor] pluggable anchor commitments
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2020-03-09 19:49:05 -07:00
commit 3dda93e30d
37 files changed
+1848 -604

No files matched your search

+196 -180
View File
@@ -503,7 +503,8 @@ type commitment struct {
// evaluating all the add/remove/settle log entries before the listed
// indexes.
//
// NOTE: This is the balance *after* subtracting any commitment fee.
// NOTE: This is the balance *after* subtracting any commitment fee,
// AND anchor output values.
ourBalance lnwire.MilliSatoshi
theirBalance lnwire.MilliSatoshi
@@ -595,7 +596,7 @@ func locateOutputIndex(p *PaymentDescriptor, tx *wire.MsgTx, ourCommit bool,
// we need to keep track of the indexes of each HTLC in order to properly write
// the current state to disk, and also to locate the PaymentDescriptor
// corresponding to HTLC outputs in the commitment transaction.
func (c *commitment) populateHtlcIndexes() error {
func (c *commitment) populateHtlcIndexes(chanType channeldb.ChannelType) error {
// First, we'll set up some state to allow us to locate the output
// index of the all the HTLC's within the commitment transaction. We
// must keep this index so we can validate the HTLC signatures sent to
@@ -607,8 +608,10 @@ func (c *commitment) populateHtlcIndexes() error {
// populateIndex is a helper function that populates the necessary
// indexes within the commitment view for a particular HTLC.
populateIndex := func(htlc *PaymentDescriptor, incoming bool) error {
isDust := htlcIsDust(incoming, c.isOurs, c.feePerKw,
htlc.Amount.ToSatoshis(), c.dustLimit)
isDust := htlcIsDust(
chanType, incoming, c.isOurs, c.feePerKw,
htlc.Amount.ToSatoshis(), c.dustLimit,
)
var err error
switch {
@@ -773,6 +776,7 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
ourWitnessScript, theirWitnessScript []byte
pd PaymentDescriptor
err error
chanType = lc.channelState.ChanType
)
// If the either outputs is dust from the local or remote node's
@@ -780,22 +784,28 @@ func (lc *LightningChannel) diskHtlcToPayDesc(feeRate chainfee.SatPerKWeight,
// generate them in order to locate the outputs within the commitment
// transaction. As we'll mark dust with a special output index in the
// on-disk state snapshot.
isDustLocal := htlcIsDust(htlc.Incoming, true, feeRate,
htlc.Amt.ToSatoshis(), lc.channelState.LocalChanCfg.DustLimit)
isDustLocal := htlcIsDust(
chanType, htlc.Incoming, true, feeRate,
htlc.Amt.ToSatoshis(), lc.channelState.LocalChanCfg.DustLimit,
)
if !isDustLocal && localCommitKeys != nil {
ourP2WSH, ourWitnessScript, err = genHtlcScript(
htlc.Incoming, true, htlc.RefundTimeout, htlc.RHash,
localCommitKeys)
chanType, htlc.Incoming, true, htlc.RefundTimeout,
htlc.RHash, localCommitKeys,
)
if err != nil {
return pd, err
}
}
isDustRemote := htlcIsDust(htlc.Incoming, false, feeRate,
htlc.Amt.ToSatoshis(), lc.channelState.RemoteChanCfg.DustLimit)
isDustRemote := htlcIsDust(
chanType, htlc.Incoming, false, feeRate,
htlc.Amt.ToSatoshis(), lc.channelState.RemoteChanCfg.DustLimit,
)
if !isDustRemote && remoteCommitKeys != nil {
theirP2WSH, theirWitnessScript, err = genHtlcScript(
htlc.Incoming, false, htlc.RefundTimeout, htlc.RHash,
remoteCommitKeys)
chanType, htlc.Incoming, false, htlc.RefundTimeout,
htlc.RHash, remoteCommitKeys,
)
if err != nil {
return pd, err
}
@@ -926,7 +936,8 @@ func (lc *LightningChannel) diskCommitToMemCommit(isLocal bool,
// Finally, we'll re-populate the HTLC index for this state so we can
// properly locate each HTLC within the commitment transaction.
if err := commit.populateHtlcIndexes(); err != nil {
err = commit.populateHtlcIndexes(lc.channelState.ChanType)
if err != nil {
return nil, err
}
@@ -1406,11 +1417,14 @@ func (lc *LightningChannel) logUpdateToPayDesc(logUpdate *channeldb.LogUpdate,
pd.OnionBlob = make([]byte, len(wireMsg.OnionBlob))
copy(pd.OnionBlob[:], wireMsg.OnionBlob[:])
isDustRemote := htlcIsDust(false, false, feeRate,
wireMsg.Amount.ToSatoshis(), remoteDustLimit)
isDustRemote := htlcIsDust(
lc.channelState.ChanType, false, false, feeRate,
wireMsg.Amount.ToSatoshis(), remoteDustLimit,
)
if !isDustRemote {
theirP2WSH, theirWitnessScript, err := genHtlcScript(
false, false, wireMsg.Expiry, wireMsg.PaymentHash,
lc.channelState.ChanType, false, false,
wireMsg.Expiry, wireMsg.PaymentHash,
remoteCommitKeys,
)
if err != nil {
@@ -2008,6 +2022,10 @@ type BreachRetribution struct {
// party) within the breach transaction.
LocalOutpoint wire.OutPoint
// LocalDelay is the CSV delay for the to_remote script on the breached
// commitment.
LocalDelay uint32
// RemoteOutputSignDesc is a SignDescriptor which is capable of
// generating the signature required to claim the funds as described
// within the revocation clause of the remote party's commitment
@@ -2021,6 +2039,10 @@ type BreachRetribution struct {
// party within the breach transaction.
RemoteOutpoint wire.OutPoint
// RemoteDelay specifies the CSV delay applied to to-local scripts on
// the breaching commitment transaction.
RemoteDelay uint32
// HtlcRetributions is a slice of HTLC retributions for each output
// active HTLC output within the breached commitment transaction.
HtlcRetributions []HtlcRetribution
@@ -2029,10 +2051,6 @@ type BreachRetribution struct {
// breaching commitment transaction. This allows downstream clients to
// have access to the public keys used in the scripts.
KeyRing *CommitmentKeyRing
// RemoteDelay specifies the CSV delay applied to to-local scripts on
// the breaching commitment transaction.
RemoteDelay uint32
}
// NewBreachRetribution creates a new fully populated BreachRetribution for the
@@ -2085,9 +2103,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// Since it is the remote breach we are reconstructing, the output going
// to us will be a to-remote script with our local params.
ourDelay := uint32(chanState.LocalChanCfg.CsvDelay)
ourScript, err := CommitScriptToRemote(
chanState.ChanType, ourDelay, keyRing.ToRemoteKey,
ourScript, ourDelay, err := CommitScriptToRemote(
chanState.ChanType, keyRing.ToRemoteKey,
)
if err != nil {
return nil, err
@@ -2157,15 +2174,10 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// remote commitment transaction.
htlcRetributions := make([]HtlcRetribution, 0, len(revokedSnapshot.Htlcs))
for _, htlc := range revokedSnapshot.Htlcs {
var (
htlcWitnessScript []byte
err error
)
// If the HTLC is dust, then we'll skip it as it doesn't have
// an output on the commitment transaction.
if htlcIsDust(
htlc.Incoming, false,
chanState.ChanType, htlc.Incoming, false,
chainfee.SatPerKWeight(revokedSnapshot.FeePerKw),
htlc.Amt.ToSatoshis(), chanState.RemoteChanCfg.DustLimit,
) {
@@ -2185,31 +2197,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
// If this is an incoming HTLC, then this means that they were
// the sender of the HTLC (relative to us). So we'll
// re-generate the sender HTLC script.
if htlc.Incoming {
htlcWitnessScript, err = input.SenderHTLCScript(
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
keyRing.RevocationKey, htlc.RHash[:],
)
if err != nil {
return nil, err
}
} else {
// Otherwise, is this was an outgoing HTLC that we
// sent, then from the PoV of the remote commitment
// state, they're the receiver of this HTLC.
htlcWitnessScript, err = input.ReceiverHTLCScript(
htlc.RefundTimeout, keyRing.LocalHtlcKey,
keyRing.RemoteHtlcKey, keyRing.RevocationKey,
htlc.RHash[:],
)
if err != nil {
return nil, err
}
}
htlcPkScript, err := input.WitnessScriptHash(htlcWitnessScript)
// re-generate the sender HTLC script. Otherwise, is this was
// an outgoing HTLC that we sent, then from the PoV of the
// remote commitment state, they're the receiver of this HTLC.
htlcPkScript, htlcWitnessScript, err := genHtlcScript(
chanState.ChanType, htlc.Incoming, false,
htlc.RefundTimeout, htlc.RHash, keyRing,
)
if err != nil {
return nil, err
}
@@ -2245,33 +2239,23 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
PendingHTLCs: revokedSnapshot.Htlcs,
LocalOutpoint: ourOutpoint,
LocalOutputSignDesc: ourSignDesc,
LocalDelay: ourDelay,
RemoteOutpoint: theirOutpoint,
RemoteOutputSignDesc: theirSignDesc,
RemoteDelay: theirDelay,
HtlcRetributions: htlcRetributions,
KeyRing: keyRing,
RemoteDelay: theirDelay,
}, nil
}
// htlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
// transaction based on the current fee rate.
func htlcTimeoutFee(feePerKw chainfee.SatPerKWeight) btcutil.Amount {
return feePerKw.FeeForWeight(input.HtlcTimeoutWeight)
}
// htlcSuccessFee returns the fee in satoshis required for an HTLC success
// transaction based on the current fee rate.
func htlcSuccessFee(feePerKw chainfee.SatPerKWeight) btcutil.Amount {
return feePerKw.FeeForWeight(input.HtlcSuccessWeight)
}
// htlcIsDust determines if an HTLC output is dust or not depending on two
// bits: if the HTLC is incoming and if the HTLC will be placed on our
// commitment transaction, or theirs. These two pieces of information are
// require as we currently used second-level HTLC transactions as off-chain
// covenants. Depending on the two bits, we'll either be using a timeout or
// success transaction which have different weights.
func htlcIsDust(incoming, ourCommit bool, feePerKw chainfee.SatPerKWeight,
func htlcIsDust(chanType channeldb.ChannelType,
incoming, ourCommit bool, feePerKw chainfee.SatPerKWeight,
htlcAmt, dustLimit btcutil.Amount) bool {
// First we'll determine the fee required for this HTLC based on if this is
@@ -2283,25 +2267,25 @@ func htlcIsDust(incoming, ourCommit bool, feePerKw chainfee.SatPerKWeight,
// If this is an incoming HTLC on our commitment transaction, then the
// second-level transaction will be a success transaction.
case incoming && ourCommit:
htlcFee = htlcSuccessFee(feePerKw)
htlcFee = HtlcSuccessFee(chanType, feePerKw)
// If this is an incoming HTLC on their commitment transaction, then
// we'll be using a second-level timeout transaction as they've added
// this HTLC.
case incoming && !ourCommit:
htlcFee = htlcTimeoutFee(feePerKw)
htlcFee = HtlcTimeoutFee(chanType, feePerKw)
// If this is an outgoing HTLC on our commitment transaction, then
// we'll be using a timeout transaction as we're the sender of the
// HTLC.
case !incoming && ourCommit:
htlcFee = htlcTimeoutFee(feePerKw)
htlcFee = HtlcTimeoutFee(chanType, feePerKw)
// If this is an outgoing HTLC on their commitment transaction, then
// we'll be using an HTLC success transaction as they're the receiver
// of this HTLC.
case !incoming && !ourCommit:
htlcFee = htlcSuccessFee(feePerKw)
htlcFee = HtlcSuccessFee(chanType, feePerKw)
}
return (htlcAmt - htlcFee) < dustLimit
@@ -2391,6 +2375,29 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
return nil, err
}
// We'll assert that there hasn't been a mistake during fee calculation
// leading to a fee too low.
var totalOut btcutil.Amount
for _, txOut := range commitTx.txn.TxOut {
totalOut += btcutil.Amount(txOut.Value)
}
fee := lc.channelState.Capacity - totalOut
// Since the transaction is not signed yet, we use the witness weight
// used for weight calculation.
uTx := btcutil.NewTx(commitTx.txn)
weight := blockchain.GetTransactionWeight(uTx) +
input.WitnessCommitmentTxWeight
effFeeRate := chainfee.SatPerKWeight(fee) * 1000 /
chainfee.SatPerKWeight(weight)
if effFeeRate < chainfee.FeePerKwFloor {
return nil, fmt.Errorf("height=%v, for ChannelPoint(%v) "+
"attempts to create commitment wigh feerate %v: %v",
nextHeight, lc.channelState.FundingOutpoint,
effFeeRate, spew.Sdump(commitTx))
}
// With the commitment view created, store the resulting balances and
// transaction with the other parameters for this height.
c := &commitment{
@@ -2422,7 +2429,7 @@ func (lc *LightningChannel) fetchCommitmentView(remoteChain bool,
// Finally, we'll populate all the HTLC indexes so we can track the
// locations of each HTLC in the commitment state.
if err := c.populateHtlcIndexes(); err != nil {
if err := c.populateHtlcIndexes(lc.channelState.ChanType); err != nil {
return nil, err
}
@@ -2737,12 +2744,14 @@ func processFeeUpdate(feeUpdate *PaymentDescriptor, nextHeight uint64,
// signature can be submitted to the sigPool to generate all the signatures
// asynchronously and in parallel.
func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
chanType channeldb.ChannelType,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
remoteCommitView *commitment) ([]SignJob, chan struct{}, error) {
txHash := remoteCommitView.txn.TxHash()
dustLimit := remoteChanCfg.DustLimit
feePerKw := remoteCommitView.feePerKw
sigHashType := HtlcSigHashType(chanType)
// With the keys generated, we'll make a slice with enough capacity to
// hold potentially all the HTLCs. The actual slice may be a bit
@@ -2758,8 +2767,10 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
// dust output after taking into account second-level HTLC fees, then a
// sigJob will be generated and appended to the current batch.
for _, htlc := range remoteCommitView.incomingHTLCs {
if htlcIsDust(true, false, feePerKw, htlc.Amount.ToSatoshis(),
dustLimit) {
if htlcIsDust(
chanType, true, false, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
@@ -2774,7 +2785,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
// HTLC timeout transaction for them. The output of the timeout
// transaction needs to account for fees, so we'll compute the
// required fee and output now.
htlcFee := htlcTimeoutFee(feePerKw)
htlcFee := HtlcTimeoutFee(chanType, feePerKw)
outputAmt := htlc.Amount.ToSatoshis() - htlcFee
// With the fee calculate, we can properly create the HTLC
@@ -2784,7 +2795,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
Index: uint32(htlc.remoteOutputIndex),
}
sigJob.Tx, err = createHtlcTimeoutTx(
op, outputAmt, htlc.Timeout,
chanType, op, outputAmt, htlc.Timeout,
uint32(remoteChanCfg.CsvDelay),
keyRing.RevocationKey, keyRing.ToLocalKey,
)
@@ -2802,7 +2813,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
Output: &wire.TxOut{
Value: int64(htlc.Amount.ToSatoshis()),
},
HashType: txscript.SigHashAll,
HashType: sigHashType,
SigHashes: txscript.NewTxSigHashes(sigJob.Tx),
InputIndex: 0,
}
@@ -2811,8 +2822,10 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
sigBatch = append(sigBatch, sigJob)
}
for _, htlc := range remoteCommitView.outgoingHTLCs {
if htlcIsDust(false, false, feePerKw, htlc.Amount.ToSatoshis(),
dustLimit) {
if htlcIsDust(
chanType, false, false, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
@@ -2825,7 +2838,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
// HTLC success transaction for them. The output of the timeout
// transaction needs to account for fees, so we'll compute the
// required fee and output now.
htlcFee := htlcSuccessFee(feePerKw)
htlcFee := HtlcSuccessFee(chanType, feePerKw)
outputAmt := htlc.Amount.ToSatoshis() - htlcFee
// With the proper output amount calculated, we can now
@@ -2836,7 +2849,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
Index: uint32(htlc.remoteOutputIndex),
}
sigJob.Tx, err = createHtlcSuccessTx(
op, outputAmt, uint32(remoteChanCfg.CsvDelay),
chanType, op, outputAmt, uint32(remoteChanCfg.CsvDelay),
keyRing.RevocationKey, keyRing.ToLocalKey,
)
if err != nil {
@@ -2853,7 +2866,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
Output: &wire.TxOut{
Value: int64(htlc.Amount.ToSatoshis()),
},
HashType: txscript.SigHashAll,
HashType: sigHashType,
SigHashes: txscript.NewTxSigHashes(sigJob.Tx),
InputIndex: 0,
}
@@ -3341,7 +3354,8 @@ func (lc *LightningChannel) SignNextCommitment() (lnwire.Sig, []lnwire.Sig, []ch
// need to generate signatures of each of them for the remote party's
// commitment state. We do so in two phases: first we generate and
// submit the set of signature jobs to the worker pool.
sigBatch, cancelChan, err := genRemoteHtlcSigJobs(keyRing,
sigBatch, cancelChan, err := genRemoteHtlcSigJobs(
keyRing, lc.channelState.ChanType,
&lc.channelState.LocalChanCfg, &lc.channelState.RemoteChanCfg,
newCommitView,
)
@@ -3773,23 +3787,28 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool,
// weight, needed to calculate the transaction fee.
var totalHtlcWeight int64
for _, htlc := range filteredHTLCView.ourUpdates {
if htlcIsDust(remoteChain, !remoteChain, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit) {
if htlcIsDust(
lc.channelState.ChanType, remoteChain, !remoteChain,
feePerKw, htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
totalHtlcWeight += input.HTLCWeight
}
for _, htlc := range filteredHTLCView.theirUpdates {
if htlcIsDust(!remoteChain, !remoteChain, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit) {
if htlcIsDust(
lc.channelState.ChanType, !remoteChain, !remoteChain,
feePerKw, htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
totalHtlcWeight += input.HTLCWeight
}
totalCommitWeight := input.CommitWeight + totalHtlcWeight
totalCommitWeight := CommitWeight(lc.channelState.ChanType) +
totalHtlcWeight
return ourBalance, theirBalance, totalCommitWeight, filteredHTLCView, nil
}
@@ -3799,10 +3818,12 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool,
// directly into the pool of workers.
func genHtlcSigValidationJobs(localCommitmentView *commitment,
keyRing *CommitmentKeyRing, htlcSigs []lnwire.Sig,
chanType channeldb.ChannelType,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig) ([]VerifyJob, error) {
txHash := localCommitmentView.txn.TxHash()
feePerKw := localCommitmentView.feePerKw
sigHashType := HtlcSigHashType(chanType)
// With the required state generated, we'll create a slice with large
// enough capacity to hold verification jobs for all HTLC's in this
@@ -3842,12 +3863,14 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
Index: uint32(htlc.localOutputIndex),
}
htlcFee := htlcSuccessFee(feePerKw)
htlcFee := HtlcSuccessFee(chanType, feePerKw)
outputAmt := htlc.Amount.ToSatoshis() - htlcFee
successTx, err := createHtlcSuccessTx(op,
outputAmt, uint32(localChanCfg.CsvDelay),
keyRing.RevocationKey, keyRing.ToLocalKey)
successTx, err := createHtlcSuccessTx(
chanType, op, outputAmt,
uint32(localChanCfg.CsvDelay),
keyRing.RevocationKey, keyRing.ToLocalKey,
)
if err != nil {
return nil, err
}
@@ -3855,7 +3878,7 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
hashCache := txscript.NewTxSigHashes(successTx)
sigHash, err := txscript.CalcWitnessSigHash(
htlc.ourWitnessScript, hashCache,
txscript.SigHashAll, successTx, 0,
sigHashType, successTx, 0,
int64(htlc.Amount.ToSatoshis()),
)
if err != nil {
@@ -3894,11 +3917,11 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
Index: uint32(htlc.localOutputIndex),
}
htlcFee := htlcTimeoutFee(feePerKw)
htlcFee := HtlcTimeoutFee(chanType, feePerKw)
outputAmt := htlc.Amount.ToSatoshis() - htlcFee
timeoutTx, err := createHtlcTimeoutTx(op,
outputAmt, htlc.Timeout,
timeoutTx, err := createHtlcTimeoutTx(
chanType, op, outputAmt, htlc.Timeout,
uint32(localChanCfg.CsvDelay),
keyRing.RevocationKey, keyRing.ToLocalKey,
)
@@ -3909,7 +3932,7 @@ func genHtlcSigValidationJobs(localCommitmentView *commitment,
hashCache := txscript.NewTxSigHashes(timeoutTx)
sigHash, err := txscript.CalcWitnessSigHash(
htlc.ourWitnessScript, hashCache,
txscript.SigHashAll, timeoutTx, 0,
sigHashType, timeoutTx, 0,
int64(htlc.Amount.ToSatoshis()),
)
if err != nil {
@@ -4115,7 +4138,8 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig lnwire.Sig,
// generated, we'll submit these jobs to the worker pool.
verifyJobs, err := genHtlcSigValidationJobs(
localCommitmentView, keyRing, htlcSigs,
&lc.channelState.LocalChanCfg, &lc.channelState.RemoteChanCfg,
lc.channelState.ChanType, &lc.channelState.LocalChanCfg,
&lc.channelState.RemoteChanCfg,
)
if err != nil {
return err
@@ -5040,8 +5064,8 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
}
// CommitOutputResolution carries the necessary information required to allow
// us to sweep our direct commitment output in the case that either party goes
// to chain.
// us to sweep our commitment output in the case that either party goes to
// chain.
type CommitOutputResolution struct {
// SelfOutPoint is the full outpoint that points to out pay-to-self
// output within the closing commitment transaction.
@@ -5053,8 +5077,7 @@ type CommitOutputResolution struct {
// MaturityDelay is the relative time-lock, in blocks for all outputs
// that pay to the local party within the broadcast commitment
// transaction. This value will be non-zero iff, this output was on our
// commitment transaction.
// transaction.
MaturityDelay uint32
}
@@ -5123,6 +5146,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
chainfee.SatPerKWeight(remoteCommit.FeePerKw), false, signer,
remoteCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, *commitSpend.SpenderTxHash,
chanState.ChanType,
)
if err != nil {
return nil, fmt.Errorf("unable to create htlc "+
@@ -5134,9 +5158,8 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
// Before we can generate the proper sign descriptor, we'll need to
// locate the output index of our non-delayed output on the commitment
// transaction.
localDelay := uint32(chanState.LocalChanCfg.CsvDelay)
selfScript, err := CommitScriptToRemote(
chanState.ChanType, localDelay, keyRing.ToRemoteKey,
selfScript, maturityDelay, err := CommitScriptToRemote(
chanState.ChanType, keyRing.ToRemoteKey,
)
if err != nil {
return nil, fmt.Errorf("unable to create self commit "+
@@ -5177,7 +5200,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
},
HashType: txscript.SigHashAll,
},
MaturityDelay: 0,
MaturityDelay: maturityDelay,
}
}
@@ -5241,7 +5264,8 @@ type IncomingHtlcResolution struct {
// pass after the SignedSuccessTx is confirmed in the chain before the
// output can be swept.
//
// NOTE: If SignedSuccessTx is nil, then this field isn't needed.
// NOTE: If SignedTimeoutTx is nil, then this field denotes the CSV
// delay needed to spend from the commitment transaction.
CsvDelay uint32
// ClaimOutpoint is the final outpoint that needs to be spent in order
@@ -5281,7 +5305,8 @@ type OutgoingHtlcResolution struct {
// pass after the SignedTimeoutTx is confirmed in the chain before the
// output can be swept.
//
// NOTE: If SignedTimeoutTx is nil, then this field isn't needed.
// NOTE: If SignedTimeoutTx is nil, then this field denotes the CSV
// delay needed to spend from the commitment transaction.
CsvDelay uint32
// ClaimOutpoint is the final outpoint that needs to be spent in order
@@ -5318,31 +5343,27 @@ func newOutgoingHtlcResolution(signer input.Signer,
localChanCfg *channeldb.ChannelConfig, commitHash chainhash.Hash,
htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw chainfee.SatPerKWeight, csvDelay uint32,
localCommit bool) (*OutgoingHtlcResolution, error) {
localCommit bool, chanType channeldb.ChannelType) (*OutgoingHtlcResolution, error) {
op := wire.OutPoint{
Hash: commitHash,
Index: uint32(htlc.OutputIndex),
}
// First, we'll re-generate the script used to send the HTLC to
// the remote party within their commitment transaction.
htlcScriptHash, htlcScript, err := genHtlcScript(
chanType, false, localCommit, htlc.RefundTimeout, htlc.RHash,
keyRing,
)
if err != nil {
return nil, err
}
// If we're spending this HTLC output from the remote node's
// commitment, then we won't need to go to the second level as our
// outputs don't have a CSV delay.
if !localCommit {
// First, we'll re-generate the script used to send the HTLC to
// the remote party within their commitment transaction.
htlcReceiverScript, err := input.ReceiverHTLCScript(htlc.RefundTimeout,
keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
keyRing.RevocationKey, htlc.RHash[:],
)
if err != nil {
return nil, err
}
htlcScriptHash, err := input.WitnessScriptHash(htlcReceiverScript)
if err != nil {
return nil, err
}
// With the script generated, we can completely populated the
// SignDescriptor needed to sweep the output.
return &OutgoingHtlcResolution{
@@ -5351,13 +5372,14 @@ func newOutgoingHtlcResolution(signer input.Signer,
SweepSignDesc: input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcReceiverScript,
WitnessScript: htlcScript,
Output: &wire.TxOut{
PkScript: htlcScriptHash,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
},
CsvDelay: HtlcSecondLevelInputSequence(chanType),
}, nil
}
@@ -5367,14 +5389,14 @@ func newOutgoingHtlcResolution(signer input.Signer,
// In order to properly reconstruct the HTLC transaction, we'll need to
// re-calculate the fee required at this state, so we can add the
// correct output value amount to the transaction.
htlcFee := htlcTimeoutFee(feePerKw)
htlcFee := HtlcTimeoutFee(chanType, feePerKw)
secondLevelOutputAmt := htlc.Amt.ToSatoshis() - htlcFee
// With the fee calculated, re-construct the second level timeout
// transaction.
timeoutTx, err := createHtlcTimeoutTx(
op, secondLevelOutputAmt, htlc.RefundTimeout, csvDelay,
keyRing.RevocationKey, keyRing.ToLocalKey,
chanType, op, secondLevelOutputAmt, htlc.RefundTimeout,
csvDelay, keyRing.RevocationKey, keyRing.ToLocalKey,
)
if err != nil {
return nil, err
@@ -5383,15 +5405,10 @@ func newOutgoingHtlcResolution(signer input.Signer,
// With the transaction created, we can generate a sign descriptor
// that's capable of generating the signature required to spend the
// HTLC output using the timeout transaction.
htlcCreationScript, err := input.SenderHTLCScript(keyRing.LocalHtlcKey,
keyRing.RemoteHtlcKey, keyRing.RevocationKey, htlc.RHash[:])
if err != nil {
return nil, err
}
timeoutSignDesc := input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcCreationScript,
WitnessScript: htlcScript,
Output: &wire.TxOut{
Value: int64(htlc.Amt.ToSatoshis()),
},
@@ -5402,8 +5419,9 @@ func newOutgoingHtlcResolution(signer input.Signer,
// With the sign desc created, we can now construct the full witness
// for the timeout transaction, and populate it as well.
sigHashType := HtlcSigHashType(chanType)
timeoutWitness, err := input.SenderHtlcSpendTimeout(
htlc.Signature, signer, &timeoutSignDesc, timeoutTx,
htlc.Signature, sigHashType, signer, &timeoutSignDesc, timeoutTx,
)
if err != nil {
return nil, err
@@ -5419,7 +5437,7 @@ func newOutgoingHtlcResolution(signer input.Signer,
if err != nil {
return nil, err
}
htlcScriptHash, err := input.WitnessScriptHash(htlcSweepScript)
htlcSweepScriptHash, err := input.WitnessScriptHash(htlcSweepScript)
if err != nil {
return nil, err
}
@@ -5440,7 +5458,7 @@ func newOutgoingHtlcResolution(signer input.Signer,
SingleTweak: localDelayTweak,
WitnessScript: htlcSweepScript,
Output: &wire.TxOut{
PkScript: htlcScriptHash,
PkScript: htlcSweepScriptHash,
Value: int64(secondLevelOutputAmt),
},
HashType: txscript.SigHashAll,
@@ -5455,48 +5473,45 @@ func newOutgoingHtlcResolution(signer input.Signer,
// they can just sweep the output immediately with knowledge of the pre-image.
//
// TODO(roasbeef) consolidate code with above func
func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw chainfee.SatPerKWeight, csvDelay uint32,
localCommit bool) (*IncomingHtlcResolution, error) {
func newIncomingHtlcResolution(signer input.Signer,
localChanCfg *channeldb.ChannelConfig, commitHash chainhash.Hash,
htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
feePerKw chainfee.SatPerKWeight, csvDelay uint32, localCommit bool,
chanType channeldb.ChannelType) (*IncomingHtlcResolution, error) {
op := wire.OutPoint{
Hash: commitHash,
Index: uint32(htlc.OutputIndex),
}
// First, we'll re-generate the script the remote party used to
// send the HTLC to us in their commitment transaction.
htlcScriptHash, htlcScript, err := genHtlcScript(
chanType, true, localCommit, htlc.RefundTimeout, htlc.RHash,
keyRing,
)
if err != nil {
return nil, err
}
// If we're spending this output from the remote node's commitment,
// then we can skip the second layer and spend the output directly.
if !localCommit {
// First, we'll re-generate the script the remote party used to
// send the HTLC to us in their commitment transaction.
htlcSenderScript, err := input.SenderHTLCScript(
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
keyRing.RevocationKey, htlc.RHash[:],
)
if err != nil {
return nil, err
}
htlcScriptHash, err := input.WitnessScriptHash(htlcSenderScript)
if err != nil {
return nil, err
}
// With the script generated, we can completely populated the
// SignDescriptor needed to sweep the output.
return &IncomingHtlcResolution{
ClaimOutpoint: op,
CsvDelay: csvDelay,
SweepSignDesc: input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcSenderScript,
WitnessScript: htlcScript,
Output: &wire.TxOut{
PkScript: htlcScriptHash,
Value: int64(htlc.Amt.ToSatoshis()),
},
HashType: txscript.SigHashAll,
},
CsvDelay: HtlcSecondLevelInputSequence(chanType),
}, nil
}
@@ -5504,10 +5519,10 @@ func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
// First, we'll reconstruct the original HTLC success transaction,
// taking into account the fee rate used.
htlcFee := htlcSuccessFee(feePerKw)
htlcFee := HtlcSuccessFee(chanType, feePerKw)
secondLevelOutputAmt := htlc.Amt.ToSatoshis() - htlcFee
successTx, err := createHtlcSuccessTx(
op, secondLevelOutputAmt, csvDelay,
chanType, op, secondLevelOutputAmt, csvDelay,
keyRing.RevocationKey, keyRing.ToLocalKey,
)
if err != nil {
@@ -5516,17 +5531,10 @@ func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
// Once we've created the second-level transaction, we'll generate the
// SignDesc needed spend the HTLC output using the success transaction.
htlcCreationScript, err := input.ReceiverHTLCScript(htlc.RefundTimeout,
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
keyRing.RevocationKey, htlc.RHash[:],
)
if err != nil {
return nil, err
}
successSignDesc := input.SignDescriptor{
KeyDesc: localChanCfg.HtlcBasePoint,
SingleTweak: keyRing.LocalHtlcKeyTweak,
WitnessScript: htlcCreationScript,
WitnessScript: htlcScript,
Output: &wire.TxOut{
Value: int64(htlc.Amt.ToSatoshis()),
},
@@ -5539,8 +5547,10 @@ func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
// the success transaction. Don't specify the preimage yet. The preimage
// will be supplied by the contract resolver, either directly or when it
// becomes known.
sigHashType := HtlcSigHashType(chanType)
successWitness, err := input.ReceiverHtlcSpendRedeem(
htlc.Signature, nil, signer, &successSignDesc, successTx,
htlc.Signature, sigHashType, nil, signer, &successSignDesc,
successTx,
)
if err != nil {
return nil, err
@@ -5556,7 +5566,7 @@ func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
if err != nil {
return nil, err
}
htlcScriptHash, err := input.WitnessScriptHash(htlcSweepScript)
htlcSweepScriptHash, err := input.WitnessScriptHash(htlcSweepScript)
if err != nil {
return nil, err
}
@@ -5576,7 +5586,7 @@ func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.Chan
SingleTweak: localDelayTweak,
WitnessScript: htlcSweepScript,
Output: &wire.TxOut{
PkScript: htlcScriptHash,
PkScript: htlcSweepScriptHash,
Value: int64(secondLevelOutputAmt),
},
HashType: txscript.SigHashAll,
@@ -5614,7 +5624,8 @@ func (r *OutgoingHtlcResolution) HtlcPoint() wire.OutPoint {
func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
signer input.Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
commitHash chainhash.Hash) (*HtlcResolutions, error) {
commitHash chainhash.Hash, chanType channeldb.ChannelType) (
*HtlcResolutions, error) {
// TODO(roasbeef): don't need to swap csv delay?
dustLimit := remoteChanCfg.DustLimit
@@ -5627,11 +5638,15 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
incomingResolutions := make([]IncomingHtlcResolution, 0, len(htlcs))
outgoingResolutions := make([]OutgoingHtlcResolution, 0, len(htlcs))
for _, htlc := range htlcs {
htlc := htlc
// We'll skip any HTLC's which were dust on the commitment
// transaction, as these don't have a corresponding output
// within the commitment transaction.
if htlcIsDust(htlc.Incoming, ourCommit, feePerKw,
htlc.Amt.ToSatoshis(), dustLimit) {
if htlcIsDust(
chanType, htlc.Incoming, ourCommit, feePerKw,
htlc.Amt.ToSatoshis(), dustLimit,
) {
continue
}
@@ -5641,8 +5656,9 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
// Otherwise, we'll create an incoming HTLC resolution
// as we can satisfy the contract.
ihr, err := newIncomingHtlcResolution(
signer, localChanCfg, commitHash, &htlc, keyRing,
feePerKw, uint32(csvDelay), ourCommit,
signer, localChanCfg, commitHash, &htlc,
keyRing, feePerKw, uint32(csvDelay), ourCommit,
chanType,
)
if err != nil {
return nil, err
@@ -5654,7 +5670,7 @@ func extractHtlcResolutions(feePerKw chainfee.SatPerKWeight, ourCommit bool,
ohr, err := newOutgoingHtlcResolution(
signer, localChanCfg, commitHash, &htlc, keyRing,
feePerKw, uint32(csvDelay), ourCommit,
feePerKw, uint32(csvDelay), ourCommit, chanType,
)
if err != nil {
return nil, err
@@ -5833,7 +5849,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Si
htlcResolutions, err := extractHtlcResolutions(
chainfee.SatPerKWeight(localCommit.FeePerKw), true, signer,
localCommit.Htlcs, keyRing, &chanState.LocalChanCfg,
&chanState.RemoteChanCfg, txHash,
&chanState.RemoteChanCfg, txHash, chanState.ChanType,
)
if err != nil {
return nil, err
@@ -6133,7 +6149,7 @@ func (lc *LightningChannel) availableCommitmentBalance(view *htlcView,
// For an extra HTLC fee to be paid on our commitment, the HTLC must be
// large enough to make a non-dust HTLC timeout transaction.
htlcFee := lnwire.NewMSatFromSatoshis(
htlcTimeoutFee(feePerKw),
HtlcTimeoutFee(lc.channelState.ChanType, feePerKw),
)
// If we are looking at the remote commitment, we must use the remote
@@ -6143,7 +6159,7 @@ func (lc *LightningChannel) availableCommitmentBalance(view *htlcView,
lc.channelState.RemoteChanCfg.DustLimit,
)
htlcFee = lnwire.NewMSatFromSatoshis(
htlcSuccessFee(feePerKw),
HtlcSuccessFee(lc.channelState.ChanType, feePerKw),
)
}
@@ -6351,7 +6367,7 @@ func CreateCooperativeCloseTx(fundingTxIn wire.TxIn,
// CalcFee returns the commitment fee to use for the given
// fee rate (fee-per-kw).
func (lc *LightningChannel) CalcFee(feeRate chainfee.SatPerKWeight) btcutil.Amount {
return feeRate.FeeForWeight(input.CommitWeight)
return feeRate.FeeForWeight(CommitWeight(lc.channelState.ChanType))
}
// MaxFeeRate returns the maximum fee rate given an allocation of the channel
+14 -7
View File
@@ -1011,7 +1011,8 @@ func TestHTLCDustLimit(t *testing.T) {
// The amount of the HTLC should be above Alice's dust limit and below
// Bob's dust limit.
htlcSat := (btcutil.Amount(500) + htlcTimeoutFee(
htlcSat := (btcutil.Amount(500) + HtlcTimeoutFee(
aliceChannel.channelState.ChanType,
chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
),
@@ -1119,8 +1120,12 @@ func TestHTLCSigNumber(t *testing.T) {
t.Fatalf("unable to get fee: %v", err)
}
belowDust := btcutil.Amount(500) + htlcTimeoutFee(feePerKw)
aboveDust := btcutil.Amount(1400) + htlcSuccessFee(feePerKw)
belowDust := btcutil.Amount(500) + HtlcTimeoutFee(
channeldb.SingleFunderTweaklessBit, feePerKw,
)
aboveDust := btcutil.Amount(1400) + HtlcSuccessFee(
channeldb.SingleFunderTweaklessBit, feePerKw,
)
// ===================================================================
// Test that Bob will reject a commitment if Alice doesn't send enough
@@ -1278,7 +1283,8 @@ func TestChannelBalanceDustLimit(t *testing.T) {
defaultFee := calcStaticFee(1)
aliceBalance := aliceChannel.channelState.LocalCommitment.LocalBalance.ToSatoshis()
htlcSat := aliceBalance - defaultFee
htlcSat += htlcSuccessFee(
htlcSat += HtlcSuccessFee(
aliceChannel.channelState.ChanType,
chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
),
@@ -4759,10 +4765,10 @@ func TestChanAvailableBalanceNearHtlcFee(t *testing.T) {
aliceChannel.channelState.LocalCommitment.CommitFee,
)
htlcTimeoutFee := lnwire.NewMSatFromSatoshis(
htlcTimeoutFee(feeRate),
HtlcTimeoutFee(aliceChannel.channelState.ChanType, feeRate),
)
htlcSuccessFee := lnwire.NewMSatFromSatoshis(
htlcSuccessFee(feeRate),
HtlcSuccessFee(aliceChannel.channelState.ChanType, feeRate),
)
// Helper method to check the current reported balance.
@@ -6273,7 +6279,8 @@ func TestChanReserveLocalInitiatorDustHtlc(t *testing.T) {
// limit (1300 sat). It is considered dust if the amount remaining
// after paying the HTLC fee is below the dustlimit, so we choose a
// size of 500+htlcFee.
htlcSat := btcutil.Amount(500) + htlcTimeoutFee(
htlcSat := btcutil.Amount(500) + HtlcTimeoutFee(
aliceChannel.channelState.ChanType,
chainfee.SatPerKWeight(
aliceChannel.channelState.LocalCommitment.FeePerKw,
),
+225 -39
View File
@@ -5,6 +5,7 @@ import (
"github.com/btcsuite/btcd/blockchain"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/channeldb"
@@ -13,6 +14,9 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
)
// anchorSize is the constant anchor output size.
const anchorSize = btcutil.Amount(330)
// CommitmentKeyRing holds all derived keys needed to construct commitment and
// HTLC transactions. The keys are derived differently depending whether the
// commitment transaction is ours or the remote peer's. Private keys associated
@@ -183,13 +187,34 @@ type ScriptInfo struct {
// CommitScriptToRemote creates the script that will pay to the non-owner of
// the commitment transaction, adding a delay to the script based on the
// channel type.
func CommitScriptToRemote(_ channeldb.ChannelType, csvTimeout uint32,
key *btcec.PublicKey) (*ScriptInfo, error) {
// channel type. The second return value is the CSV deleay of the output
// script, what must be satisfied in order to spend the output.
func CommitScriptToRemote(chanType channeldb.ChannelType,
key *btcec.PublicKey) (*ScriptInfo, uint32, error) {
// If this channel type has anchors, we derive the delayed to_remote
// script.
if chanType.HasAnchors() {
script, err := input.CommitScriptToRemoteConfirmed(key)
if err != nil {
return nil, 0, err
}
p2wsh, err := input.WitnessScriptHash(script)
if err != nil {
return nil, 0, err
}
return &ScriptInfo{
PkScript: p2wsh,
WitnessScript: script,
}, 1, nil
}
// Otherwise the to_remote will be a simple p2wkh.
p2wkh, err := input.CommitScriptUnencumbered(key)
if err != nil {
return nil, err
return nil, 0, err
}
// Since this is a regular P2WKH, the WitnessScipt and PkScript should
@@ -197,7 +222,100 @@ func CommitScriptToRemote(_ channeldb.ChannelType, csvTimeout uint32,
return &ScriptInfo{
WitnessScript: p2wkh,
PkScript: p2wkh,
}, nil
}, 0, nil
}
// HtlcSigHashType returns the sighash type to use for HTLC success and timeout
// transactions given the channel type.
func HtlcSigHashType(chanType channeldb.ChannelType) txscript.SigHashType {
if chanType.HasAnchors() {
return txscript.SigHashSingle | txscript.SigHashAnyOneCanPay
}
return txscript.SigHashAll
}
// HtlcSecondLevelInputSequence dictates the sequence number we must use on the
// input to a second level HTLC transaction.
func HtlcSecondLevelInputSequence(chanType channeldb.ChannelType) uint32 {
if chanType.HasAnchors() {
return 1
}
return 0
}
// CommitWeight returns the base commitment weight before adding HTLCs.
func CommitWeight(chanType channeldb.ChannelType) int64 {
// If this commitment has anchors, it will be slightly heavier.
if chanType.HasAnchors() {
return input.AnchorCommitWeight
}
return input.CommitWeight
}
// HtlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
// transaction based on the current fee rate.
func HtlcTimeoutFee(chanType channeldb.ChannelType,
feePerKw chainfee.SatPerKWeight) btcutil.Amount {
if chanType.HasAnchors() {
return feePerKw.FeeForWeight(input.HtlcTimeoutWeightConfirmed)
}
return feePerKw.FeeForWeight(input.HtlcTimeoutWeight)
}
// HtlcSuccessFee returns the fee in satoshis required for an HTLC success
// transaction based on the current fee rate.
func HtlcSuccessFee(chanType channeldb.ChannelType,
feePerKw chainfee.SatPerKWeight) btcutil.Amount {
if chanType.HasAnchors() {
return feePerKw.FeeForWeight(input.HtlcSuccessWeightConfirmed)
}
return feePerKw.FeeForWeight(input.HtlcSuccessWeight)
}
// CommitScriptAnchors return the scripts to use for the local and remote
// anchor.
func CommitScriptAnchors(localChanCfg,
remoteChanCfg *channeldb.ChannelConfig) (*ScriptInfo,
*ScriptInfo, error) {
// Helper to create anchor ScriptInfo from key.
anchorScript := func(key *btcec.PublicKey) (*ScriptInfo, error) {
script, err := input.CommitScriptAnchor(key)
if err != nil {
return nil, err
}
scriptHash, err := input.WitnessScriptHash(script)
if err != nil {
return nil, err
}
return &ScriptInfo{
PkScript: scriptHash,
WitnessScript: script,
}, nil
}
// Get the script used for the anchor output spendable by the local
// node.
localAnchor, err := anchorScript(localChanCfg.MultiSigKey.PubKey)
if err != nil {
return nil, nil, err
}
// And the anchor spemdable by the remote node.
remoteAnchor, err := anchorScript(remoteChanCfg.MultiSigKey.PubKey)
if err != nil {
return nil, nil, err
}
return localAnchor, remoteAnchor, nil
}
// CommitmentBuilder is a type that wraps the type of channel we are dealing
@@ -216,6 +334,11 @@ type CommitmentBuilder struct {
// NewCommitmentBuilder creates a new CommitmentBuilder from chanState.
func NewCommitmentBuilder(chanState *channeldb.OpenChannel) *CommitmentBuilder {
// The anchor channel type MUST be tweakless.
if chanState.ChanType.HasAnchors() && !chanState.ChanType.IsTweakless() {
panic("invalid channel type combination")
}
return &CommitmentBuilder{
chanState: chanState,
obfuscator: createStateHintObfuscator(chanState),
@@ -248,8 +371,9 @@ type unsignedCommitmentTx struct {
// fee is the total fee of the commitment transaction.
fee btcutil.Amount
// ourBalance|theirBalance is the balances of this commitment. This can
// be different than the balances before creating the commitment
// ourBalance|theirBalance are the balances of this commitment *after*
// subtracting commitment fees and anchor outputs. This can be
// different than the balances before creating the commitment
// transaction as one party must pay the commitment fee.
ourBalance lnwire.MilliSatoshi
theirBalance lnwire.MilliSatoshi
@@ -258,7 +382,7 @@ type unsignedCommitmentTx struct {
// createUnsignedCommitmentTx generates the unsigned commitment transaction for
// a commitment view and returns it as part of the unsignedCommitmentTx. The
// passed in balances should be balances *before* subtracting any commitment
// fees.
// fees, but after anchor outputs.
func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
theirBalance lnwire.MilliSatoshi, isOurs bool,
feePerKw chainfee.SatPerKWeight, height uint64,
@@ -272,18 +396,20 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
numHTLCs := int64(0)
for _, htlc := range filteredHTLCView.ourUpdates {
if htlcIsDust(false, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit) {
if htlcIsDust(
cb.chanState.ChanType, false, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
numHTLCs++
}
for _, htlc := range filteredHTLCView.theirUpdates {
if htlcIsDust(true, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit) {
if htlcIsDust(
cb.chanState.ChanType, true, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
@@ -294,7 +420,8 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
// on its total weight. Once we have the total weight, we'll multiply
// by the current fee-per-kw, then divide by 1000 to get the proper
// fee.
totalCommitWeight := input.CommitWeight + (input.HTLCWeight * numHTLCs)
totalCommitWeight := CommitWeight(cb.chanState.ChanType) +
input.HTLCWeight*numHTLCs
// With the weight known, we can now calculate the commitment fee,
// ensuring that we account for any dust outputs trimmed above.
@@ -333,12 +460,14 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
&cb.chanState.LocalChanCfg, &cb.chanState.RemoteChanCfg,
ourBalance.ToSatoshis(), theirBalance.ToSatoshis(),
numHTLCs,
)
} else {
commitTx, err = CreateCommitTx(
cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
&cb.chanState.RemoteChanCfg, &cb.chanState.LocalChanCfg,
theirBalance.ToSatoshis(), ourBalance.ToSatoshis(),
numHTLCs,
)
}
if err != nil {
@@ -356,24 +485,34 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
// purposes of sorting.
cltvs := make([]uint32, len(commitTx.TxOut))
for _, htlc := range filteredHTLCView.ourUpdates {
if htlcIsDust(false, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit) {
if htlcIsDust(
cb.chanState.ChanType, false, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
err := addHTLC(commitTx, isOurs, false, htlc, keyRing)
err := addHTLC(
commitTx, isOurs, false, htlc, keyRing,
cb.chanState.ChanType,
)
if err != nil {
return nil, err
}
cltvs = append(cltvs, htlc.Timeout)
}
for _, htlc := range filteredHTLCView.theirUpdates {
if htlcIsDust(true, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit) {
if htlcIsDust(
cb.chanState.ChanType, true, isOurs, feePerKw,
htlc.Amount.ToSatoshis(), dustLimit,
) {
continue
}
err := addHTLC(commitTx, isOurs, true, htlc, keyRing)
err := addHTLC(
commitTx, isOurs, true, htlc, keyRing,
cb.chanState.ChanType,
)
if err != nil {
return nil, err
}
@@ -430,7 +569,8 @@ func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
func CreateCommitTx(chanType channeldb.ChannelType,
fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
amountToLocal, amountToRemote btcutil.Amount) (*wire.MsgTx, error) {
amountToLocal, amountToRemote btcutil.Amount,
numHTLCs int64) (*wire.MsgTx, error) {
// First, we create the script for the delayed "pay-to-self" output.
// This output has 2 main redemption clauses: either we can redeem the
@@ -452,8 +592,8 @@ func CreateCommitTx(chanType channeldb.ChannelType,
}
// Next, we create the script paying to the remote.
toRemoteScript, err := CommitScriptToRemote(
chanType, uint32(remoteChanCfg.CsvDelay), keyRing.ToRemoteKey,
toRemoteScript, _, err := CommitScriptToRemote(
chanType, keyRing.ToRemoteKey,
)
if err != nil {
return nil, err
@@ -466,26 +606,58 @@ func CreateCommitTx(chanType channeldb.ChannelType,
commitTx.AddTxIn(&fundingOutput)
// Avoid creating dust outputs within the commitment transaction.
if amountToLocal >= localChanCfg.DustLimit {
localOutput := amountToLocal >= localChanCfg.DustLimit
if localOutput {
commitTx.AddTxOut(&wire.TxOut{
PkScript: toLocalScriptHash,
Value: int64(amountToLocal),
})
}
if amountToRemote >= localChanCfg.DustLimit {
remoteOutput := amountToRemote >= localChanCfg.DustLimit
if remoteOutput {
commitTx.AddTxOut(&wire.TxOut{
PkScript: toRemoteScript.PkScript,
Value: int64(amountToRemote),
})
}
// If this channel type has anchors, we'll also add those.
if chanType.HasAnchors() {
localAnchor, remoteAnchor, err := CommitScriptAnchors(
localChanCfg, remoteChanCfg,
)
if err != nil {
return nil, err
}
// Add local anchor output only if we have a commitment output
// or there are HTLCs.
if localOutput || numHTLCs > 0 {
commitTx.AddTxOut(&wire.TxOut{
PkScript: localAnchor.PkScript,
Value: int64(anchorSize),
})
}
// Add anchor output to remote only if they have a commitment
// output or there are HTLCs.
if remoteOutput || numHTLCs > 0 {
commitTx.AddTxOut(&wire.TxOut{
PkScript: remoteAnchor.PkScript,
Value: int64(anchorSize),
})
}
}
return commitTx, nil
}
// genHtlcScript generates the proper P2WSH public key scripts for the HTLC
// output modified by two-bits denoting if this is an incoming HTLC, and if the
// HTLC is being applied to their commitment transaction or ours.
func genHtlcScript(isIncoming, ourCommit bool, timeout uint32, rHash [32]byte,
func genHtlcScript(chanType channeldb.ChannelType, isIncoming, ourCommit bool,
timeout uint32, rHash [32]byte,
keyRing *CommitmentKeyRing) ([]byte, []byte, error) {
var (
@@ -493,6 +665,12 @@ func genHtlcScript(isIncoming, ourCommit bool, timeout uint32, rHash [32]byte,
err error
)
// Choose scripts based on channel type.
confirmedHtlcSpends := false
if chanType.HasAnchors() {
confirmedHtlcSpends = true
}
// Generate the proper redeem scripts for the HTLC output modified by
// two-bits denoting if this is an incoming HTLC, and if the HTLC is
// being applied to their commitment transaction or ours.
@@ -501,30 +679,37 @@ func genHtlcScript(isIncoming, ourCommit bool, timeout uint32, rHash [32]byte,
// transaction. So we need to use the receiver's version of HTLC the
// script.
case isIncoming && ourCommit:
witnessScript, err = input.ReceiverHTLCScript(timeout,
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
keyRing.RevocationKey, rHash[:])
witnessScript, err = input.ReceiverHTLCScript(
timeout, keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
)
// We're being paid via an HTLC by the remote party, and the HTLC is
// being added to their commitment transaction, so we use the sender's
// version of the HTLC script.
case isIncoming && !ourCommit:
witnessScript, err = input.SenderHTLCScript(keyRing.RemoteHtlcKey,
keyRing.LocalHtlcKey, keyRing.RevocationKey, rHash[:])
witnessScript, err = input.SenderHTLCScript(
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
)
// We're sending an HTLC which is being added to our commitment
// transaction. Therefore, we need to use the sender's version of the
// HTLC script.
case !isIncoming && ourCommit:
witnessScript, err = input.SenderHTLCScript(keyRing.LocalHtlcKey,
keyRing.RemoteHtlcKey, keyRing.RevocationKey, rHash[:])
witnessScript, err = input.SenderHTLCScript(
keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
)
// Finally, we're paying the remote party via an HTLC, which is being
// added to their commitment transaction. Therefore, we use the
// receiver's version of the HTLC script.
case !isIncoming && !ourCommit:
witnessScript, err = input.ReceiverHTLCScript(timeout, keyRing.LocalHtlcKey,
keyRing.RemoteHtlcKey, keyRing.RevocationKey, rHash[:])
witnessScript, err = input.ReceiverHTLCScript(
timeout, keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
)
}
if err != nil {
return nil, nil, err
@@ -549,13 +734,14 @@ func genHtlcScript(isIncoming, ourCommit bool, timeout uint32, rHash [32]byte,
// the descriptor itself.
func addHTLC(commitTx *wire.MsgTx, ourCommit bool,
isIncoming bool, paymentDesc *PaymentDescriptor,
keyRing *CommitmentKeyRing) error {
keyRing *CommitmentKeyRing, chanType channeldb.ChannelType) error {
timeout := paymentDesc.Timeout
rHash := paymentDesc.RHash
p2wsh, witnessScript, err := genHtlcScript(isIncoming, ourCommit,
timeout, rHash, keyRing)
p2wsh, witnessScript, err := genHtlcScript(
chanType, isIncoming, ourCommit, timeout, rHash, keyRing,
)
if err != nil {
return err
}
+13 -9
View File
@@ -700,7 +700,8 @@ func testCancelNonExistentReservation(miner *rpctest.Harness,
// Create our own reservation, give it some ID.
res, err := lnwallet.NewChannelReservation(
10000, 10000, feePerKw, alice, 22, 10, &testHdSeed,
lnwire.FFAnnounceChannel, true, nil, [32]byte{},
lnwire.FFAnnounceChannel, lnwallet.CommitmentTypeTweakless,
nil, [32]byte{},
)
if err != nil {
t.Fatalf("unable to create res: %v", err)
@@ -738,7 +739,7 @@ func testReservationInitiatorBalanceBelowDustCancel(miner *rpctest.Harness,
FundingFeePerKw: 1000,
PushMSat: 0,
Flags: lnwire.FFAnnounceChannel,
Tweakless: true,
CommitType: lnwallet.CommitmentTypeTweakless,
}
_, err = alice.InitChannelReservation(req)
switch {
@@ -793,7 +794,8 @@ func assertContributionInitPopulated(t *testing.T, c *lnwallet.ChannelContributi
}
func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
alice, bob *lnwallet.LightningWallet, t *testing.T, tweakless bool,
alice, bob *lnwallet.LightningWallet, t *testing.T,
commitType lnwallet.CommitmentType,
aliceChanFunder chanfunding.Assembler,
fetchFundingTx func() *wire.MsgTx, pendingChanID [32]byte) {
@@ -823,7 +825,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
FundingFeePerKw: feePerKw,
PushMSat: pushAmt,
Flags: lnwire.FFAnnounceChannel,
Tweakless: tweakless,
CommitType: commitType,
ChanFunder: aliceChanFunder,
}
aliceChanReservation, err := alice.InitChannelReservation(aliceReq)
@@ -874,7 +876,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
FundingFeePerKw: feePerKw,
PushMSat: pushAmt,
Flags: lnwire.FFAnnounceChannel,
Tweakless: tweakless,
CommitType: commitType,
}
bobChanReservation, err := bob.InitChannelReservation(bobReq)
if err != nil {
@@ -2543,7 +2545,8 @@ var walletTests = []walletTestCase{
bob *lnwallet.LightningWallet, t *testing.T) {
testSingleFunderReservationWorkflow(
miner, alice, bob, t, false, nil, nil,
miner, alice, bob, t,
lnwallet.CommitmentTypeLegacy, nil, nil,
[32]byte{},
)
},
@@ -2554,7 +2557,8 @@ var walletTests = []walletTestCase{
bob *lnwallet.LightningWallet, t *testing.T) {
testSingleFunderReservationWorkflow(
miner, alice, bob, t, true, nil, nil,
miner, alice, bob, t,
lnwallet.CommitmentTypeTweakless, nil, nil,
[32]byte{},
)
},
@@ -2809,8 +2813,8 @@ func testSingleFunderExternalFundingTx(miner *rpctest.Harness,
// pending channel ID generated above to allow Alice and Bob to track
// the funding flow externally.
testSingleFunderReservationWorkflow(
miner, alice, bob, t, true, aliceExternalFunder,
func() *wire.MsgTx {
miner, alice, bob, t, lnwallet.CommitmentTypeTweakless,
aliceExternalFunder, func() *wire.MsgTx {
return fundingTx
}, pendingChanID,
)
+68 -3
View File
@@ -15,6 +15,39 @@ import (
"github.com/lightningnetwork/lnd/lnwire"
)
// CommitmentType is an enum indicating the commitment type we should use for
// the channel we are opening.
type CommitmentType int
const (
// CommitmentTypeLegacy is the legacy commitment format with a tweaked
// to_remote key.
CommitmentTypeLegacy = iota
// CommitmentTypeTweakless is a newer commitment format where the
// to_remote key is static.
CommitmentTypeTweakless
// CommitmentTypeAnchors is a commitment type that is tweakless, and
// has extra anchor ouputs in order to bump the fee of the commitment
// transaction.
CommitmentTypeAnchors
)
// String returns the name of the CommitmentType.
func (c CommitmentType) String() string {
switch c {
case CommitmentTypeLegacy:
return "legacy"
case CommitmentTypeTweakless:
return "tweakless"
case CommitmentTypeAnchors:
return "anchors"
default:
return "invalid"
}
}
// ChannelContribution is the primary constituent of the funding workflow
// within lnwallet. Each side first exchanges their respective contributions
// along with channel specific parameters like the min fee/KB. Once
@@ -136,7 +169,7 @@ type ChannelReservation struct {
func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
commitFeePerKw chainfee.SatPerKWeight, wallet *LightningWallet,
id uint64, pushMSat lnwire.MilliSatoshi, chainHash *chainhash.Hash,
flags lnwire.FundingFlag, tweaklessCommit bool,
flags lnwire.FundingFlag, commitType CommitmentType,
fundingAssembler chanfunding.Assembler,
pendingChanID [32]byte) (*ChannelReservation, error) {
@@ -146,12 +179,25 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
initiator bool
)
commitFee := commitFeePerKw.FeeForWeight(input.CommitWeight)
// Based on the channel type, we determine the initial commit weight
// and fee.
commitWeight := int64(input.CommitWeight)
if commitType == CommitmentTypeAnchors {
commitWeight = input.AnchorCommitWeight
}
commitFee := commitFeePerKw.FeeForWeight(commitWeight)
localFundingMSat := lnwire.NewMSatFromSatoshis(localFundingAmt)
// TODO(halseth): make method take remote funding amount directly
// instead of inferring it from capacity and local amt.
capacityMSat := lnwire.NewMSatFromSatoshis(capacity)
// The total fee paid by the initiator will be the commitment fee in
// addition to the two anchor outputs.
feeMSat := lnwire.NewMSatFromSatoshis(commitFee)
if commitType == CommitmentTypeAnchors {
feeMSat += 2 * lnwire.NewMSatFromSatoshis(anchorSize)
}
// If we're the responder to a single-funder reservation, then we have
// no initial balance in the channel unless the remote party is pushing
@@ -213,6 +259,16 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
)
}
// Similarly we ensure their balance is reasonable if we are not the
// initiator.
if !initiator && theirBalance.ToSatoshis() <= 2*DefaultDustLimit() {
return nil, ErrFunderBalanceDust(
int64(commitFee),
int64(theirBalance.ToSatoshis()),
int64(2*DefaultDustLimit()),
)
}
// Next we'll set the channel type based on what we can ascertain about
// the balances/push amount within the channel.
var chanType channeldb.ChannelType
@@ -221,7 +277,11 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
// non-zero push amt (there's no pushing for dual funder), then this is
// a single-funder channel.
if ourBalance == 0 || theirBalance == 0 || pushMSat != 0 {
if tweaklessCommit {
// Both the tweakless type and the anchor type is tweakless,
// hence set the bit.
if commitType == CommitmentTypeTweakless ||
commitType == CommitmentTypeAnchors {
chanType |= channeldb.SingleFunderTweaklessBit
} else {
chanType |= channeldb.SingleFunderBit
@@ -241,6 +301,11 @@ func NewChannelReservation(capacity, localFundingAmt btcutil.Amount,
chanType |= channeldb.DualFunderBit
}
// We are adding anchor outputs to our commitment.
if commitType == CommitmentTypeAnchors {
chanType |= channeldb.AnchorOutputsBit
}
return &ChannelReservation{
ourContribution: &ChannelContribution{
FundingAmount: ourBalance.ToSatoshis(),
+17 -9
View File
@@ -7,6 +7,7 @@ import (
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/input"
)
@@ -44,8 +45,8 @@ var (
// In order to spend the HTLC output, the witness for the passed transaction
// should be:
// * <0> <sender sig> <recvr sig> <preimage>
func createHtlcSuccessTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
csvDelay uint32,
func createHtlcSuccessTx(chanType channeldb.ChannelType,
htlcOutput wire.OutPoint, htlcAmt btcutil.Amount, csvDelay uint32,
revocationKey, delayKey *btcec.PublicKey) (*wire.MsgTx, error) {
// Create a version two transaction (as the success version of this
@@ -53,10 +54,13 @@ func createHtlcSuccessTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
successTx := wire.NewMsgTx(2)
// The input to the transaction is the outpoint that creates the
// original HTLC on the sender's commitment transaction.
successTx.AddTxIn(&wire.TxIn{
// original HTLC on the sender's commitment transaction. Set the
// sequence number based on the channel type.
txin := &wire.TxIn{
PreviousOutPoint: htlcOutput,
})
Sequence: HtlcSecondLevelInputSequence(chanType),
}
successTx.AddTxIn(txin)
// Next, we'll generate the script used as the output for all second
// level HTLC which forces a covenant w.r.t what can be done with all
@@ -97,7 +101,8 @@ func createHtlcSuccessTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
// NOTE: The passed amount for the HTLC should take into account the required
// fee rate at the time the HTLC was created. The fee should be able to
// entirely pay for this (tiny: 1-in 1-out) transaction.
func createHtlcTimeoutTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
func createHtlcTimeoutTx(chanType channeldb.ChannelType,
htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
cltvExpiry, csvDelay uint32,
revocationKey, delayKey *btcec.PublicKey) (*wire.MsgTx, error) {
@@ -108,10 +113,13 @@ func createHtlcTimeoutTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
timeoutTx.LockTime = cltvExpiry
// The input to the transaction is the outpoint that creates the
// original HTLC on the sender's commitment transaction.
timeoutTx.AddTxIn(&wire.TxIn{
// original HTLC on the sender's commitment transaction. Set the
// sequence number based on the channel type.
txin := &wire.TxIn{
PreviousOutPoint: htlcOutput,
})
Sequence: HtlcSecondLevelInputSequence(chanType),
}
timeoutTx.AddTxIn(txin)
// Next, we'll generate the script used as the output for all second
// level HTLC which forces a covenant w.r.t what can be done with all
+4 -3
View File
@@ -851,9 +851,10 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
// Generate second-level HTLC transactions for HTLCs in
// commitment tx.
htlcResolutions, err := extractHtlcResolutions(
chainfee.SatPerKWeight(test.commitment.FeePerKw), true, signer,
htlcs, keys, &channel.channelState.LocalChanCfg,
chainfee.SatPerKWeight(test.commitment.FeePerKw), true,
signer, htlcs, keys, &channel.channelState.LocalChanCfg,
&channel.channelState.RemoteChanCfg, commitTx.TxHash(),
channel.channelState.ChanType,
)
if err != nil {
t.Errorf("Case %d: Failed to extract HTLC resolutions: %v", i, err)
@@ -1089,7 +1090,7 @@ func testSpendValidation(t *testing.T, tweakless bool) {
}
commitmentTx, err := CreateCommitTx(
channelType, *fakeFundingTxIn, keyRing, aliceChanCfg,
bobChanCfg, channelBalance, channelBalance,
bobChanCfg, channelBalance, channelBalance, 0,
)
if err != nil {
t.Fatalf("unable to create commitment transaction: %v", nil)
+6 -6
View File
@@ -98,9 +98,9 @@ type InitFundingReserveMsg struct {
// output selected to fund the channel should satisfy.
MinConfs int32
// Tweakless indicates if the channel should use the new tweakless
// commitment format or not.
Tweakless bool
// CommitType indicates what type of commitment type the channel should
// be using, like tweakless or anchors.
CommitType CommitmentType
// ChanFunder is an optional channel funder that allows the caller to
// control exactly how the channel funding is carried out. If not
@@ -568,7 +568,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
reservation, err := NewChannelReservation(
capacity, localFundingAmt, req.CommitFeePerKw, l, id,
req.PushMSat, l.Cfg.NetParams.GenesisHash, req.Flags,
req.Tweakless, req.ChanFunder, req.PendingChanID,
req.CommitType, req.ChanFunder, req.PendingChanID,
)
if err != nil {
if fundingIntent != nil {
@@ -784,7 +784,7 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
ourCommitTx, err := CreateCommitTx(
chanType, fundingTxIn, localCommitmentKeys, ourChanCfg,
theirChanCfg, localBalance, remoteBalance,
theirChanCfg, localBalance, remoteBalance, 0,
)
if err != nil {
return nil, nil, err
@@ -797,7 +797,7 @@ func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
theirCommitTx, err := CreateCommitTx(
chanType, fundingTxIn, remoteCommitmentKeys, theirChanCfg,
ourChanCfg, remoteBalance, localBalance,
ourChanCfg, remoteBalance, localBalance, 0,
)
if err != nil {
return nil, nil, err