You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
473 lines
15 KiB
473 lines
15 KiB
package input |
|
|
|
import ( |
|
"fmt" |
|
|
|
"github.com/btcsuite/btcd/txscript" |
|
"github.com/btcsuite/btcd/wire" |
|
) |
|
|
|
// WitnessGenerator represents a function that is able to generate the final |
|
// witness for a particular public key script. Additionally, if required, this |
|
// function will also return the sigScript for spending nested P2SH witness |
|
// outputs. This function acts as an abstraction layer, hiding the details of |
|
// the underlying script. |
|
type WitnessGenerator func(tx *wire.MsgTx, hc *txscript.TxSigHashes, |
|
inputIndex int) (*Script, error) |
|
|
|
// WitnessType determines how an output's witness will be generated. This |
|
// interface can be implemented to be used for custom sweep scripts if the |
|
// pre-defined StandardWitnessType list doesn't provide a suitable one. |
|
type WitnessType interface { |
|
// String returns a human readable version of the WitnessType. |
|
String() string |
|
|
|
// WitnessGenerator will return a WitnessGenerator function that an |
|
// output uses to generate the witness and optionally the sigScript for |
|
// a sweep transaction. |
|
WitnessGenerator(signer Signer, |
|
descriptor *SignDescriptor) WitnessGenerator |
|
|
|
// SizeUpperBound returns the maximum length of the witness of this |
|
// WitnessType if it would be included in a tx. It also returns if the |
|
// output itself is a nested p2sh output, if so then we need to take |
|
// into account the extra sigScript data size. |
|
SizeUpperBound() (int, bool, error) |
|
|
|
// AddWeightEstimation adds the estimated size of the witness in bytes |
|
// to the given weight estimator. |
|
AddWeightEstimation(e *TxWeightEstimator) error |
|
} |
|
|
|
// StandardWitnessType is a numeric representation of standard pre-defined types |
|
// of witness configurations. |
|
type StandardWitnessType uint16 |
|
|
|
// A compile time check to ensure StandardWitnessType implements the |
|
// WitnessType interface. |
|
var _ WitnessType = (StandardWitnessType)(0) |
|
|
|
const ( |
|
// CommitmentTimeLock is a witness that allows us to spend our output |
|
// on our local commitment transaction after a relative lock-time |
|
// lockout. |
|
CommitmentTimeLock StandardWitnessType = 0 |
|
|
|
// CommitmentNoDelay is a witness that allows us to spend a settled |
|
// no-delay output immediately on a counterparty's commitment |
|
// transaction. |
|
CommitmentNoDelay StandardWitnessType = 1 |
|
|
|
// CommitmentRevoke is a witness that allows us to sweep the settled |
|
// output of a malicious counterparty's who broadcasts a revoked |
|
// commitment transaction. |
|
CommitmentRevoke StandardWitnessType = 2 |
|
|
|
// HtlcOfferedRevoke is a witness that allows us to sweep an HTLC which |
|
// we offered to the remote party in the case that they broadcast a |
|
// revoked commitment state. |
|
HtlcOfferedRevoke StandardWitnessType = 3 |
|
|
|
// HtlcAcceptedRevoke is a witness that allows us to sweep an HTLC |
|
// output sent to us in the case that the remote party broadcasts a |
|
// revoked commitment state. |
|
HtlcAcceptedRevoke StandardWitnessType = 4 |
|
|
|
// HtlcOfferedTimeoutSecondLevel is a witness that allows us to sweep |
|
// an HTLC output that we extended to a party, but was never fulfilled. |
|
// This HTLC output isn't directly on the commitment transaction, but |
|
// is the result of a confirmed second-level HTLC transaction. As a |
|
// result, we can only spend this after a CSV delay. |
|
HtlcOfferedTimeoutSecondLevel StandardWitnessType = 5 |
|
|
|
// HtlcOfferedTimeoutSecondLevelInputConfirmed is a witness that allows |
|
// us to sweep an HTLC output that we extended to a party, but was |
|
// never fulfilled. This _is_ the HTLC output directly on our |
|
// commitment transaction, and the input to the second-level HTLC |
|
// tiemout transaction. It can only be spent after CLTV expiry, and |
|
// commitment confirmation. |
|
HtlcOfferedTimeoutSecondLevelInputConfirmed StandardWitnessType = 15 |
|
|
|
// HtlcAcceptedSuccessSecondLevel is a witness that allows us to sweep |
|
// an HTLC output that was offered to us, and for which we have a |
|
// payment preimage. This HTLC output isn't directly on our commitment |
|
// transaction, but is the result of confirmed second-level HTLC |
|
// transaction. As a result, we can only spend this after a CSV delay. |
|
HtlcAcceptedSuccessSecondLevel StandardWitnessType = 6 |
|
|
|
// HtlcAcceptedSuccessSecondLevelInputConfirmed is a witness that |
|
// allows us to sweep an HTLC output that was offered to us, and for |
|
// which we have a payment preimage. This _is_ the HTLC output directly |
|
// on our commitment transaction, and the input to the second-level |
|
// HTLC success transaction. It can only be spent after the commitment |
|
// has confirmed. |
|
HtlcAcceptedSuccessSecondLevelInputConfirmed StandardWitnessType = 16 |
|
|
|
// HtlcOfferedRemoteTimeout is a witness that allows us to sweep an |
|
// HTLC that we offered to the remote party which lies in the |
|
// commitment transaction of the remote party. We can spend this output |
|
// after the absolute CLTV timeout of the HTLC as passed. |
|
HtlcOfferedRemoteTimeout StandardWitnessType = 7 |
|
|
|
// HtlcAcceptedRemoteSuccess is a witness that allows us to sweep an |
|
// HTLC that was offered to us by the remote party. We use this witness |
|
// in the case that the remote party goes to chain, and we know the |
|
// pre-image to the HTLC. We can sweep this without any additional |
|
// timeout. |
|
HtlcAcceptedRemoteSuccess StandardWitnessType = 8 |
|
|
|
// HtlcSecondLevelRevoke is a witness that allows us to sweep an HTLC |
|
// from the remote party's commitment transaction in the case that the |
|
// broadcast a revoked commitment, but then also immediately attempt to |
|
// go to the second level to claim the HTLC. |
|
HtlcSecondLevelRevoke StandardWitnessType = 9 |
|
|
|
// WitnessKeyHash is a witness type that allows us to spend a regular |
|
// p2wkh output that's sent to an output which is under complete |
|
// control of the backing wallet. |
|
WitnessKeyHash StandardWitnessType = 10 |
|
|
|
// NestedWitnessKeyHash is a witness type that allows us to sweep an |
|
// output that sends to a nested P2SH script that pays to a key solely |
|
// under our control. The witness generated needs to include the |
|
NestedWitnessKeyHash StandardWitnessType = 11 |
|
|
|
// CommitSpendNoDelayTweakless is similar to the CommitSpendNoDelay |
|
// type, but it omits the tweak that randomizes the key we need to |
|
// spend with a channel peer supplied set of randomness. |
|
CommitSpendNoDelayTweakless StandardWitnessType = 12 |
|
|
|
// CommitmentToRemoteConfirmed is a witness that allows us to spend our |
|
// output on the counterparty's commitment transaction after a |
|
// confirmation. |
|
CommitmentToRemoteConfirmed StandardWitnessType = 13 |
|
|
|
// CommitmentAnchor is a witness that allows us to spend our anchor on |
|
// the commitment transaction. |
|
CommitmentAnchor StandardWitnessType = 14 |
|
) |
|
|
|
// String returns a human readable version of the target WitnessType. |
|
// |
|
// NOTE: This is part of the WitnessType interface. |
|
func (wt StandardWitnessType) String() string { |
|
switch wt { |
|
case CommitmentTimeLock: |
|
return "CommitmentTimeLock" |
|
|
|
case CommitmentToRemoteConfirmed: |
|
return "CommitmentToRemoteConfirmed" |
|
|
|
case CommitmentAnchor: |
|
return "CommitmentAnchor" |
|
|
|
case CommitmentNoDelay: |
|
return "CommitmentNoDelay" |
|
|
|
case CommitSpendNoDelayTweakless: |
|
return "CommitmentNoDelayTweakless" |
|
|
|
case CommitmentRevoke: |
|
return "CommitmentRevoke" |
|
|
|
case HtlcOfferedRevoke: |
|
return "HtlcOfferedRevoke" |
|
|
|
case HtlcAcceptedRevoke: |
|
return "HtlcAcceptedRevoke" |
|
|
|
case HtlcOfferedTimeoutSecondLevel: |
|
return "HtlcOfferedTimeoutSecondLevel" |
|
|
|
case HtlcOfferedTimeoutSecondLevelInputConfirmed: |
|
return "HtlcOfferedTimeoutSecondLevelInputConfirmed" |
|
|
|
case HtlcAcceptedSuccessSecondLevel: |
|
return "HtlcAcceptedSuccessSecondLevel" |
|
|
|
case HtlcAcceptedSuccessSecondLevelInputConfirmed: |
|
return "HtlcAcceptedSuccessSecondLevelInputConfirmed" |
|
|
|
case HtlcOfferedRemoteTimeout: |
|
return "HtlcOfferedRemoteTimeout" |
|
|
|
case HtlcAcceptedRemoteSuccess: |
|
return "HtlcAcceptedRemoteSuccess" |
|
|
|
case HtlcSecondLevelRevoke: |
|
return "HtlcSecondLevelRevoke" |
|
|
|
case WitnessKeyHash: |
|
return "WitnessKeyHash" |
|
|
|
case NestedWitnessKeyHash: |
|
return "NestedWitnessKeyHash" |
|
|
|
default: |
|
return fmt.Sprintf("Unknown WitnessType: %v", uint32(wt)) |
|
} |
|
} |
|
|
|
// WitnessGenerator will return a WitnessGenerator function that an output uses |
|
// to generate the witness and optionally the sigScript for a sweep |
|
// transaction. The sigScript will be generated if the witness type warrants |
|
// one for spending, such as the NestedWitnessKeyHash witness type. |
|
// |
|
// NOTE: This is part of the WitnessType interface. |
|
func (wt StandardWitnessType) WitnessGenerator(signer Signer, |
|
descriptor *SignDescriptor) WitnessGenerator { |
|
|
|
return func(tx *wire.MsgTx, hc *txscript.TxSigHashes, |
|
inputIndex int) (*Script, error) { |
|
|
|
desc := descriptor |
|
desc.SigHashes = hc |
|
desc.InputIndex = inputIndex |
|
|
|
switch wt { |
|
case CommitmentTimeLock: |
|
witness, err := CommitSpendTimeout(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case CommitmentToRemoteConfirmed: |
|
witness, err := CommitSpendToRemoteConfirmed( |
|
signer, desc, tx, |
|
) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case CommitmentAnchor: |
|
witness, err := CommitSpendAnchor(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case CommitmentNoDelay: |
|
witness, err := CommitSpendNoDelay(signer, desc, tx, false) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case CommitSpendNoDelayTweakless: |
|
witness, err := CommitSpendNoDelay(signer, desc, tx, true) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case CommitmentRevoke: |
|
witness, err := CommitSpendRevoke(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case HtlcOfferedRevoke: |
|
witness, err := ReceiverHtlcSpendRevoke(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case HtlcAcceptedRevoke: |
|
witness, err := SenderHtlcSpendRevoke(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case HtlcOfferedTimeoutSecondLevel: |
|
witness, err := HtlcSecondLevelSpend(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case HtlcAcceptedSuccessSecondLevel: |
|
witness, err := HtlcSecondLevelSpend(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case HtlcOfferedRemoteTimeout: |
|
// We pass in a value of -1 for the timeout, as we |
|
// expect the caller to have already set the lock time |
|
// value. |
|
witness, err := ReceiverHtlcSpendTimeout(signer, desc, tx, -1) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case HtlcSecondLevelRevoke: |
|
witness, err := HtlcSpendRevoke(signer, desc, tx) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
return &Script{ |
|
Witness: witness, |
|
}, nil |
|
|
|
case WitnessKeyHash: |
|
fallthrough |
|
case NestedWitnessKeyHash: |
|
return signer.ComputeInputScript(tx, desc) |
|
|
|
default: |
|
return nil, fmt.Errorf("unknown witness type: %v", wt) |
|
} |
|
} |
|
} |
|
|
|
// SizeUpperBound returns the maximum length of the witness of this witness |
|
// type if it would be included in a tx. We also return if the output itself is |
|
// a nested p2sh output, if so then we need to take into account the extra |
|
// sigScript data size. |
|
// |
|
// NOTE: This is part of the WitnessType interface. |
|
func (wt StandardWitnessType) SizeUpperBound() (int, bool, error) { |
|
switch wt { |
|
|
|
// Outputs on a remote commitment transaction that pay directly to us. |
|
case CommitSpendNoDelayTweakless: |
|
fallthrough |
|
case WitnessKeyHash: |
|
fallthrough |
|
case CommitmentNoDelay: |
|
return P2WKHWitnessSize, false, nil |
|
|
|
// Outputs on a past commitment transaction that pay directly |
|
// to us. |
|
case CommitmentTimeLock: |
|
return ToLocalTimeoutWitnessSize, false, nil |
|
|
|
// 1 CSV time locked output to us on remote commitment. |
|
case CommitmentToRemoteConfirmed: |
|
return ToRemoteConfirmedWitnessSize, false, nil |
|
|
|
// Anchor output on the commitment transaction. |
|
case CommitmentAnchor: |
|
return AnchorWitnessSize, false, nil |
|
|
|
// Outgoing second layer HTLC's that have confirmed within the |
|
// chain, and the output they produced is now mature enough to |
|
// sweep. |
|
case HtlcOfferedTimeoutSecondLevel: |
|
return ToLocalTimeoutWitnessSize, false, nil |
|
|
|
// Input to the outgoing HTLC second layer timeout transaction. |
|
case HtlcOfferedTimeoutSecondLevelInputConfirmed: |
|
return OfferedHtlcTimeoutWitnessSizeConfirmed, false, nil |
|
|
|
// Incoming second layer HTLC's that have confirmed within the |
|
// chain, and the output they produced is now mature enough to |
|
// sweep. |
|
case HtlcAcceptedSuccessSecondLevel: |
|
return ToLocalTimeoutWitnessSize, false, nil |
|
|
|
// Input to the incoming second-layer HTLC success transaction. |
|
case HtlcAcceptedSuccessSecondLevelInputConfirmed: |
|
return AcceptedHtlcSuccessWitnessSizeConfirmed, false, nil |
|
|
|
// An HTLC on the commitment transaction of the remote party, |
|
// that has had its absolute timelock expire. |
|
case HtlcOfferedRemoteTimeout: |
|
return AcceptedHtlcTimeoutWitnessSize, false, nil |
|
|
|
// An HTLC on the commitment transaction of the remote party, |
|
// that can be swept with the preimage. |
|
case HtlcAcceptedRemoteSuccess: |
|
return OfferedHtlcSuccessWitnessSize, false, nil |
|
|
|
// A nested P2SH input that has a p2wkh witness script. We'll mark this |
|
// as nested P2SH so the caller can estimate the weight properly |
|
// including the sigScript. |
|
case NestedWitnessKeyHash: |
|
return P2WKHWitnessSize, true, nil |
|
|
|
// The revocation output on a revoked commitment transaction. |
|
case CommitmentRevoke: |
|
return ToLocalPenaltyWitnessSize, false, nil |
|
|
|
// The revocation output on a revoked HTLC that we offered to the remote |
|
// party. |
|
case HtlcOfferedRevoke: |
|
return OfferedHtlcPenaltyWitnessSize, false, nil |
|
|
|
// The revocation output on a revoked HTLC that was sent to us. |
|
case HtlcAcceptedRevoke: |
|
return AcceptedHtlcPenaltyWitnessSize, false, nil |
|
|
|
// The revocation output of a second level output of an HTLC. |
|
case HtlcSecondLevelRevoke: |
|
return ToLocalPenaltyWitnessSize, false, nil |
|
} |
|
|
|
return 0, false, fmt.Errorf("unexpected witness type: %v", wt) |
|
} |
|
|
|
// AddWeightEstimation adds the estimated size of the witness in bytes to the |
|
// given weight estimator. |
|
// |
|
// NOTE: This is part of the WitnessType interface. |
|
func (wt StandardWitnessType) AddWeightEstimation(e *TxWeightEstimator) error { |
|
// For fee estimation purposes, we'll now attempt to obtain an |
|
// upper bound on the weight this input will add when fully |
|
// populated. |
|
size, isNestedP2SH, err := wt.SizeUpperBound() |
|
if err != nil { |
|
return err |
|
} |
|
|
|
// If this is a nested P2SH input, then we'll need to factor in |
|
// the additional data push within the sigScript. |
|
if isNestedP2SH { |
|
e.AddNestedP2WSHInput(size) |
|
} else { |
|
e.AddWitnessInput(size) |
|
} |
|
|
|
return nil |
|
}
|
|
|