Merge pull request #5708 from guggero/remote-signer-extract-wallet

refactor: move towards more configurable implementation details
This commit is contained in:
Oliver Gugger 2021-10-08 14:23:03 +02:00 committed by GitHub
commit 00af978bf2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
44 changed files with 4102 additions and 3681 deletions

View file

@ -50,7 +50,7 @@ jobs:
name: Bitcoind Integration ARM name: Bitcoind Integration ARM
script: script:
- bash ./scripts/install_bitcoind.sh - bash ./scripts/install_bitcoind.sh
- GOARM=7 GOARCH=arm GOOS=linux make itest-parallel backend=bitcoind tranches=2 parallel=2 - GOARM=7 GOARCH=arm GOOS=linux make itest-parallel backend=bitcoind tranches=3 parallel=3
arch: arm64 arch: arm64
services: services:
- docker - docker

View file

@ -17,7 +17,6 @@ import (
"github.com/btcsuite/btcd/rpcclient" "github.com/btcsuite/btcd/rpcclient"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/btcsuite/btcwallet/chain" "github.com/btcsuite/btcwallet/chain"
"github.com/btcsuite/btcwallet/wallet"
"github.com/lightninglabs/neutrino" "github.com/lightninglabs/neutrino"
"github.com/lightningnetwork/lnd/blockcache" "github.com/lightningnetwork/lnd/blockcache"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
@ -35,6 +34,7 @@ import (
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/routing/chainview" "github.com/lightningnetwork/lnd/routing/chainview"
"github.com/lightningnetwork/lnd/walletunlocker"
) )
// Config houses necessary fields that a chainControl instance needs to // Config houses necessary fields that a chainControl instance needs to
@ -77,26 +77,12 @@ type Config struct {
// state. // state.
ChanStateDB *channeldb.ChannelStateDB ChanStateDB *channeldb.ChannelStateDB
// BlockCacheSize is the size (in bytes) of blocks kept in memory. // BlockCache is the main cache for storing block information.
BlockCacheSize uint64 BlockCache *blockcache.BlockCache
// PrivateWalletPw is the private wallet password to the underlying // WalletUnlockParams are the parameters that were used for unlocking
// btcwallet instance. // the main wallet.
PrivateWalletPw []byte WalletUnlockParams *walletunlocker.WalletUnlockParams
// PublicWalletPw is the public wallet password to the underlying btcwallet
// instance.
PublicWalletPw []byte
// Birthday specifies the time the wallet was initially created.
Birthday time.Time
// RecoveryWindow specifies the address look-ahead for which to scan when
// restoring a wallet.
RecoveryWindow uint32
// Wallet is a pointer to the backing wallet instance.
Wallet *wallet.Wallet
// NeutrinoCS is a pointer to a neutrino ChainService. Must be non-nil if // NeutrinoCS is a pointer to a neutrino ChainService. Must be non-nil if
// using neutrino. // using neutrino.
@ -113,13 +99,6 @@ type Config struct {
// TCP connections to Bitcoin peers in the event of a pruned block being // TCP connections to Bitcoin peers in the event of a pruned block being
// requested. // requested.
Dialer chain.Dialer Dialer chain.Dialer
// LoaderOptions holds functional wallet db loader options.
LoaderOptions []btcwallet.LoaderOption
// CoinSelectionStrategy is the strategy that is used for selecting
// coins when funding a transaction.
CoinSelectionStrategy wallet.CoinSelectionStrategy
} }
const ( const (
@ -181,53 +160,80 @@ var DefaultLtcChannelConstraints = channeldb.ChannelConstraints{
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2, MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
} }
// ChainControl couples the three primary interfaces lnd utilizes for a // PartialChainControl contains all the primary interfaces of the chain control
// particular chain together. A single ChainControl instance will exist for all // that can be purely constructed from the global configuration. No wallet
// the chains lnd is currently active on. // instance is required for constructing this partial state.
type ChainControl struct { type PartialChainControl struct {
// ChainIO represents an abstraction over a source that can query the blockchain. // Cfg is the configuration that was used to create the partial chain
ChainIO lnwallet.BlockChainIO // control.
Cfg *Config
// HealthCheck is a function which can be used to send a low-cost, fast // HealthCheck is a function which can be used to send a low-cost, fast
// query to the chain backend to ensure we still have access to our // query to the chain backend to ensure we still have access to our
// node. // node.
HealthCheck func() error HealthCheck func() error
// FeeEstimator is used to estimate an optimal fee for transactions important to us. // FeeEstimator is used to estimate an optimal fee for transactions
// important to us.
FeeEstimator chainfee.Estimator FeeEstimator chainfee.Estimator
// ChainNotifier is used to receive blockchain events that we are
// interested in.
ChainNotifier chainntnfs.ChainNotifier
// ChainView is used in the router for maintaining an up-to-date graph.
ChainView chainview.FilteredChainView
// ChainSource is the primary chain interface. This is used to operate
// the wallet and do things such as rescanning, sending transactions,
// notifications for received funds, etc.
ChainSource chain.Interface
// RoutingPolicy is the routing policy we have decided to use.
RoutingPolicy htlcswitch.ForwardingPolicy
// MinHtlcIn is the minimum HTLC we will accept.
MinHtlcIn lnwire.MilliSatoshi
// ChannelConstraints is the set of default constraints that will be
// used for any incoming or outgoing channel reservation requests.
ChannelConstraints channeldb.ChannelConstraints
}
// ChainControl couples the three primary interfaces lnd utilizes for a
// particular chain together. A single ChainControl instance will exist for all
// the chains lnd is currently active on.
type ChainControl struct {
// PartialChainControl is the part of the chain control that was
// initialized purely from the configuration and doesn't contain any
// wallet related elements.
*PartialChainControl
// ChainIO represents an abstraction over a source that can query the
// blockchain.
ChainIO lnwallet.BlockChainIO
// Signer is used to provide signatures over things like transactions. // Signer is used to provide signatures over things like transactions.
Signer input.Signer Signer input.Signer
// KeyRing represents a set of keys that we have the private keys to. // KeyRing represents a set of keys that we have the private keys to.
KeyRing keychain.SecretKeyRing KeyRing keychain.SecretKeyRing
// Wc is an abstraction over some basic wallet commands. This base set of commands // Wc is an abstraction over some basic wallet commands. This base set
// will be provided to the Wallet *LightningWallet raw pointer below. // of commands will be provided to the Wallet *LightningWallet raw
// pointer below.
Wc lnwallet.WalletController Wc lnwallet.WalletController
// MsgSigner is used to sign arbitrary messages. // MsgSigner is used to sign arbitrary messages.
MsgSigner lnwallet.MessageSigner MsgSigner lnwallet.MessageSigner
// ChainNotifier is used to receive blockchain events that we are interested in. // Wallet is our LightningWallet that also contains the abstract Wc
ChainNotifier chainntnfs.ChainNotifier // above. This wallet handles all of the lightning operations.
// ChainView is used in the router for maintaining an up-to-date graph.
ChainView chainview.FilteredChainView
// Wallet is our LightningWallet that also contains the abstract Wc above. This wallet
// handles all of the lightning operations.
Wallet *lnwallet.LightningWallet Wallet *lnwallet.LightningWallet
// RoutingPolicy is the routing policy we have decided to use.
RoutingPolicy htlcswitch.ForwardingPolicy
// MinHtlcIn is the minimum HTLC we will accept.
MinHtlcIn lnwire.MilliSatoshi
} }
// GenDefaultBtcChannelConstraints generates the default set of channel // GenDefaultBtcConstraints generates the default set of channel constraints
// constraints that are to be used when funding a Bitcoin channel. // that are to be used when funding a Bitcoin channel.
func GenDefaultBtcConstraints() channeldb.ChannelConstraints { func GenDefaultBtcConstraints() channeldb.ChannelConstraints {
// We use the dust limit for the maximally sized witness program with // We use the dust limit for the maximally sized witness program with
// a 40-byte data push. // a 40-byte data push.
@ -239,25 +245,21 @@ func GenDefaultBtcConstraints() channeldb.ChannelConstraints {
} }
} }
// NewChainControl attempts to create a ChainControl instance according // NewPartialChainControl creates a new partial chain control that contains all
// to the parameters in the passed configuration. Currently three // the parts that can be purely constructed from the passed in global
// branches of ChainControl instances exist: one backed by a running btcd // configuration and doesn't need any wallet instance yet.
// full-node, another backed by a running bitcoind full-node, and the other func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
// backed by a running neutrino light client instance. When running with a
// neutrino light client instance, `neutrinoCS` must be non-nil.
func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
*ChainControl, func(), error) {
// Set the RPC config from the "home" chain. Multi-chain isn't yet // Set the RPC config from the "home" chain. Multi-chain isn't yet
// active, so we'll restrict usage to a particular chain for now. // active, so we'll restrict usage to a particular chain for now.
homeChainConfig := cfg.Bitcoin homeChainConfig := cfg.Bitcoin
if cfg.PrimaryChain() == LitecoinChain { if cfg.PrimaryChain() == LitecoinChain {
homeChainConfig = cfg.Litecoin homeChainConfig = cfg.Litecoin
} }
log.Infof("Primary chain is set to: %v", log.Infof("Primary chain is set to: %v", cfg.PrimaryChain())
cfg.PrimaryChain())
cc := &ChainControl{} cc := &PartialChainControl{
Cfg: cfg,
}
switch cfg.PrimaryChain() { switch cfg.PrimaryChain() {
case BitcoinChain: case BitcoinChain:
@ -288,20 +290,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
"unknown", cfg.PrimaryChain()) "unknown", cfg.PrimaryChain())
} }
walletConfig := &btcwallet.Config{
PrivatePass: cfg.PrivateWalletPw,
PublicPass: cfg.PublicWalletPw,
Birthday: cfg.Birthday,
RecoveryWindow: cfg.RecoveryWindow,
NetParams: cfg.ActiveNetParams.Params,
CoinType: cfg.ActiveNetParams.CoinType,
Wallet: cfg.Wallet,
LoaderOptions: cfg.LoaderOptions,
CoinSelectionStrategy: cfg.CoinSelectionStrategy,
}
var err error var err error
heightHintCacheConfig := chainntnfs.CacheConfig{ heightHintCacheConfig := chainntnfs.CacheConfig{
QueryDisable: cfg.HeightHintCacheQueryDisable, QueryDisable: cfg.HeightHintCacheQueryDisable,
} }
@ -327,10 +316,10 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
// along with the wallet's ChainSource, which are all backed by // along with the wallet's ChainSource, which are all backed by
// the neutrino light client. // the neutrino light client.
cc.ChainNotifier = neutrinonotify.New( cc.ChainNotifier = neutrinonotify.New(
cfg.NeutrinoCS, hintCache, hintCache, blockCache, cfg.NeutrinoCS, hintCache, hintCache, cfg.BlockCache,
) )
cc.ChainView, err = chainview.NewCfFilteredChainView( cc.ChainView, err = chainview.NewCfFilteredChainView(
cfg.NeutrinoCS, blockCache, cfg.NeutrinoCS, cfg.BlockCache,
) )
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -347,13 +336,13 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
cfg.FeeURL = cfg.NeutrinoMode.FeeURL cfg.FeeURL = cfg.NeutrinoMode.FeeURL
} }
walletConfig.ChainSource = chain.NewNeutrinoClient( cc.ChainSource = chain.NewNeutrinoClient(
cfg.ActiveNetParams.Params, cfg.NeutrinoCS, cfg.ActiveNetParams.Params, cfg.NeutrinoCS,
) )
// Get our best block as a health check. // Get our best block as a health check.
cc.HealthCheck = func() error { cc.HealthCheck = func() error {
_, _, err := walletConfig.ChainSource.GetBestBlock() _, _, err := cc.ChainSource.GetBestBlock()
return err return err
} }
@ -432,12 +421,12 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
cc.ChainNotifier = bitcoindnotify.New( cc.ChainNotifier = bitcoindnotify.New(
bitcoindConn, cfg.ActiveNetParams.Params, hintCache, bitcoindConn, cfg.ActiveNetParams.Params, hintCache,
hintCache, blockCache, hintCache, cfg.BlockCache,
) )
cc.ChainView = chainview.NewBitcoindFilteredChainView( cc.ChainView = chainview.NewBitcoindFilteredChainView(
bitcoindConn, blockCache, bitcoindConn, cfg.BlockCache,
) )
walletConfig.ChainSource = bitcoindConn.NewBitcoindClient() cc.ChainSource = bitcoindConn.NewBitcoindClient()
// If we're not in regtest mode, then we'll attempt to use a // If we're not in regtest mode, then we'll attempt to use a
// proper fee estimator for testnet. // proper fee estimator for testnet.
@ -564,7 +553,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
} }
cc.ChainNotifier, err = btcdnotify.New( cc.ChainNotifier, err = btcdnotify.New(
rpcConfig, cfg.ActiveNetParams.Params, hintCache, rpcConfig, cfg.ActiveNetParams.Params, hintCache,
hintCache, blockCache, hintCache, cfg.BlockCache,
) )
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -573,7 +562,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
// Finally, we'll create an instance of the default chain view to be // Finally, we'll create an instance of the default chain view to be
// used within the routing layer. // used within the routing layer.
cc.ChainView, err = chainview.NewBtcdFilteredChainView( cc.ChainView, err = chainview.NewBtcdFilteredChainView(
*rpcConfig, blockCache, *rpcConfig, cfg.BlockCache,
) )
if err != nil { if err != nil {
log.Errorf("unable to create chain view: %v", err) log.Errorf("unable to create chain view: %v", err)
@ -588,11 +577,11 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
return nil, nil, err return nil, nil, err
} }
walletConfig.ChainSource = chainRPC cc.ChainSource = chainRPC
// Use a query for our best block as a health check. // Use a query for our best block as a health check.
cc.HealthCheck = func() error { cc.HealthCheck = func() error {
_, _, err := walletConfig.ChainSource.GetBestBlock() _, _, err := cc.ChainSource.GetBestBlock()
return err return err
} }
@ -648,12 +637,6 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
} }
ccCleanup := func() { ccCleanup := func() {
if cc.Wallet != nil {
if err := cc.Wallet.Shutdown(); err != nil {
log.Errorf("Failed to shutdown wallet: %v", err)
}
}
if cc.FeeEstimator != nil { if cc.FeeEstimator != nil {
if err := cc.FeeEstimator.Stop(); err != nil { if err := cc.FeeEstimator.Stop(); err != nil {
log.Errorf("Failed to stop feeEstimator: %v", err) log.Errorf("Failed to stop feeEstimator: %v", err)
@ -666,7 +649,37 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
return nil, nil, err return nil, nil, err
} }
wc, err := btcwallet.New(*walletConfig, blockCache) // Select the default channel constraints for the primary chain.
cc.ChannelConstraints = GenDefaultBtcConstraints()
if cfg.PrimaryChain() == LitecoinChain {
cc.ChannelConstraints = DefaultLtcChannelConstraints
}
return cc, ccCleanup, nil
}
// NewChainControl attempts to create a ChainControl instance according
// to the parameters in the passed configuration. Currently three
// branches of ChainControl instances exist: one backed by a running btcd
// full-node, another backed by a running bitcoind full-node, and the other
// backed by a running neutrino light client instance. When running with a
// neutrino light client instance, `neutrinoCS` must be non-nil.
func NewChainControl(walletConfig *btcwallet.Config,
pcc *PartialChainControl) (*ChainControl, func(), error) {
cc := &ChainControl{
PartialChainControl: pcc,
}
ccCleanup := func() {
if cc.Wallet != nil {
if err := cc.Wallet.Shutdown(); err != nil {
log.Errorf("Failed to shutdown wallet: %v", err)
}
}
}
wc, err := btcwallet.New(*walletConfig, pcc.Cfg.BlockCache)
if err != nil { if err != nil {
fmt.Printf("unable to create wallet controller: %v\n", err) fmt.Printf("unable to create wallet controller: %v\n", err)
return nil, ccCleanup, err return nil, ccCleanup, err
@ -677,29 +690,23 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
cc.ChainIO = wc cc.ChainIO = wc
cc.Wc = wc cc.Wc = wc
// Select the default channel constraints for the primary chain.
channelConstraints := GenDefaultBtcConstraints()
if cfg.PrimaryChain() == LitecoinChain {
channelConstraints = DefaultLtcChannelConstraints
}
keyRing := keychain.NewBtcWalletKeyRing( keyRing := keychain.NewBtcWalletKeyRing(
wc.InternalWallet(), cfg.ActiveNetParams.CoinType, wc.InternalWallet(), walletConfig.CoinType,
) )
cc.KeyRing = keyRing cc.KeyRing = keyRing
// Create, and start the lnwallet, which handles the core payment // Create, and start the lnwallet, which handles the core payment
// channel logic, and exposes control via proxy state machines. // channel logic, and exposes control via proxy state machines.
walletCfg := lnwallet.Config{ walletCfg := lnwallet.Config{
Database: cfg.ChanStateDB, Database: pcc.Cfg.ChanStateDB,
Notifier: cc.ChainNotifier, Notifier: cc.ChainNotifier,
WalletController: wc, WalletController: wc,
Signer: cc.Signer, Signer: cc.Signer,
FeeEstimator: cc.FeeEstimator, FeeEstimator: cc.FeeEstimator,
SecretKeyRing: keyRing, SecretKeyRing: keyRing,
ChainIO: cc.ChainIO, ChainIO: cc.ChainIO,
DefaultConstraints: channelConstraints, DefaultConstraints: cc.ChannelConstraints,
NetParams: *cfg.ActiveNetParams.Params, NetParams: *walletConfig.NetParams,
} }
lnWallet, err := lnwallet.NewLightningWallet(walletCfg) lnWallet, err := lnwallet.NewLightningWallet(walletCfg)
if err != nil { if err != nil {

View file

@ -31,11 +31,12 @@ func main() {
// Help was requested, exit normally. // Help was requested, exit normally.
os.Exit(0) os.Exit(0)
} }
implCfg := loadedConfig.ImplementationConfig(shutdownInterceptor)
// Call the "real" main in a nested manner so the defers will properly // Call the "real" main in a nested manner so the defers will properly
// be executed in the case of a graceful shutdown. // be executed in the case of a graceful shutdown.
if err = lnd.Main( if err = lnd.Main(
loadedConfig, lnd.ListenerCfg{}, shutdownInterceptor, loadedConfig, lnd.ListenerCfg{}, implCfg, shutdownInterceptor,
); err != nil { ); err != nil {
_, _ = fmt.Fprintln(os.Stderr, err) _, _ = fmt.Fprintln(os.Stderr, err)
os.Exit(1) os.Exit(1)

View file

@ -1536,6 +1536,21 @@ func (c *Config) graphDatabaseDir() string {
) )
} }
// ImplementationConfig returns the configuration of what actual implementations
// should be used when creating the main lnd instance.
func (c *Config) ImplementationConfig(
interceptor signal.Interceptor) *ImplementationCfg {
defaultImpl := NewDefaultWalletImpl(c, ltndLog, interceptor)
return &ImplementationCfg{
GrpcRegistrar: defaultImpl,
RestRegistrar: defaultImpl,
ExternalValidator: defaultImpl,
DatabaseBuilder: NewDefaultDatabaseBuilder(c, ltndLog),
ChainControlBuilder: defaultImpl,
}
}
// CleanAndExpandPath expands environment variables and leading ~ in the // CleanAndExpandPath expands environment variables and leading ~ in the
// passed path, cleans the result, and returns it. // passed path, cleans the result, and returns it.
// This function is taken from https://github.com/btcsuite/btcd // This function is taken from https://github.com/btcsuite/btcd

1100
config_builder.go Normal file

File diff suppressed because it is too large Load diff

View file

@ -15,6 +15,7 @@ import (
"github.com/lightningnetwork/lnd/batch" "github.com/lightningnetwork/lnd/batch"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
@ -316,6 +317,10 @@ type AuthenticatedGossiper struct {
// selfKey is the identity public key of the backing Lightning node. // selfKey is the identity public key of the backing Lightning node.
selfKey *btcec.PublicKey selfKey *btcec.PublicKey
// selfKeyLoc is the locator for the identity public key of the backing
// Lightning node.
selfKeyLoc keychain.KeyLocator
// channelMtx is used to restrict the database access to one // channelMtx is used to restrict the database access to one
// goroutine per channel ID. This is done to ensure that when // goroutine per channel ID. This is done to ensure that when
// the gossiper is handling an announcement, the db state stays // the gossiper is handling an announcement, the db state stays
@ -355,9 +360,10 @@ type AuthenticatedGossiper struct {
// New creates a new AuthenticatedGossiper instance, initialized with the // New creates a new AuthenticatedGossiper instance, initialized with the
// passed configuration parameters. // passed configuration parameters.
func New(cfg Config, selfKey *btcec.PublicKey) *AuthenticatedGossiper { func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper {
gossiper := &AuthenticatedGossiper{ gossiper := &AuthenticatedGossiper{
selfKey: selfKey, selfKey: selfKeyDesc.PubKey,
selfKeyLoc: selfKeyDesc.KeyLocator,
cfg: &cfg, cfg: &cfg,
networkMsgs: make(chan *networkMsg), networkMsgs: make(chan *networkMsg),
quit: make(chan struct{}), quit: make(chan struct{}),
@ -2567,7 +2573,7 @@ func (d *AuthenticatedGossiper) updateChannel(info *channeldb.ChannelEdgeInfo,
// We'll generate a new signature over a digest of the channel // We'll generate a new signature over a digest of the channel
// announcement itself and update the timestamp to ensure it propagate. // announcement itself and update the timestamp to ensure it propagate.
err := netann.SignChannelUpdate( err := netann.SignChannelUpdate(
d.cfg.AnnSigner, d.selfKey, chanUpdate, d.cfg.AnnSigner, d.selfKeyLoc, chanUpdate,
netann.ChanUpdSetTimestamp, netann.ChanUpdSetTimestamp,
) )
if err != nil { if err != nil {

View file

@ -25,6 +25,7 @@ import (
"github.com/lightningnetwork/lnd/batch" "github.com/lightningnetwork/lnd/batch"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/kvdb" "github.com/lightningnetwork/lnd/kvdb"
"github.com/lightningnetwork/lnd/lnpeer" "github.com/lightningnetwork/lnd/lnpeer"
"github.com/lightningnetwork/lnd/lntest/mock" "github.com/lightningnetwork/lnd/lntest/mock"
@ -46,11 +47,15 @@ var (
R: new(big.Int), R: new(big.Int),
S: new(big.Int), S: new(big.Int),
} }
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10) _, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10) _, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
selfKeyPriv, _ = btcec.NewPrivateKey(btcec.S256()) selfKeyPriv, _ = btcec.NewPrivateKey(btcec.S256())
selfKeyPub = selfKeyPriv.PubKey() selfKeyDesc = &keychain.KeyDescriptor{
PubKey: selfKeyPriv.PubKey(),
KeyLocator: testKeyLoc,
}
bitcoinKeyPriv1, _ = btcec.NewPrivateKey(btcec.S256()) bitcoinKeyPriv1, _ = btcec.NewPrivateKey(btcec.S256())
bitcoinKeyPub1 = bitcoinKeyPriv1.PubKey() bitcoinKeyPub1 = bitcoinKeyPriv1.PubKey()
@ -568,7 +573,7 @@ func createNodeAnnouncement(priv *btcec.PrivateKey,
} }
signer := mock.SingleSigner{Privkey: priv} signer := mock.SingleSigner{Privkey: priv}
sig, err := netann.SignAnnouncement(&signer, priv.PubKey(), a) sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -618,9 +623,8 @@ func createUpdateAnnouncement(blockHeight uint32,
} }
func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error { func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error {
pub := nodeKey.PubKey()
signer := mock.SingleSigner{Privkey: nodeKey} signer := mock.SingleSigner{Privkey: nodeKey}
sig, err := netann.SignAnnouncement(&signer, pub, a) sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a)
if err != nil { if err != nil {
return err return err
} }
@ -667,9 +671,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
a := createAnnouncementWithoutProof(blockHeight, key1.PubKey(), key2.PubKey(), extraBytes...) a := createAnnouncementWithoutProof(blockHeight, key1.PubKey(), key2.PubKey(), extraBytes...)
pub := key1.PubKey()
signer := mock.SingleSigner{Privkey: key1} signer := mock.SingleSigner{Privkey: key1}
sig, err := netann.SignAnnouncement(&signer, pub, a) sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -678,9 +681,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
return nil, err return nil, err
} }
pub = key2.PubKey()
signer = mock.SingleSigner{Privkey: key2} signer = mock.SingleSigner{Privkey: key2}
sig, err = netann.SignAnnouncement(&signer, pub, a) sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -689,9 +691,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
return nil, err return nil, err
} }
pub = bitcoinKeyPriv1.PubKey()
signer = mock.SingleSigner{Privkey: bitcoinKeyPriv1} signer = mock.SingleSigner{Privkey: bitcoinKeyPriv1}
sig, err = netann.SignAnnouncement(&signer, pub, a) sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -700,9 +701,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
return nil, err return nil, err
} }
pub = bitcoinKeyPriv2.PubKey()
signer = mock.SingleSigner{Privkey: bitcoinKeyPriv2} signer = mock.SingleSigner{Privkey: bitcoinKeyPriv2}
sig, err = netann.SignAnnouncement(&signer, pub, a) sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -785,7 +785,7 @@ func createTestCtx(startHeight uint32) (*testCtx, func(), error) {
MinimumBatchSize: 10, MinimumBatchSize: 10,
MaxChannelUpdateBurst: DefaultMaxChannelUpdateBurst, MaxChannelUpdateBurst: DefaultMaxChannelUpdateBurst,
ChannelUpdateInterval: DefaultChannelUpdateInterval, ChannelUpdateInterval: DefaultChannelUpdateInterval,
}, selfKeyPub) }, selfKeyDesc)
if err := gossiper.Start(); err != nil { if err := gossiper.Start(); err != nil {
cleanUpDb() cleanUpDb()
@ -1480,7 +1480,10 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
NumActiveSyncers: 3, NumActiveSyncers: 3,
MinimumBatchSize: 10, MinimumBatchSize: 10,
SubBatchDelay: time.Second * 5, SubBatchDelay: time.Second * 5,
}, ctx.gossiper.selfKey) }, &keychain.KeyDescriptor{
PubKey: ctx.gossiper.selfKey,
KeyLocator: ctx.gossiper.selfKeyLoc,
})
if err != nil { if err != nil {
t.Fatalf("unable to recreate gossiper: %v", err) t.Fatalf("unable to recreate gossiper: %v", err)
} }
@ -2056,7 +2059,9 @@ func TestForwardPrivateNodeAnnouncement(t *testing.T) {
// We'll start off by processing a channel announcement without a proof // We'll start off by processing a channel announcement without a proof
// (i.e., an unadvertised channel), followed by a node announcement for // (i.e., an unadvertised channel), followed by a node announcement for
// this same channel announcement. // this same channel announcement.
chanAnn := createAnnouncementWithoutProof(startingHeight-2, selfKeyPub, remoteKeyPub1) chanAnn := createAnnouncementWithoutProof(
startingHeight-2, selfKeyDesc.PubKey, remoteKeyPub1,
)
pubKey := remoteKeyPriv1.PubKey() pubKey := remoteKeyPriv1.PubKey()
select { select {
@ -3671,8 +3676,12 @@ func TestProcessChannelAnnouncementOptionalMsgFields(t *testing.T) {
} }
defer cleanup() defer cleanup()
chanAnn1 := createAnnouncementWithoutProof(100, selfKeyPub, remoteKeyPub1) chanAnn1 := createAnnouncementWithoutProof(
chanAnn2 := createAnnouncementWithoutProof(101, selfKeyPub, remoteKeyPub1) 100, selfKeyDesc.PubKey, remoteKeyPub1,
)
chanAnn2 := createAnnouncementWithoutProof(
101, selfKeyDesc.PubKey, remoteKeyPub1,
)
// assertOptionalMsgFields is a helper closure that ensures the optional // assertOptionalMsgFields is a helper closure that ensures the optional
// message fields were set as intended. // message fields were set as intended.

View file

@ -353,6 +353,10 @@ you.
* [Only upload itest logs on failure, fix more * [Only upload itest logs on failure, fix more
flakes](https://github.com/lightningnetwork/lnd/pull/5833). flakes](https://github.com/lightningnetwork/lnd/pull/5833).
* [The interfaces for signing messages and the code for initializing a wallet
was refactored as a preparation for supporting remote
signing](https://github.com/lightningnetwork/lnd/pull/5708).
## Database ## Database
* [Ensure single writer for legacy * [Ensure single writer for legacy

View file

@ -294,6 +294,10 @@ type Config struct {
// Lightning Network. // Lightning Network.
IDKey *btcec.PublicKey IDKey *btcec.PublicKey
// IDKeyLoc is the locator for the key that is used to identify this
// node within the LightningNetwork.
IDKeyLoc keychain.KeyLocator
// Wallet handles the parts of the funding process that involves moving // Wallet handles the parts of the funding process that involves moving
// funds from on-chain transaction outputs into Lightning channels. // funds from on-chain transaction outputs into Lightning channels.
Wallet *lnwallet.LightningWallet Wallet *lnwallet.LightningWallet
@ -322,8 +326,8 @@ type Config struct {
// //
// TODO(roasbeef): should instead pass on this responsibility to a // TODO(roasbeef): should instead pass on this responsibility to a
// distinct sub-system? // distinct sub-system?
SignMessage func(pubKey *btcec.PublicKey, SignMessage func(keyLoc keychain.KeyLocator,
msg []byte) (input.Signature, error) msg []byte) (*btcec.Signature, error)
// CurrentNodeAnnouncement should return the latest, fully signed node // CurrentNodeAnnouncement should return the latest, fully signed node
// announcement from the backing Lightning Network node. // announcement from the backing Lightning Network node.
@ -2523,7 +2527,7 @@ func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel,
ann, err := f.newChanAnnouncement( ann, err := f.newChanAnnouncement(
f.cfg.IDKey, completeChan.IdentityPub, f.cfg.IDKey, completeChan.IdentityPub,
completeChan.LocalChanCfg.MultiSigKey.PubKey, &completeChan.LocalChanCfg.MultiSigKey,
completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID, completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID,
chanID, fwdMinHTLC, fwdMaxHTLC, chanID, fwdMinHTLC, fwdMaxHTLC,
) )
@ -2686,7 +2690,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
// public and usable for other nodes for routing. // public and usable for other nodes for routing.
err = f.announceChannel( err = f.announceChannel(
f.cfg.IDKey, completeChan.IdentityPub, f.cfg.IDKey, completeChan.IdentityPub,
completeChan.LocalChanCfg.MultiSigKey.PubKey, &completeChan.LocalChanCfg.MultiSigKey,
completeChan.RemoteChanCfg.MultiSigKey.PubKey, completeChan.RemoteChanCfg.MultiSigKey.PubKey,
*shortChanID, chanID, *shortChanID, chanID,
) )
@ -2826,10 +2830,11 @@ type chanAnnouncement struct {
// identity pub keys of both parties to the channel, and the second segment is // identity pub keys of both parties to the channel, and the second segment is
// authenticated only by us and contains our directional routing policy for the // authenticated only by us and contains our directional routing policy for the
// channel. // channel.
func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey, func (f *Manager) newChanAnnouncement(localPubKey,
localFundingKey, remoteFundingKey *btcec.PublicKey, remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor,
shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) { chanID lnwire.ChannelID, fwdMinHTLC,
fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) {
chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash
@ -2857,7 +2862,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
if bytes.Compare(selfBytes, remoteBytes) == -1 { if bytes.Compare(selfBytes, remoteBytes) == -1 {
copy(chanAnn.NodeID1[:], localPubKey.SerializeCompressed()) copy(chanAnn.NodeID1[:], localPubKey.SerializeCompressed())
copy(chanAnn.NodeID2[:], remotePubKey.SerializeCompressed()) copy(chanAnn.NodeID2[:], remotePubKey.SerializeCompressed())
copy(chanAnn.BitcoinKey1[:], localFundingKey.SerializeCompressed()) copy(chanAnn.BitcoinKey1[:], localFundingKey.PubKey.SerializeCompressed())
copy(chanAnn.BitcoinKey2[:], remoteFundingKey.SerializeCompressed()) copy(chanAnn.BitcoinKey2[:], remoteFundingKey.SerializeCompressed())
// If we're the first node then update the chanFlags to // If we're the first node then update the chanFlags to
@ -2867,7 +2872,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
copy(chanAnn.NodeID1[:], remotePubKey.SerializeCompressed()) copy(chanAnn.NodeID1[:], remotePubKey.SerializeCompressed())
copy(chanAnn.NodeID2[:], localPubKey.SerializeCompressed()) copy(chanAnn.NodeID2[:], localPubKey.SerializeCompressed())
copy(chanAnn.BitcoinKey1[:], remoteFundingKey.SerializeCompressed()) copy(chanAnn.BitcoinKey1[:], remoteFundingKey.SerializeCompressed())
copy(chanAnn.BitcoinKey2[:], localFundingKey.SerializeCompressed()) copy(chanAnn.BitcoinKey2[:], localFundingKey.PubKey.SerializeCompressed())
// If we're the second node then update the chanFlags to // If we're the second node then update the chanFlags to
// indicate the "direction" of the update. // indicate the "direction" of the update.
@ -2906,7 +2911,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
if err != nil { if err != nil {
return nil, err return nil, err
} }
sig, err := f.cfg.SignMessage(f.cfg.IDKey, chanUpdateMsg) sig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanUpdateMsg)
if err != nil { if err != nil {
return nil, errors.Errorf("unable to generate channel "+ return nil, errors.Errorf("unable to generate channel "+
"update announcement signature: %v", err) "update announcement signature: %v", err)
@ -2928,12 +2933,14 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
if err != nil { if err != nil {
return nil, err return nil, err
} }
nodeSig, err := f.cfg.SignMessage(f.cfg.IDKey, chanAnnMsg) nodeSig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanAnnMsg)
if err != nil { if err != nil {
return nil, errors.Errorf("unable to generate node "+ return nil, errors.Errorf("unable to generate node "+
"signature for channel announcement: %v", err) "signature for channel announcement: %v", err)
} }
bitcoinSig, err := f.cfg.SignMessage(localFundingKey, chanAnnMsg) bitcoinSig, err := f.cfg.SignMessage(
localFundingKey.KeyLocator, chanAnnMsg,
)
if err != nil { if err != nil {
return nil, errors.Errorf("unable to generate bitcoin "+ return nil, errors.Errorf("unable to generate bitcoin "+
"signature for node public key: %v", err) "signature for node public key: %v", err)
@ -2969,7 +2976,8 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
// the network during its next trickle. // the network during its next trickle.
// This method is synchronous and will return when all the network requests // This method is synchronous and will return when all the network requests
// finish, either successfully or with an error. // finish, either successfully or with an error.
func (f *Manager) announceChannel(localIDKey, remoteIDKey, localFundingKey, func (f *Manager) announceChannel(localIDKey, remoteIDKey *btcec.PublicKey,
localFundingKey *keychain.KeyDescriptor,
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID, remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
chanID lnwire.ChannelID) error { chanID lnwire.ChannelID) error {

View file

@ -110,6 +110,8 @@ var (
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10) _, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10) _, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
fundingNetParams = chainreg.BitcoinTestNetParams fundingNetParams = chainreg.BitcoinTestNetParams
) )
@ -355,11 +357,12 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
fundingCfg := Config{ fundingCfg := Config{
IDKey: privKey.PubKey(), IDKey: privKey.PubKey(),
IDKeyLoc: testKeyLoc,
Wallet: lnw, Wallet: lnw,
Notifier: chainNotifier, Notifier: chainNotifier,
FeeEstimator: estimator, FeeEstimator: estimator,
SignMessage: func(pubKey *btcec.PublicKey, SignMessage: func(_ keychain.KeyLocator,
msg []byte) (input.Signature, error) { _ []byte) (*btcec.Signature, error) {
return testSig, nil return testSig, nil
}, },
@ -502,11 +505,13 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
f, err := NewFundingManager(Config{ f, err := NewFundingManager(Config{
IDKey: oldCfg.IDKey, IDKey: oldCfg.IDKey,
IDKeyLoc: oldCfg.IDKeyLoc,
Wallet: oldCfg.Wallet, Wallet: oldCfg.Wallet,
Notifier: oldCfg.Notifier, Notifier: oldCfg.Notifier,
FeeEstimator: oldCfg.FeeEstimator, FeeEstimator: oldCfg.FeeEstimator,
SignMessage: func(pubKey *btcec.PublicKey, SignMessage: func(_ keychain.KeyLocator,
msg []byte) (input.Signature, error) { _ []byte) (*btcec.Signature, error) {
return testSig, nil return testSig, nil
}, },
SendAnnouncement: func(msg lnwire.Message, SendAnnouncement: func(msg lnwire.Message,

View file

@ -9,6 +9,7 @@ import (
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/zpay32" "github.com/lightningnetwork/lnd/zpay32"
) )
@ -31,9 +32,11 @@ func Fuzz_encode(data []byte) int {
// Then, initialize the testMessageSigner so we can encode out // Then, initialize the testMessageSigner so we can encode out
// invoices with this private key. // invoices with this private key.
testMessageSigner := zpay32.MessageSigner{ testMessageSigner := zpay32.MessageSigner{
SignCompact: func(hash []byte) ([]byte, error) { SignCompact: func(msg []byte) ([]byte, error) {
sig, err := btcec.SignCompact(btcec.S256(), hash := chainhash.HashB(msg)
testPrivKey, hash, true) sig, err := btcec.SignCompact(
btcec.S256(), testPrivKey, hash, true,
)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't sign the "+ return nil, fmt.Errorf("can't sign the "+
"message: %v", err) "message: %v", err)

View file

@ -14,6 +14,7 @@ import (
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/chainntnfs" "github.com/lightningnetwork/lnd/chainntnfs"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/clock" "github.com/lightningnetwork/lnd/clock"
@ -80,8 +81,11 @@ var (
testNetParams = &chaincfg.MainNetParams testNetParams = &chaincfg.MainNetParams
testMessageSigner = zpay32.MessageSigner{ testMessageSigner = zpay32.MessageSigner{
SignCompact: func(hash []byte) ([]byte, error) { SignCompact: func(msg []byte) ([]byte, error) {
sig, err := btcec.SignCompact(btcec.S256(), testPrivKey, hash, true) hash := chainhash.HashB(msg)
sig, err := btcec.SignCompact(
btcec.S256(), testPrivKey, hash, true,
)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't sign the message: %v", err) return nil, fmt.Errorf("can't sign the message: %v", err)
} }

View file

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcwallet/waddrmgr" "github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet" "github.com/btcsuite/btcwallet/wallet"
"github.com/btcsuite/btcwallet/walletdb" "github.com/btcsuite/btcwallet/walletdb"
@ -390,31 +391,49 @@ func (b *BtcWalletKeyRing) ECDH(keyDesc KeyDescriptor,
return h, nil return h, nil
} }
// SignDigest signs the given SHA256 message digest with the private key // SignMessage signs the given message, single or double SHA256 hashing it
// described in the key descriptor. // first, with the private key described in the key locator.
// //
// NOTE: This is part of the keychain.DigestSignerRing interface. // NOTE: This is part of the keychain.MessageSignerRing interface.
func (b *BtcWalletKeyRing) SignDigest(keyDesc KeyDescriptor, func (b *BtcWalletKeyRing) SignMessage(keyLoc KeyLocator,
digest [32]byte) (*btcec.Signature, error) { msg []byte, doubleHash bool) (*btcec.Signature, error) {
privKey, err := b.DerivePrivKey(keyDesc) privKey, err := b.DerivePrivKey(KeyDescriptor{
KeyLocator: keyLoc,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return privKey.Sign(digest[:])
var digest []byte
if doubleHash {
digest = chainhash.DoubleHashB(msg)
} else {
digest = chainhash.HashB(msg)
}
return privKey.Sign(digest)
} }
// SignDigestCompact signs the given SHA256 message digest with the private key // SignMessageCompact signs the given message, single or double SHA256 hashing
// described in the key descriptor and returns the signature in the compact, // it first, with the private key described in the key locator and returns
// public key recoverable format. // the signature in the compact, public key recoverable format.
// //
// NOTE: This is part of the keychain.DigestSignerRing interface. // NOTE: This is part of the keychain.MessageSignerRing interface.
func (b *BtcWalletKeyRing) SignDigestCompact(keyDesc KeyDescriptor, func (b *BtcWalletKeyRing) SignMessageCompact(keyLoc KeyLocator,
digest [32]byte) ([]byte, error) { msg []byte, doubleHash bool) ([]byte, error) {
privKey, err := b.DerivePrivKey(keyDesc) privKey, err := b.DerivePrivKey(KeyDescriptor{
KeyLocator: keyLoc,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
return btcec.SignCompact(btcec.S256(), privKey, digest[:], true)
var digest []byte
if doubleHash {
digest = chainhash.DoubleHashB(msg)
} else {
digest = chainhash.HashB(msg)
}
return btcec.SignCompact(btcec.S256(), privKey, digest, true)
} }

View file

@ -178,7 +178,7 @@ type SecretKeyRing interface {
ECDHRing ECDHRing
DigestSignerRing MessageSignerRing
// DerivePrivKey attempts to derive the private key that corresponds to // DerivePrivKey attempts to derive the private key that corresponds to
// the passed key descriptor. If the public key is set, then this // the passed key descriptor. If the public key is set, then this
@ -188,35 +188,41 @@ type SecretKeyRing interface {
DerivePrivKey(keyDesc KeyDescriptor) (*btcec.PrivateKey, error) DerivePrivKey(keyDesc KeyDescriptor) (*btcec.PrivateKey, error)
} }
// DigestSignerRing is an interface that abstracts away basic low-level ECDSA // MessageSignerRing is an interface that abstracts away basic low-level ECDSA
// signing on keys within a key ring. // signing on keys within a key ring.
type DigestSignerRing interface { type MessageSignerRing interface {
// SignDigest signs the given SHA256 message digest with the private key // SignMessage signs the given message, single or double SHA256 hashing
// described in the key descriptor. // it first, with the private key described in the key locator.
SignDigest(keyDesc KeyDescriptor, digest [32]byte) (*btcec.Signature, SignMessage(keyLoc KeyLocator, msg []byte,
error) doubleHash bool) (*btcec.Signature, error)
// SignDigestCompact signs the given SHA256 message digest with the // SignMessageCompact signs the given message, single or double SHA256
// private key described in the key descriptor and returns the signature // hashing it first, with the private key described in the key locator
// in the compact, public key recoverable format. // and returns the signature in the compact, public key recoverable
SignDigestCompact(keyDesc KeyDescriptor, digest [32]byte) ([]byte, error) // format.
SignMessageCompact(keyLoc KeyLocator, msg []byte,
doubleHash bool) ([]byte, error)
} }
// SingleKeyDigestSigner is an abstraction interface that hides the // SingleKeyMessageSigner is an abstraction interface that hides the
// implementation of the low-level ECDSA signing operations by wrapping a // implementation of the low-level ECDSA signing operations by wrapping a
// single, specific private key. // single, specific private key.
type SingleKeyDigestSigner interface { type SingleKeyMessageSigner interface {
// PubKey returns the public key of the wrapped private key. // PubKey returns the public key of the wrapped private key.
PubKey() *btcec.PublicKey PubKey() *btcec.PublicKey
// SignDigest signs the given SHA256 message digest with the wrapped // KeyLocator returns the locator that describes the wrapped private
// private key. // key.
SignDigest(digest [32]byte) (*btcec.Signature, error) KeyLocator() KeyLocator
// SignDigestCompact signs the given SHA256 message digest with the // SignMessage signs the given message, single or double SHA256 hashing
// wrapped private key and returns the signature in the compact, public // it first, with the wrapped private key.
// key recoverable format. SignMessage(message []byte, doubleHash bool) (*btcec.Signature, error)
SignDigestCompact(digest [32]byte) ([]byte, error)
// SignMessageCompact signs the given message, single or double SHA256
// hashing it first, with the wrapped private key and returns the
// signature in the compact, public key recoverable format.
SignMessageCompact(message []byte, doubleHash bool) ([]byte, error)
} }
// ECDHRing is an interface that abstracts away basic low-level ECDH shared key // ECDHRing is an interface that abstracts away basic low-level ECDH shared key

View file

@ -1,56 +1,91 @@
package keychain package keychain
import "github.com/btcsuite/btcd/btcec" import (
"github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
func NewPubKeyDigestSigner(keyDesc KeyDescriptor, func NewPubKeyMessageSigner(pubKey *btcec.PublicKey, keyLoc KeyLocator,
signer DigestSignerRing) *PubKeyDigestSigner { signer MessageSignerRing) *PubKeyMessageSigner {
return &PubKeyDigestSigner{ return &PubKeyMessageSigner{
keyDesc: keyDesc, pubKey: pubKey,
keyLoc: keyLoc,
digestSigner: signer, digestSigner: signer,
} }
} }
type PubKeyDigestSigner struct { type PubKeyMessageSigner struct {
keyDesc KeyDescriptor pubKey *btcec.PublicKey
digestSigner DigestSignerRing keyLoc KeyLocator
digestSigner MessageSignerRing
} }
func (p *PubKeyDigestSigner) PubKey() *btcec.PublicKey { func (p *PubKeyMessageSigner) PubKey() *btcec.PublicKey {
return p.keyDesc.PubKey return p.pubKey
} }
func (p *PubKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature, func (p *PubKeyMessageSigner) KeyLocator() KeyLocator {
error) { return p.keyLoc
return p.digestSigner.SignDigest(p.keyDesc, digest)
} }
func (p *PubKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte, func (p *PubKeyMessageSigner) SignMessage(message []byte,
error) { doubleHash bool) (*btcec.Signature, error) {
return p.digestSigner.SignDigestCompact(p.keyDesc, digest) return p.digestSigner.SignMessage(p.keyLoc, message, doubleHash)
} }
type PrivKeyDigestSigner struct { func (p *PubKeyMessageSigner) SignMessageCompact(msg []byte,
PrivKey *btcec.PrivateKey doubleHash bool) ([]byte, error) {
return p.digestSigner.SignMessageCompact(p.keyLoc, msg, doubleHash)
} }
func (p *PrivKeyDigestSigner) PubKey() *btcec.PublicKey { func NewPrivKeyMessageSigner(privKey *btcec.PrivateKey,
return p.PrivKey.PubKey() keyLoc KeyLocator) *PrivKeyMessageSigner {
return &PrivKeyMessageSigner{
privKey: privKey,
keyLoc: keyLoc,
}
} }
func (p *PrivKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature, type PrivKeyMessageSigner struct {
error) { keyLoc KeyLocator
privKey *btcec.PrivateKey
return p.PrivKey.Sign(digest[:])
} }
func (p *PrivKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte, func (p *PrivKeyMessageSigner) PubKey() *btcec.PublicKey {
error) { return p.privKey.PubKey()
return btcec.SignCompact(btcec.S256(), p.PrivKey, digest[:], true)
} }
var _ SingleKeyDigestSigner = (*PubKeyDigestSigner)(nil) func (p *PrivKeyMessageSigner) KeyLocator() KeyLocator {
var _ SingleKeyDigestSigner = (*PrivKeyDigestSigner)(nil) return p.keyLoc
}
func (p *PrivKeyMessageSigner) SignMessage(msg []byte,
doubleHash bool) (*btcec.Signature, error) {
var digest []byte
if doubleHash {
digest = chainhash.DoubleHashB(msg)
} else {
digest = chainhash.HashB(msg)
}
return p.privKey.Sign(digest)
}
func (p *PrivKeyMessageSigner) SignMessageCompact(msg []byte,
doubleHash bool) ([]byte, error) {
var digest []byte
if doubleHash {
digest = chainhash.DoubleHashB(msg)
} else {
digest = chainhash.HashB(msg)
}
return btcec.SignCompact(btcec.S256(), p.privKey, digest, true)
}
var _ SingleKeyMessageSigner = (*PubKeyMessageSigner)(nil)
var _ SingleKeyMessageSigner = (*PrivKeyMessageSigner)(nil)

937
lnd.go

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,6 @@ import (
"time" "time"
"github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil" "github.com/btcsuite/btcutil"
"github.com/davecgh/go-spew/spew" "github.com/davecgh/go-spew/spew"
@ -426,14 +425,11 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig,
return nil, nil, err return nil, nil, err
} }
payReqString, err := payReq.Encode( payReqString, err := payReq.Encode(zpay32.MessageSigner{
zpay32.MessageSigner{ SignCompact: func(msg []byte) ([]byte, error) {
SignCompact: func(msg []byte) ([]byte, error) { return cfg.NodeSigner.SignMessageCompact(msg, false)
hash := chainhash.HashB(msg)
return cfg.NodeSigner.SignDigestCompact(hash)
},
}, },
) })
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }

File diff suppressed because it is too large Load diff

View file

@ -1086,6 +1086,12 @@ message SignMessageRequest {
base64. base64.
*/ */
bytes msg = 1; bytes msg = 1;
/*
Instead of the default double-SHA256 hashing of the message before signing,
only use one round of hashing instead.
*/
bool single_hash = 2;
} }
message SignMessageResponse { message SignMessageResponse {
// The signature for the given message // The signature for the given message

View file

@ -6187,6 +6187,10 @@
"type": "string", "type": "string",
"format": "byte", "format": "byte",
"description": "The message to be signed. When using REST, this field must be encoded as\nbase64." "description": "The message to be signed. When using REST, this field must be encoded as\nbase64."
},
"single_hash": {
"type": "boolean",
"description": "Instead of the default double-SHA256 hashing of the message before signing,\nonly use one round of hashing instead."
} }
} }
}, },

View file

@ -548,6 +548,8 @@ type SignMessageReq struct {
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"` Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
// The key locator that identifies which key to use for signing. // The key locator that identifies which key to use for signing.
KeyLoc *KeyLocator `protobuf:"bytes,2,opt,name=key_loc,json=keyLoc,proto3" json:"key_loc,omitempty"` KeyLoc *KeyLocator `protobuf:"bytes,2,opt,name=key_loc,json=keyLoc,proto3" json:"key_loc,omitempty"`
// Double-SHA256 hash instead of just the default single round.
DoubleHash bool `protobuf:"varint,3,opt,name=double_hash,json=doubleHash,proto3" json:"double_hash,omitempty"`
} }
func (x *SignMessageReq) Reset() { func (x *SignMessageReq) Reset() {
@ -596,6 +598,13 @@ func (x *SignMessageReq) GetKeyLoc() *KeyLocator {
return nil return nil
} }
func (x *SignMessageReq) GetDoubleHash() bool {
if x != nil {
return x.DoubleHash
}
return false
}
type SignMessageResp struct { type SignMessageResp struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -939,62 +948,64 @@ var file_signrpc_signer_proto_rawDesc = []byte{
0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x73,
0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69,
0x70, 0x74, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73, 0x70, 0x74, 0x52, 0x0c, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x73,
0x22, 0x50, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x22, 0x71, 0x0a, 0x0e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52,
0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52,
0x03, 0x6d, 0x73, 0x67, 0x12, 0x2c, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x63, 0x18, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x2c, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x63, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e,
0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4c, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4c,
0x6f, 0x63, 0x22, 0x2f, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x6f, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x68, 0x61, 0x73,
0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x48,
0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x61, 0x73, 0x68, 0x22, 0x2f, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x75, 0x72, 0x65, 0x22, 0x5a, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01, 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x74, 0x75, 0x72, 0x65, 0x22, 0x5a, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65,
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18,
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69,
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73,
0x29, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b,
0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79,
0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0xa2, 0x01, 0x0a, 0x10, 0x53, 0x22, 0x29, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01,
0x29, 0x0a, 0x10, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0xa2, 0x01, 0x0a, 0x10,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x07, 0x6b, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75,
0x79, 0x5f, 0x6c, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x69, 0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x70, 0x68, 0x65,
0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x07, 0x6b,
0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x12, 0x31, 0x0a, 0x08, 0x65, 0x79, 0x5f, 0x6c, 0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73,
0x6b, 0x65, 0x79, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f,
0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x72, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x12, 0x31, 0x0a,
0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x22, 0x08, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x32, 0x0a, 0x11, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x6b, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63,
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x22, 0x32, 0x0a, 0x11, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,
0x4b, 0x65, 0x79, 0x32, 0xd4, 0x02, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x34, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f,
0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x61, 0x77, 0x12, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65,
0x10, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x32, 0xd4, 0x02, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12,
0x71, 0x1a, 0x11, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x34, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x61, 0x77,
0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x49, 0x12, 0x10, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52,
0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x10, 0x2e, 0x73, 0x69, 0x67, 0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67,
0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x73, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65,
0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x10, 0x2e, 0x73, 0x69,
0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e,
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72,
0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d,
0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63,
0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a,
0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65,
0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, 0x0d, 0x56, 0x65, 0x72,
0x65, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67,
0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61,
0x12, 0x48, 0x0a, 0x0f, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e,
0x4b, 0x65, 0x79, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x68, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73,
0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x70, 0x12, 0x48, 0x0a, 0x0f, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65,
0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x64, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53,
0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 0x69, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64,
0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67,
0x72, 0x70, 0x63, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e,
0x74, 0x6f, 0x33, 0x69, 0x6e, 0x67, 0x6e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x2f, 0x6c, 0x6e, 0x64, 0x2f, 0x6c,
0x6e, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (

View file

@ -190,6 +190,9 @@ message SignMessageReq {
// The key locator that identifies which key to use for signing. // The key locator that identifies which key to use for signing.
KeyLocator key_loc = 2; KeyLocator key_loc = 2;
// Double-SHA256 hash instead of just the default single round.
bool double_hash = 3;
} }
message SignMessageResp { message SignMessageResp {
/* /*

View file

@ -354,6 +354,10 @@
"key_loc": { "key_loc": {
"$ref": "#/definitions/signrpcKeyLocator", "$ref": "#/definitions/signrpcKeyLocator",
"description": "The key locator that identifies which key to use for signing." "description": "The key locator that identifies which key to use for signing."
},
"double_hash": {
"type": "boolean",
"description": "Double-SHA256 hash instead of just the default single round."
} }
} }
}, },

View file

@ -446,7 +446,7 @@ func (s *Server) ComputeInputScript(ctx context.Context,
// SignMessage signs a message with the key specified in the key locator. The // SignMessage signs a message with the key specified in the key locator. The
// returned signature is fixed-size LN wire format encoded. // returned signature is fixed-size LN wire format encoded.
func (s *Server) SignMessage(ctx context.Context, func (s *Server) SignMessage(_ context.Context,
in *SignMessageReq) (*SignMessageResp, error) { in *SignMessageReq) (*SignMessageResp, error) {
if in.Msg == nil { if in.Msg == nil {
@ -457,20 +457,16 @@ func (s *Server) SignMessage(ctx context.Context,
} }
// Describe the private key we'll be using for signing. // Describe the private key we'll be using for signing.
keyDescriptor := keychain.KeyDescriptor{ keyLocator := keychain.KeyLocator{
KeyLocator: keychain.KeyLocator{ Family: keychain.KeyFamily(in.KeyLoc.KeyFamily),
Family: keychain.KeyFamily(in.KeyLoc.KeyFamily), Index: uint32(in.KeyLoc.KeyIndex),
Index: uint32(in.KeyLoc.KeyIndex),
},
} }
// The signature is over the sha256 hash of the message.
var digest [32]byte
copy(digest[:], chainhash.HashB(in.Msg))
// Create the raw ECDSA signature first and convert it to the final wire // Create the raw ECDSA signature first and convert it to the final wire
// format after. // format after.
sig, err := s.cfg.KeyRing.SignDigest(keyDescriptor, digest) sig, err := s.cfg.KeyRing.SignMessage(
keyLocator, in.Msg, in.DoubleHash,
)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't sign the hash: %v", err) return nil, fmt.Errorf("can't sign the hash: %v", err)
} }

View file

@ -2,7 +2,7 @@ package mock
import ( import (
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
) )
@ -12,8 +12,8 @@ type SecretKeyRing struct {
} }
// DeriveNextKey currently returns dummy values. // DeriveNextKey currently returns dummy values.
func (s *SecretKeyRing) DeriveNextKey(keyFam keychain.KeyFamily) ( func (s *SecretKeyRing) DeriveNextKey(
keychain.KeyDescriptor, error) { _ keychain.KeyFamily) (keychain.KeyDescriptor, error) {
return keychain.KeyDescriptor{ return keychain.KeyDescriptor{
PubKey: s.RootKey.PubKey(), PubKey: s.RootKey.PubKey(),
@ -21,36 +21,50 @@ func (s *SecretKeyRing) DeriveNextKey(keyFam keychain.KeyFamily) (
} }
// DeriveKey currently returns dummy values. // DeriveKey currently returns dummy values.
func (s *SecretKeyRing) DeriveKey(keyLoc keychain.KeyLocator) (keychain.KeyDescriptor, func (s *SecretKeyRing) DeriveKey(
error) { _ keychain.KeyLocator) (keychain.KeyDescriptor, error) {
return keychain.KeyDescriptor{ return keychain.KeyDescriptor{
PubKey: s.RootKey.PubKey(), PubKey: s.RootKey.PubKey(),
}, nil }, nil
} }
// DerivePrivKey currently returns dummy values. // DerivePrivKey currently returns dummy values.
func (s *SecretKeyRing) DerivePrivKey(keyDesc keychain.KeyDescriptor) (*btcec.PrivateKey, func (s *SecretKeyRing) DerivePrivKey(
error) { _ keychain.KeyDescriptor) (*btcec.PrivateKey, error) {
return s.RootKey, nil return s.RootKey, nil
} }
// ECDH currently returns dummy values. // ECDH currently returns dummy values.
func (s *SecretKeyRing) ECDH(_ keychain.KeyDescriptor, pubKey *btcec.PublicKey) ([32]byte, func (s *SecretKeyRing) ECDH(_ keychain.KeyDescriptor,
error) { _ *btcec.PublicKey) ([32]byte, error) {
return [32]byte{}, nil return [32]byte{}, nil
} }
// SignDigest signs the passed digest and ignores the KeyDescriptor. // SignMessage signs the passed message and ignores the KeyDescriptor.
func (s *SecretKeyRing) SignDigest(_ keychain.KeyDescriptor, func (s *SecretKeyRing) SignMessage(_ keychain.KeyLocator,
digest [32]byte) (*btcec.Signature, error) { msg []byte, doubleHash bool) (*btcec.Signature, error) {
return s.RootKey.Sign(digest[:]) var digest []byte
if doubleHash {
digest = chainhash.DoubleHashB(msg)
} else {
digest = chainhash.HashB(msg)
}
return s.RootKey.Sign(digest)
} }
// SignDigestCompact signs the passed digest. // SignMessageCompact signs the passed message.
func (s *SecretKeyRing) SignDigestCompact(_ keychain.KeyDescriptor, func (s *SecretKeyRing) SignMessageCompact(_ keychain.KeyLocator,
digest [32]byte) ([]byte, error) { msg []byte, doubleHash bool) ([]byte, error) {
return btcec.SignCompact(btcec.S256(), s.RootKey, digest[:], true) var digest []byte
if doubleHash {
digest = chainhash.DoubleHashB(msg)
} else {
digest = chainhash.HashB(msg)
}
return btcec.SignCompact(btcec.S256(), s.RootKey, digest, true)
} }

View file

@ -7,8 +7,12 @@ import (
"github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
)
var (
idKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
) )
// DummySignature is a dummy Signature implementation. // DummySignature is a dummy Signature implementation.
@ -46,6 +50,7 @@ func (d *DummySigner) ComputeInputScript(tx *wire.MsgTx,
// everything with a single private key. // everything with a single private key.
type SingleSigner struct { type SingleSigner struct {
Privkey *btcec.PrivateKey Privkey *btcec.PrivateKey
KeyLoc keychain.KeyLocator
} }
// SignOutputRaw generates a signature for the passed transaction using the // SignOutputRaw generates a signature for the passed transaction using the
@ -110,10 +115,15 @@ func (s *SingleSigner) ComputeInputScript(tx *wire.MsgTx,
// SignMessage takes a public key and a message and only signs the message // SignMessage takes a public key and a message and only signs the message
// with the stored private key if the public key matches the private key. // with the stored private key if the public key matches the private key.
func (s *SingleSigner) SignMessage(pubKey *btcec.PublicKey, func (s *SingleSigner) SignMessage(keyLoc keychain.KeyLocator,
msg []byte) (input.Signature, error) { msg []byte) (*btcec.Signature, error) {
if !pubKey.IsEqual(s.Privkey.PubKey()) { mockKeyLoc := s.KeyLoc
if s.KeyLoc.IsEmpty() {
mockKeyLoc = idKeyLoc
}
if keyLoc != mockKeyLoc {
return nil, fmt.Errorf("unknown public key") return nil, fmt.Errorf("unknown public key")
} }

View file

@ -126,11 +126,13 @@ func (b *BtcWallet) deriveKeyByLocator(keyLoc keychain.KeyLocator) (*btcec.Priva
// fetchPrivKey attempts to retrieve the raw private key corresponding to the // fetchPrivKey attempts to retrieve the raw private key corresponding to the
// passed public key if populated, or the key descriptor path (if non-empty). // passed public key if populated, or the key descriptor path (if non-empty).
func (b *BtcWallet) fetchPrivKey(keyDesc *keychain.KeyDescriptor) (*btcec.PrivateKey, error) { func (b *BtcWallet) fetchPrivKey(
keyDesc *keychain.KeyDescriptor) (*btcec.PrivateKey, error) {
// If the key locator within the descriptor *isn't* empty, then we can // If the key locator within the descriptor *isn't* empty, then we can
// directly derive the keys raw. // directly derive the keys raw.
emptyLocator := keyDesc.KeyLocator.IsEmpty() emptyLocator := keyDesc.KeyLocator.IsEmpty()
if !emptyLocator { if !emptyLocator || keyDesc.PubKey == nil {
return b.deriveKeyByLocator(keyDesc.KeyLocator) return b.deriveKeyByLocator(keyDesc.KeyLocator)
} }
@ -259,18 +261,18 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx,
var _ input.Signer = (*BtcWallet)(nil) var _ input.Signer = (*BtcWallet)(nil)
// SignMessage attempts to sign a target message with the private key that // 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 // corresponds to the passed key locator. If the target private key is unable to
// be found, then an error will be returned. The actual digest signed is the // be found, then an error will be returned. The actual digest signed is the
// double SHA-256 of the passed message. // double SHA-256 of the passed message.
// //
// NOTE: This is a part of the MessageSigner interface. // NOTE: This is a part of the MessageSigner interface.
func (b *BtcWallet) SignMessage(pubKey *btcec.PublicKey, func (b *BtcWallet) SignMessage(keyLoc keychain.KeyLocator,
msg []byte) (input.Signature, error) { msg []byte) (*btcec.Signature, error) {
// First attempt to fetch the private key which corresponds to the // First attempt to fetch the private key which corresponds to the
// specified public key. // specified public key.
privKey, err := b.fetchPrivKey(&keychain.KeyDescriptor{ privKey, err := b.fetchPrivKey(&keychain.KeyDescriptor{
PubKey: pubKey, KeyLocator: keyLoc,
}) })
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -15,7 +15,7 @@ import (
"github.com/btcsuite/btcwallet/waddrmgr" "github.com/btcsuite/btcwallet/waddrmgr"
"github.com/btcsuite/btcwallet/wallet/txauthor" "github.com/btcsuite/btcwallet/wallet/txauthor"
"github.com/btcsuite/btcwallet/wtxmgr" "github.com/btcsuite/btcwallet/wtxmgr"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet/chainfee" "github.com/lightningnetwork/lnd/lnwallet/chainfee"
) )
@ -440,10 +440,11 @@ type BlockChainIO interface {
// to attest to some message. // to attest to some message.
type MessageSigner interface { type MessageSigner interface {
// SignMessage attempts to sign a target message with the private key // SignMessage attempts to sign a target message with the private key
// that corresponds to the passed public key. If the target private key // described in the key locator. If the target private key is unable to
// is unable to be found, then an error will be returned. The actual // be found, then an error will be returned. The actual digest signed is
// digest signed is the double SHA-256 of the passed message. // the double SHA-256 of the passed message.
SignMessage(pubKey *btcec.PublicKey, msg []byte) (input.Signature, error) SignMessage(keyLoc keychain.KeyLocator, msg []byte) (*btcec.Signature,
error)
} }
// WalletDriver represents a "driver" for a particular concrete // WalletDriver represents a "driver" for a particular concrete

View file

@ -70,6 +70,12 @@ func NewSigFromSignature(e input.Signature) (Sig, error) {
return Sig{}, fmt.Errorf("cannot decode empty signature") return Sig{}, fmt.Errorf("cannot decode empty signature")
} }
// Nil is still a valid interface, apparently. So we need a more
// explicit check here.
if ecsig, ok := e.(*btcec.Signature); ok && ecsig == nil {
return Sig{}, fmt.Errorf("cannot decode empty signature")
}
// Serialize the signature with all the checks that entails. // Serialize the signature with all the checks that entails.
return NewSigFromRawSignature(e.Serialize()) return NewSigFromRawSignature(e.Serialize())
} }

View file

@ -99,6 +99,7 @@ func Start(extraArgs string, rpcReady Callback) {
Ready: rpcListening, Ready: rpcListening,
}}, }},
} }
implCfg := loadedConfig.ImplementationConfig(shutdownInterceptor)
// Call the "real" main in a nested manner so the defers will properly // Call the "real" main in a nested manner so the defers will properly
// be executed in the case of a graceful shutdown. // be executed in the case of a graceful shutdown.
@ -107,7 +108,7 @@ func Start(extraArgs string, rpcReady Callback) {
defer close(quit) defer close(quit)
if err := lnd.Main( if err := lnd.Main(
loadedConfig, cfg, shutdownInterceptor, loadedConfig, cfg, implCfg, shutdownInterceptor,
); err != nil { ); err != nil {
if e, ok := err.(*flags.Error); ok && if e, ok := err.(*flags.Error); ok &&
e.Type == flags.ErrHelp { e.Type == flags.ErrHelp {

View file

@ -8,6 +8,7 @@ import (
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcd/wire"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
@ -43,6 +44,10 @@ type ChanStatusConfig struct {
// OurPubKey is the public key identifying this node on the network. // OurPubKey is the public key identifying this node on the network.
OurPubKey *btcec.PublicKey OurPubKey *btcec.PublicKey
// OurKeyLoc is the locator for the public key identifying this node on
// the network.
OurKeyLoc keychain.KeyLocator
// MessageSigner signs messages that validate under OurPubKey. // MessageSigner signs messages that validate under OurPubKey.
MessageSigner lnwallet.MessageSigner MessageSigner lnwallet.MessageSigner
@ -621,7 +626,7 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint,
} }
err = SignChannelUpdate( err = SignChannelUpdate(
m.cfg.MessageSigner, m.cfg.OurPubKey, chanUpdate, m.cfg.MessageSigner, m.cfg.OurKeyLoc, chanUpdate,
ChanUpdSetDisable(disabled), ChanUpdSetTimestamp, ChanUpdSetDisable(disabled), ChanUpdSetTimestamp,
) )
if err != nil { if err != nil {

View file

@ -19,6 +19,10 @@ import (
"github.com/lightningnetwork/lnd/netann" "github.com/lightningnetwork/lnd/netann"
) )
var (
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
)
// randOutpoint creates a random wire.Outpoint. // randOutpoint creates a random wire.Outpoint.
func randOutpoint(t *testing.T) wire.OutPoint { func randOutpoint(t *testing.T) wire.OutPoint {
t.Helper() t.Helper()
@ -310,7 +314,7 @@ func newManagerCfg(t *testing.T, numChannels int,
if err != nil { if err != nil {
t.Fatalf("unable to generate key pair: %v", err) t.Fatalf("unable to generate key pair: %v", err)
} }
privKeySigner := &keychain.PrivKeyDigestSigner{PrivKey: privKey} privKeySigner := keychain.NewPrivKeyMessageSigner(privKey, testKeyLoc)
graph := newMockGraph( graph := newMockGraph(
t, numChannels, startEnabled, startEnabled, privKey.PubKey(), t, numChannels, startEnabled, startEnabled, privKey.PubKey(),
@ -322,6 +326,7 @@ func newManagerCfg(t *testing.T, numChannels int,
ChanEnableTimeout: 500 * time.Millisecond, ChanEnableTimeout: 500 * time.Millisecond,
ChanDisableTimeout: time.Second, ChanDisableTimeout: time.Second,
OurPubKey: privKey.PubKey(), OurPubKey: privKey.PubKey(),
OurKeyLoc: testKeyLoc,
MessageSigner: netann.NewNodeSigner(privKeySigner), MessageSigner: netann.NewNodeSigner(privKeySigner),
IsChannelActive: htlcSwitch.HasActiveLink, IsChannelActive: htlcSwitch.HasActiveLink,
ApplyChannelUpdate: graph.ApplyChannelUpdate, ApplyChannelUpdate: graph.ApplyChannelUpdate,

View file

@ -7,6 +7,7 @@ import (
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
@ -55,7 +56,7 @@ func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) {
// monotonically increase from the prior. // monotonically increase from the prior.
// //
// NOTE: This method modifies the given update. // NOTE: This method modifies the given update.
func SignChannelUpdate(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, func SignChannelUpdate(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
update *lnwire.ChannelUpdate, mods ...ChannelUpdateModifier) error { update *lnwire.ChannelUpdate, mods ...ChannelUpdateModifier) error {
// Apply the requested changes to the channel update. // Apply the requested changes to the channel update.
@ -64,7 +65,7 @@ func SignChannelUpdate(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey,
} }
// Create the DER-encoded ECDSA signature over the message digest. // Create the DER-encoded ECDSA signature over the message digest.
sig, err := SignAnnouncement(signer, pubKey, update) sig, err := SignAnnouncement(signer, keyLoc, update)
if err != nil { if err != nil {
return err return err
} }

View file

@ -6,7 +6,6 @@ import (
"time" "time"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
@ -18,8 +17,8 @@ type mockSigner struct {
err error err error
} }
func (m *mockSigner) SignMessage(pk *btcec.PublicKey, func (m *mockSigner) SignMessage(_ keychain.KeyLocator,
msg []byte) (input.Signature, error) { _ []byte) (*btcec.Signature, error) {
if m.err != nil { if m.err != nil {
return nil, m.err return nil, m.err
@ -32,7 +31,7 @@ var _ lnwallet.MessageSigner = (*mockSigner)(nil)
var ( var (
privKey, _ = btcec.NewPrivateKey(btcec.S256()) privKey, _ = btcec.NewPrivateKey(btcec.S256())
privKeySigner = &keychain.PrivKeyDigestSigner{PrivKey: privKey} privKeySigner = keychain.NewPrivKeyMessageSigner(privKey, testKeyLoc)
pubKey = privKey.PubKey() pubKey = privKey.PubKey()
@ -130,7 +129,7 @@ func TestUpdateDisableFlag(t *testing.T) {
// Attempt to update and sign the new update, specifying // Attempt to update and sign the new update, specifying
// disabled or enabled as prescribed in the test case. // disabled or enabled as prescribed in the test case.
err := netann.SignChannelUpdate( err := netann.SignChannelUpdate(
tc.signer, pubKey, newUpdate, tc.signer, testKeyLoc, newUpdate,
netann.ChanUpdSetDisable(tc.disable), netann.ChanUpdSetDisable(tc.disable),
netann.ChanUpdSetTimestamp, netann.ChanUpdSetTimestamp,
) )

View file

@ -4,7 +4,7 @@ import (
"net" "net"
"time" "time"
"github.com/btcsuite/btcd/btcec" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
@ -40,7 +40,7 @@ func NodeAnnSetTimestamp(nodeAnn *lnwire.NodeAnnouncement) {
// update should be the most recent, valid update, otherwise the timestamp may // update should be the most recent, valid update, otherwise the timestamp may
// not monotonically increase from the prior. // not monotonically increase from the prior.
func SignNodeAnnouncement(signer lnwallet.MessageSigner, func SignNodeAnnouncement(signer lnwallet.MessageSigner,
pubKey *btcec.PublicKey, nodeAnn *lnwire.NodeAnnouncement, keyLoc keychain.KeyLocator, nodeAnn *lnwire.NodeAnnouncement,
mods ...NodeAnnModifier) error { mods ...NodeAnnModifier) error {
// Apply the requested changes to the node announcement. // Apply the requested changes to the node announcement.
@ -49,7 +49,7 @@ func SignNodeAnnouncement(signer lnwallet.MessageSigner,
} }
// Create the DER-encoded ECDSA signature over the message digest. // Create the DER-encoded ECDSA signature over the message digest.
sig, err := SignAnnouncement(signer, pubKey, nodeAnn) sig, err := SignAnnouncement(signer, keyLoc, nodeAnn)
if err != nil { if err != nil {
return err return err
} }

View file

@ -4,8 +4,6 @@ import (
"fmt" "fmt"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
) )
@ -13,33 +11,31 @@ import (
// NodeSigner is an implementation of the MessageSigner interface backed by the // NodeSigner is an implementation of the MessageSigner interface backed by the
// identity private key of running lnd node. // identity private key of running lnd node.
type NodeSigner struct { type NodeSigner struct {
keySigner keychain.SingleKeyDigestSigner keySigner keychain.SingleKeyMessageSigner
} }
// NewNodeSigner creates a new instance of the NodeSigner backed by the target // NewNodeSigner creates a new instance of the NodeSigner backed by the target
// private key. // private key.
func NewNodeSigner(keySigner keychain.SingleKeyDigestSigner) *NodeSigner { func NewNodeSigner(keySigner keychain.SingleKeyMessageSigner) *NodeSigner {
return &NodeSigner{ return &NodeSigner{
keySigner: keySigner, keySigner: keySigner,
} }
} }
// SignMessage signs a double-sha256 digest of the passed msg under the // SignMessage signs a double-sha256 digest of the passed msg under the
// resident node's private key. If the target public key is _not_ the node's // resident node's private key described in the key locator. If the target key
// private key, then an error will be returned. // locator is _not_ the node's private key, then an error will be returned.
func (n *NodeSigner) SignMessage(pubKey *btcec.PublicKey, func (n *NodeSigner) SignMessage(keyLoc keychain.KeyLocator,
msg []byte) (input.Signature, error) { msg []byte) (*btcec.Signature, error) {
// If this isn't our identity public key, then we'll exit early with an // If this isn't our identity public key, then we'll exit early with an
// error as we can't sign with this key. // error as we can't sign with this key.
if !pubKey.IsEqual(n.keySigner.PubKey()) { if keyLoc != n.keySigner.KeyLocator() {
return nil, fmt.Errorf("unknown public key") return nil, fmt.Errorf("unknown public key locator")
} }
// Otherwise, we'll sign the dsha256 of the target message. // Otherwise, we'll sign the double-sha256 of the target message.
var digest [32]byte sig, err := n.keySigner.SignMessage(msg, true)
copy(digest[:], chainhash.DoubleHashB(msg))
sig, err := n.keySigner.SignDigest(digest)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't sign the message: %v", err) return nil, fmt.Errorf("can't sign the message: %v", err)
} }
@ -47,29 +43,13 @@ func (n *NodeSigner) SignMessage(pubKey *btcec.PublicKey,
return sig, nil return sig, nil
} }
// SignCompact signs a double-sha256 digest of the msg parameter under the // SignMessageCompact signs a single or double sha256 digest of the msg
// resident node's private key. The returned signature is a pubkey-recoverable // parameter under the resident node's private key. The returned signature is a
// signature. // pubkey-recoverable signature.
func (n *NodeSigner) SignCompact(msg []byte) ([]byte, error) { func (n *NodeSigner) SignMessageCompact(msg []byte, doubleHash bool) ([]byte,
// We'll sign the dsha256 of the target message. error) {
digest := chainhash.DoubleHashB(msg)
return n.SignDigestCompact(digest) return n.keySigner.SignMessageCompact(msg, doubleHash)
}
// SignDigestCompact signs the provided message digest under the resident
// node's private key. The returned signature is a pubkey-recoverable signature.
func (n *NodeSigner) SignDigestCompact(hash []byte) ([]byte, error) {
var digest [32]byte
copy(digest[:], hash)
// keychain.SignDigestCompact returns a pubkey-recoverable signature.
sig, err := n.keySigner.SignDigestCompact(digest)
if err != nil {
return nil, fmt.Errorf("can't sign the hash: %v", err)
}
return sig, nil
} }
// A compile time check to ensure that NodeSigner implements the MessageSigner // A compile time check to ensure that NodeSigner implements the MessageSigner

View file

@ -3,15 +3,15 @@ package netann
import ( import (
"fmt" "fmt"
"github.com/btcsuite/btcd/btcec"
"github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwallet" "github.com/lightningnetwork/lnd/lnwallet"
"github.com/lightningnetwork/lnd/lnwire" "github.com/lightningnetwork/lnd/lnwire"
) )
// SignAnnouncement signs any type of gossip message that is announced on the // SignAnnouncement signs any type of gossip message that is announced on the
// network. // network.
func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey, func SignAnnouncement(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
msg lnwire.Message) (input.Signature, error) { msg lnwire.Message) (input.Signature, error) {
var ( var (
@ -33,5 +33,5 @@ func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey,
return nil, fmt.Errorf("unable to get data to sign: %v", err) return nil, fmt.Errorf("unable to get data to sign: %v", err)
} }
return signer.SignMessage(pubKey, data) return signer.SignMessage(keyLoc, data)
} }

View file

@ -43,6 +43,8 @@ const (
var ( var (
// Just use some arbitrary bytes as delivery script. // Just use some arbitrary bytes as delivery script.
dummyDeliveryScript = channels.AlicesPrivKey dummyDeliveryScript = channels.AlicesPrivKey
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
) )
// noUpdate is a function which can be used as a parameter in createTestPeer to // noUpdate is a function which can be used as a parameter in createTestPeer to
@ -58,10 +60,15 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
mockSwitch *mockMessageSwitch) ( mockSwitch *mockMessageSwitch) (
*Brontide, *lnwallet.LightningChannel, func(), error) { *Brontide, *lnwallet.LightningChannel, func(), error) {
nodeKeyLocator := keychain.KeyLocator{
Family: keychain.KeyFamilyNodeKey,
}
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes( aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
btcec.S256(), channels.AlicesPrivKey, btcec.S256(), channels.AlicesPrivKey,
) )
aliceKeySigner := &keychain.PrivKeyDigestSigner{PrivKey: aliceKeyPriv} aliceKeySigner := keychain.NewPrivKeyMessageSigner(
aliceKeyPriv, nodeKeyLocator,
)
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes( bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(
btcec.S256(), channels.BobsPrivKey, btcec.S256(), channels.BobsPrivKey,
) )
@ -325,6 +332,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
Graph: dbAlice.ChannelGraph(), Graph: dbAlice.ChannelGraph(),
MessageSigner: nodeSignerAlice, MessageSigner: nodeSignerAlice,
OurPubKey: aliceKeyPub, OurPubKey: aliceKeyPub,
OurKeyLoc: testKeyLoc,
IsChannelActive: func(lnwire.ChannelID) bool { return true }, IsChannelActive: func(lnwire.ChannelID) bool { return true },
ApplyChannelUpdate: func(*lnwire.ChannelUpdate) error { return nil }, ApplyChannelUpdate: func(*lnwire.ChannelUpdate) error { return nil },
}) })

View file

@ -137,7 +137,7 @@ var _ autopilot.ChannelController = (*chanController)(nil)
// interfaces needed to drive it won't be launched before the Manager's // interfaces needed to drive it won't be launched before the Manager's
// StartAgent method is called. // StartAgent method is called.
func initAutoPilot(svr *server, cfg *lncfg.AutoPilot, func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
chainCfg *lncfg.Chain, netParams chainreg.BitcoinNetParams) ( minHTLCIn lnwire.MilliSatoshi, netParams chainreg.BitcoinNetParams) (
*autopilot.ManagerCfg, error) { *autopilot.ManagerCfg, error) {
atplLog.Infof("Instantiating autopilot with active=%v, "+ atplLog.Infof("Instantiating autopilot with active=%v, "+
@ -177,7 +177,7 @@ func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
private: cfg.Private, private: cfg.Private,
minConfs: cfg.MinConfs, minConfs: cfg.MinConfs,
confTarget: cfg.ConfTarget, confTarget: cfg.ConfTarget,
chanMinHtlcIn: chainCfg.MinHTLCIn, chanMinHtlcIn: minHTLCIn,
netParams: netParams, netParams: netParams,
}, },
WalletBalance: func() (btcutil.Amount, error) { WalletBalance: func() (btcutil.Amount, error) {

View file

@ -386,6 +386,15 @@ func (r *InterceptorChain) AddMacaroonService(svc *macaroons.Service) {
r.svc = svc r.svc = svc
} }
// MacaroonService returns the currently registered macaroon service. This might
// be nil if none was registered (yet).
func (r *InterceptorChain) MacaroonService() *macaroons.Service {
r.RLock()
defer r.RUnlock()
return r.svc
}
// AddPermission adds a new macaroon rule for the given method. // AddPermission adds a new macaroon rule for the given method.
func (r *InterceptorChain) AddPermission(method string, ops []bakery.Op) error { func (r *InterceptorChain) AddPermission(method string, ops []bakery.Op) error {
r.Lock() r.Lock()

View file

@ -611,16 +611,12 @@ type rpcServer struct {
// selfNode is our own pubkey. // selfNode is our own pubkey.
selfNode route.Vertex selfNode route.Vertex
// interceptorChain is the the interceptor added to our gRPC server. // interceptorChain is the interceptor added to our gRPC server.
interceptorChain *rpcperms.InterceptorChain interceptorChain *rpcperms.InterceptorChain
// extSubserverCfg is optional and specifies the registration // implCfg is the configuration for some of the interfaces that can be
// callback and permissions to register external gRPC subservers. // provided externally.
extSubserverCfg *RPCSubserverConfig implCfg *ImplementationCfg
// extRestRegistrar is optional and specifies the registration
// callback to register external REST subservers.
extRestRegistrar RestRegistrar
// interceptor is used to be able to request a shutdown // interceptor is used to be able to request a shutdown
interceptor signal.Interceptor interceptor signal.Interceptor
@ -634,9 +630,7 @@ var _ lnrpc.LightningServer = (*rpcServer)(nil)
// dependencies are added, this will be an non-functioning RPC server only to // dependencies are added, this will be an non-functioning RPC server only to
// be used to register the LightningService with the gRPC server. // be used to register the LightningService with the gRPC server.
func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain, func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain,
extSubserverCfg *RPCSubserverConfig, implCfg *ImplementationCfg, interceptor signal.Interceptor) *rpcServer {
extRestRegistrar RestRegistrar,
interceptor signal.Interceptor) *rpcServer {
// We go trhough the list of registered sub-servers, and create a gRPC // We go trhough the list of registered sub-servers, and create a gRPC
// handler for each. These are used to register with the gRPC server // handler for each. These are used to register with the gRPC server
@ -654,8 +648,7 @@ func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain,
cfg: cfg, cfg: cfg,
subGrpcHandlers: subServerHandlers, subGrpcHandlers: subServerHandlers,
interceptorChain: interceptorChain, interceptorChain: interceptorChain,
extSubserverCfg: extSubserverCfg, implCfg: implCfg,
extRestRegistrar: extRestRegistrar,
quit: make(chan struct{}, 1), quit: make(chan struct{}, 1),
interceptor: interceptor, interceptor: interceptor,
} }
@ -785,30 +778,22 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service,
// External subserver possibly need to register their own permissions // External subserver possibly need to register their own permissions
// and macaroon validator. // and macaroon validator.
if r.extSubserverCfg != nil { for method, ops := range r.implCfg.ExternalValidator.Permissions() {
macValidator := r.extSubserverCfg.MacaroonValidator err := r.interceptorChain.AddPermission(method, ops)
for method, ops := range r.extSubserverCfg.Permissions { if err != nil {
err := r.interceptorChain.AddPermission(method, ops) return err
if err != nil { }
return err
}
// Give the external subservers the possibility // Give the external subservers the possibility to also use
// to also use their own validator to check any // their own validator to check any macaroons attached to calls
// macaroons attached to calls to this method. // to this method. This allows them to have their own root key
// This allows them to have their own root key // ID database and permission entities.
// ID database and permission entities. err = macService.RegisterExternalValidator(
if macValidator != nil { method, r.implCfg.ExternalValidator,
err := macService.RegisterExternalValidator( )
method, macValidator, if err != nil {
) return fmt.Errorf("could not register external "+
if err != nil { "macaroon validator: %v", err)
return fmt.Errorf("could "+
"not register "+
"external macaroon "+
"validator: %v", err)
}
}
} }
} }
@ -846,13 +831,10 @@ func (r *rpcServer) RegisterWithGrpcServer(grpcServer *grpc.Server) error {
// their own, we just let them register their services to the same // their own, we just let them register their services to the same
// server instance so all of them can be exposed on the same // server instance so all of them can be exposed on the same
// port/listener. // port/listener.
if r.extSubserverCfg != nil && r.extSubserverCfg.Registrar != nil { err := r.implCfg.RegisterGrpcSubserver(grpcServer)
registerer := r.extSubserverCfg.Registrar if err != nil {
err := registerer.RegisterGrpcSubserver(grpcServer) rpcsLog.Errorf("error registering external gRPC "+
if err != nil { "subserver: %v", err)
rpcsLog.Errorf("error registering external gRPC "+
"subserver: %v", err)
}
} }
return nil return nil
@ -908,14 +890,12 @@ func (r *rpcServer) RegisterWithRestProxy(restCtx context.Context,
// Before listening on any of the interfaces, we also want to give the // Before listening on any of the interfaces, we also want to give the
// external subservers a chance to register their own REST proxy stub // external subservers a chance to register their own REST proxy stub
// with our mux instance. // with our mux instance.
if r.extRestRegistrar != nil { err = r.implCfg.RegisterRestSubserver(
err := r.extRestRegistrar.RegisterRestSubserver( restCtx, restMux, restProxyDest, restDialOpts,
restCtx, restMux, restProxyDest, restDialOpts, )
) if err != nil {
if err != nil { rpcsLog.Errorf("error registering external REST subserver: %v",
rpcsLog.Errorf("error registering "+ err)
"external REST subserver: %v", err)
}
} }
return nil return nil
} }
@ -1522,7 +1502,7 @@ var (
// SignMessage signs a message with the resident node's private key. The // SignMessage signs a message with the resident node's private key. The
// returned signature string is zbase32 encoded and pubkey recoverable, meaning // returned signature string is zbase32 encoded and pubkey recoverable, meaning
// that only the message digest and signature are needed for verification. // that only the message digest and signature are needed for verification.
func (r *rpcServer) SignMessage(ctx context.Context, func (r *rpcServer) SignMessage(_ context.Context,
in *lnrpc.SignMessageRequest) (*lnrpc.SignMessageResponse, error) { in *lnrpc.SignMessageRequest) (*lnrpc.SignMessageResponse, error) {
if in.Msg == nil { if in.Msg == nil {
@ -1530,7 +1510,9 @@ func (r *rpcServer) SignMessage(ctx context.Context,
} }
in.Msg = append(signedMsgPrefix, in.Msg...) in.Msg = append(signedMsgPrefix, in.Msg...)
sigBytes, err := r.server.nodeSigner.SignCompact(in.Msg) sigBytes, err := r.server.nodeSigner.SignMessageCompact(
in.Msg, !in.SingleHash,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -157,6 +157,9 @@ type server struct {
// to authenticate any incoming connections. // to authenticate any incoming connections.
identityECDH keychain.SingleKeyECDH identityECDH keychain.SingleKeyECDH
// identityKeyLoc is the key locator for the above wrapped identity key.
identityKeyLoc keychain.KeyLocator
// nodeSigner is an implementation of the MessageSigner implementation // nodeSigner is an implementation of the MessageSigner implementation
// that's backed by the identity private key of the running lnd node. // that's backed by the identity private key of the running lnd node.
nodeSigner *netann.NodeSigner nodeSigner *netann.NodeSigner
@ -442,17 +445,20 @@ func noiseDial(idKey keychain.SingleKeyECDH,
// newServer creates a new instance of the server which is to listen using the // newServer creates a new instance of the server which is to listen using the
// passed listener address. // passed listener address.
func newServer(cfg *Config, listenAddrs []net.Addr, func newServer(cfg *Config, listenAddrs []net.Addr,
dbs *databaseInstances, cc *chainreg.ChainControl, dbs *DatabaseInstances, cc *chainreg.ChainControl,
nodeKeyDesc *keychain.KeyDescriptor, nodeKeyDesc *keychain.KeyDescriptor,
chansToRestore walletunlocker.ChannelsToRecover, chansToRestore walletunlocker.ChannelsToRecover,
chanPredicate chanacceptor.ChannelAcceptor, chanPredicate chanacceptor.ChannelAcceptor,
torController *tor.Controller) (*server, error) { torController *tor.Controller) (*server, error) {
var ( var (
err error err error
nodeKeyECDH = keychain.NewPubKeyECDH(*nodeKeyDesc, cc.KeyRing) nodeKeyECDH = keychain.NewPubKeyECDH(*nodeKeyDesc, cc.KeyRing)
nodeKeySigner = keychain.NewPubKeyDigestSigner(
*nodeKeyDesc, cc.KeyRing, // We just derived the full descriptor, so we know the public
// key is set on it.
nodeKeySigner = keychain.NewPubKeyMessageSigner(
nodeKeyDesc.PubKey, nodeKeyDesc.KeyLocator, cc.KeyRing,
) )
) )
@ -470,11 +476,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
} }
var serializedPubKey [33]byte var serializedPubKey [33]byte
copy(serializedPubKey[:], nodeKeyECDH.PubKey().SerializeCompressed()) copy(serializedPubKey[:], nodeKeyDesc.PubKey.SerializeCompressed())
// Initialize the sphinx router. // Initialize the sphinx router.
replayLog := htlcswitch.NewDecayedLog( replayLog := htlcswitch.NewDecayedLog(
dbs.decayedLogDB, cc.ChainNotifier, dbs.DecayedLogDB, cc.ChainNotifier,
) )
sphinxRouter := sphinx.NewRouter( sphinxRouter := sphinx.NewRouter(
nodeKeyECDH, cfg.ActiveNetParams.Params, replayLog, nodeKeyECDH, cfg.ActiveNetParams.Params, replayLog,
@ -521,10 +527,10 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
s := &server{ s := &server{
cfg: cfg, cfg: cfg,
graphDB: dbs.graphDB.ChannelGraph(), graphDB: dbs.GraphDB.ChannelGraph(),
chanStateDB: dbs.chanStateDB.ChannelStateDB(), chanStateDB: dbs.ChanStateDB.ChannelStateDB(),
addrSource: dbs.chanStateDB, addrSource: dbs.ChanStateDB,
miscDB: dbs.chanStateDB, miscDB: dbs.ChanStateDB,
cc: cc, cc: cc,
sigPool: lnwallet.NewSigPool(cfg.Workers.Sig, cc.Signer), sigPool: lnwallet.NewSigPool(cfg.Workers.Sig, cc.Signer),
writePool: writePool, writePool: writePool,
@ -532,11 +538,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
chansToRestore: chansToRestore, chansToRestore: chansToRestore,
channelNotifier: channelnotifier.New( channelNotifier: channelnotifier.New(
dbs.chanStateDB.ChannelStateDB(), dbs.ChanStateDB.ChannelStateDB(),
), ),
identityECDH: nodeKeyECDH, identityECDH: nodeKeyECDH,
nodeSigner: netann.NewNodeSigner(nodeKeySigner), identityKeyLoc: nodeKeyDesc.KeyLocator,
nodeSigner: netann.NewNodeSigner(nodeKeySigner),
listenAddrs: listenAddrs, listenAddrs: listenAddrs,
@ -566,7 +573,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
} }
s.witnessBeacon = &preimageBeacon{ s.witnessBeacon = &preimageBeacon{
wCache: dbs.chanStateDB.NewWitnessCache(), wCache: dbs.ChanStateDB.NewWitnessCache(),
subscribers: make(map[uint64]*preimageSubscriber), subscribers: make(map[uint64]*preimageSubscriber),
} }
@ -580,7 +587,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
uint32(currentHeight), currentHash, cc.ChainNotifier, uint32(currentHeight), currentHash, cc.ChainNotifier,
) )
s.invoices = invoices.NewRegistry( s.invoices = invoices.NewRegistry(
dbs.chanStateDB, expiryWatcher, &registryConfig, dbs.ChanStateDB, expiryWatcher, &registryConfig,
) )
s.htlcNotifier = htlcswitch.NewHtlcNotifier(time.Now) s.htlcNotifier = htlcswitch.NewHtlcNotifier(time.Now)
@ -589,7 +596,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
thresholdMSats := lnwire.NewMSatFromSatoshis(thresholdSats) thresholdMSats := lnwire.NewMSatFromSatoshis(thresholdSats)
s.htlcSwitch, err = htlcswitch.New(htlcswitch.Config{ s.htlcSwitch, err = htlcswitch.New(htlcswitch.Config{
DB: dbs.chanStateDB, DB: dbs.ChanStateDB,
FetchAllOpenChannels: s.chanStateDB.FetchAllOpenChannels, FetchAllOpenChannels: s.chanStateDB.FetchAllOpenChannels,
FetchClosedChannels: s.chanStateDB.FetchClosedChannels, FetchClosedChannels: s.chanStateDB.FetchClosedChannels,
LocalChannelClose: func(pubKey []byte, LocalChannelClose: func(pubKey []byte,
@ -606,7 +613,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
peer.HandleLocalCloseChanReqs(request) peer.HandleLocalCloseChanReqs(request)
}, },
FwdingLog: dbs.chanStateDB.ForwardingLog(), FwdingLog: dbs.ChanStateDB.ForwardingLog(),
SwitchPackager: channeldb.NewSwitchPackager(), SwitchPackager: channeldb.NewSwitchPackager(),
ExtractErrorEncrypter: s.sphinx.ExtractErrorEncrypter, ExtractErrorEncrypter: s.sphinx.ExtractErrorEncrypter,
FetchLastChannelUpdate: s.fetchLastChanUpdate(), FetchLastChannelUpdate: s.fetchLastChanUpdate(),
@ -630,12 +637,13 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
ChanStatusSampleInterval: cfg.ChanStatusSampleInterval, ChanStatusSampleInterval: cfg.ChanStatusSampleInterval,
ChanEnableTimeout: cfg.ChanEnableTimeout, ChanEnableTimeout: cfg.ChanEnableTimeout,
ChanDisableTimeout: cfg.ChanDisableTimeout, ChanDisableTimeout: cfg.ChanDisableTimeout,
OurPubKey: nodeKeyECDH.PubKey(), OurPubKey: nodeKeyDesc.PubKey,
OurKeyLoc: nodeKeyDesc.KeyLocator,
MessageSigner: s.nodeSigner, MessageSigner: s.nodeSigner,
IsChannelActive: s.htlcSwitch.HasActiveLink, IsChannelActive: s.htlcSwitch.HasActiveLink,
ApplyChannelUpdate: s.applyChannelUpdate, ApplyChannelUpdate: s.applyChannelUpdate,
DB: s.chanStateDB, DB: s.chanStateDB,
Graph: dbs.graphDB.ChannelGraph(), Graph: dbs.GraphDB.ChannelGraph(),
} }
chanStatusMgr, err := netann.NewChanStatusManager(chanStatusMgrCfg) chanStatusMgr, err := netann.NewChanStatusManager(chanStatusMgrCfg)
@ -727,7 +735,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
// As the graph can be obtained at anytime from the network, we won't // As the graph can be obtained at anytime from the network, we won't
// replicate it, and instead it'll only be stored locally. // replicate it, and instead it'll only be stored locally.
chanGraph := dbs.graphDB.ChannelGraph() chanGraph := dbs.GraphDB.ChannelGraph()
// We'll now reconstruct a node announcement based on our current // We'll now reconstruct a node announcement based on our current
// configuration so we can send it out as a sort of heart beat within // configuration so we can send it out as a sort of heart beat within
@ -758,7 +766,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
Features: s.featureMgr.Get(feature.SetNodeAnn), Features: s.featureMgr.Get(feature.SetNodeAnn),
Color: color, Color: color,
} }
copy(selfNode.PubKeyBytes[:], nodeKeyECDH.PubKey().SerializeCompressed()) copy(selfNode.PubKeyBytes[:], nodeKeyDesc.PubKey.SerializeCompressed())
// Based on the disk representation of the node announcement generated // Based on the disk representation of the node announcement generated
// above, we'll generate a node announcement that can go out on the // above, we'll generate a node announcement that can go out on the
@ -771,7 +779,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
// With the announcement generated, we'll sign it to properly // With the announcement generated, we'll sign it to properly
// authenticate the message on the network. // authenticate the message on the network.
authSig, err := netann.SignAnnouncement( authSig, err := netann.SignAnnouncement(
s.nodeSigner, nodeKeyECDH.PubKey(), nodeAnn, s.nodeSigner, nodeKeyDesc.KeyLocator, nodeAnn,
) )
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to generate signature for "+ return nil, fmt.Errorf("unable to generate signature for "+
@ -794,7 +802,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
// The router will get access to the payment ID sequencer, such that it // The router will get access to the payment ID sequencer, such that it
// can generate unique payment IDs. // can generate unique payment IDs.
sequencer, err := htlcswitch.NewPersistentSequencer(dbs.chanStateDB) sequencer, err := htlcswitch.NewPersistentSequencer(dbs.ChanStateDB)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -839,7 +847,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
} }
s.missionControl, err = routing.NewMissionControl( s.missionControl, err = routing.NewMissionControl(
dbs.chanStateDB, selfNode.PubKeyBytes, dbs.ChanStateDB, selfNode.PubKeyBytes,
&routing.MissionControlConfig{ &routing.MissionControlConfig{
ProbabilityEstimatorCfg: estimatorCfg, ProbabilityEstimatorCfg: estimatorCfg,
MaxMcHistory: routingConfig.MaxMcHistory, MaxMcHistory: routingConfig.MaxMcHistory,
@ -876,7 +884,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
PathFindingConfig: pathFindingConfig, PathFindingConfig: pathFindingConfig,
} }
paymentControl := channeldb.NewPaymentControl(dbs.chanStateDB) paymentControl := channeldb.NewPaymentControl(dbs.ChanStateDB)
s.controlTower = routing.NewControlTower(paymentControl) s.controlTower = routing.NewControlTower(paymentControl)
@ -906,11 +914,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
} }
chanSeries := discovery.NewChanSeries(s.graphDB) chanSeries := discovery.NewChanSeries(s.graphDB)
gossipMessageStore, err := discovery.NewMessageStore(dbs.chanStateDB) gossipMessageStore, err := discovery.NewMessageStore(dbs.ChanStateDB)
if err != nil { if err != nil {
return nil, err return nil, err
} }
waitingProofStore, err := channeldb.NewWaitingProofStore(dbs.chanStateDB) waitingProofStore, err := channeldb.NewWaitingProofStore(dbs.ChanStateDB)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -942,9 +950,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
PinnedSyncers: cfg.Gossip.PinnedSyncers, PinnedSyncers: cfg.Gossip.PinnedSyncers,
MaxChannelUpdateBurst: cfg.Gossip.MaxChannelUpdateBurst, MaxChannelUpdateBurst: cfg.Gossip.MaxChannelUpdateBurst,
ChannelUpdateInterval: cfg.Gossip.ChannelUpdateInterval, ChannelUpdateInterval: cfg.Gossip.ChannelUpdateInterval,
}, }, nodeKeyDesc)
nodeKeyECDH.PubKey(),
)
s.localChanMgr = &localchans.Manager{ s.localChanMgr = &localchans.Manager{
ForAllOutgoingChannels: s.chanRouter.ForAllOutgoingChannels, ForAllOutgoingChannels: s.chanRouter.ForAllOutgoingChannels,
@ -954,7 +960,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
} }
utxnStore, err := contractcourt.NewNurseryStore( utxnStore, err := contractcourt.NewNurseryStore(
s.cfg.ActiveNetParams.GenesisHash, dbs.chanStateDB, s.cfg.ActiveNetParams.GenesisHash, dbs.ChanStateDB,
) )
if err != nil { if err != nil {
srvrLog.Errorf("unable to create nursery store: %v", err) srvrLog.Errorf("unable to create nursery store: %v", err)
@ -965,7 +971,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
sweep.DefaultBatchWindowDuration) sweep.DefaultBatchWindowDuration)
sweeperStore, err := sweep.NewSweeperStore( sweeperStore, err := sweep.NewSweeperStore(
dbs.chanStateDB, s.cfg.ActiveNetParams.GenesisHash, dbs.ChanStateDB, s.cfg.ActiveNetParams.GenesisHash,
) )
if err != nil { if err != nil {
srvrLog.Errorf("unable to create sweeper store: %v", err) srvrLog.Errorf("unable to create sweeper store: %v", err)
@ -1115,7 +1121,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
PaymentsExpirationGracePeriod: cfg.PaymentsExpirationGracePeriod, PaymentsExpirationGracePeriod: cfg.PaymentsExpirationGracePeriod,
IsForwardedHTLC: s.htlcSwitch.IsForwardedHTLC, IsForwardedHTLC: s.htlcSwitch.IsForwardedHTLC,
Clock: clock.NewDefaultClock(), Clock: clock.NewDefaultClock(),
}, dbs.chanStateDB) }, dbs.ChanStateDB)
s.breachArbiter = contractcourt.NewBreachArbiter(&contractcourt.BreachConfig{ s.breachArbiter = contractcourt.NewBreachArbiter(&contractcourt.BreachConfig{
CloseLink: closeLink, CloseLink: closeLink,
@ -1127,7 +1133,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
ContractBreaches: contractBreaches, ContractBreaches: contractBreaches,
Signer: cc.Wallet.Cfg.Signer, Signer: cc.Wallet.Cfg.Signer,
Store: contractcourt.NewRetributionStore( Store: contractcourt.NewRetributionStore(
dbs.chanStateDB, dbs.ChanStateDB,
), ),
}) })
@ -1150,7 +1156,8 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
s.fundingMgr, err = funding.NewFundingManager(funding.Config{ s.fundingMgr, err = funding.NewFundingManager(funding.Config{
NoWumboChans: !cfg.ProtocolOptions.Wumbo(), NoWumboChans: !cfg.ProtocolOptions.Wumbo(),
IDKey: nodeKeyECDH.PubKey(), IDKey: nodeKeyDesc.PubKey,
IDKeyLoc: nodeKeyDesc.KeyLocator,
Wallet: cc.Wallet, Wallet: cc.Wallet,
PublishTransaction: cc.Wallet.PublishTransaction, PublishTransaction: cc.Wallet.PublishTransaction,
UpdateLabel: func(hash chainhash.Hash, label string) error { UpdateLabel: func(hash chainhash.Hash, label string) error {
@ -1158,15 +1165,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
}, },
Notifier: cc.ChainNotifier, Notifier: cc.ChainNotifier,
FeeEstimator: cc.FeeEstimator, FeeEstimator: cc.FeeEstimator,
SignMessage: func(pubKey *btcec.PublicKey, SignMessage: cc.MsgSigner.SignMessage,
msg []byte) (input.Signature, error) {
if pubKey.IsEqual(nodeKeyECDH.PubKey()) {
return s.nodeSigner.SignMessage(pubKey, msg)
}
return cc.MsgSigner.SignMessage(pubKey, msg)
},
CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) { CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) {
return s.genNodeAnnouncement(true) return s.genNodeAnnouncement(true)
}, },
@ -1348,7 +1347,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
// static backup of the latest channel state. // static backup of the latest channel state.
chanNotifier := &channelNotifier{ chanNotifier := &channelNotifier{
chanNotifier: s.channelNotifier, chanNotifier: s.channelNotifier,
addrs: dbs.chanStateDB, addrs: dbs.ChanStateDB,
} }
backupFile := chanbackup.NewMultiFile(cfg.BackupFilePath) backupFile := chanbackup.NewMultiFile(cfg.BackupFilePath)
startingChans, err := chanbackup.FetchStaticChanBackups( startingChans, err := chanbackup.FetchStaticChanBackups(
@ -1416,7 +1415,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
SecretKeyRing: s.cc.KeyRing, SecretKeyRing: s.cc.KeyRing,
Dial: cfg.net.Dial, Dial: cfg.net.Dial,
AuthDial: authDial, AuthDial: authDial,
DB: dbs.towerClientDB, DB: dbs.TowerClientDB,
Policy: policy, Policy: policy,
ChainHash: *s.cfg.ActiveNetParams.GenesisHash, ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
MinBackoff: 10 * time.Second, MinBackoff: 10 * time.Second,
@ -1439,7 +1438,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
SecretKeyRing: s.cc.KeyRing, SecretKeyRing: s.cc.KeyRing,
Dial: cfg.net.Dial, Dial: cfg.net.Dial,
AuthDial: authDial, AuthDial: authDial,
DB: dbs.towerClientDB, DB: dbs.TowerClientDB,
Policy: anchorPolicy, Policy: anchorPolicy,
ChainHash: *s.cfg.ActiveNetParams.GenesisHash, ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
MinBackoff: 10 * time.Second, MinBackoff: 10 * time.Second,
@ -2613,7 +2612,7 @@ func (s *server) genNodeAnnouncement(refresh bool,
// Otherwise, we'll sign a new update after applying all of the passed // Otherwise, we'll sign a new update after applying all of the passed
// modifiers. // modifiers.
err := netann.SignNodeAnnouncement( err := netann.SignNodeAnnouncement(
s.nodeSigner, s.identityECDH.PubKey(), s.currentNodeAnn, s.nodeSigner, s.identityKeyLoc, s.currentNodeAnn,
modifiers..., modifiers...,
) )
if err != nil { if err != nil {

View file

@ -27,6 +27,45 @@ var (
ErrUnlockTimeout = errors.New("got no unlock message before timeout") ErrUnlockTimeout = errors.New("got no unlock message before timeout")
) )
// WalletUnlockParams holds the variables used to parameterize the unlocking of
// lnd's wallet after it has already been created.
type WalletUnlockParams struct {
// Password is the public and private wallet passphrase.
Password []byte
// Birthday specifies the approximate time that this wallet was created.
// This is used to bound any rescans on startup.
Birthday time.Time
// RecoveryWindow specifies the address lookahead when entering recovery
// mode. A recovery will be attempted if this value is non-zero.
RecoveryWindow uint32
// Wallet is the loaded and unlocked Wallet. This is returned
// from the unlocker service to avoid it being unlocked twice (once in
// the unlocker service to check if the password is correct and again
// later when lnd actually uses it). Because unlocking involves scrypt
// which is resource intensive, we want to avoid doing it twice.
Wallet *wallet.Wallet
// ChansToRestore a set of static channel backups that should be
// restored before the main server instance starts up.
ChansToRestore ChannelsToRecover
// UnloadWallet is a function for unloading the wallet, which should
// be called on shutdown.
UnloadWallet func() error
// StatelessInit signals that the user requested the daemon to be
// initialized stateless, which means no unencrypted macaroons should be
// written to disk.
StatelessInit bool
// MacResponseChan is the channel for sending back the admin macaroon to
// the WalletUnlocker service.
MacResponseChan chan []byte
}
// ChannelsToRecover wraps any set of packed (serialized+encrypted) channel // ChannelsToRecover wraps any set of packed (serialized+encrypted) channel
// back ups together. These can be passed in when unlocking the wallet, or // back ups together. These can be passed in when unlocking the wallet, or
// creating a new wallet for the first time with an existing seed. // creating a new wallet for the first time with an existing seed.

View file

@ -102,8 +102,10 @@ var (
testMessageSigner = MessageSigner{ testMessageSigner = MessageSigner{
SignCompact: func(msg []byte) ([]byte, error) { SignCompact: func(msg []byte) ([]byte, error) {
sig, err := btcec.SignCompact(btcec.S256(), hash := chainhash.HashB(msg)
testPrivKey, chainhash.HashB(msg), true) sig, err := btcec.SignCompact(
btcec.S256(), testPrivKey, hash, true,
)
if err != nil { if err != nil {
return nil, fmt.Errorf("can't sign the "+ return nil, fmt.Errorf("can't sign the "+
"message: %v", err) "message: %v", err)