2017-09-26 07:05:24 +03:00
|
|
|
package lnwallet
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2018-01-17 05:38:49 +03:00
|
|
|
"crypto/sha256"
|
2017-09-26 07:05:24 +03:00
|
|
|
"fmt"
|
2018-01-17 05:38:49 +03:00
|
|
|
"sync"
|
2017-09-26 07:05:24 +03:00
|
|
|
|
|
|
|
"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 {
|
2018-01-17 05:38:49 +03:00
|
|
|
activeSpendNtfn chan *chainntnfs.SpendDetail
|
2017-09-26 07:05:24 +03:00
|
|
|
}
|
|
|
|
|
2018-01-17 05:38:49 +03:00
|
|
|
func (m *mockNotfier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
|
|
|
|
numConfs, heightHint uint32) (*chainntnfs.ConfirmationEvent, error) {
|
2017-09-26 07:05:24 +03:00
|
|
|
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
|
|
|
|
}
|
2018-01-17 05:38:49 +03:00
|
|
|
func (m *mockNotfier) RegisterSpendNtfn(outpoint *wire.OutPoint,
|
|
|
|
heightHint uint32) (*chainntnfs.SpendEvent, error) {
|
|
|
|
|
|
|
|
spendChan := make(chan *chainntnfs.SpendDetail)
|
|
|
|
m.activeSpendNtfn = spendChan
|
2017-09-26 07:05:24 +03:00
|
|
|
return &chainntnfs.SpendEvent{
|
2018-01-17 05:38:49 +03:00
|
|
|
Spend: spendChan,
|
2017-09-26 07:05:24 +03:00
|
|
|
Cancel: func() {},
|
|
|
|
}, nil
|
|
|
|
}
|
2018-01-17 05:38:49 +03:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|