lnd.xprv/input/witnessgen.go

267 lines
7.7 KiB
Go
Raw Normal View History

package input
import (
"fmt"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
)
// WitnessType determines how an output's witness will be generated. The
// default commitmentTimeLock type will generate a witness that will allow
// spending of a time-locked transaction enforced by CheckSequenceVerify.
type WitnessType uint16
const (
// CommitmentTimeLock is a witness that allows us to spend the output of
// a commitment transaction after a relative lock-time lockout.
CommitmentTimeLock WitnessType = 0
// CommitmentNoDelay is a witness that allows us to spend a settled
// no-delay output immediately on a counterparty's commitment
// transaction.
CommitmentNoDelay WitnessType = 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 WitnessType = 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 WitnessType = 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 WitnessType = 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 WitnessType = 5
// 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 WitnessType = 6
// 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 WitnessType = 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 WitnessType = 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 WitnessType = 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 WitnessType = 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 WitnessType = 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 = 12
)
// Stirng returns a human readable version of the target WitnessType.
func (wt WitnessType) String() string {
switch wt {
case CommitmentTimeLock:
return "CommitmentTimeLock"
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 HtlcAcceptedSuccessSecondLevel:
return "HtlcAcceptedSuccessSecondLevel"
case HtlcOfferedRemoteTimeout:
return "HtlcOfferedRemoteTimeout"
case HtlcAcceptedRemoteSuccess:
return "HtlcAcceptedRemoteSuccess"
case HtlcSecondLevelRevoke:
return "HtlcSecondLevelRevoke"
default:
return fmt.Sprintf("Unknown WitnessType: %v", uint32(wt))
}
}
// WitnessGenerator represents a function which 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)
// GenWitnessFunc 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.
func (wt WitnessType) GenWitnessFunc(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 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)
}
}
}