multi: move Input interface and related code
This commit is a step to split the lnwallet package. It puts the Input interface and implementations in a separate package along with all their dependencies from lnwallet.
This commit is contained in:
66 files changed
+811
-689
No files matched your search
@@ -10,6 +10,7 @@ import (
|
||||
base "github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
"github.com/go-errors/errors"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
)
|
||||
@@ -132,18 +133,18 @@ func (b *BtcWallet) fetchPrivKey(keyDesc *keychain.KeyDescriptor) (*btcec.Privat
|
||||
// maybeTweakPrivKey examines the single and double tweak parameters on the
|
||||
// passed sign descriptor and may perform a mapping on the passed private key
|
||||
// in order to utilize the tweaks, if populated.
|
||||
func maybeTweakPrivKey(signDesc *lnwallet.SignDescriptor,
|
||||
func maybeTweakPrivKey(signDesc *input.SignDescriptor,
|
||||
privKey *btcec.PrivateKey) (*btcec.PrivateKey, error) {
|
||||
|
||||
var retPriv *btcec.PrivateKey
|
||||
switch {
|
||||
|
||||
case signDesc.SingleTweak != nil:
|
||||
retPriv = lnwallet.TweakPrivKey(privKey,
|
||||
retPriv = input.TweakPrivKey(privKey,
|
||||
signDesc.SingleTweak)
|
||||
|
||||
case signDesc.DoubleTweak != nil:
|
||||
retPriv = lnwallet.DeriveRevocationPrivKey(privKey,
|
||||
retPriv = input.DeriveRevocationPrivKey(privKey,
|
||||
signDesc.DoubleTweak)
|
||||
|
||||
default:
|
||||
@@ -158,7 +159,7 @@ func maybeTweakPrivKey(signDesc *lnwallet.SignDescriptor,
|
||||
//
|
||||
// This is a part of the WalletController interface.
|
||||
func (b *BtcWallet) SignOutputRaw(tx *wire.MsgTx,
|
||||
signDesc *lnwallet.SignDescriptor) ([]byte, error) {
|
||||
signDesc *input.SignDescriptor) ([]byte, error) {
|
||||
|
||||
witnessScript := signDesc.WitnessScript
|
||||
|
||||
@@ -199,7 +200,7 @@ func (b *BtcWallet) SignOutputRaw(tx *wire.MsgTx,
|
||||
//
|
||||
// This is a part of the WalletController interface.
|
||||
func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx,
|
||||
signDesc *lnwallet.SignDescriptor) (*lnwallet.InputScript, error) {
|
||||
signDesc *input.SignDescriptor) (*input.Script, error) {
|
||||
|
||||
outputScript := signDesc.Output.PkScript
|
||||
walletAddr, err := b.fetchOutputAddr(outputScript)
|
||||
@@ -214,7 +215,7 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx,
|
||||
}
|
||||
|
||||
var witnessProgram []byte
|
||||
inputScript := &lnwallet.InputScript{}
|
||||
inputScript := &input.Script{}
|
||||
|
||||
switch {
|
||||
|
||||
@@ -282,7 +283,7 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx,
|
||||
|
||||
// A compile time check to ensure that BtcWallet implements the Signer
|
||||
// interface.
|
||||
var _ lnwallet.Signer = (*BtcWallet)(nil)
|
||||
var _ input.Signer = (*BtcWallet)(nil)
|
||||
|
||||
// SignMessage attempts to sign a target message with the private key that
|
||||
// corresponds to the passed public key. If the target private key is unable to
|
||||
|
||||
+95
-94
@@ -9,17 +9,18 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcutil/txsort"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
var zeroHash chainhash.Hash
|
||||
@@ -967,16 +968,16 @@ func deriveCommitmentKeys(commitPoint *btcec.PublicKey, isOurCommit bool,
|
||||
keyRing := &CommitmentKeyRing{
|
||||
CommitPoint: commitPoint,
|
||||
|
||||
LocalCommitKeyTweak: SingleTweakBytes(
|
||||
LocalCommitKeyTweak: input.SingleTweakBytes(
|
||||
commitPoint, localChanCfg.PaymentBasePoint.PubKey,
|
||||
),
|
||||
LocalHtlcKeyTweak: SingleTweakBytes(
|
||||
LocalHtlcKeyTweak: input.SingleTweakBytes(
|
||||
commitPoint, localChanCfg.HtlcBasePoint.PubKey,
|
||||
),
|
||||
LocalHtlcKey: TweakPubKey(
|
||||
LocalHtlcKey: input.TweakPubKey(
|
||||
localChanCfg.HtlcBasePoint.PubKey, commitPoint,
|
||||
),
|
||||
RemoteHtlcKey: TweakPubKey(
|
||||
RemoteHtlcKey: input.TweakPubKey(
|
||||
remoteChanCfg.HtlcBasePoint.PubKey, commitPoint,
|
||||
),
|
||||
}
|
||||
@@ -1003,9 +1004,9 @@ func deriveCommitmentKeys(commitPoint *btcec.PublicKey, isOurCommit bool,
|
||||
|
||||
// With the base points assigned, we can now derive the actual keys
|
||||
// using the base point, and the current commitment tweak.
|
||||
keyRing.DelayKey = TweakPubKey(delayBasePoint, commitPoint)
|
||||
keyRing.NoDelayKey = TweakPubKey(noDelayBasePoint, commitPoint)
|
||||
keyRing.RevocationKey = DeriveRevocationPubkey(
|
||||
keyRing.DelayKey = input.TweakPubKey(delayBasePoint, commitPoint)
|
||||
keyRing.NoDelayKey = input.TweakPubKey(noDelayBasePoint, commitPoint)
|
||||
keyRing.RevocationKey = input.DeriveRevocationPubkey(
|
||||
revocationBasePoint, commitPoint,
|
||||
)
|
||||
|
||||
@@ -1285,11 +1286,11 @@ type LightningChannel struct {
|
||||
// Signer is the main signer instances that will be responsible for
|
||||
// signing any HTLC and commitment transaction generated by the state
|
||||
// machine.
|
||||
Signer Signer
|
||||
Signer input.Signer
|
||||
|
||||
// signDesc is the primary sign descriptor that is capable of signing
|
||||
// the commitment transaction that spends the multi-sig output.
|
||||
signDesc *SignDescriptor
|
||||
signDesc *input.SignDescriptor
|
||||
|
||||
channelEvents chainntnfs.ChainNotifier
|
||||
|
||||
@@ -1363,7 +1364,7 @@ type LightningChannel struct {
|
||||
// settled channel state. Throughout state transitions, then channel will
|
||||
// automatically persist pertinent state to the database in an efficient
|
||||
// manner.
|
||||
func NewLightningChannel(signer Signer, pCache PreimageCache,
|
||||
func NewLightningChannel(signer input.Signer, pCache PreimageCache,
|
||||
state *channeldb.OpenChannel,
|
||||
sigPool *SigPool) (*LightningChannel, error) {
|
||||
|
||||
@@ -1423,16 +1424,16 @@ func (lc *LightningChannel) createSignDesc() error {
|
||||
localKey := lc.localChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
||||
remoteKey := lc.remoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
||||
|
||||
multiSigScript, err := GenMultiSigScript(localKey, remoteKey)
|
||||
multiSigScript, err := input.GenMultiSigScript(localKey, remoteKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fundingPkScript, err := WitnessScriptHash(multiSigScript)
|
||||
fundingPkScript, err := input.WitnessScriptHash(multiSigScript)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
lc.signDesc = &SignDescriptor{
|
||||
lc.signDesc = &input.SignDescriptor{
|
||||
KeyDesc: lc.localChanCfg.MultiSigKey,
|
||||
WitnessScript: multiSigScript,
|
||||
Output: &wire.TxOut{
|
||||
@@ -1616,7 +1617,7 @@ func (lc *LightningChannel) restoreCommitState(
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
localCommitPoint := ComputeCommitmentPoint(ourRevPreImage[:])
|
||||
localCommitPoint := input.ComputeCommitmentPoint(ourRevPreImage[:])
|
||||
remoteCommitPoint := lc.channelState.RemoteCurrentRevocation
|
||||
|
||||
// With the revocation state reconstructed, we can now convert the disk
|
||||
@@ -1839,7 +1840,7 @@ type HtlcRetribution struct {
|
||||
// SignDesc is a design descriptor capable of generating the necessary
|
||||
// signatures to satisfy the revocation clause of the HTLC's public key
|
||||
// script.
|
||||
SignDesc SignDescriptor
|
||||
SignDesc input.SignDescriptor
|
||||
|
||||
// OutPoint is the target outpoint of this HTLC pointing to the
|
||||
// breached commitment transaction.
|
||||
@@ -1895,7 +1896,7 @@ type BreachRetribution struct {
|
||||
//
|
||||
// NOTE: A nil value indicates that the local output is considered dust
|
||||
// according to the remote party's dust limit.
|
||||
LocalOutputSignDesc *SignDescriptor
|
||||
LocalOutputSignDesc *input.SignDescriptor
|
||||
|
||||
// LocalOutpoint is the outpoint of the output paying to us (the local
|
||||
// party) within the breach transaction.
|
||||
@@ -1908,7 +1909,7 @@ type BreachRetribution struct {
|
||||
//
|
||||
// NOTE: A nil value indicates that the local output is considered dust
|
||||
// according to the remote party's dust limit.
|
||||
RemoteOutputSignDesc *SignDescriptor
|
||||
RemoteOutputSignDesc *input.SignDescriptor
|
||||
|
||||
// RemoteOutpoint is the outpoint of the output paying to the remote
|
||||
// party within the breach transaction.
|
||||
@@ -1963,17 +1964,17 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// number so we can have the proper witness script to sign and include
|
||||
// within the final witness.
|
||||
remoteDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
|
||||
remotePkScript, err := CommitScriptToSelf(
|
||||
remotePkScript, err := input.CommitScriptToSelf(
|
||||
remoteDelay, keyRing.DelayKey, keyRing.RevocationKey,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
remoteWitnessHash, err := WitnessScriptHash(remotePkScript)
|
||||
remoteWitnessHash, err := input.WitnessScriptHash(remotePkScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
localPkScript, err := CommitScriptUnencumbered(keyRing.NoDelayKey)
|
||||
localPkScript, err := input.CommitScriptUnencumbered(keyRing.NoDelayKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1999,8 +2000,8 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// commitment outputs. If either is considered dust using the remote
|
||||
// party's dust limit, the respective sign descriptor will be nil.
|
||||
var (
|
||||
localSignDesc *SignDescriptor
|
||||
remoteSignDesc *SignDescriptor
|
||||
localSignDesc *input.SignDescriptor
|
||||
remoteSignDesc *input.SignDescriptor
|
||||
)
|
||||
|
||||
// Compute the local and remote balances in satoshis.
|
||||
@@ -2010,7 +2011,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// If the local balance exceeds the remote party's dust limit,
|
||||
// instantiate the local sign descriptor.
|
||||
if localAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||
localSignDesc = &SignDescriptor{
|
||||
localSignDesc = &input.SignDescriptor{
|
||||
SingleTweak: keyRing.LocalCommitKeyTweak,
|
||||
KeyDesc: chanState.LocalChanCfg.PaymentBasePoint,
|
||||
WitnessScript: localPkScript,
|
||||
@@ -2025,7 +2026,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// Similarly, if the remote balance exceeds the remote party's dust
|
||||
// limit, assemble the remote sign descriptor.
|
||||
if remoteAmt >= chanState.RemoteChanCfg.DustLimit {
|
||||
remoteSignDesc = &SignDescriptor{
|
||||
remoteSignDesc = &input.SignDescriptor{
|
||||
KeyDesc: chanState.LocalChanCfg.RevocationBasePoint,
|
||||
DoubleTweak: commitmentSecret,
|
||||
WitnessScript: remotePkScript,
|
||||
@@ -2061,7 +2062,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// as we'll need it if we're revoking an HTLC output on the
|
||||
// remote commitment transaction, and *they* go to the second
|
||||
// level.
|
||||
secondLevelWitnessScript, err := secondLevelHtlcScript(
|
||||
secondLevelWitnessScript, err := input.SecondLevelHtlcScript(
|
||||
keyRing.RevocationKey, keyRing.DelayKey, remoteDelay,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -2072,7 +2073,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// the sender of the HTLC (relative to us). So we'll
|
||||
// re-generate the sender HTLC script.
|
||||
if htlc.Incoming {
|
||||
htlcWitnessScript, err = senderHTLCScript(
|
||||
htlcWitnessScript, err = input.SenderHTLCScript(
|
||||
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
|
||||
keyRing.RevocationKey, htlc.RHash[:],
|
||||
)
|
||||
@@ -2084,7 +2085,7 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// 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 = receiverHTLCScript(
|
||||
htlcWitnessScript, err = input.ReceiverHTLCScript(
|
||||
htlc.RefundTimeout, keyRing.LocalHtlcKey,
|
||||
keyRing.RemoteHtlcKey, keyRing.RevocationKey,
|
||||
htlc.RHash[:],
|
||||
@@ -2094,13 +2095,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
}
|
||||
}
|
||||
|
||||
htlcPkScript, err := WitnessScriptHash(htlcWitnessScript)
|
||||
htlcPkScript, err := input.WitnessScriptHash(htlcWitnessScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
htlcRetributions = append(htlcRetributions, HtlcRetribution{
|
||||
SignDesc: SignDescriptor{
|
||||
SignDesc: input.SignDescriptor{
|
||||
KeyDesc: chanState.LocalChanCfg.RevocationBasePoint,
|
||||
DoubleTweak: commitmentSecret,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
@@ -2141,13 +2142,13 @@ func NewBreachRetribution(chanState *channeldb.OpenChannel, stateNum uint64,
|
||||
// htlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
|
||||
// transaction based on the current fee rate.
|
||||
func htlcTimeoutFee(feePerKw SatPerKWeight) btcutil.Amount {
|
||||
return feePerKw.FeeForWeight(HtlcTimeoutWeight)
|
||||
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 SatPerKWeight) btcutil.Amount {
|
||||
return feePerKw.FeeForWeight(HtlcSuccessWeight)
|
||||
return feePerKw.FeeForWeight(input.HtlcSuccessWeight)
|
||||
}
|
||||
|
||||
// htlcIsDust determines if an HTLC output is dust or not depending on two
|
||||
@@ -2344,7 +2345,7 @@ func (lc *LightningChannel) createCommitmentTx(c *commitment,
|
||||
// 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 := CommitWeight + (HtlcWeight * numHTLCs)
|
||||
totalCommitWeight := input.CommitWeight + (input.HtlcWeight * numHTLCs)
|
||||
|
||||
// With the weight known, we can now calculate the commitment fee,
|
||||
// ensuring that we account for any dust outputs trimmed above.
|
||||
@@ -2793,7 +2794,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
|
||||
// Finally, we'll generate a sign descriptor to generate a
|
||||
// signature to give to the remote party for this commitment
|
||||
// transaction. Note we use the raw HTLC amount.
|
||||
sigJob.SignDesc = SignDescriptor{
|
||||
sigJob.SignDesc = input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.HtlcBasePoint,
|
||||
SingleTweak: keyRing.LocalHtlcKeyTweak,
|
||||
WitnessScript: htlc.theirWitnessScript,
|
||||
@@ -2844,7 +2845,7 @@ func genRemoteHtlcSigJobs(keyRing *CommitmentKeyRing,
|
||||
// Finally, we'll generate a sign descriptor to generate a
|
||||
// signature to give to the remote party for this commitment
|
||||
// transaction. Note we use the raw HTLC amount.
|
||||
sigJob.SignDesc = SignDescriptor{
|
||||
sigJob.SignDesc = input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.HtlcBasePoint,
|
||||
SingleTweak: keyRing.LocalHtlcKeyTweak,
|
||||
WitnessScript: htlc.theirWitnessScript,
|
||||
@@ -3539,7 +3540,7 @@ func ChanSyncMsg(c *channeldb.OpenChannel) (*lnwire.ChannelReestablish, error) {
|
||||
NextLocalCommitHeight: nextLocalCommitHeight,
|
||||
RemoteCommitTailHeight: remoteChainTipHeight,
|
||||
LastRemoteCommitSecret: lastCommitSecret,
|
||||
LocalUnrevokedCommitPoint: ComputeCommitmentPoint(
|
||||
LocalUnrevokedCommitPoint: input.ComputeCommitmentPoint(
|
||||
currentCommitSecret[:],
|
||||
),
|
||||
}, nil
|
||||
@@ -3607,7 +3608,7 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool,
|
||||
continue
|
||||
}
|
||||
|
||||
totalHtlcWeight += HtlcWeight
|
||||
totalHtlcWeight += input.HtlcWeight
|
||||
}
|
||||
for _, htlc := range filteredHTLCView.theirUpdates {
|
||||
if htlcIsDust(!remoteChain, !remoteChain, feePerKw,
|
||||
@@ -3615,10 +3616,10 @@ func (lc *LightningChannel) computeView(view *htlcView, remoteChain bool,
|
||||
continue
|
||||
}
|
||||
|
||||
totalHtlcWeight += HtlcWeight
|
||||
totalHtlcWeight += input.HtlcWeight
|
||||
}
|
||||
|
||||
totalCommitWeight := CommitWeight + totalHtlcWeight
|
||||
totalCommitWeight := input.CommitWeight + totalHtlcWeight
|
||||
return ourBalance, theirBalance, totalCommitWeight, filteredHTLCView
|
||||
}
|
||||
|
||||
@@ -4011,7 +4012,7 @@ func (lc *LightningChannel) ReceiveNewCommitment(commitSig lnwire.Sig,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
commitPoint := ComputeCommitmentPoint(commitSecret[:])
|
||||
commitPoint := input.ComputeCommitmentPoint(commitSecret[:])
|
||||
keyRing := deriveCommitmentKeys(commitPoint, true, lc.localChanCfg,
|
||||
lc.remoteChanCfg)
|
||||
|
||||
@@ -4238,7 +4239,7 @@ func (lc *LightningChannel) ReceiveRevocation(revMsg *lnwire.RevokeAndAck) (
|
||||
// revealed secret to derive a revocation key with our revocation base
|
||||
// point, then it matches the current revocation of the remote party.
|
||||
currentCommitPoint := lc.channelState.RemoteCurrentRevocation
|
||||
derivedCommitPoint := ComputeCommitmentPoint(revMsg.Revocation[:])
|
||||
derivedCommitPoint := input.ComputeCommitmentPoint(revMsg.Revocation[:])
|
||||
if !derivedCommitPoint.IsEqual(currentCommitPoint) {
|
||||
return nil, nil, nil, fmt.Errorf("revocation key mismatch")
|
||||
}
|
||||
@@ -4476,7 +4477,7 @@ func (lc *LightningChannel) NextRevocationKey() (*btcec.PublicKey, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ComputeCommitmentPoint(revocation[:]), nil
|
||||
return input.ComputeCommitmentPoint(revocation[:]), nil
|
||||
}
|
||||
|
||||
// InitNextRevocation inserts the passed commitment point as the _next_
|
||||
@@ -4852,7 +4853,7 @@ 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 = receiverHTLCScript(timeout,
|
||||
witnessScript, err = input.ReceiverHTLCScript(timeout,
|
||||
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
|
||||
keyRing.RevocationKey, rHash[:])
|
||||
|
||||
@@ -4860,21 +4861,21 @@ func genHtlcScript(isIncoming, ourCommit bool, timeout uint32, rHash [32]byte,
|
||||
// being added to their commitment transaction, so we use the sender's
|
||||
// version of the HTLC script.
|
||||
case isIncoming && !ourCommit:
|
||||
witnessScript, err = senderHTLCScript(keyRing.RemoteHtlcKey,
|
||||
witnessScript, err = input.SenderHTLCScript(keyRing.RemoteHtlcKey,
|
||||
keyRing.LocalHtlcKey, keyRing.RevocationKey, rHash[:])
|
||||
|
||||
// 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 = senderHTLCScript(keyRing.LocalHtlcKey,
|
||||
witnessScript, err = input.SenderHTLCScript(keyRing.LocalHtlcKey,
|
||||
keyRing.RemoteHtlcKey, keyRing.RevocationKey, rHash[:])
|
||||
|
||||
// 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 = receiverHTLCScript(timeout, keyRing.LocalHtlcKey,
|
||||
witnessScript, err = input.ReceiverHTLCScript(timeout, keyRing.LocalHtlcKey,
|
||||
keyRing.RemoteHtlcKey, keyRing.RevocationKey, rHash[:])
|
||||
}
|
||||
if err != nil {
|
||||
@@ -4883,7 +4884,7 @@ func genHtlcScript(isIncoming, ourCommit bool, timeout uint32, rHash [32]byte,
|
||||
|
||||
// Now that we have the redeem scripts, create the P2WSH public key
|
||||
// script for the output itself.
|
||||
htlcP2WSH, err := WitnessScriptHash(witnessScript)
|
||||
htlcP2WSH, err := input.WitnessScriptHash(witnessScript)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -4952,7 +4953,7 @@ func (lc *LightningChannel) getSignedCommitTx() (*wire.MsgTx, error) {
|
||||
ourKey := lc.localChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
||||
theirKey := lc.remoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
||||
|
||||
commitTx.TxIn[0].Witness = SpendMultiSig(
|
||||
commitTx.TxIn[0].Witness = input.SpendMultiSig(
|
||||
lc.signDesc.WitnessScript, ourKey,
|
||||
ourSig, theirKey, theirSig,
|
||||
)
|
||||
@@ -4970,7 +4971,7 @@ type CommitOutputResolution struct {
|
||||
|
||||
// SelfOutputSignDesc is a fully populated sign descriptor capable of
|
||||
// generating a valid signature to sweep the output paying to us.
|
||||
SelfOutputSignDesc SignDescriptor
|
||||
SelfOutputSignDesc input.SignDescriptor
|
||||
|
||||
// MaturityDelay is the relative time-lock, in blocks for all outputs
|
||||
// that pay to the local party within the broadcast commitment
|
||||
@@ -5026,7 +5027,7 @@ type UnilateralCloseSummary struct {
|
||||
// happen in case we have lost state) it should be set to an empty struct, in
|
||||
// which case we will attempt to sweep the non-HTLC output using the passed
|
||||
// commitPoint.
|
||||
func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer input.Signer,
|
||||
pCache PreimageCache, commitSpend *chainntnfs.SpendDetail,
|
||||
remoteCommit channeldb.ChannelCommitment,
|
||||
commitPoint *btcec.PublicKey) (*UnilateralCloseSummary, error) {
|
||||
@@ -5054,7 +5055,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
// 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.
|
||||
selfP2WKH, err := CommitScriptUnencumbered(keyRing.NoDelayKey)
|
||||
selfP2WKH, err := input.CommitScriptUnencumbered(keyRing.NoDelayKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to create self commit script: %v", err)
|
||||
}
|
||||
@@ -5083,7 +5084,7 @@ func NewUnilateralCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
localPayBase := chanState.LocalChanCfg.PaymentBasePoint
|
||||
commitResolution = &CommitOutputResolution{
|
||||
SelfOutPoint: *selfPoint,
|
||||
SelfOutputSignDesc: SignDescriptor{
|
||||
SelfOutputSignDesc: input.SignDescriptor{
|
||||
KeyDesc: localPayBase,
|
||||
SingleTweak: keyRing.LocalCommitKeyTweak,
|
||||
WitnessScript: selfP2WKH,
|
||||
@@ -5170,7 +5171,7 @@ type IncomingHtlcResolution struct {
|
||||
// SweepSignDesc is a sign descriptor that has been populated with the
|
||||
// necessary items required to spend the sole output of the above
|
||||
// transaction.
|
||||
SweepSignDesc SignDescriptor
|
||||
SweepSignDesc input.SignDescriptor
|
||||
}
|
||||
|
||||
// OutgoingHtlcResolution houses the information necessary to sweep any
|
||||
@@ -5210,7 +5211,7 @@ type OutgoingHtlcResolution struct {
|
||||
// SweepSignDesc is a sign descriptor that has been populated with the
|
||||
// necessary items required to spend the sole output of the above
|
||||
// transaction.
|
||||
SweepSignDesc SignDescriptor
|
||||
SweepSignDesc input.SignDescriptor
|
||||
}
|
||||
|
||||
// HtlcResolutions contains the items necessary to sweep HTLC's on chain
|
||||
@@ -5230,7 +5231,7 @@ type HtlcResolutions struct {
|
||||
// newOutgoingHtlcResolution generates a new HTLC resolution capable of
|
||||
// allowing the caller to sweep an outgoing HTLC present on either their, or
|
||||
// the remote party's commitment transaction.
|
||||
func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
func newOutgoingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
|
||||
feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32, localCommit bool,
|
||||
) (*OutgoingHtlcResolution, error) {
|
||||
@@ -5246,14 +5247,14 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
if !localCommit {
|
||||
// First, we'll re-generate the script used to send the HTLC to
|
||||
// the remote party within their commitment transaction.
|
||||
htlcReceiverScript, err := receiverHTLCScript(htlc.RefundTimeout,
|
||||
htlcReceiverScript, err := input.ReceiverHTLCScript(htlc.RefundTimeout,
|
||||
keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
|
||||
keyRing.RevocationKey, htlc.RHash[:],
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
htlcScriptHash, err := WitnessScriptHash(htlcReceiverScript)
|
||||
htlcScriptHash, err := input.WitnessScriptHash(htlcReceiverScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -5263,7 +5264,7 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
return &OutgoingHtlcResolution{
|
||||
Expiry: htlc.RefundTimeout,
|
||||
ClaimOutpoint: op,
|
||||
SweepSignDesc: SignDescriptor{
|
||||
SweepSignDesc: input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.HtlcBasePoint,
|
||||
SingleTweak: keyRing.LocalHtlcKeyTweak,
|
||||
WitnessScript: htlcReceiverScript,
|
||||
@@ -5298,12 +5299,12 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
// 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 := senderHTLCScript(keyRing.LocalHtlcKey,
|
||||
htlcCreationScript, err := input.SenderHTLCScript(keyRing.LocalHtlcKey,
|
||||
keyRing.RemoteHtlcKey, keyRing.RevocationKey, htlc.RHash[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
timeoutSignDesc := SignDescriptor{
|
||||
timeoutSignDesc := input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.HtlcBasePoint,
|
||||
SingleTweak: keyRing.LocalHtlcKeyTweak,
|
||||
WitnessScript: htlcCreationScript,
|
||||
@@ -5317,7 +5318,7 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
|
||||
// With the sign desc created, we can now construct the full witness
|
||||
// for the timeout transaction, and populate it as well.
|
||||
timeoutWitness, err := senderHtlcSpendTimeout(
|
||||
timeoutWitness, err := input.SenderHtlcSpendTimeout(
|
||||
htlc.Signature, signer, &timeoutSignDesc, timeoutTx,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -5328,18 +5329,18 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
// Finally, we'll generate the script output that the timeout
|
||||
// transaction creates so we can generate the signDesc required to
|
||||
// complete the claim process after a delay period.
|
||||
htlcSweepScript, err := secondLevelHtlcScript(
|
||||
htlcSweepScript, err := input.SecondLevelHtlcScript(
|
||||
keyRing.RevocationKey, keyRing.DelayKey, csvDelay,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
htlcScriptHash, err := WitnessScriptHash(htlcSweepScript)
|
||||
htlcScriptHash, err := input.WitnessScriptHash(htlcSweepScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localDelayTweak := SingleTweakBytes(
|
||||
localDelayTweak := input.SingleTweakBytes(
|
||||
keyRing.CommitPoint, localChanCfg.DelayBasePoint.PubKey,
|
||||
)
|
||||
return &OutgoingHtlcResolution{
|
||||
@@ -5350,7 +5351,7 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
Hash: timeoutTx.TxHash(),
|
||||
Index: 0,
|
||||
},
|
||||
SweepSignDesc: SignDescriptor{
|
||||
SweepSignDesc: input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.DelayBasePoint,
|
||||
SingleTweak: localDelayTweak,
|
||||
WitnessScript: htlcSweepScript,
|
||||
@@ -5370,7 +5371,7 @@ func newOutgoingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
// they can just sweep the output immediately with knowledge of the pre-image.
|
||||
//
|
||||
// TODO(roasbeef) consolidate code with above func
|
||||
func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
func newIncomingHtlcResolution(signer input.Signer, localChanCfg *channeldb.ChannelConfig,
|
||||
commitHash chainhash.Hash, htlc *channeldb.HTLC, keyRing *CommitmentKeyRing,
|
||||
feePerKw SatPerKWeight, dustLimit btcutil.Amount, csvDelay uint32,
|
||||
localCommit bool, preimage [32]byte) (*IncomingHtlcResolution, error) {
|
||||
@@ -5385,14 +5386,14 @@ func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
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 := senderHTLCScript(
|
||||
htlcSenderScript, err := input.SenderHTLCScript(
|
||||
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
|
||||
keyRing.RevocationKey, htlc.RHash[:],
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
htlcScriptHash, err := WitnessScriptHash(htlcSenderScript)
|
||||
htlcScriptHash, err := input.WitnessScriptHash(htlcSenderScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -5403,7 +5404,7 @@ func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
Preimage: preimage,
|
||||
ClaimOutpoint: op,
|
||||
CsvDelay: csvDelay,
|
||||
SweepSignDesc: SignDescriptor{
|
||||
SweepSignDesc: input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.HtlcBasePoint,
|
||||
SingleTweak: keyRing.LocalHtlcKeyTweak,
|
||||
WitnessScript: htlcSenderScript,
|
||||
@@ -5432,14 +5433,14 @@ func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
|
||||
// Once we've created the second-level transaction, we'll generate the
|
||||
// SignDesc needed spend the HTLC output using the success transaction.
|
||||
htlcCreationScript, err := receiverHTLCScript(htlc.RefundTimeout,
|
||||
htlcCreationScript, err := input.ReceiverHTLCScript(htlc.RefundTimeout,
|
||||
keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
|
||||
keyRing.RevocationKey, htlc.RHash[:],
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
successSignDesc := SignDescriptor{
|
||||
successSignDesc := input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.HtlcBasePoint,
|
||||
SingleTweak: keyRing.LocalHtlcKeyTweak,
|
||||
WitnessScript: htlcCreationScript,
|
||||
@@ -5453,7 +5454,7 @@ func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
|
||||
// Next, we'll construct the full witness needed to satisfy the input
|
||||
// of the success transaction.
|
||||
successWitness, err := receiverHtlcSpendRedeem(
|
||||
successWitness, err := input.ReceiverHtlcSpendRedeem(
|
||||
htlc.Signature, preimage[:], signer, &successSignDesc, successTx,
|
||||
)
|
||||
if err != nil {
|
||||
@@ -5464,18 +5465,18 @@ func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
// Finally, we'll generate the script that the second-level transaction
|
||||
// creates so we can generate the proper signDesc to sweep it after the
|
||||
// CSV delay has passed.
|
||||
htlcSweepScript, err := secondLevelHtlcScript(
|
||||
htlcSweepScript, err := input.SecondLevelHtlcScript(
|
||||
keyRing.RevocationKey, keyRing.DelayKey, csvDelay,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
htlcScriptHash, err := WitnessScriptHash(htlcSweepScript)
|
||||
htlcScriptHash, err := input.WitnessScriptHash(htlcSweepScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
localDelayTweak := SingleTweakBytes(
|
||||
localDelayTweak := input.SingleTweakBytes(
|
||||
keyRing.CommitPoint, localChanCfg.DelayBasePoint.PubKey,
|
||||
)
|
||||
return &IncomingHtlcResolution{
|
||||
@@ -5486,7 +5487,7 @@ func newIncomingHtlcResolution(signer Signer, localChanCfg *channeldb.ChannelCon
|
||||
Hash: successTx.TxHash(),
|
||||
Index: 0,
|
||||
},
|
||||
SweepSignDesc: SignDescriptor{
|
||||
SweepSignDesc: input.SignDescriptor{
|
||||
KeyDesc: localChanCfg.DelayBasePoint,
|
||||
SingleTweak: localDelayTweak,
|
||||
WitnessScript: htlcSweepScript,
|
||||
@@ -5527,7 +5528,7 @@ func (r *OutgoingHtlcResolution) HtlcPoint() wire.OutPoint {
|
||||
// the local key used when generating the HTLC scrips. This function is to be
|
||||
// used in two cases: force close, or a unilateral close.
|
||||
func extractHtlcResolutions(feePerKw SatPerKWeight, ourCommit bool,
|
||||
signer Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing,
|
||||
signer input.Signer, htlcs []channeldb.HTLC, keyRing *CommitmentKeyRing,
|
||||
localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
|
||||
commitHash chainhash.Hash, pCache PreimageCache) (*HtlcResolutions, error) {
|
||||
|
||||
@@ -5672,7 +5673,7 @@ func (lc *LightningChannel) ForceClose() (*LocalForceCloseSummary, error) {
|
||||
// NewLocalForceCloseSummary generates a LocalForceCloseSummary from the given
|
||||
// channel state. The passed commitTx must be a fully signed commitment
|
||||
// transaction corresponding to localCommit.
|
||||
func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer input.Signer,
|
||||
pCache PreimageCache, commitTx *wire.MsgTx,
|
||||
localCommit channeldb.ChannelCommitment) (*LocalForceCloseSummary, error) {
|
||||
|
||||
@@ -5687,15 +5688,15 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
commitPoint := ComputeCommitmentPoint(revocation[:])
|
||||
commitPoint := input.ComputeCommitmentPoint(revocation[:])
|
||||
keyRing := deriveCommitmentKeys(commitPoint, true, &chanState.LocalChanCfg,
|
||||
&chanState.RemoteChanCfg)
|
||||
selfScript, err := CommitScriptToSelf(csvTimeout, keyRing.DelayKey,
|
||||
selfScript, err := input.CommitScriptToSelf(csvTimeout, keyRing.DelayKey,
|
||||
keyRing.RevocationKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payToUsScriptHash, err := WitnessScriptHash(selfScript)
|
||||
payToUsScriptHash, err := input.WitnessScriptHash(selfScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -5725,7 +5726,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
// nil.
|
||||
var commitResolution *CommitOutputResolution
|
||||
if len(delayScript) != 0 {
|
||||
singleTweak := SingleTweakBytes(
|
||||
singleTweak := input.SingleTweakBytes(
|
||||
commitPoint, chanState.LocalChanCfg.DelayBasePoint.PubKey,
|
||||
)
|
||||
localBalance := localCommit.LocalBalance
|
||||
@@ -5734,7 +5735,7 @@ func NewLocalForceCloseSummary(chanState *channeldb.OpenChannel, signer Signer,
|
||||
Hash: commitTx.TxHash(),
|
||||
Index: delayIndex,
|
||||
},
|
||||
SelfOutputSignDesc: SignDescriptor{
|
||||
SelfOutputSignDesc: input.SignDescriptor{
|
||||
KeyDesc: chanState.LocalChanCfg.DelayBasePoint,
|
||||
SingleTweak: singleTweak,
|
||||
WitnessScript: selfScript,
|
||||
@@ -5896,7 +5897,7 @@ func (lc *LightningChannel) CompleteCooperativeClose(localSig, remoteSig []byte,
|
||||
// pubkeys+sigs on the stack.
|
||||
ourKey := lc.localChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
||||
theirKey := lc.remoteChanCfg.MultiSigKey.PubKey.SerializeCompressed()
|
||||
witness := SpendMultiSig(lc.signDesc.WitnessScript, ourKey,
|
||||
witness := input.SpendMultiSig(lc.signDesc.WitnessScript, ourKey,
|
||||
localSig, theirKey, remoteSig)
|
||||
closeTx.TxIn[0].Witness = witness
|
||||
|
||||
@@ -6101,7 +6102,7 @@ func (lc *LightningChannel) generateRevocation(height uint64) (*lnwire.RevokeAnd
|
||||
return nil, err
|
||||
}
|
||||
|
||||
revocationMsg.NextRevocationKey = ComputeCommitmentPoint(nextCommitSecret[:])
|
||||
revocationMsg.NextRevocationKey = input.ComputeCommitmentPoint(nextCommitSecret[:])
|
||||
revocationMsg.ChanID = lnwire.NewChanIDFromOutPoint(
|
||||
&lc.channelState.FundingOutpoint)
|
||||
|
||||
@@ -6122,19 +6123,19 @@ func CreateCommitTx(fundingOutput wire.TxIn,
|
||||
// output after a relative block delay, or the remote node can claim
|
||||
// the funds with the revocation key if we broadcast a revoked
|
||||
// commitment transaction.
|
||||
ourRedeemScript, err := CommitScriptToSelf(csvTimeout, keyRing.DelayKey,
|
||||
ourRedeemScript, err := input.CommitScriptToSelf(csvTimeout, keyRing.DelayKey,
|
||||
keyRing.RevocationKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
payToUsScriptHash, err := WitnessScriptHash(ourRedeemScript)
|
||||
payToUsScriptHash, err := input.WitnessScriptHash(ourRedeemScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Next, we create the script paying to them. This is just a regular
|
||||
// P2WPKH output, without any added CSV delay.
|
||||
theirWitnessKeyHash, err := CommitScriptUnencumbered(keyRing.NoDelayKey)
|
||||
theirWitnessKeyHash, err := input.CommitScriptUnencumbered(keyRing.NoDelayKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -6203,7 +6204,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 SatPerKWeight) btcutil.Amount {
|
||||
return feeRate.FeeForWeight(CommitWeight)
|
||||
return feeRate.FeeForWeight(input.CommitWeight)
|
||||
}
|
||||
|
||||
// RemoteNextRevocation returns the channelState's RemoteNextRevocation.
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
@@ -403,7 +404,7 @@ func TestCheckCommitTxSize(t *testing.T) {
|
||||
}
|
||||
|
||||
actualCost := blockchain.GetTransactionWeight(btcutil.NewTx(commitTx))
|
||||
estimatedCost := estimateCommitTxWeight(count, false)
|
||||
estimatedCost := input.EstimateCommitTxWeight(count, false)
|
||||
|
||||
diff := int(estimatedCost - actualCost)
|
||||
if 0 > diff || BaseCommitmentTxSizeEstimationError < diff {
|
||||
@@ -624,7 +625,7 @@ func TestForceClose(t *testing.T) {
|
||||
|
||||
// Factoring in the fee rate, Alice's amount should properly reflect
|
||||
// that we've added two additional HTLC to the commitment transaction.
|
||||
totalCommitWeight := CommitWeight + (HtlcWeight * 2)
|
||||
totalCommitWeight := input.CommitWeight + (input.HtlcWeight * 2)
|
||||
feePerKw := SatPerKWeight(aliceChannel.channelState.LocalCommitment.FeePerKw)
|
||||
commitFee := feePerKw.FeeForWeight(totalCommitWeight)
|
||||
expectedAmount := (aliceChannel.Capacity / 2) - htlcAmount.ToSatoshis() - commitFee
|
||||
@@ -680,7 +681,7 @@ func TestForceClose(t *testing.T) {
|
||||
Value: htlcResolution.SweepSignDesc.Output.Value,
|
||||
})
|
||||
htlcResolution.SweepSignDesc.InputIndex = 0
|
||||
sweepTx.TxIn[0].Witness, err = htlcSpendSuccess(aliceChannel.Signer,
|
||||
sweepTx.TxIn[0].Witness, err = input.HtlcSpendSuccess(aliceChannel.Signer,
|
||||
&htlcResolution.SweepSignDesc, sweepTx,
|
||||
uint32(aliceChannel.channelState.LocalChanCfg.CsvDelay))
|
||||
if err != nil {
|
||||
@@ -741,7 +742,7 @@ func TestForceClose(t *testing.T) {
|
||||
Value: inHtlcResolution.SweepSignDesc.Output.Value,
|
||||
})
|
||||
inHtlcResolution.SweepSignDesc.InputIndex = 0
|
||||
sweepTx.TxIn[0].Witness, err = htlcSpendSuccess(aliceChannel.Signer,
|
||||
sweepTx.TxIn[0].Witness, err = input.HtlcSpendSuccess(aliceChannel.Signer,
|
||||
&inHtlcResolution.SweepSignDesc, sweepTx,
|
||||
uint32(aliceChannel.channelState.LocalChanCfg.CsvDelay))
|
||||
if err != nil {
|
||||
@@ -4789,7 +4790,7 @@ func TestChannelUnilateralCloseHtlcResolution(t *testing.T) {
|
||||
|
||||
// With the transaction constructed, we'll generate a witness that
|
||||
// should be valid for it, and verify using an instance of Script.
|
||||
sweepTx.TxIn[0].Witness, err = receiverHtlcSpendTimeout(
|
||||
sweepTx.TxIn[0].Witness, err = input.ReceiverHtlcSpendTimeout(
|
||||
aliceChannel.Signer, &outHtlcResolution.SweepSignDesc,
|
||||
sweepTx, int32(outHtlcResolution.Expiry),
|
||||
)
|
||||
@@ -4823,7 +4824,7 @@ func TestChannelUnilateralCloseHtlcResolution(t *testing.T) {
|
||||
inHtlcResolution.SweepSignDesc.SigHashes = txscript.NewTxSigHashes(
|
||||
sweepTx,
|
||||
)
|
||||
sweepTx.TxIn[0].Witness, err = SenderHtlcSpendRedeem(
|
||||
sweepTx.TxIn[0].Witness, err = input.SenderHtlcSpendRedeem(
|
||||
aliceChannel.Signer, &inHtlcResolution.SweepSignDesc,
|
||||
sweepTx, preimageBob[:],
|
||||
)
|
||||
@@ -4954,7 +4955,7 @@ func TestChannelUnilateralClosePendingCommit(t *testing.T) {
|
||||
Value: aliceSignDesc.Output.Value,
|
||||
})
|
||||
aliceSignDesc.SigHashes = txscript.NewTxSigHashes(sweepTx)
|
||||
sweepTx.TxIn[0].Witness, err = CommitSpendNoDelay(
|
||||
sweepTx.TxIn[0].Witness, err = input.CommitSpendNoDelay(
|
||||
aliceChannel.Signer, &aliceSignDesc, sweepTx,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ import (
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
)
|
||||
|
||||
@@ -37,7 +38,7 @@ type Config struct {
|
||||
// used to generate signature for all inputs to potential funding
|
||||
// transactions, as well as for spends from the funding transaction to
|
||||
// update the commitment state.
|
||||
Signer Signer
|
||||
Signer input.Signer
|
||||
|
||||
// FeeEstimator is the implementation that the wallet will use for the
|
||||
// calculation of on-chain transaction fees.
|
||||
|
||||
@@ -253,30 +253,6 @@ type BlockChainIO interface {
|
||||
GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error)
|
||||
}
|
||||
|
||||
// Signer represents an abstract object capable of generating raw signatures as
|
||||
// well as full complete input scripts given a valid SignDescriptor and
|
||||
// transaction. This interface fully abstracts away signing paving the way for
|
||||
// Signer implementations such as hardware wallets, hardware tokens, HSM's, or
|
||||
// simply a regular wallet.
|
||||
type Signer interface {
|
||||
// SignOutputRaw generates a signature for the passed transaction
|
||||
// according to the data within the passed SignDescriptor.
|
||||
//
|
||||
// NOTE: The resulting signature should be void of a sighash byte.
|
||||
SignOutputRaw(tx *wire.MsgTx, signDesc *SignDescriptor) ([]byte, error)
|
||||
|
||||
// ComputeInputScript generates a complete InputIndex for the passed
|
||||
// transaction with the signature as defined within the passed
|
||||
// SignDescriptor. This method should be capable of generating the
|
||||
// proper input script for both regular p2wkh output and p2wkh outputs
|
||||
// nested within a regular p2sh output.
|
||||
//
|
||||
// NOTE: This method will ignore any tweak parameters set within the
|
||||
// passed SignDescriptor as it assumes a set of typical script
|
||||
// templates (p2wkh, np2wkh, etc).
|
||||
ComputeInputScript(tx *wire.MsgTx, signDesc *SignDescriptor) (*InputScript, error)
|
||||
}
|
||||
|
||||
// MessageSigner represents an abstract object capable of signing arbitrary
|
||||
// messages. The capabilities of this interface are used to sign announcements
|
||||
// to the network, or just arbitrary messages that leverage the wallet's keys
|
||||
|
||||
+11
-10
@@ -35,6 +35,7 @@ import (
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs/btcdnotify"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/btcwallet"
|
||||
@@ -353,7 +354,7 @@ func loadTestCredits(miner *rpctest.Harness, w *lnwallet.LightningWallet,
|
||||
func createTestWallet(tempTestDir string, miningNode *rpctest.Harness,
|
||||
netParams *chaincfg.Params, notifier chainntnfs.ChainNotifier,
|
||||
wc lnwallet.WalletController, keyRing keychain.SecretKeyRing,
|
||||
signer lnwallet.Signer, bio lnwallet.BlockChainIO) (*lnwallet.LightningWallet, error) {
|
||||
signer input.Signer, bio lnwallet.BlockChainIO) (*lnwallet.LightningWallet, error) {
|
||||
|
||||
dbDir := filepath.Join(tempTestDir, "cdb")
|
||||
cdb, err := channeldb.Open(dbDir)
|
||||
@@ -434,7 +435,7 @@ func testDualFundingReservationWorkflow(miner *rpctest.Harness,
|
||||
ChanReserve: fundingAmount / 100,
|
||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(fundingAmount),
|
||||
MinHTLC: 1,
|
||||
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
|
||||
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
|
||||
CsvDelay: csvDelay,
|
||||
}
|
||||
err = aliceChanReservation.CommitConstraints(channelConstraints)
|
||||
@@ -866,7 +867,7 @@ func testSingleFunderReservationWorkflow(miner *rpctest.Harness,
|
||||
ChanReserve: fundingAmt / 100,
|
||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(fundingAmt),
|
||||
MinHTLC: 1,
|
||||
MaxAcceptedHtlcs: lnwallet.MaxHTLCNumber / 2,
|
||||
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
|
||||
CsvDelay: csvDelay,
|
||||
}
|
||||
err = aliceChanReservation.CommitConstraints(channelConstraints)
|
||||
@@ -1528,7 +1529,7 @@ func testPublishTransaction(r *rpctest.Harness,
|
||||
|
||||
// Now we can populate the sign descriptor which we'll use to
|
||||
// generate the signature.
|
||||
signDesc := &lnwallet.SignDescriptor{
|
||||
signDesc := &input.SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: pubKey.PubKey,
|
||||
},
|
||||
@@ -1783,10 +1784,10 @@ func testSignOutputUsingTweaks(r *rpctest.Harness,
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
commitPreimage)
|
||||
|
||||
revocationKey := lnwallet.DeriveRevocationPubkey(pubKey.PubKey, commitPoint)
|
||||
commitTweak := lnwallet.SingleTweakBytes(commitPoint, pubKey.PubKey)
|
||||
revocationKey := input.DeriveRevocationPubkey(pubKey.PubKey, commitPoint)
|
||||
commitTweak := input.SingleTweakBytes(commitPoint, pubKey.PubKey)
|
||||
|
||||
tweakedPub := lnwallet.TweakPubKey(pubKey.PubKey, commitPoint)
|
||||
tweakedPub := input.TweakPubKey(pubKey.PubKey, commitPoint)
|
||||
|
||||
// As we'd like to test both single and double tweaks, we'll repeat
|
||||
// the same set up twice. The first will use a regular single tweak,
|
||||
@@ -1856,7 +1857,7 @@ func testSignOutputUsingTweaks(r *rpctest.Harness,
|
||||
// private tweak value as the key in the script is derived
|
||||
// based on this tweak value and the key we originally
|
||||
// generated above.
|
||||
signDesc := &lnwallet.SignDescriptor{
|
||||
signDesc := &input.SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: baseKey.PubKey,
|
||||
},
|
||||
@@ -2392,8 +2393,8 @@ func runTests(t *testing.T, walletDriver *lnwallet.WalletDriver,
|
||||
var (
|
||||
bio lnwallet.BlockChainIO
|
||||
|
||||
aliceSigner lnwallet.Signer
|
||||
bobSigner lnwallet.Signer
|
||||
aliceSigner input.Signer
|
||||
bobSigner input.Signer
|
||||
|
||||
aliceKeyRing keychain.SecretKeyRing
|
||||
bobKeyRing keychain.SecretKeyRing
|
||||
|
||||
@@ -3,10 +3,11 @@ package lnwallet
|
||||
import (
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcwallet/wallet/txrules"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
)
|
||||
|
||||
// DefaultDustLimit is used to calculate the dust HTLC amount which will be
|
||||
// send to other node during funding process.
|
||||
func DefaultDustLimit() btcutil.Amount {
|
||||
return txrules.GetDustThreshold(P2WSHSize, txrules.DefaultRelayFeePerKb)
|
||||
return txrules.GetDustThreshold(input.P2WSHSize, txrules.DefaultRelayFeePerKb)
|
||||
}
|
||||
+9
-20
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
@@ -49,18 +50,6 @@ func (c *ChannelContribution) toChanConfig() channeldb.ChannelConfig {
|
||||
return *c.ChannelConfig
|
||||
}
|
||||
|
||||
// InputScript represents any script inputs required to redeem a previous
|
||||
// output. This struct is used rather than just a witness, or scripSig in order
|
||||
// to accommodate nested p2sh which utilizes both types of input scripts.
|
||||
type InputScript struct {
|
||||
// Witness is the full witness stack required to unlock this output.
|
||||
Witness wire.TxWitness
|
||||
|
||||
// SigScript will only be populated if this is an input script sweeping
|
||||
// a nested p2sh output.
|
||||
SigScript []byte
|
||||
}
|
||||
|
||||
// ChannelReservation represents an intent to open a lightning payment channel
|
||||
// with a counterparty. The funding processes from reservation to channel opening
|
||||
// is a 3-step process. In order to allow for full concurrency during the
|
||||
@@ -102,8 +91,8 @@ type ChannelReservation struct {
|
||||
|
||||
// In order of sorted inputs. Sorting is done in accordance
|
||||
// to BIP-69: https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
|
||||
ourFundingInputScripts []*InputScript
|
||||
theirFundingInputScripts []*InputScript
|
||||
ourFundingInputScripts []*input.Script
|
||||
theirFundingInputScripts []*input.Script
|
||||
|
||||
// Our signature for their version of the commitment transaction.
|
||||
ourCommitmentSig []byte
|
||||
@@ -149,7 +138,7 @@ func NewChannelReservation(capacity, fundingAmt btcutil.Amount,
|
||||
initiator bool
|
||||
)
|
||||
|
||||
commitFee := commitFeePerKw.FeeForWeight(CommitWeight)
|
||||
commitFee := commitFeePerKw.FeeForWeight(input.CommitWeight)
|
||||
fundingMSat := lnwire.NewMSatFromSatoshis(fundingAmt)
|
||||
capacityMSat := lnwire.NewMSatFromSatoshis(capacity)
|
||||
feeMSat := lnwire.NewMSatFromSatoshis(commitFee)
|
||||
@@ -320,9 +309,9 @@ func (r *ChannelReservation) CommitConstraints(c *channeldb.ChannelConstraints)
|
||||
|
||||
// Fail if maxHtlcs is above the maximum allowed number of 483. This
|
||||
// number is specified in BOLT-02.
|
||||
if c.MaxAcceptedHtlcs > uint16(MaxHTLCNumber/2) {
|
||||
if c.MaxAcceptedHtlcs > uint16(input.MaxHTLCNumber/2) {
|
||||
return ErrMaxHtlcNumTooLarge(
|
||||
c.MaxAcceptedHtlcs, uint16(MaxHTLCNumber/2),
|
||||
c.MaxAcceptedHtlcs, uint16(input.MaxHTLCNumber/2),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -424,7 +413,7 @@ func (r *ChannelReservation) TheirContribution() *ChannelContribution {
|
||||
//
|
||||
// NOTE: These signatures will only be populated after a call to
|
||||
// .ProcessContribution()
|
||||
func (r *ChannelReservation) OurSignatures() ([]*InputScript, []byte) {
|
||||
func (r *ChannelReservation) OurSignatures() ([]*input.Script, []byte) {
|
||||
r.RLock()
|
||||
defer r.RUnlock()
|
||||
return r.ourFundingInputScripts, r.ourCommitmentSig
|
||||
@@ -443,7 +432,7 @@ func (r *ChannelReservation) OurSignatures() ([]*InputScript, []byte) {
|
||||
// block until the funding transaction obtains the configured number of
|
||||
// confirmations. Once the method unblocks, a LightningChannel instance is
|
||||
// returned, marking the channel available for updates.
|
||||
func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*InputScript,
|
||||
func (r *ChannelReservation) CompleteReservation(fundingInputScripts []*input.Script,
|
||||
commitmentSig []byte) (*channeldb.OpenChannel, error) {
|
||||
|
||||
// TODO(roasbeef): add flag for watch or not?
|
||||
@@ -494,7 +483,7 @@ func (r *ChannelReservation) CompleteReservationSingle(fundingPoint *wire.OutPoi
|
||||
//
|
||||
// NOTE: These attributes will be unpopulated before a call to
|
||||
// .CompleteReservation().
|
||||
func (r *ChannelReservation) TheirSignatures() ([]*InputScript, []byte) {
|
||||
func (r *ChannelReservation) TheirSignatures() ([]*input.Script, []byte) {
|
||||
r.RLock()
|
||||
defer r.RUnlock()
|
||||
return r.theirFundingInputScripts, r.theirCommitmentSig
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,917 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
)
|
||||
|
||||
// TestRevocationKeyDerivation tests that given a public key, and a revocation
|
||||
// hash, the homomorphic revocation public and private key derivation work
|
||||
// properly.
|
||||
func TestRevocationKeyDerivation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// First, we'll generate a commitment point, and a commitment secret.
|
||||
// These will be used to derive the ultimate revocation keys.
|
||||
revocationPreimage := testHdSeed.CloneBytes()
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
revocationPreimage)
|
||||
|
||||
// With the commitment secrets generated, we'll now create the base
|
||||
// keys we'll use to derive the revocation key from.
|
||||
basePriv, basePub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
testWalletPrivKey)
|
||||
|
||||
// With the point and key obtained, we can now derive the revocation
|
||||
// key itself.
|
||||
revocationPub := DeriveRevocationPubkey(basePub, commitPoint)
|
||||
|
||||
// The revocation public key derived from the original public key, and
|
||||
// the one derived from the private key should be identical.
|
||||
revocationPriv := DeriveRevocationPrivKey(basePriv, commitSecret)
|
||||
if !revocationPub.IsEqual(revocationPriv.PubKey()) {
|
||||
t.Fatalf("derived public keys don't match!")
|
||||
}
|
||||
}
|
||||
|
||||
// TestTweakKeyDerivation tests that given a public key, and commitment tweak,
|
||||
// then we're able to properly derive a tweaked private key that corresponds to
|
||||
// the computed tweak public key. This scenario ensure that our key derivation
|
||||
// for any of the non revocation keys on the commitment transaction is correct.
|
||||
func TestTweakKeyDerivation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// First, we'll generate a base public key that we'll be "tweaking".
|
||||
baseSecret := testHdSeed.CloneBytes()
|
||||
basePriv, basePub := btcec.PrivKeyFromBytes(btcec.S256(), baseSecret)
|
||||
|
||||
// With the base key create, we'll now create a commitment point, and
|
||||
// from that derive the bytes we'll used to tweak the base public key.
|
||||
commitPoint := ComputeCommitmentPoint(bobsPrivKey)
|
||||
commitTweak := SingleTweakBytes(commitPoint, basePub)
|
||||
|
||||
// Next, we'll modify the public key. When we apply the same operation
|
||||
// to the private key we should get a key that matches.
|
||||
tweakedPub := TweakPubKey(basePub, commitPoint)
|
||||
|
||||
// Finally, attempt to re-generate the private key that matches the
|
||||
// tweaked public key. The derived key should match exactly.
|
||||
derivedPriv := TweakPrivKey(basePriv, commitTweak)
|
||||
if !derivedPriv.PubKey().IsEqual(tweakedPub) {
|
||||
t.Fatalf("pub keys don't match")
|
||||
}
|
||||
}
|
||||
|
||||
// makeWitnessTestCase is a helper function used within test cases involving
|
||||
// the validity of a crafted witness. This function is a wrapper function which
|
||||
// allows constructing table-driven tests. In the case of an error while
|
||||
// constructing the witness, the test fails fatally.
|
||||
func makeWitnessTestCase(t *testing.T,
|
||||
f func() (wire.TxWitness, error)) func() wire.TxWitness {
|
||||
|
||||
return func() wire.TxWitness {
|
||||
witness, err := f()
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create witness test case: %v", err)
|
||||
}
|
||||
|
||||
return witness
|
||||
}
|
||||
}
|
||||
|
||||
// TestHTLCSenderSpendValidation tests all possible valid+invalid redemption
|
||||
// paths in the script used within the sender's commitment transaction for an
|
||||
// outgoing HTLC.
|
||||
//
|
||||
// The following cases are exercised by this test:
|
||||
// sender script:
|
||||
// * receiver spends
|
||||
// * revoke w/ sig
|
||||
// * HTLC with invalid preimage size
|
||||
// * HTLC with valid preimage size + sig
|
||||
// * sender spends
|
||||
// * invalid lock-time for CLTV
|
||||
// * invalid sequence for CSV
|
||||
// * valid lock-time+sequence, valid sig
|
||||
func TestHTLCSenderSpendValidation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// We generate a fake output, and the corresponding txin. This output
|
||||
// doesn't need to exist, as we'll only be validating spending from the
|
||||
// transaction that references this.
|
||||
txid, err := chainhash.NewHash(testHdSeed.CloneBytes())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create txid: %v", err)
|
||||
}
|
||||
fundingOut := &wire.OutPoint{
|
||||
Hash: *txid,
|
||||
Index: 50,
|
||||
}
|
||||
fakeFundingTxIn := wire.NewTxIn(fundingOut, nil, nil)
|
||||
|
||||
// Next we'll the commitment secret for our commitment tx and also the
|
||||
// revocation key that we'll use as well.
|
||||
revokePreimage := testHdSeed.CloneBytes()
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
revokePreimage)
|
||||
|
||||
// Generate a payment preimage to be used below.
|
||||
paymentPreimage := revokePreimage
|
||||
paymentPreimage[0] ^= 1
|
||||
paymentHash := sha256.Sum256(paymentPreimage[:])
|
||||
|
||||
// We'll also need some tests keys for alice and bob, and metadata of
|
||||
// the HTLC output.
|
||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
testWalletPrivKey)
|
||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
bobsPrivKey)
|
||||
paymentAmt := btcutil.Amount(1 * 10e8)
|
||||
|
||||
aliceLocalKey := TweakPubKey(aliceKeyPub, commitPoint)
|
||||
bobLocalKey := TweakPubKey(bobKeyPub, commitPoint)
|
||||
|
||||
// As we'll be modeling spends from Alice's commitment transaction,
|
||||
// we'll be using Bob's base point for the revocation key.
|
||||
revocationKey := DeriveRevocationPubkey(bobKeyPub, commitPoint)
|
||||
|
||||
// Generate the raw HTLC redemption scripts, and its p2wsh counterpart.
|
||||
htlcWitnessScript, err := senderHTLCScript(aliceLocalKey, bobLocalKey,
|
||||
revocationKey, paymentHash[:])
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create htlc sender script: %v", err)
|
||||
}
|
||||
htlcPkScript, err := WitnessScriptHash(htlcWitnessScript)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create p2wsh htlc script: %v", err)
|
||||
}
|
||||
|
||||
// This will be Alice's commitment transaction. In this scenario Alice
|
||||
// is sending an HTLC to a node she has a path to (could be Bob, could
|
||||
// be multiple hops down, it doesn't really matter).
|
||||
htlcOutput := &wire.TxOut{
|
||||
Value: int64(paymentAmt),
|
||||
PkScript: htlcPkScript,
|
||||
}
|
||||
senderCommitTx := wire.NewMsgTx(2)
|
||||
senderCommitTx.AddTxIn(fakeFundingTxIn)
|
||||
senderCommitTx.AddTxOut(htlcOutput)
|
||||
|
||||
prevOut := &wire.OutPoint{
|
||||
Hash: senderCommitTx.TxHash(),
|
||||
Index: 0,
|
||||
}
|
||||
|
||||
sweepTx := wire.NewMsgTx(2)
|
||||
sweepTx.AddTxIn(wire.NewTxIn(prevOut, nil, nil))
|
||||
sweepTx.AddTxOut(
|
||||
&wire.TxOut{
|
||||
PkScript: []byte("doesn't matter"),
|
||||
Value: 1 * 10e8,
|
||||
},
|
||||
)
|
||||
sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx)
|
||||
|
||||
bobCommitTweak := SingleTweakBytes(commitPoint, bobKeyPub)
|
||||
aliceCommitTweak := SingleTweakBytes(commitPoint, aliceKeyPub)
|
||||
|
||||
// Finally, we'll create mock signers for both of them based on their
|
||||
// private keys. This test simplifies a bit and uses the same key as
|
||||
// the base point for all scripts and derivations.
|
||||
bobSigner := &mockSigner{privkeys: []*btcec.PrivateKey{bobKeyPriv}}
|
||||
aliceSigner := &mockSigner{privkeys: []*btcec.PrivateKey{aliceKeyPriv}}
|
||||
|
||||
// We'll also generate a signature on the sweep transaction above
|
||||
// that will act as Bob's signature to Alice for the second level HTLC
|
||||
// transaction.
|
||||
bobSignDesc := SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: bobCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
bobRecvrSig, err := bobSigner.SignOutputRaw(sweepTx, &bobSignDesc)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate alice signature: %v", err)
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
witness func() wire.TxWitness
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
// revoke w/ sig
|
||||
// TODO(roasbeef): test invalid revoke
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
DoubleTweak: commitSecret,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return senderHtlcSpendRevoke(bobSigner, signDesc,
|
||||
revocationKey, sweepTx)
|
||||
}),
|
||||
true,
|
||||
},
|
||||
{
|
||||
// HTLC with invalid preimage size
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: bobCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return SenderHtlcSpendRedeem(bobSigner, signDesc,
|
||||
sweepTx,
|
||||
// Invalid preimage length
|
||||
bytes.Repeat([]byte{1}, 45))
|
||||
}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
// HTLC with valid preimage size + sig
|
||||
// TODO(roasbeef): invalid preimage
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: bobCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return SenderHtlcSpendRedeem(bobSigner, signDesc,
|
||||
sweepTx, paymentPreimage)
|
||||
}),
|
||||
true,
|
||||
},
|
||||
{
|
||||
// valid spend to the transition the state of the HTLC
|
||||
// output with the second level HTLC timeout
|
||||
// transaction.
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
},
|
||||
SingleTweak: aliceCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return senderHtlcSpendTimeout(bobRecvrSig, aliceSigner,
|
||||
signDesc, sweepTx)
|
||||
}),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
// TODO(roasbeef): set of cases to ensure able to sign w/ keypath and
|
||||
// not
|
||||
|
||||
for i, testCase := range testCases {
|
||||
sweepTx.TxIn[0].Witness = testCase.witness()
|
||||
|
||||
vm, err := txscript.NewEngine(htlcPkScript,
|
||||
sweepTx, 0, txscript.StandardVerifyFlags, nil,
|
||||
nil, int64(paymentAmt))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create engine: %v", err)
|
||||
}
|
||||
|
||||
// This buffer will trace execution of the Script, only dumping
|
||||
// out to stdout in the case that a test fails.
|
||||
var debugBuf bytes.Buffer
|
||||
|
||||
done := false
|
||||
for !done {
|
||||
dis, err := vm.DisasmPC()
|
||||
if err != nil {
|
||||
t.Fatalf("stepping (%v)\n", err)
|
||||
}
|
||||
debugBuf.WriteString(fmt.Sprintf("stepping %v\n", dis))
|
||||
|
||||
done, err = vm.Step()
|
||||
if err != nil && testCase.valid {
|
||||
fmt.Println(debugBuf.String())
|
||||
t.Fatalf("spend test case #%v failed, spend "+
|
||||
"should be valid: %v", i, err)
|
||||
} else if err == nil && !testCase.valid && done {
|
||||
fmt.Println(debugBuf.String())
|
||||
t.Fatalf("spend test case #%v succeed, spend "+
|
||||
"should be invalid: %v", i, err)
|
||||
}
|
||||
|
||||
debugBuf.WriteString(fmt.Sprintf("Stack: %v", vm.GetStack()))
|
||||
debugBuf.WriteString(fmt.Sprintf("AltStack: %v", vm.GetAltStack()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestHTLCReceiverSpendValidation tests all possible valid+invalid redemption
|
||||
// paths in the script used within the receiver's commitment transaction for an
|
||||
// incoming HTLC.
|
||||
//
|
||||
// The following cases are exercised by this test:
|
||||
// * receiver spends
|
||||
// * HTLC redemption w/ invalid preimage size
|
||||
// * HTLC redemption w/ invalid sequence
|
||||
// * HTLC redemption w/ valid preimage size
|
||||
// * sender spends
|
||||
// * revoke w/ sig
|
||||
// * refund w/ invalid lock time
|
||||
// * refund w/ valid lock time
|
||||
func TestHTLCReceiverSpendValidation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// We generate a fake output, and the corresponding txin. This output
|
||||
// doesn't need to exist, as we'll only be validating spending from the
|
||||
// transaction that references this.
|
||||
txid, err := chainhash.NewHash(testHdSeed.CloneBytes())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create txid: %v", err)
|
||||
}
|
||||
fundingOut := &wire.OutPoint{
|
||||
Hash: *txid,
|
||||
Index: 50,
|
||||
}
|
||||
fakeFundingTxIn := wire.NewTxIn(fundingOut, nil, nil)
|
||||
|
||||
// Next we'll the commitment secret for our commitment tx and also the
|
||||
// revocation key that we'll use as well.
|
||||
revokePreimage := testHdSeed.CloneBytes()
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
revokePreimage)
|
||||
|
||||
// Generate a payment preimage to be used below.
|
||||
paymentPreimage := revokePreimage
|
||||
paymentPreimage[0] ^= 1
|
||||
paymentHash := sha256.Sum256(paymentPreimage[:])
|
||||
|
||||
// We'll also need some tests keys for alice and bob, and metadata of
|
||||
// the HTLC output.
|
||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
testWalletPrivKey)
|
||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
bobsPrivKey)
|
||||
paymentAmt := btcutil.Amount(1 * 10e8)
|
||||
cltvTimeout := uint32(8)
|
||||
|
||||
aliceLocalKey := TweakPubKey(aliceKeyPub, commitPoint)
|
||||
bobLocalKey := TweakPubKey(bobKeyPub, commitPoint)
|
||||
|
||||
// As we'll be modeling spends from Bob's commitment transaction, we'll
|
||||
// be using Alice's base point for the revocation key.
|
||||
revocationKey := DeriveRevocationPubkey(aliceKeyPub, commitPoint)
|
||||
|
||||
// Generate the raw HTLC redemption scripts, and its p2wsh counterpart.
|
||||
htlcWitnessScript, err := receiverHTLCScript(cltvTimeout, aliceLocalKey,
|
||||
bobLocalKey, revocationKey, paymentHash[:])
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create htlc sender script: %v", err)
|
||||
}
|
||||
htlcPkScript, err := WitnessScriptHash(htlcWitnessScript)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create p2wsh htlc script: %v", err)
|
||||
}
|
||||
|
||||
// This will be Bob's commitment transaction. In this scenario Alice is
|
||||
// sending an HTLC to a node she has a path to (could be Bob, could be
|
||||
// multiple hops down, it doesn't really matter).
|
||||
htlcOutput := &wire.TxOut{
|
||||
Value: int64(paymentAmt),
|
||||
PkScript: htlcWitnessScript,
|
||||
}
|
||||
|
||||
receiverCommitTx := wire.NewMsgTx(2)
|
||||
receiverCommitTx.AddTxIn(fakeFundingTxIn)
|
||||
receiverCommitTx.AddTxOut(htlcOutput)
|
||||
|
||||
prevOut := &wire.OutPoint{
|
||||
Hash: receiverCommitTx.TxHash(),
|
||||
Index: 0,
|
||||
}
|
||||
|
||||
sweepTx := wire.NewMsgTx(2)
|
||||
sweepTx.AddTxIn(&wire.TxIn{
|
||||
PreviousOutPoint: *prevOut,
|
||||
})
|
||||
sweepTx.AddTxOut(
|
||||
&wire.TxOut{
|
||||
PkScript: []byte("doesn't matter"),
|
||||
Value: 1 * 10e8,
|
||||
},
|
||||
)
|
||||
sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx)
|
||||
|
||||
bobCommitTweak := SingleTweakBytes(commitPoint, bobKeyPub)
|
||||
aliceCommitTweak := SingleTweakBytes(commitPoint, aliceKeyPub)
|
||||
|
||||
// Finally, we'll create mock signers for both of them based on their
|
||||
// private keys. This test simplifies a bit and uses the same key as
|
||||
// the base point for all scripts and derivations.
|
||||
bobSigner := &mockSigner{privkeys: []*btcec.PrivateKey{bobKeyPriv}}
|
||||
aliceSigner := &mockSigner{privkeys: []*btcec.PrivateKey{aliceKeyPriv}}
|
||||
|
||||
// We'll also generate a signature on the sweep transaction above
|
||||
// that will act as Alice's signature to Bob for the second level HTLC
|
||||
// transaction.
|
||||
aliceSignDesc := SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
},
|
||||
SingleTweak: aliceCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
aliceSenderSig, err := aliceSigner.SignOutputRaw(sweepTx, &aliceSignDesc)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate alice signature: %v", err)
|
||||
}
|
||||
|
||||
// TODO(roasbeef): modify valid to check precise script errors?
|
||||
testCases := []struct {
|
||||
witness func() wire.TxWitness
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
// HTLC redemption w/ invalid preimage size
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: bobCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return receiverHtlcSpendRedeem(aliceSenderSig,
|
||||
bytes.Repeat([]byte{1}, 45), bobSigner,
|
||||
signDesc, sweepTx)
|
||||
|
||||
}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
// HTLC redemption w/ valid preimage size
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: bobCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return receiverHtlcSpendRedeem(aliceSenderSig,
|
||||
paymentPreimage[:], bobSigner,
|
||||
signDesc, sweepTx)
|
||||
}),
|
||||
true,
|
||||
},
|
||||
{
|
||||
// revoke w/ sig
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
},
|
||||
DoubleTweak: commitSecret,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return receiverHtlcSpendRevoke(aliceSigner,
|
||||
signDesc, revocationKey, sweepTx)
|
||||
}),
|
||||
true,
|
||||
},
|
||||
{
|
||||
// refund w/ invalid lock time
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
},
|
||||
SingleTweak: aliceCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return receiverHtlcSpendTimeout(aliceSigner, signDesc,
|
||||
sweepTx, int32(cltvTimeout-2))
|
||||
}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
// refund w/ valid lock time
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
},
|
||||
SingleTweak: aliceCommitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return receiverHtlcSpendTimeout(aliceSigner, signDesc,
|
||||
sweepTx, int32(cltvTimeout))
|
||||
}),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
sweepTx.TxIn[0].Witness = testCase.witness()
|
||||
|
||||
vm, err := txscript.NewEngine(htlcPkScript,
|
||||
sweepTx, 0, txscript.StandardVerifyFlags, nil,
|
||||
nil, int64(paymentAmt))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create engine: %v", err)
|
||||
}
|
||||
|
||||
// This buffer will trace execution of the Script, only dumping
|
||||
// out to stdout in the case that a test fails.
|
||||
var debugBuf bytes.Buffer
|
||||
|
||||
done := false
|
||||
for !done {
|
||||
dis, err := vm.DisasmPC()
|
||||
if err != nil {
|
||||
t.Fatalf("stepping (%v)\n", err)
|
||||
}
|
||||
debugBuf.WriteString(fmt.Sprintf("stepping %v\n", dis))
|
||||
|
||||
done, err = vm.Step()
|
||||
if err != nil && testCase.valid {
|
||||
fmt.Println(debugBuf.String())
|
||||
t.Fatalf("spend test case #%v failed, spend should be valid: %v", i, err)
|
||||
} else if err == nil && !testCase.valid && done {
|
||||
fmt.Println(debugBuf.String())
|
||||
t.Fatalf("spend test case #%v succeed, spend should be invalid: %v", i, err)
|
||||
}
|
||||
|
||||
debugBuf.WriteString(fmt.Sprintf("Stack: %v", vm.GetStack()))
|
||||
debugBuf.WriteString(fmt.Sprintf("AltStack: %v", vm.GetAltStack()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSecondLevelHtlcSpends tests all the possible redemption clauses from the
|
||||
// HTLC success and timeout covenant transactions.
|
||||
func TestSecondLevelHtlcSpends(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// We'll start be creating a creating a 2BTC HTLC.
|
||||
const htlcAmt = btcutil.Amount(2 * 10e8)
|
||||
|
||||
// In all of our scenarios, the CSV timeout to claim a self output will
|
||||
// be 5 blocks.
|
||||
const claimDelay = 5
|
||||
|
||||
// First we'll set up some initial key state for Alice and Bob that
|
||||
// will be used in the scripts we created below.
|
||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
testWalletPrivKey)
|
||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
bobsPrivKey)
|
||||
|
||||
revokePreimage := testHdSeed.CloneBytes()
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(
|
||||
btcec.S256(), revokePreimage)
|
||||
|
||||
// As we're modeling this as Bob sweeping the HTLC on-chain from his
|
||||
// commitment transaction after a period of time, we'll be using a
|
||||
// revocation key derived from Alice's base point and his secret.
|
||||
revocationKey := DeriveRevocationPubkey(aliceKeyPub, commitPoint)
|
||||
|
||||
// Next, craft a fake HTLC outpoint that we'll use to generate the
|
||||
// sweeping transaction using.
|
||||
txid, err := chainhash.NewHash(testHdSeed.CloneBytes())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create txid: %v", err)
|
||||
}
|
||||
htlcOutPoint := &wire.OutPoint{
|
||||
Hash: *txid,
|
||||
Index: 0,
|
||||
}
|
||||
sweepTx := wire.NewMsgTx(2)
|
||||
sweepTx.AddTxIn(wire.NewTxIn(htlcOutPoint, nil, nil))
|
||||
sweepTx.AddTxOut(
|
||||
&wire.TxOut{
|
||||
PkScript: []byte("doesn't matter"),
|
||||
Value: 1 * 10e8,
|
||||
},
|
||||
)
|
||||
sweepTxSigHashes := txscript.NewTxSigHashes(sweepTx)
|
||||
|
||||
// The delay key will be crafted using Bob's public key as the output
|
||||
// we created will be spending from Alice's commitment transaction.
|
||||
delayKey := TweakPubKey(bobKeyPub, commitPoint)
|
||||
|
||||
// The commit tweak will be required in order for Bob to derive the
|
||||
// proper key need to spend the output.
|
||||
commitTweak := SingleTweakBytes(commitPoint, bobKeyPub)
|
||||
|
||||
// Finally we'll generate the HTLC script itself that we'll be spending
|
||||
// from. The revocation clause can be claimed by Alice, while Bob can
|
||||
// sweep the output after a particular delay.
|
||||
htlcWitnessScript, err := secondLevelHtlcScript(revocationKey,
|
||||
delayKey, claimDelay)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create htlc script: %v", err)
|
||||
}
|
||||
htlcPkScript, err := WitnessScriptHash(htlcWitnessScript)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create htlc output: %v", err)
|
||||
}
|
||||
|
||||
htlcOutput := &wire.TxOut{
|
||||
PkScript: htlcPkScript,
|
||||
Value: int64(htlcAmt),
|
||||
}
|
||||
|
||||
// TODO(roasbeef): make actually use timeout/success txns?
|
||||
|
||||
// Finally, we'll create mock signers for both of them based on their
|
||||
// private keys. This test simplifies a bit and uses the same key as
|
||||
// the base point for all scripts and derivations.
|
||||
bobSigner := &mockSigner{privkeys: []*btcec.PrivateKey{bobKeyPriv}}
|
||||
aliceSigner := &mockSigner{privkeys: []*btcec.PrivateKey{aliceKeyPriv}}
|
||||
|
||||
testCases := []struct {
|
||||
witness func() wire.TxWitness
|
||||
valid bool
|
||||
}{
|
||||
{
|
||||
// Sender of the HTLC attempts to activate the
|
||||
// revocation clause, but uses the wrong key (fails to
|
||||
// use the double tweak in this case).
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
},
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return htlcSpendRevoke(aliceSigner, signDesc,
|
||||
sweepTx)
|
||||
}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Sender of HTLC activates the revocation clause.
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
},
|
||||
DoubleTweak: commitSecret,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return htlcSpendRevoke(aliceSigner, signDesc,
|
||||
sweepTx)
|
||||
}),
|
||||
true,
|
||||
},
|
||||
{
|
||||
// Receiver of the HTLC attempts to sweep, but tries to
|
||||
// do so pre-maturely with a smaller CSV delay (2
|
||||
// blocks instead of 5 blocks).
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: commitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return htlcSpendSuccess(bobSigner, signDesc,
|
||||
sweepTx, claimDelay-3)
|
||||
}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Receiver of the HTLC sweeps with the proper CSV
|
||||
// delay, but uses the wrong key (leaves off the single
|
||||
// tweak).
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return htlcSpendSuccess(bobSigner, signDesc,
|
||||
sweepTx, claimDelay)
|
||||
}),
|
||||
false,
|
||||
},
|
||||
{
|
||||
// Receiver of the HTLC sweeps with the proper CSV
|
||||
// delay, and the correct key.
|
||||
makeWitnessTestCase(t, func() (wire.TxWitness, error) {
|
||||
signDesc := &SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
SingleTweak: commitTweak,
|
||||
WitnessScript: htlcWitnessScript,
|
||||
Output: htlcOutput,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: sweepTxSigHashes,
|
||||
InputIndex: 0,
|
||||
}
|
||||
|
||||
return htlcSpendSuccess(bobSigner, signDesc,
|
||||
sweepTx, claimDelay)
|
||||
}),
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, testCase := range testCases {
|
||||
sweepTx.TxIn[0].Witness = testCase.witness()
|
||||
|
||||
vm, err := txscript.NewEngine(htlcPkScript,
|
||||
sweepTx, 0, txscript.StandardVerifyFlags, nil,
|
||||
nil, int64(htlcAmt))
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create engine: %v", err)
|
||||
}
|
||||
|
||||
// This buffer will trace execution of the Script, only dumping
|
||||
// out to stdout in the case that a test fails.
|
||||
var debugBuf bytes.Buffer
|
||||
|
||||
done := false
|
||||
for !done {
|
||||
dis, err := vm.DisasmPC()
|
||||
if err != nil {
|
||||
t.Fatalf("stepping (%v)\n", err)
|
||||
}
|
||||
debugBuf.WriteString(fmt.Sprintf("stepping %v\n", dis))
|
||||
|
||||
done, err = vm.Step()
|
||||
if err != nil && testCase.valid {
|
||||
fmt.Println(debugBuf.String())
|
||||
t.Fatalf("spend test case #%v failed, spend "+
|
||||
"should be valid: %v", i, err)
|
||||
} else if err == nil && !testCase.valid && done {
|
||||
fmt.Println(debugBuf.String())
|
||||
t.Fatalf("spend test case #%v succeed, spend "+
|
||||
"should be invalid: %v", i, err)
|
||||
}
|
||||
|
||||
debugBuf.WriteString(fmt.Sprintf("Stack: %v", vm.GetStack()))
|
||||
debugBuf.WriteString(fmt.Sprintf("AltStack: %v", vm.GetAltStack()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSpecificationKeyDerivation implements the test vectors provided in
|
||||
// BOLT-03, Appendix E.
|
||||
func TestSpecificationKeyDerivation(t *testing.T) {
|
||||
const (
|
||||
baseSecretHex = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
|
||||
perCommitmentSecretHex = "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"
|
||||
basePointHex = "036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2"
|
||||
perCommitmentPointHex = "025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"
|
||||
)
|
||||
|
||||
baseSecret, err := privkeyFromHex(baseSecretHex)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse serialized privkey: %v", err)
|
||||
}
|
||||
perCommitmentSecret, err := privkeyFromHex(perCommitmentSecretHex)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse serialized privkey: %v", err)
|
||||
}
|
||||
basePoint, err := pubkeyFromHex(basePointHex)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse serialized pubkey: %v", err)
|
||||
}
|
||||
perCommitmentPoint, err := pubkeyFromHex(perCommitmentPointHex)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to parse serialized pubkey: %v", err)
|
||||
}
|
||||
|
||||
// name: derivation of key from basepoint and per_commitment_point
|
||||
const expectedLocalKeyHex = "0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5"
|
||||
actualLocalKey := TweakPubKey(basePoint, perCommitmentPoint)
|
||||
actualLocalKeyHex := pubkeyToHex(actualLocalKey)
|
||||
if actualLocalKeyHex != expectedLocalKeyHex {
|
||||
t.Errorf("Incorrect derivation of local public key: "+
|
||||
"expected %v, got %v", expectedLocalKeyHex, actualLocalKeyHex)
|
||||
}
|
||||
|
||||
// name: derivation of secret key from basepoint secret and per_commitment_secret
|
||||
const expectedLocalPrivKeyHex = "cbced912d3b21bf196a766651e436aff192362621ce317704ea2f75d87e7be0f"
|
||||
tweak := SingleTweakBytes(perCommitmentPoint, basePoint)
|
||||
actualLocalPrivKey := TweakPrivKey(baseSecret, tweak)
|
||||
actualLocalPrivKeyHex := privkeyToHex(actualLocalPrivKey)
|
||||
if actualLocalPrivKeyHex != expectedLocalPrivKeyHex {
|
||||
t.Errorf("Incorrect derivation of local private key: "+
|
||||
"expected %v, got %v, %v", expectedLocalPrivKeyHex,
|
||||
actualLocalPrivKeyHex, hex.EncodeToString(tweak))
|
||||
}
|
||||
|
||||
// name: derivation of revocation key from basepoint and per_commitment_point
|
||||
const expectedRevocationKeyHex = "02916e326636d19c33f13e8c0c3a03dd157f332f3e99c317c141dd865eb01f8ff0"
|
||||
actualRevocationKey := DeriveRevocationPubkey(basePoint, perCommitmentPoint)
|
||||
actualRevocationKeyHex := pubkeyToHex(actualRevocationKey)
|
||||
if actualRevocationKeyHex != expectedRevocationKeyHex {
|
||||
t.Errorf("Incorrect derivation of revocation public key: "+
|
||||
"expected %v, got %v", expectedRevocationKeyHex,
|
||||
actualRevocationKeyHex)
|
||||
}
|
||||
|
||||
// name: derivation of revocation secret from basepoint_secret and per_commitment_secret
|
||||
const expectedRevocationPrivKeyHex = "d09ffff62ddb2297ab000cc85bcb4283fdeb6aa052affbc9dddcf33b61078110"
|
||||
actualRevocationPrivKey := DeriveRevocationPrivKey(baseSecret,
|
||||
perCommitmentSecret)
|
||||
actualRevocationPrivKeyHex := privkeyToHex(actualRevocationPrivKey)
|
||||
if actualRevocationPrivKeyHex != expectedRevocationPrivKeyHex {
|
||||
t.Errorf("Incorrect derivation of revocation private key: "+
|
||||
"expected %v, got %v", expectedRevocationPrivKeyHex,
|
||||
actualRevocationPrivKeyHex)
|
||||
}
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrTweakOverdose signals a SignDescriptor is invalid because both of its
|
||||
// SingleTweak and DoubleTweak are non-nil.
|
||||
ErrTweakOverdose = errors.New("sign descriptor should only have one tweak")
|
||||
)
|
||||
|
||||
// SignDescriptor houses the necessary information required to successfully sign
|
||||
// a given output. This struct is used by the Signer interface in order to gain
|
||||
// access to critical data needed to generate a valid signature.
|
||||
type SignDescriptor struct {
|
||||
// KeyDesc is a descriptor that precisely describes *which* key to use
|
||||
// for signing. This may provide the raw public key directly, or
|
||||
// require the Signer to re-derive the key according to the populated
|
||||
// derivation path.
|
||||
KeyDesc keychain.KeyDescriptor
|
||||
|
||||
// SingleTweak is a scalar value that will be added to the private key
|
||||
// corresponding to the above public key to obtain the private key to
|
||||
// be used to sign this input. This value is typically derived via the
|
||||
// following computation:
|
||||
//
|
||||
// * derivedKey = privkey + sha256(perCommitmentPoint || pubKey) mod N
|
||||
//
|
||||
// NOTE: If this value is nil, then the input can be signed using only
|
||||
// the above public key. Either a SingleTweak should be set or a
|
||||
// DoubleTweak, not both.
|
||||
SingleTweak []byte
|
||||
|
||||
// DoubleTweak is a private key that will be used in combination with
|
||||
// its corresponding private key to derive the private key that is to
|
||||
// be used to sign the target input. Within the Lightning protocol,
|
||||
// this value is typically the commitment secret from a previously
|
||||
// revoked commitment transaction. This value is in combination with
|
||||
// two hash values, and the original private key to derive the private
|
||||
// key to be used when signing.
|
||||
//
|
||||
// * k = (privKey*sha256(pubKey || tweakPub) +
|
||||
// tweakPriv*sha256(tweakPub || pubKey)) mod N
|
||||
//
|
||||
// NOTE: If this value is nil, then the input can be signed using only
|
||||
// the above public key. Either a SingleTweak should be set or a
|
||||
// DoubleTweak, not both.
|
||||
DoubleTweak *btcec.PrivateKey
|
||||
|
||||
// WitnessScript is the full script required to properly redeem the
|
||||
// output. This field will only be populated if a p2wsh or a p2sh
|
||||
// output is being signed.
|
||||
WitnessScript []byte
|
||||
|
||||
// Output is the target output which should be signed. The PkScript and
|
||||
// Value fields within the output should be properly populated,
|
||||
// otherwise an invalid signature may be generated.
|
||||
Output *wire.TxOut
|
||||
|
||||
// HashType is the target sighash type that should be used when
|
||||
// generating the final sighash, and signature.
|
||||
HashType txscript.SigHashType
|
||||
|
||||
// SigHashes is the pre-computed sighash midstate to be used when
|
||||
// generating the final sighash for signing.
|
||||
SigHashes *txscript.TxSigHashes
|
||||
|
||||
// InputIndex is the target input within the transaction that should be
|
||||
// signed.
|
||||
InputIndex int
|
||||
}
|
||||
|
||||
// WriteSignDescriptor serializes a SignDescriptor struct into the passed
|
||||
// io.Writer stream.
|
||||
//
|
||||
// NOTE: We assume the SigHashes and InputIndex fields haven't been assigned
|
||||
// yet, since that is usually done just before broadcast by the witness
|
||||
// generator.
|
||||
func WriteSignDescriptor(w io.Writer, sd *SignDescriptor) error {
|
||||
err := binary.Write(w, binary.BigEndian, sd.KeyDesc.Family)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Write(w, binary.BigEndian, sd.KeyDesc.Index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = binary.Write(w, binary.BigEndian, sd.KeyDesc.PubKey != nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if sd.KeyDesc.PubKey != nil {
|
||||
serializedPubKey := sd.KeyDesc.PubKey.SerializeCompressed()
|
||||
if err := wire.WriteVarBytes(w, 0, serializedPubKey); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := wire.WriteVarBytes(w, 0, sd.SingleTweak); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var doubleTweakBytes []byte
|
||||
if sd.DoubleTweak != nil {
|
||||
doubleTweakBytes = sd.DoubleTweak.Serialize()
|
||||
}
|
||||
if err := wire.WriteVarBytes(w, 0, doubleTweakBytes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := wire.WriteVarBytes(w, 0, sd.WitnessScript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := writeTxOut(w, sd.Output); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var scratch [4]byte
|
||||
binary.BigEndian.PutUint32(scratch[:], uint32(sd.HashType))
|
||||
if _, err := w.Write(scratch[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadSignDescriptor deserializes a SignDescriptor struct from the passed
|
||||
// io.Reader stream.
|
||||
func ReadSignDescriptor(r io.Reader, sd *SignDescriptor) error {
|
||||
err := binary.Read(r, binary.BigEndian, &sd.KeyDesc.Family)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = binary.Read(r, binary.BigEndian, &sd.KeyDesc.Index)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var hasKey bool
|
||||
err = binary.Read(r, binary.BigEndian, &hasKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if hasKey {
|
||||
pubKeyBytes, err := wire.ReadVarBytes(r, 0, 34, "pubkey")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sd.KeyDesc.PubKey, err = btcec.ParsePubKey(
|
||||
pubKeyBytes, btcec.S256(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
singleTweak, err := wire.ReadVarBytes(r, 0, 32, "singleTweak")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Serializing a SignDescriptor with a nil-valued SingleTweak results
|
||||
// in deserializing a zero-length slice. Since a nil-valued SingleTweak
|
||||
// has special meaning and a zero-length slice for a SingleTweak is
|
||||
// invalid, we can use the zero-length slice as the flag for a
|
||||
// nil-valued SingleTweak.
|
||||
if len(singleTweak) == 0 {
|
||||
sd.SingleTweak = nil
|
||||
} else {
|
||||
sd.SingleTweak = singleTweak
|
||||
}
|
||||
|
||||
doubleTweakBytes, err := wire.ReadVarBytes(r, 0, 32, "doubleTweak")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Serializing a SignDescriptor with a nil-valued DoubleTweak results
|
||||
// in deserializing a zero-length slice. Since a nil-valued DoubleTweak
|
||||
// has special meaning and a zero-length slice for a DoubleTweak is
|
||||
// invalid, we can use the zero-length slice as the flag for a
|
||||
// nil-valued DoubleTweak.
|
||||
if len(doubleTweakBytes) == 0 {
|
||||
sd.DoubleTweak = nil
|
||||
} else {
|
||||
sd.DoubleTweak, _ = btcec.PrivKeyFromBytes(btcec.S256(), doubleTweakBytes)
|
||||
}
|
||||
|
||||
// Only one tweak should ever be set, fail if both are present.
|
||||
if sd.SingleTweak != nil && sd.DoubleTweak != nil {
|
||||
return ErrTweakOverdose
|
||||
}
|
||||
|
||||
witnessScript, err := wire.ReadVarBytes(r, 0, 500, "witnessScript")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sd.WitnessScript = witnessScript
|
||||
|
||||
txOut := &wire.TxOut{}
|
||||
if err := readTxOut(r, txOut); err != nil {
|
||||
return err
|
||||
}
|
||||
sd.Output = txOut
|
||||
|
||||
var hashType [4]byte
|
||||
if _, err := io.ReadFull(r, hashType[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
sd.HashType = txscript.SigHashType(binary.BigEndian.Uint32(hashType[:]))
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
)
|
||||
|
||||
func TestSignDescriptorSerialization(t *testing.T) {
|
||||
keys := [][]byte{
|
||||
{0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
||||
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
||||
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
||||
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
||||
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
||||
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
||||
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
||||
0xb4, 0x12, 0xa3,
|
||||
},
|
||||
{0x04, 0x11, 0xdb, 0x93, 0xe1, 0xdc, 0xdb, 0x8a,
|
||||
0x01, 0x6b, 0x49, 0x84, 0x0f, 0x8c, 0x53, 0xbc, 0x1e,
|
||||
0xb6, 0x8a, 0x38, 0x2e, 0x97, 0xb1, 0x48, 0x2e, 0xca,
|
||||
0xd7, 0xb1, 0x48, 0xa6, 0x90, 0x9a, 0x5c, 0xb2, 0xe0,
|
||||
0xea, 0xdd, 0xfb, 0x84, 0xcc, 0xf9, 0x74, 0x44, 0x64,
|
||||
0xf8, 0x2e, 0x16, 0x0b, 0xfa, 0x9b, 0x8b, 0x64, 0xf9,
|
||||
0xd4, 0xc0, 0x3f, 0x99, 0x9b, 0x86, 0x43, 0xf6, 0x56,
|
||||
0xb4, 0x12, 0xa3,
|
||||
},
|
||||
}
|
||||
|
||||
signDescriptors := []SignDescriptor{
|
||||
{
|
||||
SingleTweak: []byte{
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x02, 0x02,
|
||||
},
|
||||
WitnessScript: []byte{
|
||||
0x00, 0x14, 0xee, 0x91, 0x41, 0x7e, 0x85, 0x6c, 0xde,
|
||||
0x10, 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 0xbd, 0x69, 0xe2,
|
||||
0xef, 0xb5, 0x71, 0x48,
|
||||
},
|
||||
Output: &wire.TxOut{
|
||||
Value: 5000000000,
|
||||
PkScript: []byte{
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
||||
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
||||
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
||||
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
||||
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
||||
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
||||
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
||||
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
||||
0xa6, // 65-byte signature
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
HashType: txscript.SigHashAll,
|
||||
},
|
||||
|
||||
// Test serializing a SignDescriptor with a nil-valued PrivateTweak
|
||||
{
|
||||
SingleTweak: nil,
|
||||
WitnessScript: []byte{
|
||||
0x00, 0x14, 0xee, 0x91, 0x41, 0x7e, 0x85, 0x6c, 0xde,
|
||||
0x10, 0xa2, 0x91, 0x1e, 0xdc, 0xbd, 0xbd, 0x69, 0xe2,
|
||||
0xef, 0xb5, 0x71, 0x48,
|
||||
},
|
||||
Output: &wire.TxOut{
|
||||
Value: 5000000000,
|
||||
PkScript: []byte{
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
||||
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
||||
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
||||
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
||||
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
||||
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
||||
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
||||
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
||||
0xa6, // 65-byte signature
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
},
|
||||
HashType: txscript.SigHashAll,
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < len(signDescriptors); i++ {
|
||||
// Parse pubkeys for each sign descriptor.
|
||||
sd := &signDescriptors[i]
|
||||
pubkey, err := btcec.ParsePubKey(keys[i], btcec.S256())
|
||||
if err != nil {
|
||||
t.Fatalf("unable to parse pubkey: %v", err)
|
||||
}
|
||||
sd.KeyDesc = keychain.KeyDescriptor{
|
||||
KeyLocator: keychain.KeyLocator{
|
||||
Family: 50,
|
||||
Index: 99,
|
||||
},
|
||||
PubKey: pubkey,
|
||||
}
|
||||
|
||||
// Test that serialize -> deserialize yields same result as original.
|
||||
var buf bytes.Buffer
|
||||
if err := WriteSignDescriptor(&buf, sd); err != nil {
|
||||
t.Fatalf("unable to serialize sign descriptor[%v]: %v", i, sd)
|
||||
}
|
||||
|
||||
desSd := &SignDescriptor{}
|
||||
if err := ReadSignDescriptor(&buf, desSd); err != nil {
|
||||
t.Fatalf("unable to deserialize sign descriptor[%v]: %v", i, sd)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(sd, desSd) {
|
||||
t.Fatalf("original and deserialized sign descriptors not equal:\n"+
|
||||
"original : %+v\n"+
|
||||
"deserialized : %+v\n",
|
||||
sd, desSd)
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
-3
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
@@ -76,7 +77,7 @@ type SignJob struct {
|
||||
// SignDesc is intended to be a full populated SignDescriptor which
|
||||
// encodes the necessary material (keys, witness script, etc) required
|
||||
// to generate a valid signature for the specified input.
|
||||
SignDesc SignDescriptor
|
||||
SignDesc input.SignDescriptor
|
||||
|
||||
// Tx is the transaction to be signed. This is required to generate the
|
||||
// proper sighash for the input to be signed.
|
||||
@@ -127,7 +128,7 @@ type SigPool struct {
|
||||
started uint32 // To be used atomically.
|
||||
stopped uint32 // To be used atomically.
|
||||
|
||||
signer Signer
|
||||
signer input.Signer
|
||||
|
||||
verifyJobs chan VerifyJob
|
||||
signJobs chan SignJob
|
||||
@@ -141,7 +142,7 @@ type SigPool struct {
|
||||
// NewSigPool creates a new signature pool with the specified number of
|
||||
// workers. The recommended parameter for the number of works is the number of
|
||||
// physical CPU cores available on the target machine.
|
||||
func NewSigPool(numWorkers int, signer Signer) *SigPool {
|
||||
func NewSigPool(numWorkers int, signer input.Signer) *SigPool {
|
||||
return &SigPool{
|
||||
signer: signer,
|
||||
numWorkers: numWorkers,
|
||||
|
||||
@@ -1,497 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/blockchain"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
const (
|
||||
// CommitWeight is the weight of the base commitment transaction which
|
||||
// includes: one p2wsh input, out p2wkh output, and one p2wsh output.
|
||||
CommitWeight int64 = 724
|
||||
|
||||
// HtlcWeight is the weight of an HTLC output.
|
||||
HtlcWeight int64 = 172
|
||||
)
|
||||
|
||||
const (
|
||||
// witnessScaleFactor determines the level of "discount" witness data
|
||||
// receives compared to "base" data. A scale factor of 4, denotes that
|
||||
// witness data is 1/4 as cheap as regular non-witness data. Value copied
|
||||
// here for convenience.
|
||||
witnessScaleFactor = blockchain.WitnessScaleFactor
|
||||
|
||||
// The weight(weight), which is different from the !size! (see BIP-141),
|
||||
// is calculated as:
|
||||
// Weight = 4 * BaseSize + WitnessSize (weight).
|
||||
// BaseSize - size of the transaction without witness data (bytes).
|
||||
// WitnessSize - witness size (bytes).
|
||||
// Weight - the metric for determining the weight of the transaction.
|
||||
|
||||
// P2WPKHSize 22 bytes
|
||||
// - OP_0: 1 byte
|
||||
// - OP_DATA: 1 byte (PublicKeyHASH160 length)
|
||||
// - PublicKeyHASH160: 20 bytes
|
||||
P2WPKHSize = 1 + 1 + 20
|
||||
|
||||
// P2WSHSize 34 bytes
|
||||
// - OP_0: 1 byte
|
||||
// - OP_DATA: 1 byte (WitnessScriptSHA256 length)
|
||||
// - WitnessScriptSHA256: 32 bytes
|
||||
P2WSHSize = 1 + 1 + 32
|
||||
|
||||
// P2PKHOutputSize 34 bytes
|
||||
// - value: 8 bytes
|
||||
// - var_int: 1 byte (pkscript_length)
|
||||
// - pkscript (p2pkh): 25 bytes
|
||||
P2PKHOutputSize = 8 + 1 + 25
|
||||
|
||||
// P2WKHOutputSize 31 bytes
|
||||
// - value: 8 bytes
|
||||
// - var_int: 1 byte (pkscript_length)
|
||||
// - pkscript (p2wpkh): 22 bytes
|
||||
P2WKHOutputSize = 8 + 1 + P2WPKHSize
|
||||
|
||||
// P2WSHOutputSize 43 bytes
|
||||
// - value: 8 bytes
|
||||
// - var_int: 1 byte (pkscript_length)
|
||||
// - pkscript (p2wsh): 34 bytes
|
||||
P2WSHOutputSize = 8 + 1 + P2WSHSize
|
||||
|
||||
// P2SHOutputSize 32 bytes
|
||||
// - value: 8 bytes
|
||||
// - var_int: 1 byte (pkscript_length)
|
||||
// - pkscript (p2sh): 23 bytes
|
||||
P2SHOutputSize = 8 + 1 + 23
|
||||
|
||||
// P2PKHScriptSigSize 108 bytes
|
||||
// - OP_DATA: 1 byte (signature length)
|
||||
// - signature
|
||||
// - OP_DATA: 1 byte (pubkey length)
|
||||
// - pubkey
|
||||
P2PKHScriptSigSize = 1 + 73 + 1 + 33
|
||||
|
||||
// P2WKHWitnessSize 109 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - signature_length: 1 byte
|
||||
// - signature
|
||||
// - pubkey_length: 1 byte
|
||||
// - pubkey
|
||||
P2WKHWitnessSize = 1 + 1 + 73 + 1 + 33
|
||||
|
||||
// MultiSigSize 71 bytes
|
||||
// - OP_2: 1 byte
|
||||
// - OP_DATA: 1 byte (pubKeyAlice length)
|
||||
// - pubKeyAlice: 33 bytes
|
||||
// - OP_DATA: 1 byte (pubKeyBob length)
|
||||
// - pubKeyBob: 33 bytes
|
||||
// - OP_2: 1 byte
|
||||
// - OP_CHECKMULTISIG: 1 byte
|
||||
MultiSigSize = 1 + 1 + 33 + 1 + 33 + 1 + 1
|
||||
|
||||
// WitnessSize 222 bytes
|
||||
// - NumberOfWitnessElements: 1 byte
|
||||
// - NilLength: 1 byte
|
||||
// - sigAliceLength: 1 byte
|
||||
// - sigAlice: 73 bytes
|
||||
// - sigBobLength: 1 byte
|
||||
// - sigBob: 73 bytes
|
||||
// - WitnessScriptLength: 1 byte
|
||||
// - WitnessScript (MultiSig)
|
||||
WitnessSize = 1 + 1 + 1 + 73 + 1 + 73 + 1 + MultiSigSize
|
||||
|
||||
// InputSize 41 bytes
|
||||
// - PreviousOutPoint:
|
||||
// - Hash: 32 bytes
|
||||
// - Index: 4 bytes
|
||||
// - OP_DATA: 1 byte (ScriptSigLength)
|
||||
// - ScriptSig: 0 bytes
|
||||
// - Witness <---- we use "Witness" instead of "ScriptSig" for
|
||||
// transaction validation, but "Witness" is stored
|
||||
// separately and weight for it size is smaller. So
|
||||
// we separate the calculation of ordinary data
|
||||
// from witness data.
|
||||
// - Sequence: 4 bytes
|
||||
InputSize = 32 + 4 + 1 + 4
|
||||
|
||||
// FundingInputSize represents the size of an input to a funding
|
||||
// transaction, and is equivalent to the size of a standard segwit input
|
||||
// as calculated above.
|
||||
FundingInputSize = InputSize
|
||||
|
||||
// CommitmentDelayOutput 43 bytes
|
||||
// - Value: 8 bytes
|
||||
// - VarInt: 1 byte (PkScript length)
|
||||
// - PkScript (P2WSH)
|
||||
CommitmentDelayOutput = 8 + 1 + P2WSHSize
|
||||
|
||||
// CommitmentKeyHashOutput 31 bytes
|
||||
// - Value: 8 bytes
|
||||
// - VarInt: 1 byte (PkScript length)
|
||||
// - PkScript (P2WPKH)
|
||||
CommitmentKeyHashOutput = 8 + 1 + P2WPKHSize
|
||||
|
||||
// HTLCSize 43 bytes
|
||||
// - Value: 8 bytes
|
||||
// - VarInt: 1 byte (PkScript length)
|
||||
// - PkScript (PW2SH)
|
||||
HTLCSize = 8 + 1 + P2WSHSize
|
||||
|
||||
// WitnessHeaderSize 2 bytes
|
||||
// - Flag: 1 byte
|
||||
// - Marker: 1 byte
|
||||
WitnessHeaderSize = 1 + 1
|
||||
|
||||
// BaseTxSize 8 bytes
|
||||
// - Version: 4 bytes
|
||||
// - LockTime: 4 bytes
|
||||
BaseTxSize = 4 + 4
|
||||
|
||||
// BaseCommitmentTxSize 125 + 43 * num-htlc-outputs bytes
|
||||
// - Version: 4 bytes
|
||||
// - WitnessHeader <---- part of the witness data
|
||||
// - CountTxIn: 1 byte
|
||||
// - TxIn: 41 bytes
|
||||
// FundingInput
|
||||
// - CountTxOut: 1 byte
|
||||
// - TxOut: 74 + 43 * num-htlc-outputs bytes
|
||||
// OutputPayingToThem,
|
||||
// OutputPayingToUs,
|
||||
// ....HTLCOutputs...
|
||||
// - LockTime: 4 bytes
|
||||
BaseCommitmentTxSize = 4 + 1 + FundingInputSize + 1 +
|
||||
CommitmentDelayOutput + CommitmentKeyHashOutput + 4
|
||||
|
||||
// BaseCommitmentTxWeight 500 weight
|
||||
BaseCommitmentTxWeight = witnessScaleFactor * BaseCommitmentTxSize
|
||||
|
||||
// WitnessCommitmentTxWeight 224 weight
|
||||
WitnessCommitmentTxWeight = WitnessHeaderSize + WitnessSize
|
||||
|
||||
// HTLCWeight 172 weight
|
||||
HTLCWeight = witnessScaleFactor * HTLCSize
|
||||
|
||||
// HtlcTimeoutWeight is the weight of the HTLC timeout transaction
|
||||
// which will transition an outgoing HTLC to the delay-and-claim state.
|
||||
HtlcTimeoutWeight = 663
|
||||
|
||||
// HtlcSuccessWeight is the weight of the HTLC success transaction
|
||||
// which will transition an incoming HTLC to the delay-and-claim state.
|
||||
HtlcSuccessWeight = 703
|
||||
|
||||
// MaxHTLCNumber is the maximum number HTLCs which can be included in a
|
||||
// commitment transaction. This limit was chosen such that, in the case
|
||||
// of a contract breach, the punishment transaction is able to sweep
|
||||
// all the HTLC's yet still remain below the widely used standard
|
||||
// weight limits.
|
||||
MaxHTLCNumber = 966
|
||||
|
||||
// ToLocalScriptSize 79 bytes
|
||||
// - OP_IF: 1 byte
|
||||
// - OP_DATA: 1 byte
|
||||
// - revoke_key: 33 bytes
|
||||
// - OP_ELSE: 1 byte
|
||||
// - OP_DATA: 1 byte
|
||||
// - csv_delay: 4 bytes
|
||||
// - OP_CHECKSEQUENCEVERIFY: 1 byte
|
||||
// - OP_DROP: 1 byte
|
||||
// - OP_DATA: 1 byte
|
||||
// - delay_key: 33 bytes
|
||||
// - OP_ENDIF: 1 byte
|
||||
// - OP_CHECKSIG: 1 byte
|
||||
ToLocalScriptSize = 1 + 1 + 33 + 1 + 1 + 4 + 1 + 1 + 1 + 33 + 1 + 1
|
||||
|
||||
// ToLocalTimeoutWitnessSize 156 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - local_delay_sig_length: 1 byte
|
||||
// - local_delay_sig: 73 bytes
|
||||
// - zero_length: 1 byte
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script (to_local_script)
|
||||
ToLocalTimeoutWitnessSize = 1 + 1 + 73 + 1 + 1 + ToLocalScriptSize
|
||||
|
||||
// ToLocalPenaltyWitnessSize 156 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - revocation_sig_length: 1 byte
|
||||
// - revocation_sig: 73 bytes
|
||||
// - OP_TRUE: 1 byte
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script (to_local_script)
|
||||
ToLocalPenaltyWitnessSize = 1 + 1 + 73 + 1 + 1 + ToLocalScriptSize
|
||||
|
||||
// AcceptedHtlcScriptSize 139 bytes
|
||||
// - OP_DUP: 1 byte
|
||||
// - OP_HASH160: 1 byte
|
||||
// - OP_DATA: 1 byte (RIPEMD160(SHA256(revocationkey)) length)
|
||||
// - RIPEMD160(SHA256(revocationkey)): 20 bytes
|
||||
// - OP_EQUAL: 1 byte
|
||||
// - OP_IF: 1 byte
|
||||
// - OP_CHECKSIG: 1 byte
|
||||
// - OP_ELSE: 1 byte
|
||||
// - OP_DATA: 1 byte (remotekey length)
|
||||
// - remotekey: 33 bytes
|
||||
// - OP_SWAP: 1 byte
|
||||
// - OP_SIZE: 1 byte
|
||||
// - 32: 1 byte
|
||||
// - OP_EQUAL: 1 byte
|
||||
// - OP_IF: 1 byte
|
||||
// - OP_HASH160: 1 byte
|
||||
// - OP_DATA: 1 byte (RIPEMD160(payment_hash) length)
|
||||
// - RIPEMD160(payment_hash): 20 bytes
|
||||
// - OP_EQUALVERIFY: 1 byte
|
||||
// - 2: 1 byte
|
||||
// - OP_SWAP: 1 byte
|
||||
// - OP_DATA: 1 byte (localkey length)
|
||||
// - localkey: 33 bytes
|
||||
// - 2: 1 byte
|
||||
// - OP_CHECKMULTISIG: 1 byte
|
||||
// - OP_ELSE: 1 byte
|
||||
// - OP_DROP: 1 byte
|
||||
// - OP_DATA: 1 byte (cltv_expiry length)
|
||||
// - cltv_expiry: 4 bytes
|
||||
// - OP_CHECKLOCKTIMEVERIFY: 1 byte
|
||||
// - OP_DROP: 1 byte
|
||||
// - OP_CHECKSIG: 1 byte
|
||||
// - OP_ENDIF: 1 byte
|
||||
// - OP_ENDIF: 1 byte
|
||||
AcceptedHtlcScriptSize = 3*1 + 20 + 5*1 + 33 + 7*1 + 20 + 4*1 +
|
||||
33 + 5*1 + 4 + 5*1
|
||||
|
||||
// AcceptedHtlcTimeoutWitnessSize 216
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - sender_sig_length: 1 byte
|
||||
// - sender_sig: 73 bytes
|
||||
// - nil_length: 1 byte
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script: (accepted_htlc_script)
|
||||
AcceptedHtlcTimeoutWitnessSize = 1 + 1 + 73 + 1 + 1 + AcceptedHtlcScriptSize
|
||||
|
||||
// AcceptedHtlcSuccessWitnessSize 322 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - nil_length: 1 byte
|
||||
// - sig_alice_length: 1 byte
|
||||
// - sig_alice: 73 bytes
|
||||
// - sig_bob_length: 1 byte
|
||||
// - sig_bob: 73 bytes
|
||||
// - preimage_length: 1 byte
|
||||
// - preimage: 32 bytes
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script (accepted_htlc_script)
|
||||
AcceptedHtlcSuccessWitnessSize = 1 + 1 + 73 + 1 + 73 + 1 + 32 + 1 + AcceptedHtlcScriptSize
|
||||
|
||||
// AcceptedHtlcPenaltyWitnessSize 249 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - revocation_sig_length: 1 byte
|
||||
// - revocation_sig: 73 bytes
|
||||
// - revocation_key_length: 1 byte
|
||||
// - revocation_key: 33 bytes
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script (accepted_htlc_script)
|
||||
AcceptedHtlcPenaltyWitnessSize = 1 + 1 + 73 + 1 + 33 + 1 + AcceptedHtlcScriptSize
|
||||
|
||||
// OfferedHtlcScriptSize 133 bytes
|
||||
// - OP_DUP: 1 byte
|
||||
// - OP_HASH160: 1 byte
|
||||
// - OP_DATA: 1 byte (RIPEMD160(SHA256(revocationkey)) length)
|
||||
// - RIPEMD160(SHA256(revocationkey)): 20 bytes
|
||||
// - OP_EQUAL: 1 byte
|
||||
// - OP_IF: 1 byte
|
||||
// - OP_CHECKSIG: 1 byte
|
||||
// - OP_ELSE: 1 byte
|
||||
// - OP_DATA: 1 byte (remotekey length)
|
||||
// - remotekey: 33 bytes
|
||||
// - OP_SWAP: 1 byte
|
||||
// - OP_SIZE: 1 byte
|
||||
// - OP_DATA: 1 byte (32 length)
|
||||
// - 32: 1 byte
|
||||
// - OP_EQUAL: 1 byte
|
||||
// - OP_NOTIF: 1 byte
|
||||
// - OP_DROP: 1 byte
|
||||
// - 2: 1 byte
|
||||
// - OP_SWAP: 1 byte
|
||||
// - OP_DATA: 1 byte (localkey length)
|
||||
// - localkey: 33 bytes
|
||||
// - 2: 1 byte
|
||||
// - OP_CHECKMULTISIG: 1 byte
|
||||
// - OP_ELSE: 1 byte
|
||||
// - OP_HASH160: 1 byte
|
||||
// - OP_DATA: 1 byte (RIPEMD160(payment_hash) length)
|
||||
// - RIPEMD160(payment_hash): 20 bytes
|
||||
// - OP_EQUALVERIFY: 1 byte
|
||||
// - OP_CHECKSIG: 1 byte
|
||||
// - OP_ENDIF: 1 byte
|
||||
// - OP_ENDIF: 1 byte
|
||||
OfferedHtlcScriptSize = 3*1 + 20 + 5*1 + 33 + 10*1 + 33 + 5*1 + 20 + 4*1
|
||||
|
||||
// OfferedHtlcTimeoutWitnessSize 285 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - nil_length: 1 byte
|
||||
// - sig_alice_length: 1 byte
|
||||
// - sig_alice: 73 bytes
|
||||
// - sig_bob_length: 1 byte
|
||||
// - sig_bob: 73 bytes
|
||||
// - nil_length: 1 byte
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script (offered_htlc_script)
|
||||
OfferedHtlcTimeoutWitnessSize = 1 + 1 + 1 + 73 + 1 + 73 + 1 + 1 + OfferedHtlcScriptSize
|
||||
|
||||
// OfferedHtlcSuccessWitnessSize 317 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - nil_length: 1 byte
|
||||
// - receiver_sig_length: 1 byte
|
||||
// - receiver_sig: 73 bytes
|
||||
// - sender_sig_length: 1 byte
|
||||
// - sender_sig: 73 bytes
|
||||
// - payment_preimage_length: 1 byte
|
||||
// - payment_preimage: 32 bytes
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script (offered_htlc_script)
|
||||
OfferedHtlcSuccessWitnessSize = 1 + 1 + 1 + 73 + 1 + 73 + 1 + 32 + 1 + OfferedHtlcScriptSize
|
||||
|
||||
// OfferedHtlcPenaltyWitnessSize 243 bytes
|
||||
// - number_of_witness_elements: 1 byte
|
||||
// - revocation_sig_length: 1 byte
|
||||
// - revocation_sig: 73 bytes
|
||||
// - revocation_key_length: 1 byte
|
||||
// - revocation_key: 33 bytes
|
||||
// - witness_script_length: 1 byte
|
||||
// - witness_script (offered_htlc_script)
|
||||
OfferedHtlcPenaltyWitnessSize = 1 + 1 + 73 + 1 + 33 + 1 + OfferedHtlcScriptSize
|
||||
)
|
||||
|
||||
// estimateCommitTxWeight estimate commitment transaction weight depending on
|
||||
// the precalculated weight of base transaction, witness data, which is needed
|
||||
// for paying for funding tx, and htlc weight multiplied by their count.
|
||||
func estimateCommitTxWeight(count int, prediction bool) int64 {
|
||||
// Make prediction about the size of commitment transaction with
|
||||
// additional HTLC.
|
||||
if prediction {
|
||||
count++
|
||||
}
|
||||
|
||||
htlcWeight := int64(count * HTLCWeight)
|
||||
baseWeight := int64(BaseCommitmentTxWeight)
|
||||
witnessWeight := int64(WitnessCommitmentTxWeight)
|
||||
|
||||
return htlcWeight + baseWeight + witnessWeight
|
||||
}
|
||||
|
||||
// TxWeightEstimator is able to calculate weight estimates for transactions
|
||||
// based on the input and output types. For purposes of estimation, all
|
||||
// signatures are assumed to be of the maximum possible size, 73 bytes. Each
|
||||
// method of the estimator returns an instance with the estimate applied. This
|
||||
// allows callers to chain each of the methods
|
||||
type TxWeightEstimator struct {
|
||||
hasWitness bool
|
||||
inputCount uint32
|
||||
outputCount uint32
|
||||
inputSize int
|
||||
inputWitnessSize int
|
||||
outputSize int
|
||||
}
|
||||
|
||||
// AddP2PKHInput updates the weight estimate to account for an additional input
|
||||
// spending a P2PKH output.
|
||||
func (twe *TxWeightEstimator) AddP2PKHInput() *TxWeightEstimator {
|
||||
twe.inputSize += InputSize + P2PKHScriptSigSize
|
||||
twe.inputWitnessSize++
|
||||
twe.inputCount++
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddP2WKHInput updates the weight estimate to account for an additional input
|
||||
// spending a native P2PWKH output.
|
||||
func (twe *TxWeightEstimator) AddP2WKHInput() *TxWeightEstimator {
|
||||
twe.AddWitnessInput(P2WKHWitnessSize)
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddWitnessInput updates the weight estimate to account for an additional
|
||||
// input spending a native pay-to-witness output. This accepts the total size
|
||||
// of the witness as a parameter.
|
||||
func (twe *TxWeightEstimator) AddWitnessInput(witnessSize int) *TxWeightEstimator {
|
||||
twe.inputSize += InputSize
|
||||
twe.inputWitnessSize += witnessSize
|
||||
twe.inputCount++
|
||||
twe.hasWitness = true
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddNestedP2WKHInput updates the weight estimate to account for an additional
|
||||
// input spending a P2SH output with a nested P2WKH redeem script.
|
||||
func (twe *TxWeightEstimator) AddNestedP2WKHInput() *TxWeightEstimator {
|
||||
twe.inputSize += InputSize + P2WPKHSize
|
||||
twe.inputWitnessSize += P2WKHWitnessSize
|
||||
twe.inputSize++
|
||||
twe.hasWitness = true
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddNestedP2WSHInput updates the weight estimate to account for an additional
|
||||
// input spending a P2SH output with a nested P2WSH redeem script.
|
||||
func (twe *TxWeightEstimator) AddNestedP2WSHInput(witnessSize int) *TxWeightEstimator {
|
||||
twe.inputSize += InputSize + P2WSHSize
|
||||
twe.inputWitnessSize += witnessSize
|
||||
twe.inputSize++
|
||||
twe.hasWitness = true
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddP2PKHOutput updates the weight estimate to account for an additional P2PKH
|
||||
// output.
|
||||
func (twe *TxWeightEstimator) AddP2PKHOutput() *TxWeightEstimator {
|
||||
twe.outputSize += P2PKHOutputSize
|
||||
twe.outputCount++
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddP2WKHOutput updates the weight estimate to account for an additional
|
||||
// native P2WKH output.
|
||||
func (twe *TxWeightEstimator) AddP2WKHOutput() *TxWeightEstimator {
|
||||
twe.outputSize += P2WKHOutputSize
|
||||
twe.outputCount++
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddP2WSHOutput updates the weight estimate to account for an additional
|
||||
// native P2WSH output.
|
||||
func (twe *TxWeightEstimator) AddP2WSHOutput() *TxWeightEstimator {
|
||||
twe.outputSize += P2WSHOutputSize
|
||||
twe.outputCount++
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// AddP2SHOutput updates the weight estimate to account for an additional P2SH
|
||||
// output.
|
||||
func (twe *TxWeightEstimator) AddP2SHOutput() *TxWeightEstimator {
|
||||
twe.outputSize += P2SHOutputSize
|
||||
twe.outputCount++
|
||||
|
||||
return twe
|
||||
}
|
||||
|
||||
// Weight gets the estimated weight of the transaction.
|
||||
func (twe *TxWeightEstimator) Weight() int {
|
||||
txSizeStripped := BaseTxSize +
|
||||
wire.VarIntSerializeSize(uint64(twe.inputCount)) + twe.inputSize +
|
||||
wire.VarIntSerializeSize(uint64(twe.outputCount)) + twe.outputSize
|
||||
weight := txSizeStripped * witnessScaleFactor
|
||||
if twe.hasWitness {
|
||||
weight += WitnessHeaderSize + twe.inputWitnessSize
|
||||
}
|
||||
return weight
|
||||
}
|
||||
|
||||
// VSize gets the estimated virtual size of the transactions, in vbytes.
|
||||
func (twe *TxWeightEstimator) VSize() int {
|
||||
// A tx's vsize is 1/4 of the weight, rounded up.
|
||||
return (twe.Weight() + witnessScaleFactor - 1) / witnessScaleFactor
|
||||
}
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
)
|
||||
|
||||
// TestTxWeightEstimator tests that transaction weight estimates are calculated
|
||||
@@ -106,7 +107,7 @@ func TestTxWeightEstimator(t *testing.T) {
|
||||
}
|
||||
|
||||
for i, test := range testCases {
|
||||
var weightEstimate lnwallet.TxWeightEstimator
|
||||
var weightEstimate input.TxWeightEstimator
|
||||
tx := wire.NewMsgTx(1)
|
||||
|
||||
for j := 0; j < test.numP2PKHInputs; j++ {
|
||||
|
||||
+7
-121
@@ -6,19 +6,17 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/shachain"
|
||||
@@ -143,7 +141,7 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
|
||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity),
|
||||
ChanReserve: channelCapacity / 100,
|
||||
MinHTLC: 0,
|
||||
MaxAcceptedHtlcs: MaxHTLCNumber / 2,
|
||||
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
|
||||
CsvDelay: uint16(csvTimeoutAlice),
|
||||
},
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
@@ -168,7 +166,7 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
|
||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(channelCapacity),
|
||||
ChanReserve: channelCapacity / 100,
|
||||
MinHTLC: 0,
|
||||
MaxAcceptedHtlcs: MaxHTLCNumber / 2,
|
||||
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
|
||||
CsvDelay: uint16(csvTimeoutBob),
|
||||
},
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
@@ -197,7 +195,7 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
bobCommitPoint := ComputeCommitmentPoint(bobFirstRevoke[:])
|
||||
bobCommitPoint := input.ComputeCommitmentPoint(bobFirstRevoke[:])
|
||||
|
||||
aliceRoot, err := chainhash.NewHash(aliceKeys[0].Serialize())
|
||||
if err != nil {
|
||||
@@ -208,7 +206,7 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
aliceCommitPoint := ComputeCommitmentPoint(aliceFirstRevoke[:])
|
||||
aliceCommitPoint := input.ComputeCommitmentPoint(aliceFirstRevoke[:])
|
||||
|
||||
aliceCommitTx, bobCommitTx, err := CreateCommitmentTxns(channelBal,
|
||||
channelBal, &aliceCfg, &bobCfg, aliceCommitPoint, bobCommitPoint,
|
||||
@@ -300,8 +298,8 @@ func CreateTestChannels() (*LightningChannel, *LightningChannel, func(), error)
|
||||
Packager: channeldb.NewChannelPackager(shortChanID),
|
||||
}
|
||||
|
||||
aliceSigner := &mockSigner{privkeys: aliceKeys}
|
||||
bobSigner := &mockSigner{privkeys: bobKeys}
|
||||
aliceSigner := &input.MockSigner{Privkeys: aliceKeys}
|
||||
bobSigner := &input.MockSigner{Privkeys: bobKeys}
|
||||
|
||||
pCache := &mockPreimageCache{
|
||||
// hash -> preimage
|
||||
@@ -389,118 +387,6 @@ func initRevocationWindows(chanA, chanB *LightningChannel) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// mockSigner is a simple implementation of the Signer interface. Each one has
|
||||
// a set of private keys in a slice and can sign messages using the appropriate
|
||||
// one.
|
||||
type mockSigner struct {
|
||||
privkeys []*btcec.PrivateKey
|
||||
netParams *chaincfg.Params
|
||||
}
|
||||
|
||||
func (m *mockSigner) SignOutputRaw(tx *wire.MsgTx, signDesc *SignDescriptor) ([]byte, error) {
|
||||
pubkey := signDesc.KeyDesc.PubKey
|
||||
switch {
|
||||
case signDesc.SingleTweak != nil:
|
||||
pubkey = TweakPubKeyWithTweak(pubkey, signDesc.SingleTweak)
|
||||
case signDesc.DoubleTweak != nil:
|
||||
pubkey = DeriveRevocationPubkey(pubkey, signDesc.DoubleTweak.PubKey())
|
||||
}
|
||||
|
||||
hash160 := btcutil.Hash160(pubkey.SerializeCompressed())
|
||||
privKey := m.findKey(hash160, signDesc.SingleTweak, signDesc.DoubleTweak)
|
||||
if privKey == nil {
|
||||
return nil, fmt.Errorf("Mock signer does not have key")
|
||||
}
|
||||
|
||||
sig, err := txscript.RawTxInWitnessSignature(tx, signDesc.SigHashes,
|
||||
signDesc.InputIndex, signDesc.Output.Value, signDesc.WitnessScript,
|
||||
txscript.SigHashAll, privKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sig[:len(sig)-1], nil
|
||||
}
|
||||
|
||||
func (m *mockSigner) ComputeInputScript(tx *wire.MsgTx, signDesc *SignDescriptor) (*InputScript, error) {
|
||||
scriptType, addresses, _, err := txscript.ExtractPkScriptAddrs(
|
||||
signDesc.Output.PkScript, m.netParams)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch scriptType {
|
||||
case txscript.PubKeyHashTy:
|
||||
privKey := m.findKey(addresses[0].ScriptAddress(), signDesc.SingleTweak,
|
||||
signDesc.DoubleTweak)
|
||||
if privKey == nil {
|
||||
return nil, fmt.Errorf("Mock signer does not have key for "+
|
||||
"address %v", addresses[0])
|
||||
}
|
||||
|
||||
sigScript, err := txscript.SignatureScript(
|
||||
tx, signDesc.InputIndex, signDesc.Output.PkScript,
|
||||
txscript.SigHashAll, privKey, true,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{SigScript: sigScript}, nil
|
||||
|
||||
case txscript.WitnessV0PubKeyHashTy:
|
||||
privKey := m.findKey(addresses[0].ScriptAddress(), signDesc.SingleTweak,
|
||||
signDesc.DoubleTweak)
|
||||
if privKey == nil {
|
||||
return nil, fmt.Errorf("Mock signer does not have key for "+
|
||||
"address %v", addresses[0])
|
||||
}
|
||||
|
||||
witnessScript, err := txscript.WitnessSignature(tx, signDesc.SigHashes,
|
||||
signDesc.InputIndex, signDesc.Output.Value,
|
||||
signDesc.Output.PkScript, txscript.SigHashAll, privKey, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{Witness: witnessScript}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Unexpected script type: %v", scriptType)
|
||||
}
|
||||
}
|
||||
|
||||
// findKey searches through all stored private keys and returns one
|
||||
// corresponding to the hashed pubkey if it can be found. The public key may
|
||||
// either correspond directly to the private key or to the private key with a
|
||||
// tweak applied.
|
||||
func (m *mockSigner) findKey(needleHash160 []byte, singleTweak []byte,
|
||||
doubleTweak *btcec.PrivateKey) *btcec.PrivateKey {
|
||||
|
||||
for _, privkey := range m.privkeys {
|
||||
// First check whether public key is directly derived from private key.
|
||||
hash160 := btcutil.Hash160(privkey.PubKey().SerializeCompressed())
|
||||
if bytes.Equal(hash160, needleHash160) {
|
||||
return privkey
|
||||
}
|
||||
|
||||
// Otherwise check if public key is derived from tweaked private key.
|
||||
switch {
|
||||
case singleTweak != nil:
|
||||
privkey = TweakPrivKey(privkey, singleTweak)
|
||||
case doubleTweak != nil:
|
||||
privkey = DeriveRevocationPrivKey(privkey, doubleTweak)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
hash160 = btcutil.Hash160(privkey.PubKey().SerializeCompressed())
|
||||
if bytes.Equal(hash160, needleHash160) {
|
||||
return privkey
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type mockPreimageCache struct {
|
||||
sync.Mutex
|
||||
preimageMap map[[32]byte][]byte
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -60,12 +61,12 @@ func createHtlcSuccessTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
|
||||
// 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
|
||||
// HTLC outputs.
|
||||
witnessScript, err := secondLevelHtlcScript(revocationKey, delayKey,
|
||||
witnessScript, err := input.SecondLevelHtlcScript(revocationKey, delayKey,
|
||||
csvDelay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkScript, err := WitnessScriptHash(witnessScript)
|
||||
pkScript, err := input.WitnessScriptHash(witnessScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -115,12 +116,12 @@ func createHtlcTimeoutTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
|
||||
// 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
|
||||
// HTLC outputs.
|
||||
witnessScript, err := secondLevelHtlcScript(revocationKey, delayKey,
|
||||
witnessScript, err := input.SecondLevelHtlcScript(revocationKey, delayKey,
|
||||
csvDelay)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pkScript, err := WitnessScriptHash(witnessScript)
|
||||
pkScript, err := input.WitnessScriptHash(witnessScript)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/shachain"
|
||||
@@ -380,7 +381,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
|
||||
ChannelConstraints: channeldb.ChannelConstraints{
|
||||
DustLimit: tc.dustLimit,
|
||||
MaxPendingAmount: lnwire.NewMSatFromSatoshis(tc.fundingAmount),
|
||||
MaxAcceptedHtlcs: MaxHTLCNumber,
|
||||
MaxAcceptedHtlcs: input.MaxHTLCNumber,
|
||||
CsvDelay: tc.localCsvDelay,
|
||||
},
|
||||
MultiSigKey: keychain.KeyDescriptor{
|
||||
@@ -410,11 +411,11 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
|
||||
Capacity: tc.fundingAmount,
|
||||
RevocationProducer: shachain.NewRevocationProducer(zeroHash),
|
||||
}
|
||||
signer := &mockSigner{
|
||||
privkeys: []*btcec.PrivateKey{
|
||||
signer := &input.MockSigner{
|
||||
Privkeys: []*btcec.PrivateKey{
|
||||
tc.localFundingPrivKey, tc.localPaymentPrivKey,
|
||||
},
|
||||
netParams: tc.netParams,
|
||||
NetParams: tc.netParams,
|
||||
}
|
||||
|
||||
// Construct a LightningChannel manually because we don't have nor need all
|
||||
@@ -433,7 +434,7 @@ func TestCommitmentAndHTLCTransactions(t *testing.T) {
|
||||
|
||||
// The commitmentPoint is technically hidden in the spec, but we need it to
|
||||
// generate the correct tweak.
|
||||
tweak := SingleTweakBytes(tc.commitmentPoint, tc.localPaymentBasePoint)
|
||||
tweak := input.SingleTweakBytes(tc.commitmentPoint, tc.localPaymentBasePoint)
|
||||
keys := &CommitmentKeyRing{
|
||||
CommitPoint: tc.commitmentPoint,
|
||||
LocalCommitKeyTweak: tweak,
|
||||
@@ -1043,16 +1044,16 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
revocationPreimage := testHdSeed.CloneBytes()
|
||||
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
|
||||
revocationPreimage)
|
||||
revokePubKey := DeriveRevocationPubkey(bobKeyPub, commitPoint)
|
||||
revokePubKey := input.DeriveRevocationPubkey(bobKeyPub, commitPoint)
|
||||
|
||||
aliceDelayKey := TweakPubKey(aliceKeyPub, commitPoint)
|
||||
bobPayKey := TweakPubKey(bobKeyPub, commitPoint)
|
||||
aliceDelayKey := input.TweakPubKey(aliceKeyPub, commitPoint)
|
||||
bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint)
|
||||
|
||||
aliceCommitTweak := SingleTweakBytes(commitPoint, aliceKeyPub)
|
||||
bobCommitTweak := SingleTweakBytes(commitPoint, bobKeyPub)
|
||||
aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub)
|
||||
bobCommitTweak := input.SingleTweakBytes(commitPoint, bobKeyPub)
|
||||
|
||||
aliceSelfOutputSigner := &mockSigner{
|
||||
privkeys: []*btcec.PrivateKey{aliceKeyPriv},
|
||||
aliceSelfOutputSigner := &input.MockSigner{
|
||||
Privkeys: []*btcec.PrivateKey{aliceKeyPriv},
|
||||
}
|
||||
|
||||
// With all the test data set up, we create the commitment transaction.
|
||||
@@ -1078,7 +1079,7 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
|
||||
// We're testing an uncooperative close, output sweep, so construct a
|
||||
// transaction which sweeps the funds to a random address.
|
||||
targetOutput, err := CommitScriptUnencumbered(aliceKeyPub)
|
||||
targetOutput, err := input.CommitScriptUnencumbered(aliceKeyPub)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create target output: %v", err)
|
||||
}
|
||||
@@ -1093,13 +1094,13 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
})
|
||||
|
||||
// First, we'll test spending with Alice's key after the timeout.
|
||||
delayScript, err := CommitScriptToSelf(csvTimeout, aliceDelayKey,
|
||||
delayScript, err := input.CommitScriptToSelf(csvTimeout, aliceDelayKey,
|
||||
revokePubKey)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate alice delay script: %v", err)
|
||||
}
|
||||
sweepTx.TxIn[0].Sequence = lockTimeToSequence(false, csvTimeout)
|
||||
signDesc := &SignDescriptor{
|
||||
sweepTx.TxIn[0].Sequence = input.LockTimeToSequence(false, csvTimeout)
|
||||
signDesc := &input.SignDescriptor{
|
||||
WitnessScript: delayScript,
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: aliceKeyPub,
|
||||
@@ -1112,7 +1113,7 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
HashType: txscript.SigHashAll,
|
||||
InputIndex: 0,
|
||||
}
|
||||
aliceWitnessSpend, err := CommitSpendTimeout(aliceSelfOutputSigner,
|
||||
aliceWitnessSpend, err := input.CommitSpendTimeout(aliceSelfOutputSigner,
|
||||
signDesc, sweepTx)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate delay commit spend witness: %v", err)
|
||||
@@ -1128,12 +1129,12 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
t.Fatalf("spend from delay output is invalid: %v", err)
|
||||
}
|
||||
|
||||
bobSigner := &mockSigner{privkeys: []*btcec.PrivateKey{bobKeyPriv}}
|
||||
bobSigner := &input.MockSigner{Privkeys: []*btcec.PrivateKey{bobKeyPriv}}
|
||||
|
||||
// Next, we'll test bob spending with the derived revocation key to
|
||||
// simulate the scenario when Alice broadcasts this commitment
|
||||
// transaction after it's been revoked.
|
||||
signDesc = &SignDescriptor{
|
||||
signDesc = &input.SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
@@ -1146,7 +1147,7 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
HashType: txscript.SigHashAll,
|
||||
InputIndex: 0,
|
||||
}
|
||||
bobWitnessSpend, err := CommitSpendRevoke(bobSigner, signDesc,
|
||||
bobWitnessSpend, err := input.CommitSpendRevoke(bobSigner, signDesc,
|
||||
sweepTx)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to generate revocation witness: %v", err)
|
||||
@@ -1174,11 +1175,11 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
|
||||
// Finally, we test bob sweeping his output as normal in the case that
|
||||
// Alice broadcasts this commitment transaction.
|
||||
bobScriptP2WKH, err := CommitScriptUnencumbered(bobPayKey)
|
||||
bobScriptP2WKH, err := input.CommitScriptUnencumbered(bobPayKey)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create bob p2wkh script: %v", err)
|
||||
}
|
||||
signDesc = &SignDescriptor{
|
||||
signDesc = &input.SignDescriptor{
|
||||
KeyDesc: keychain.KeyDescriptor{
|
||||
PubKey: bobKeyPub,
|
||||
},
|
||||
@@ -1192,7 +1193,7 @@ func TestCommitmentSpendValidation(t *testing.T) {
|
||||
HashType: txscript.SigHashAll,
|
||||
InputIndex: 0,
|
||||
}
|
||||
bobRegularSpend, err := CommitSpendNoDelay(bobSigner, signDesc,
|
||||
bobRegularSpend, err := input.CommitSpendNoDelay(bobSigner, signDesc,
|
||||
sweepTx)
|
||||
if err != nil {
|
||||
t.Fatalf("unable to create bob regular spend: %v", err)
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
// writeTxOut serializes a wire.TxOut struct into the passed io.Writer stream.
|
||||
func writeTxOut(w io.Writer, txo *wire.TxOut) error {
|
||||
var scratch [8]byte
|
||||
|
||||
binary.BigEndian.PutUint64(scratch[:], uint64(txo.Value))
|
||||
if _, err := w.Write(scratch[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := wire.WriteVarBytes(w, 0, txo.PkScript); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// readTxOut deserializes a wire.TxOut struct from the passed io.Reader stream.
|
||||
func readTxOut(r io.Reader, txo *wire.TxOut) error {
|
||||
var scratch [8]byte
|
||||
|
||||
if _, err := io.ReadFull(r, scratch[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
value := int64(binary.BigEndian.Uint64(scratch[:]))
|
||||
|
||||
pkScript, err := wire.ReadVarBytes(r, 0, 80, "pkScript")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*txo = wire.TxOut{
|
||||
Value: value,
|
||||
PkScript: pkScript,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
)
|
||||
|
||||
func TestTxOutSerialization(t *testing.T) {
|
||||
txo := wire.TxOut{
|
||||
Value: 1e7,
|
||||
PkScript: []byte{
|
||||
0x41, // OP_DATA_65
|
||||
0x04, 0xd6, 0x4b, 0xdf, 0xd0, 0x9e, 0xb1, 0xc5,
|
||||
0xfe, 0x29, 0x5a, 0xbd, 0xeb, 0x1d, 0xca, 0x42,
|
||||
0x81, 0xbe, 0x98, 0x8e, 0x2d, 0xa0, 0xb6, 0xc1,
|
||||
0xc6, 0xa5, 0x9d, 0xc2, 0x26, 0xc2, 0x86, 0x24,
|
||||
0xe1, 0x81, 0x75, 0xe8, 0x51, 0xc9, 0x6b, 0x97,
|
||||
0x3d, 0x81, 0xb0, 0x1c, 0xc3, 0x1f, 0x04, 0x78,
|
||||
0x34, 0xbc, 0x06, 0xd6, 0xd6, 0xed, 0xf6, 0x20,
|
||||
0xd1, 0x84, 0x24, 0x1a, 0x6a, 0xed, 0x8b, 0x63,
|
||||
0xa6, // 65-byte signature
|
||||
0xac, // OP_CHECKSIG
|
||||
},
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
if err := writeTxOut(&buf, &txo); err != nil {
|
||||
t.Fatalf("unable to serialize txout: %v", err)
|
||||
}
|
||||
|
||||
var deserializedTxo wire.TxOut
|
||||
if err := readTxOut(&buf, &deserializedTxo); err != nil {
|
||||
t.Fatalf("unable to deserialize txout: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(txo, deserializedTxo) {
|
||||
t.Fatalf("original and deserialized txouts are different:\n"+
|
||||
"original : %+v\n"+
|
||||
"deserialized : %+v\n",
|
||||
txo, deserializedTxo)
|
||||
}
|
||||
}
|
||||
+14
-13
@@ -19,6 +19,7 @@ import (
|
||||
"github.com/btcsuite/btcutil/txsort"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/shachain"
|
||||
@@ -167,7 +168,7 @@ type addCounterPartySigsMsg struct {
|
||||
// Should be order of sorted inputs that are theirs. Sorting is done
|
||||
// in accordance to BIP-69:
|
||||
// https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
|
||||
theirFundingInputScripts []*InputScript
|
||||
theirFundingInputScripts []*input.Script
|
||||
|
||||
// This should be 1/2 of the signatures needed to successfully spend our
|
||||
// version of the commitment transaction.
|
||||
@@ -562,7 +563,7 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
|
||||
req.resp <- nil
|
||||
return
|
||||
}
|
||||
reservation.ourContribution.FirstCommitmentPoint = ComputeCommitmentPoint(
|
||||
reservation.ourContribution.FirstCommitmentPoint = input.ComputeCommitmentPoint(
|
||||
firstPreimage[:],
|
||||
)
|
||||
|
||||
@@ -712,7 +713,7 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
||||
// Finally, add the 2-of-2 multi-sig output which will set up the lightning
|
||||
// channel.
|
||||
channelCapacity := int64(pendingReservation.partialState.Capacity)
|
||||
witnessScript, multiSigOut, err := GenFundingPkScript(
|
||||
witnessScript, multiSigOut, err := input.GenFundingPkScript(
|
||||
ourKey.PubKey.SerializeCompressed(),
|
||||
theirKey.PubKey.SerializeCompressed(), channelCapacity,
|
||||
)
|
||||
@@ -729,9 +730,9 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
||||
|
||||
// Next, sign all inputs that are ours, collecting the signatures in
|
||||
// order of the inputs.
|
||||
pendingReservation.ourFundingInputScripts = make([]*InputScript, 0,
|
||||
pendingReservation.ourFundingInputScripts = make([]*input.Script, 0,
|
||||
len(ourContribution.Inputs))
|
||||
signDesc := SignDescriptor{
|
||||
signDesc := input.SignDescriptor{
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: txscript.NewTxSigHashes(fundingTx),
|
||||
}
|
||||
@@ -767,7 +768,7 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
||||
// since the outputs are canonically sorted. If this is a single funder
|
||||
// workflow, then we'll also need to send this to the remote node.
|
||||
fundingTxID := fundingTx.TxHash()
|
||||
_, multiSigIndex := FindScriptOutputIndex(fundingTx, multiSigOut.PkScript)
|
||||
_, multiSigIndex := input.FindScriptOutputIndex(fundingTx, multiSigOut.PkScript)
|
||||
fundingOutpoint := wire.NewOutPoint(&fundingTxID, multiSigIndex)
|
||||
pendingReservation.partialState.FundingOutpoint = *fundingOutpoint
|
||||
|
||||
@@ -858,7 +859,7 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
||||
|
||||
// Generate a signature for their version of the initial commitment
|
||||
// transaction.
|
||||
signDesc = SignDescriptor{
|
||||
signDesc = input.SignDescriptor{
|
||||
WitnessScript: witnessScript,
|
||||
KeyDesc: ourKey,
|
||||
Output: multiSigOut,
|
||||
@@ -966,7 +967,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs
|
||||
//
|
||||
// TODO(roasbeef): when dual funder pass actual
|
||||
// height-hint
|
||||
pkScript, err := WitnessScriptHash(
|
||||
pkScript, err := input.WitnessScriptHash(
|
||||
txin.Witness[len(txin.Witness)-1],
|
||||
)
|
||||
if err != nil {
|
||||
@@ -1013,7 +1014,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs
|
||||
// Re-generate both the witnessScript and p2sh output. We sign the
|
||||
// witnessScript script, but include the p2sh output as the subscript
|
||||
// for verification.
|
||||
witnessScript, _, err := GenFundingPkScript(
|
||||
witnessScript, _, err := input.GenFundingPkScript(
|
||||
ourKey.PubKey.SerializeCompressed(),
|
||||
theirKey.PubKey.SerializeCompressed(),
|
||||
int64(res.partialState.Capacity),
|
||||
@@ -1165,7 +1166,7 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
hashCache := txscript.NewTxSigHashes(ourCommitTx)
|
||||
theirKey := pendingReservation.theirContribution.MultiSigKey
|
||||
ourKey := pendingReservation.ourContribution.MultiSigKey
|
||||
witnessScript, _, err := GenFundingPkScript(
|
||||
witnessScript, _, err := input.GenFundingPkScript(
|
||||
ourKey.PubKey.SerializeCompressed(),
|
||||
theirKey.PubKey.SerializeCompressed(), channelValue,
|
||||
)
|
||||
@@ -1201,13 +1202,13 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
// With their signature for our version of the commitment transactions
|
||||
// verified, we can now generate a signature for their version,
|
||||
// allowing the funding transaction to be safely broadcast.
|
||||
p2wsh, err := WitnessScriptHash(witnessScript)
|
||||
p2wsh, err := input.WitnessScriptHash(witnessScript)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.completeChan <- nil
|
||||
return
|
||||
}
|
||||
signDesc := SignDescriptor{
|
||||
signDesc := input.SignDescriptor{
|
||||
WitnessScript: witnessScript,
|
||||
KeyDesc: ourKey,
|
||||
Output: &wire.TxOut{
|
||||
@@ -1401,7 +1402,7 @@ func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var weightEstimate TxWeightEstimator
|
||||
var weightEstimate input.TxWeightEstimator
|
||||
|
||||
for _, utxo := range selectedUtxos {
|
||||
switch utxo.AddressType {
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
package lnwallet
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
// 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 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) (*InputScript, 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) (*InputScript, 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 &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case CommitmentNoDelay:
|
||||
witness, err := CommitSpendNoDelay(signer, desc, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case CommitmentRevoke:
|
||||
witness, err := CommitSpendRevoke(signer, desc, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case HtlcOfferedRevoke:
|
||||
witness, err := ReceiverHtlcSpendRevoke(signer, desc, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case HtlcAcceptedRevoke:
|
||||
witness, err := SenderHtlcSpendRevoke(signer, desc, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case HtlcOfferedTimeoutSecondLevel:
|
||||
witness, err := HtlcSecondLevelSpend(signer, desc, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case HtlcAcceptedSuccessSecondLevel:
|
||||
witness, err := HtlcSecondLevelSpend(signer, desc, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{
|
||||
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 &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case HtlcSecondLevelRevoke:
|
||||
witness, err := htlcSpendRevoke(signer, desc, tx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &InputScript{
|
||||
Witness: witness,
|
||||
}, nil
|
||||
|
||||
case WitnessKeyHash:
|
||||
fallthrough
|
||||
case NestedWitnessKeyHash:
|
||||
return signer.ComputeInputScript(tx, desc)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown witness type: %v", wt)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user