1d7a1ac0ee
In this commit, we update the channel state machine tests to use a new key for each purpose. Before this commit, the same key would be used the entire time. As a result, a few bugs slipped by that would’ve been detected if we used fresh keys for each purpose. Additionally, this reflect the real world case as we always use distinct keys for each purpose to avoid key re-use.
182 lines
4.8 KiB
Go
182 lines
4.8 KiB
Go
package lnwallet
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/lightningnetwork/lnd/chainntnfs"
|
|
"github.com/roasbeef/btcd/btcec"
|
|
"github.com/roasbeef/btcd/chaincfg"
|
|
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
|
"github.com/roasbeef/btcd/txscript"
|
|
"github.com/roasbeef/btcd/wire"
|
|
"github.com/roasbeef/btcutil"
|
|
)
|
|
|
|
// 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.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])
|
|
}
|
|
|
|
scriptSig, err := txscript.SignatureScript(tx, signDesc.InputIndex,
|
|
signDesc.Output.PkScript, txscript.SigHashAll, privKey, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &InputScript{ScriptSig: scriptSig}, 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 mockNotfier struct {
|
|
activeSpendNtfn chan *chainntnfs.SpendDetail
|
|
}
|
|
|
|
func (m *mockNotfier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
|
|
numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
|
|
return nil, nil
|
|
}
|
|
func (m *mockNotfier) RegisterBlockEpochNtfn() (*chainntnfs.BlockEpochEvent, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (m *mockNotfier) Start() error {
|
|
return nil
|
|
}
|
|
|
|
func (m *mockNotfier) Stop() error {
|
|
return nil
|
|
}
|
|
func (m *mockNotfier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
|
heightHint uint32) (*chainntnfs.SpendEvent, error) {
|
|
|
|
spendChan := make(chan *chainntnfs.SpendDetail)
|
|
m.activeSpendNtfn = spendChan
|
|
return &chainntnfs.SpendEvent{
|
|
Spend: spendChan,
|
|
Cancel: func() {},
|
|
}, nil
|
|
}
|
|
|
|
type mockPreimageCache struct {
|
|
sync.Mutex
|
|
preimageMap map[[32]byte][]byte
|
|
}
|
|
|
|
func (m *mockPreimageCache) LookupPreimage(hash []byte) ([]byte, bool) {
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
var h [32]byte
|
|
copy(h[:], hash)
|
|
|
|
p, ok := m.preimageMap[h]
|
|
return p, ok
|
|
}
|
|
|
|
func (m *mockPreimageCache) AddPreimage(preimage []byte) error {
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
|
|
m.preimageMap[sha256.Sum256(preimage[:])] = preimage
|
|
|
|
return nil
|
|
}
|