lnwallet: update funding flow to utilize keychain.KeyRing
In this commit, we modify the funding flow process to obtain all keys necessary from the keychain.KeyRing interface. This ensure that all keys we generate are fully deterministic.
This commit is contained in:
parent
fe12c908f8
commit
a41f00e2d6
@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/roasbeef/btcd/blockchain"
|
||||
"github.com/roasbeef/btcd/chaincfg/chainhash"
|
||||
@ -27,24 +28,6 @@ const (
|
||||
// The size of the buffered queue of requests to the wallet from the
|
||||
// outside word.
|
||||
msgBufferSize = 100
|
||||
|
||||
// revocationRootIndex is the top level HD key index from which secrets
|
||||
// used to generate producer roots should be derived from.
|
||||
revocationRootIndex = hdkeychain.HardenedKeyStart + 1
|
||||
|
||||
// identityKeyIndex is the top level HD key index which is used to
|
||||
// generate/rotate identity keys.
|
||||
//
|
||||
// TODO(roasbeef): should instead be child to make room for future
|
||||
// rotations, etc.
|
||||
identityKeyIndex = hdkeychain.HardenedKeyStart + 2
|
||||
)
|
||||
|
||||
var (
|
||||
// Namespace bucket keys.
|
||||
lightningNamespaceKey = []byte("ln-wallet")
|
||||
waddrmgrNamespaceKey = []byte("waddrmgr")
|
||||
wtxmgrNamespaceKey = []byte("wtxmgr")
|
||||
)
|
||||
|
||||
// ErrInsufficientFunds is a type matching the error interface which is
|
||||
@ -248,6 +231,11 @@ type LightningWallet struct {
|
||||
// specific interaction is proxied to the internal wallet.
|
||||
WalletController
|
||||
|
||||
// SecretKeyRing is the interface we'll use to derive any keys related
|
||||
// to our purpose within the network including: multi-sig keys, node
|
||||
// keys, revocation keys, etc.
|
||||
keychain.SecretKeyRing
|
||||
|
||||
// This mutex is to be held when generating external keys to be used as
|
||||
// multi-sig, and commitment keys within the channel.
|
||||
keyGenMtx sync.RWMutex
|
||||
@ -297,6 +285,7 @@ func NewLightningWallet(Cfg Config) (*LightningWallet, error) {
|
||||
|
||||
return &LightningWallet{
|
||||
Cfg: Cfg,
|
||||
SecretKeyRing: Cfg.SecretKeyRing,
|
||||
WalletController: Cfg.WalletController,
|
||||
msgChan: make(chan interface{}, msgBufferSize),
|
||||
nextFundingID: 0,
|
||||
@ -319,20 +308,6 @@ func (l *LightningWallet) Startup() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Fetch the root derivation key from the wallet's HD chain. We'll use
|
||||
// this to generate specific Lightning related secrets on the fly.
|
||||
rootKey, err := l.FetchRootKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(roasbeef): always re-derive on the fly?
|
||||
rootKeyRaw := rootKey.Serialize()
|
||||
l.rootKey, err = hdkeychain.NewMaster(rootKeyRaw, &l.Cfg.NetParams)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.wg.Add(1)
|
||||
// TODO(roasbeef): multiple request handlers?
|
||||
go l.requestHandler()
|
||||
@ -390,17 +365,6 @@ func (l *LightningWallet) ActiveReservations() []*ChannelReservation {
|
||||
return reservations
|
||||
}
|
||||
|
||||
// GetIdentitykey returns the identity private key of the wallet.
|
||||
// TODO(roasbeef): should be moved elsewhere
|
||||
func (l *LightningWallet) GetIdentitykey() (*btcec.PrivateKey, error) {
|
||||
identityKey, err := l.rootKey.Child(identityKeyIndex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return identityKey.ECPrivKey()
|
||||
}
|
||||
|
||||
// requestHandler is the primary goroutine(s) responsible for handling, and
|
||||
// dispatching relies to all messages.
|
||||
func (l *LightningWallet) requestHandler() {
|
||||
@ -534,35 +498,42 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
|
||||
// key, the base revocation key, the base htlc key,the base payment
|
||||
// key, and the delayed payment key.
|
||||
//
|
||||
// TODO(roasbeef): special derivaiton?
|
||||
reservation.ourContribution.MultiSigKey, err = l.NewRawKey()
|
||||
// TODO(roasbeef): "salt" each key as well?
|
||||
reservation.ourContribution.MultiSigKey, err = l.DeriveNextKey(
|
||||
keychain.KeyFamilyMultiSig,
|
||||
)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.resp <- nil
|
||||
return
|
||||
}
|
||||
reservation.ourContribution.RevocationBasePoint, err = l.NewRawKey()
|
||||
reservation.ourContribution.RevocationBasePoint, err = l.DeriveNextKey(
|
||||
keychain.KeyFamilyRevocationBase,
|
||||
)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.resp <- nil
|
||||
return
|
||||
}
|
||||
reservation.ourContribution.HtlcBasePoint, err = l.NewRawKey()
|
||||
reservation.ourContribution.HtlcBasePoint, err = l.DeriveNextKey(
|
||||
keychain.KeyFamilyHtlcBase,
|
||||
)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.resp <- nil
|
||||
return
|
||||
}
|
||||
// TODO(roasbeef); allow for querying to extract key distinct from HD
|
||||
// chain
|
||||
// * allows for offline commitment keys
|
||||
reservation.ourContribution.PaymentBasePoint, err = l.NewRawKey()
|
||||
reservation.ourContribution.PaymentBasePoint, err = l.DeriveNextKey(
|
||||
keychain.KeyFamilyPaymentBase,
|
||||
)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.resp <- nil
|
||||
return
|
||||
}
|
||||
reservation.ourContribution.DelayBasePoint, err = l.NewRawKey()
|
||||
reservation.ourContribution.DelayBasePoint, err = l.DeriveNextKey(
|
||||
keychain.KeyFamilyDelayBase,
|
||||
)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.resp <- nil
|
||||
@ -750,8 +721,10 @@ 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(ourKey.SerializeCompressed(),
|
||||
theirKey.SerializeCompressed(), channelCapacity)
|
||||
witnessScript, multiSigOut, err := GenFundingPkScript(
|
||||
ourKey.PubKey.SerializeCompressed(),
|
||||
theirKey.PubKey.SerializeCompressed(), channelCapacity,
|
||||
)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
return
|
||||
@ -850,22 +823,22 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
||||
var stateObfuscator [StateHintSize]byte
|
||||
if chanState.ChanType == channeldb.SingleFunder {
|
||||
stateObfuscator = DeriveStateHintObfuscator(
|
||||
ourContribution.PaymentBasePoint,
|
||||
theirContribution.PaymentBasePoint,
|
||||
ourContribution.PaymentBasePoint.PubKey,
|
||||
theirContribution.PaymentBasePoint.PubKey,
|
||||
)
|
||||
} else {
|
||||
ourSer := ourContribution.PaymentBasePoint.SerializeCompressed()
|
||||
theirSer := theirContribution.PaymentBasePoint.SerializeCompressed()
|
||||
ourSer := ourContribution.PaymentBasePoint.PubKey.SerializeCompressed()
|
||||
theirSer := theirContribution.PaymentBasePoint.PubKey.SerializeCompressed()
|
||||
switch bytes.Compare(ourSer, theirSer) {
|
||||
case -1:
|
||||
stateObfuscator = DeriveStateHintObfuscator(
|
||||
ourContribution.PaymentBasePoint,
|
||||
theirContribution.PaymentBasePoint,
|
||||
ourContribution.PaymentBasePoint.PubKey,
|
||||
theirContribution.PaymentBasePoint.PubKey,
|
||||
)
|
||||
default:
|
||||
stateObfuscator = DeriveStateHintObfuscator(
|
||||
theirContribution.PaymentBasePoint,
|
||||
ourContribution.PaymentBasePoint,
|
||||
theirContribution.PaymentBasePoint.PubKey,
|
||||
ourContribution.PaymentBasePoint.PubKey,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -895,7 +868,7 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
|
||||
// transaction.
|
||||
signDesc = SignDescriptor{
|
||||
WitnessScript: witnessScript,
|
||||
PubKey: ourKey,
|
||||
KeyDesc: ourKey,
|
||||
Output: multiSigOut,
|
||||
HashType: txscript.SigHashAll,
|
||||
SigHashes: txscript.NewTxSigHashes(theirCommitTx),
|
||||
@ -1038,8 +1011,11 @@ 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(ourKey.SerializeCompressed(),
|
||||
theirKey.SerializeCompressed(), int64(res.partialState.Capacity))
|
||||
witnessScript, _, err := GenFundingPkScript(
|
||||
ourKey.PubKey.SerializeCompressed(),
|
||||
theirKey.PubKey.SerializeCompressed(),
|
||||
int64(res.partialState.Capacity),
|
||||
)
|
||||
if err != nil {
|
||||
msg.err <- err
|
||||
msg.completeChan <- nil
|
||||
@ -1066,7 +1042,7 @@ func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigs
|
||||
msg.err <- err
|
||||
msg.completeChan <- nil
|
||||
return
|
||||
} else if !sig.Verify(sigHash, theirKey) {
|
||||
} else if !sig.Verify(sigHash, theirKey.PubKey) {
|
||||
msg.err <- fmt.Errorf("counterparty's commitment signature is invalid")
|
||||
msg.completeChan <- nil
|
||||
return
|
||||
@ -1168,8 +1144,9 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
// generator state obfuscator to encode the current state number within
|
||||
// both commitment transactions.
|
||||
stateObfuscator := DeriveStateHintObfuscator(
|
||||
pendingReservation.theirContribution.PaymentBasePoint,
|
||||
pendingReservation.ourContribution.PaymentBasePoint)
|
||||
pendingReservation.theirContribution.PaymentBasePoint.PubKey,
|
||||
pendingReservation.ourContribution.PaymentBasePoint.PubKey,
|
||||
)
|
||||
err = initStateHints(ourCommitTx, theirCommitTx, stateObfuscator)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
@ -1194,8 +1171,10 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
hashCache := txscript.NewTxSigHashes(ourCommitTx)
|
||||
theirKey := pendingReservation.theirContribution.MultiSigKey
|
||||
ourKey := pendingReservation.ourContribution.MultiSigKey
|
||||
witnessScript, _, err := GenFundingPkScript(ourKey.SerializeCompressed(),
|
||||
theirKey.SerializeCompressed(), channelValue)
|
||||
witnessScript, _, err := GenFundingPkScript(
|
||||
ourKey.PubKey.SerializeCompressed(),
|
||||
theirKey.PubKey.SerializeCompressed(), channelValue,
|
||||
)
|
||||
if err != nil {
|
||||
req.err <- err
|
||||
req.completeChan <- nil
|
||||
@ -1217,8 +1196,9 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
req.err <- err
|
||||
req.completeChan <- nil
|
||||
return
|
||||
} else if !sig.Verify(sigHash, theirKey) {
|
||||
req.err <- fmt.Errorf("counterparty's commitment signature is invalid")
|
||||
} else if !sig.Verify(sigHash, theirKey.PubKey) {
|
||||
req.err <- fmt.Errorf("counterparty's commitment signature " +
|
||||
"is invalid")
|
||||
req.completeChan <- nil
|
||||
return
|
||||
}
|
||||
@ -1235,7 +1215,7 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
|
||||
}
|
||||
signDesc := SignDescriptor{
|
||||
WitnessScript: witnessScript,
|
||||
PubKey: ourKey,
|
||||
KeyDesc: ourKey,
|
||||
Output: &wire.TxOut{
|
||||
PkScript: p2wsh,
|
||||
Value: channelValue,
|
||||
|
Loading…
Reference in New Issue
Block a user