30c4196f91
In this PR, we entirely remove the closeObserver from the channel state machine. It was added very early on before most of the other aspects of the daemon were built out. This goroutine was responsible for dispatching notifications to outside parties if the commitment transaction was spent at all. This had several issues, since it was linked to the *lifetime* of the channel state machine itself. As a result of this linkage, we had to do weird stuff like hand off in memory pointers to the state machine in order to ensure notifications were properly dispatched.
150 lines
4.0 KiB
Go
150 lines
4.0 KiB
Go
package lnwallet
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha256"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/roasbeef/btcd/btcec"
|
|
"github.com/roasbeef/btcd/chaincfg"
|
|
"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 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
|
|
}
|