Merge pull request #2481 from joostjager/move-input

multi: move input to separate package
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2019-01-31 16:48:31 -08:00
commit 948646b58b
66 files changed
+1288 -1154

No files matched your search

+8 -7
View File
@@ -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
View File
@@ -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
@@ -1859,7 +1860,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.
@@ -1915,7 +1916,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.
@@ -1928,7 +1929,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.
@@ -1983,17 +1984,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
}
@@ -2019,8 +2020,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.
@@ -2030,7 +2031,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,
@@ -2045,7 +2046,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,
@@ -2081,7 +2082,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 {
@@ -2092,7 +2093,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[:],
)
@@ -2104,7 +2105,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[:],
@@ -2114,13 +2115,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,
@@ -2161,13 +2162,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
@@ -2364,7 +2365,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.
@@ -2813,7 +2814,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,
@@ -2864,7 +2865,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,
@@ -3559,7 +3560,7 @@ func ChanSyncMsg(c *channeldb.OpenChannel) (*lnwire.ChannelReestablish, error) {
NextLocalCommitHeight: nextLocalCommitHeight,
RemoteCommitTailHeight: remoteChainTipHeight,
LastRemoteCommitSecret: lastCommitSecret,
LocalUnrevokedCommitPoint: ComputeCommitmentPoint(
LocalUnrevokedCommitPoint: input.ComputeCommitmentPoint(
currentCommitSecret[:],
),
}, nil
@@ -3627,7 +3628,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,
@@ -3635,10 +3636,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
}
@@ -4031,7 +4032,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)
@@ -4258,7 +4259,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")
}
@@ -4496,7 +4497,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_
@@ -4872,7 +4873,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[:])
@@ -4880,21 +4881,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 {
@@ -4903,7 +4904,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
}
@@ -4972,7 +4973,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,
)
@@ -4990,7 +4991,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
@@ -5046,7 +5047,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) {
@@ -5074,7 +5075,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)
}
@@ -5103,7 +5104,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,
@@ -5190,7 +5191,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
@@ -5230,7 +5231,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
@@ -5250,7 +5251,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) {
@@ -5266,14 +5267,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
}
@@ -5283,7 +5284,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,
@@ -5318,12 +5319,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,
@@ -5337,7 +5338,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 {
@@ -5348,18 +5349,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{
@@ -5370,7 +5371,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,
@@ -5390,7 +5391,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) {
@@ -5405,14 +5406,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
}
@@ -5423,7 +5424,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,
@@ -5452,14 +5453,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,
@@ -5473,7 +5474,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 {
@@ -5484,18 +5485,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{
@@ -5506,7 +5507,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,
@@ -5547,7 +5548,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) {
@@ -5692,7 +5693,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) {
@@ -5707,15 +5708,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
}
@@ -5745,7 +5746,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
@@ -5754,7 +5755,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,
@@ -5916,7 +5917,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
@@ -6121,7 +6122,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)
@@ -6142,19 +6143,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
}
@@ -6223,7 +6224,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.
+8 -7
View File
@@ -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 {
@@ -5007,7 +5008,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),
)
@@ -5041,7 +5042,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[:],
)
@@ -5172,7 +5173,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
View File
@@ -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.
-24
View File
@@ -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
View File
@@ -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
+2 -1
View File
@@ -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
View File
@@ -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
File diff suppressed because it is too large. Load diff
-225
View File
@@ -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
}
-129
View File
@@ -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
View File
@@ -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,
-497
View File
@@ -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
}
+3 -2
View File
@@ -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
View File
@@ -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
+202
View File
@@ -0,0 +1,202 @@
package lnwallet
import (
"encoding/binary"
"fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/lightningnetwork/lnd/input"
)
const (
// StateHintSize is the total number of bytes used between the sequence
// number and locktime of the commitment transaction use to encode a hint
// to the state number of a particular commitment transaction.
StateHintSize = 6
// MaxStateHint is the maximum state number we're able to encode using
// StateHintSize bytes amongst the sequence number and locktime fields
// of the commitment transaction.
maxStateHint uint64 = (1 << 48) - 1
)
var (
// TimelockShift is used to make sure the commitment transaction is
// spendable by setting the locktime with it so that it is larger than
// 500,000,000, thus interpreting it as Unix epoch timestamp and not
// a block height. It is also smaller than the current timestamp which
// has bit (1 << 30) set, so there is no risk of having the commitment
// transaction be rejected. This way we can safely use the lower 24 bits
// of the locktime field for part of the obscured commitment transaction
// number.
TimelockShift = uint32(1 << 29)
)
// createHtlcSuccessTx creates a transaction that spends the output on the
// commitment transaction of the peer that receives an HTLC. This transaction
// essentially acts as an off-chain covenant as it's only permitted to spend
// the designated HTLC output, and also that spend can _only_ be used as a
// state transition to create another output which actually allows redemption
// or revocation of an HTLC.
//
// In order to spend the HTLC output, the witness for the passed transaction
// should be:
// * <0> <sender sig> <recvr sig> <preimage>
func createHtlcSuccessTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
csvDelay uint32,
revocationKey, delayKey *btcec.PublicKey) (*wire.MsgTx, error) {
// Create a version two transaction (as the success version of this
// spends an output with a CSV timeout).
successTx := wire.NewMsgTx(2)
// The input to the transaction is the outpoint that creates the
// original HTLC on the sender's commitment transaction.
successTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: htlcOutput,
})
// 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 := input.SecondLevelHtlcScript(revocationKey, delayKey,
csvDelay)
if err != nil {
return nil, err
}
pkScript, err := input.WitnessScriptHash(witnessScript)
if err != nil {
return nil, err
}
// Finally, the output is simply the amount of the HTLC (minus the
// required fees), paying to the timeout script.
successTx.AddTxOut(&wire.TxOut{
Value: int64(htlcAmt),
PkScript: pkScript,
})
return successTx, nil
}
// createHtlcTimeoutTx creates a transaction that spends the HTLC output on the
// commitment transaction of the peer that created an HTLC (the sender). This
// transaction essentially acts as an off-chain covenant as it spends a 2-of-2
// multi-sig output. This output requires a signature from both the sender and
// receiver of the HTLC. By using a distinct transaction, we're able to
// uncouple the timeout and delay clauses of the HTLC contract. This
// transaction is locked with an absolute lock-time so the sender can only
// attempt to claim the output using it after the lock time has passed.
//
// In order to spend the HTLC output, the witness for the passed transaction
// should be:
// * <0> <sender sig> <receiver sig> <0>
//
// NOTE: The passed amount for the HTLC should take into account the required
// fee rate at the time the HTLC was created. The fee should be able to
// entirely pay for this (tiny: 1-in 1-out) transaction.
func createHtlcTimeoutTx(htlcOutput wire.OutPoint, htlcAmt btcutil.Amount,
cltvExpiry, csvDelay uint32,
revocationKey, delayKey *btcec.PublicKey) (*wire.MsgTx, error) {
// Create a version two transaction (as the success version of this
// spends an output with a CSV timeout), and set the lock-time to the
// specified absolute lock-time in blocks.
timeoutTx := wire.NewMsgTx(2)
timeoutTx.LockTime = cltvExpiry
// The input to the transaction is the outpoint that creates the
// original HTLC on the sender's commitment transaction.
timeoutTx.AddTxIn(&wire.TxIn{
PreviousOutPoint: htlcOutput,
})
// 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 := input.SecondLevelHtlcScript(revocationKey, delayKey,
csvDelay)
if err != nil {
return nil, err
}
pkScript, err := input.WitnessScriptHash(witnessScript)
if err != nil {
return nil, err
}
// Finally, the output is simply the amount of the HTLC (minus the
// required fees), paying to the regular second level HTLC script.
timeoutTx.AddTxOut(&wire.TxOut{
Value: int64(htlcAmt),
PkScript: pkScript,
})
return timeoutTx, nil
}
// SetStateNumHint encodes the current state number within the passed
// commitment transaction by re-purposing the locktime and sequence fields in
// the commitment transaction to encode the obfuscated state number. The state
// number is encoded using 48 bits. The lower 24 bits of the lock time are the
// lower 24 bits of the obfuscated state number and the lower 24 bits of the
// sequence field are the higher 24 bits. Finally before encoding, the
// obfuscator is XOR'd against the state number in order to hide the exact
// state number from the PoV of outside parties.
func SetStateNumHint(commitTx *wire.MsgTx, stateNum uint64,
obfuscator [StateHintSize]byte) error {
// With the current schema we are only able to encode state num
// hints up to 2^48. Therefore if the passed height is greater than our
// state hint ceiling, then exit early.
if stateNum > maxStateHint {
return fmt.Errorf("unable to encode state, %v is greater "+
"state num that max of %v", stateNum, maxStateHint)
}
if len(commitTx.TxIn) != 1 {
return fmt.Errorf("commitment tx must have exactly 1 input, "+
"instead has %v", len(commitTx.TxIn))
}
// Convert the obfuscator into a uint64, then XOR that against the
// targeted height in order to obfuscate the state number of the
// commitment transaction in the case that either commitment
// transaction is broadcast directly on chain.
var obfs [8]byte
copy(obfs[2:], obfuscator[:])
xorInt := binary.BigEndian.Uint64(obfs[:])
stateNum = stateNum ^ xorInt
// Set the height bit of the sequence number in order to disable any
// sequence locks semantics.
commitTx.TxIn[0].Sequence = uint32(stateNum>>24) | wire.SequenceLockTimeDisabled
commitTx.LockTime = uint32(stateNum&0xFFFFFF) | TimelockShift
return nil
}
// GetStateNumHint recovers the current state number given a commitment
// transaction which has previously had the state number encoded within it via
// setStateNumHint and a shared obfuscator.
//
// See setStateNumHint for further details w.r.t exactly how the state-hints
// are encoded.
func GetStateNumHint(commitTx *wire.MsgTx, obfuscator [StateHintSize]byte) uint64 {
// Convert the obfuscator into a uint64, this will be used to
// de-obfuscate the final recovered state number.
var obfs [8]byte
copy(obfs[2:], obfuscator[:])
xorInt := binary.BigEndian.Uint64(obfs[:])
// Retrieve the state hint from the sequence number and locktime
// of the transaction.
stateNumXor := uint64(commitTx.TxIn[0].Sequence&0xFFFFFF) << 24
stateNumXor |= uint64(commitTx.LockTime & 0xFFFFFF)
// Finally, to obtain the final state number, we XOR by the obfuscator
// value to de-obfuscate the state number.
return stateNumXor ^ xorInt
}
+304 -5
View File
@@ -5,14 +5,17 @@ import (
"encoding/hex"
"fmt"
"testing"
"time"
"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/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"
@@ -378,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{
@@ -408,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
@@ -431,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,
@@ -910,3 +913,299 @@ func htlcViewFromHTLCs(htlcs []channeldb.HTLC) *htlcView {
}
return &theHTLCView
}
func TestCommitTxStateHint(t *testing.T) {
t.Parallel()
stateHintTests := []struct {
name string
from uint64
to uint64
inputs int
shouldFail bool
}{
{
name: "states 0 to 1000",
from: 0,
to: 1000,
inputs: 1,
shouldFail: false,
},
{
name: "states 'maxStateHint-1000' to 'maxStateHint'",
from: maxStateHint - 1000,
to: maxStateHint,
inputs: 1,
shouldFail: false,
},
{
name: "state 'maxStateHint+1'",
from: maxStateHint + 1,
to: maxStateHint + 10,
inputs: 1,
shouldFail: true,
},
{
name: "commit transaction with two inputs",
inputs: 2,
shouldFail: true,
},
}
var obfuscator [StateHintSize]byte
copy(obfuscator[:], testHdSeed[:StateHintSize])
timeYesterday := uint32(time.Now().Unix() - 24*60*60)
for _, test := range stateHintTests {
commitTx := wire.NewMsgTx(2)
// Add supplied number of inputs to the commitment transaction.
for i := 0; i < test.inputs; i++ {
commitTx.AddTxIn(&wire.TxIn{})
}
for i := test.from; i <= test.to; i++ {
stateNum := uint64(i)
err := SetStateNumHint(commitTx, stateNum, obfuscator)
if err != nil && !test.shouldFail {
t.Fatalf("unable to set state num %v: %v", i, err)
} else if err == nil && test.shouldFail {
t.Fatalf("Failed(%v): test should fail but did not", test.name)
}
locktime := commitTx.LockTime
sequence := commitTx.TxIn[0].Sequence
// Locktime should not be less than 500,000,000 and not larger
// than the time 24 hours ago. One day should provide a good
// enough buffer for the tests.
if locktime < 5e8 || locktime > timeYesterday {
if !test.shouldFail {
t.Fatalf("The value of locktime (%v) may cause the commitment "+
"transaction to be unspendable", locktime)
}
}
if sequence&wire.SequenceLockTimeDisabled == 0 {
if !test.shouldFail {
t.Fatalf("Sequence locktime is NOT disabled when it should be")
}
}
extractedStateNum := GetStateNumHint(commitTx, obfuscator)
if extractedStateNum != stateNum && !test.shouldFail {
t.Fatalf("state number mismatched, expected %v, got %v",
stateNum, extractedStateNum)
} else if extractedStateNum == stateNum && test.shouldFail {
t.Fatalf("Failed(%v): test should fail but did not", test.name)
}
}
t.Logf("Passed: %v", test.name)
}
}
// TestCommitmentSpendValidation test the spendability of both outputs within
// the commitment transaction.
//
// The following spending cases are covered by this test:
// * Alice's spend from the delayed output on her commitment transaction.
// * Bob's spend from Alice's delayed output when she broadcasts a revoked
// commitment transaction.
// * Bob's spend from his unencumbered output within Alice's commitment
// transaction.
func TestCommitmentSpendValidation(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)
const channelBalance = btcutil.Amount(1 * 10e8)
const csvTimeout = uint32(5)
// We also set up set some resources for the commitment transaction.
// Each side currently has 1 BTC within the channel, with a total
// channel capacity of 2BTC.
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
testWalletPrivKey)
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(btcec.S256(),
bobsPrivKey)
revocationPreimage := testHdSeed.CloneBytes()
commitSecret, commitPoint := btcec.PrivKeyFromBytes(btcec.S256(),
revocationPreimage)
revokePubKey := input.DeriveRevocationPubkey(bobKeyPub, commitPoint)
aliceDelayKey := input.TweakPubKey(aliceKeyPub, commitPoint)
bobPayKey := input.TweakPubKey(bobKeyPub, commitPoint)
aliceCommitTweak := input.SingleTweakBytes(commitPoint, aliceKeyPub)
bobCommitTweak := input.SingleTweakBytes(commitPoint, bobKeyPub)
aliceSelfOutputSigner := &input.MockSigner{
Privkeys: []*btcec.PrivateKey{aliceKeyPriv},
}
// With all the test data set up, we create the commitment transaction.
// We only focus on a single party's transactions, as the scripts are
// identical with the roles reversed.
//
// This is Alice's commitment transaction, so she must wait a CSV delay
// of 5 blocks before sweeping the output, while bob can spend
// immediately with either the revocation key, or his regular key.
keyRing := &CommitmentKeyRing{
DelayKey: aliceDelayKey,
RevocationKey: revokePubKey,
NoDelayKey: bobPayKey,
}
commitmentTx, err := CreateCommitTx(*fakeFundingTxIn, keyRing, csvTimeout,
channelBalance, channelBalance, DefaultDustLimit())
if err != nil {
t.Fatalf("unable to create commitment transaction: %v", nil)
}
delayOutput := commitmentTx.TxOut[0]
regularOutput := commitmentTx.TxOut[1]
// We're testing an uncooperative close, output sweep, so construct a
// transaction which sweeps the funds to a random address.
targetOutput, err := input.CommitScriptUnencumbered(aliceKeyPub)
if err != nil {
t.Fatalf("unable to create target output: %v", err)
}
sweepTx := wire.NewMsgTx(2)
sweepTx.AddTxIn(wire.NewTxIn(&wire.OutPoint{
Hash: commitmentTx.TxHash(),
Index: 0,
}, nil, nil))
sweepTx.AddTxOut(&wire.TxOut{
PkScript: targetOutput,
Value: 0.5 * 10e8,
})
// First, we'll test spending with Alice's key after the timeout.
delayScript, err := input.CommitScriptToSelf(csvTimeout, aliceDelayKey,
revokePubKey)
if err != nil {
t.Fatalf("unable to generate alice delay script: %v", err)
}
sweepTx.TxIn[0].Sequence = input.LockTimeToSequence(false, csvTimeout)
signDesc := &input.SignDescriptor{
WitnessScript: delayScript,
KeyDesc: keychain.KeyDescriptor{
PubKey: aliceKeyPub,
},
SingleTweak: aliceCommitTweak,
SigHashes: txscript.NewTxSigHashes(sweepTx),
Output: &wire.TxOut{
Value: int64(channelBalance),
},
HashType: txscript.SigHashAll,
InputIndex: 0,
}
aliceWitnessSpend, err := input.CommitSpendTimeout(aliceSelfOutputSigner,
signDesc, sweepTx)
if err != nil {
t.Fatalf("unable to generate delay commit spend witness: %v", err)
}
sweepTx.TxIn[0].Witness = aliceWitnessSpend
vm, err := txscript.NewEngine(delayOutput.PkScript,
sweepTx, 0, txscript.StandardVerifyFlags, nil,
nil, int64(channelBalance))
if err != nil {
t.Fatalf("unable to create engine: %v", err)
}
if err := vm.Execute(); err != nil {
t.Fatalf("spend from delay output is invalid: %v", err)
}
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 = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
PubKey: bobKeyPub,
},
DoubleTweak: commitSecret,
WitnessScript: delayScript,
SigHashes: txscript.NewTxSigHashes(sweepTx),
Output: &wire.TxOut{
Value: int64(channelBalance),
},
HashType: txscript.SigHashAll,
InputIndex: 0,
}
bobWitnessSpend, err := input.CommitSpendRevoke(bobSigner, signDesc,
sweepTx)
if err != nil {
t.Fatalf("unable to generate revocation witness: %v", err)
}
sweepTx.TxIn[0].Witness = bobWitnessSpend
vm, err = txscript.NewEngine(delayOutput.PkScript,
sweepTx, 0, txscript.StandardVerifyFlags, nil,
nil, int64(channelBalance))
if err != nil {
t.Fatalf("unable to create engine: %v", err)
}
if err := vm.Execute(); err != nil {
t.Fatalf("revocation spend is invalid: %v", err)
}
// In order to test the final scenario, we modify the TxIn of the sweep
// transaction to instead point to the regular output (non delay)
// within the commitment transaction.
sweepTx.TxIn[0] = &wire.TxIn{
PreviousOutPoint: wire.OutPoint{
Hash: commitmentTx.TxHash(),
Index: 1,
},
}
// Finally, we test bob sweeping his output as normal in the case that
// Alice broadcasts this commitment transaction.
bobScriptP2WKH, err := input.CommitScriptUnencumbered(bobPayKey)
if err != nil {
t.Fatalf("unable to create bob p2wkh script: %v", err)
}
signDesc = &input.SignDescriptor{
KeyDesc: keychain.KeyDescriptor{
PubKey: bobKeyPub,
},
SingleTweak: bobCommitTweak,
WitnessScript: bobScriptP2WKH,
SigHashes: txscript.NewTxSigHashes(sweepTx),
Output: &wire.TxOut{
Value: int64(channelBalance),
PkScript: bobScriptP2WKH,
},
HashType: txscript.SigHashAll,
InputIndex: 0,
}
bobRegularSpend, err := input.CommitSpendNoDelay(bobSigner, signDesc,
sweepTx)
if err != nil {
t.Fatalf("unable to create bob regular spend: %v", err)
}
sweepTx.TxIn[0].Witness = bobRegularSpend
vm, err = txscript.NewEngine(regularOutput.PkScript,
sweepTx, 0, txscript.StandardVerifyFlags, nil,
nil, int64(channelBalance))
if err != nil {
t.Fatalf("unable to create engine: %v", err)
}
if err := vm.Execute(); err != nil {
t.Fatalf("bob p2wkh spend is invalid: %v", err)
}
}
-46
View File
@@ -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
}
-46
View File
@@ -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
View File
@@ -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 {
-248
View File
@@ -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)
}
}
}