mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-02-21 22:11:41 +01:00
Merge pull request #5708 from guggero/remote-signer-extract-wallet
refactor: move towards more configurable implementation details
This commit is contained in:
commit
00af978bf2
44 changed files with 4102 additions and 3681 deletions
|
@ -50,7 +50,7 @@ jobs:
|
|||
name: Bitcoind Integration ARM
|
||||
script:
|
||||
- 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
|
||||
services:
|
||||
- docker
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"github.com/btcsuite/btcd/rpcclient"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/btcsuite/btcwallet/chain"
|
||||
"github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/lightninglabs/neutrino"
|
||||
"github.com/lightningnetwork/lnd/blockcache"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
|
@ -35,6 +34,7 @@ import (
|
|||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
"github.com/lightningnetwork/lnd/routing/chainview"
|
||||
"github.com/lightningnetwork/lnd/walletunlocker"
|
||||
)
|
||||
|
||||
// Config houses necessary fields that a chainControl instance needs to
|
||||
|
@ -77,26 +77,12 @@ type Config struct {
|
|||
// state.
|
||||
ChanStateDB *channeldb.ChannelStateDB
|
||||
|
||||
// BlockCacheSize is the size (in bytes) of blocks kept in memory.
|
||||
BlockCacheSize uint64
|
||||
// BlockCache is the main cache for storing block information.
|
||||
BlockCache *blockcache.BlockCache
|
||||
|
||||
// PrivateWalletPw is the private wallet password to the underlying
|
||||
// btcwallet instance.
|
||||
PrivateWalletPw []byte
|
||||
|
||||
// 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
|
||||
// WalletUnlockParams are the parameters that were used for unlocking
|
||||
// the main wallet.
|
||||
WalletUnlockParams *walletunlocker.WalletUnlockParams
|
||||
|
||||
// NeutrinoCS is a pointer to a neutrino ChainService. Must be non-nil if
|
||||
// using neutrino.
|
||||
|
@ -113,13 +99,6 @@ type Config struct {
|
|||
// TCP connections to Bitcoin peers in the event of a pruned block being
|
||||
// requested.
|
||||
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 (
|
||||
|
@ -181,53 +160,80 @@ var DefaultLtcChannelConstraints = channeldb.ChannelConstraints{
|
|||
MaxAcceptedHtlcs: input.MaxHTLCNumber / 2,
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// ChainIO represents an abstraction over a source that can query the blockchain.
|
||||
ChainIO lnwallet.BlockChainIO
|
||||
// PartialChainControl contains all the primary interfaces of the chain control
|
||||
// that can be purely constructed from the global configuration. No wallet
|
||||
// instance is required for constructing this partial state.
|
||||
type PartialChainControl struct {
|
||||
// Cfg is the configuration that was used to create the partial chain
|
||||
// control.
|
||||
Cfg *Config
|
||||
|
||||
// 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
|
||||
// node.
|
||||
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
|
||||
|
||||
// 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 input.Signer
|
||||
|
||||
// KeyRing represents a set of keys that we have the private keys to.
|
||||
KeyRing keychain.SecretKeyRing
|
||||
|
||||
// Wc is an abstraction over some basic wallet commands. This base set of commands
|
||||
// will be provided to the Wallet *LightningWallet raw pointer below.
|
||||
// Wc is an abstraction over some basic wallet commands. This base set
|
||||
// of commands will be provided to the Wallet *LightningWallet raw
|
||||
// pointer below.
|
||||
Wc lnwallet.WalletController
|
||||
|
||||
// MsgSigner is used to sign arbitrary messages.
|
||||
MsgSigner lnwallet.MessageSigner
|
||||
|
||||
// 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
|
||||
|
||||
// Wallet is our LightningWallet that also contains the abstract Wc above. This wallet
|
||||
// handles all of the lightning operations.
|
||||
// Wallet is our LightningWallet that also contains the abstract Wc
|
||||
// above. This wallet handles all of the lightning operations.
|
||||
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
|
||||
// constraints that are to be used when funding a Bitcoin channel.
|
||||
// GenDefaultBtcConstraints generates the default set of channel constraints
|
||||
// that are to be used when funding a Bitcoin channel.
|
||||
func GenDefaultBtcConstraints() channeldb.ChannelConstraints {
|
||||
// We use the dust limit for the maximally sized witness program with
|
||||
// a 40-byte data push.
|
||||
|
@ -239,25 +245,21 @@ func GenDefaultBtcConstraints() channeldb.ChannelConstraints {
|
|||
}
|
||||
}
|
||||
|
||||
// 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(cfg *Config, blockCache *blockcache.BlockCache) (
|
||||
*ChainControl, func(), error) {
|
||||
|
||||
// NewPartialChainControl creates a new partial chain control that contains all
|
||||
// the parts that can be purely constructed from the passed in global
|
||||
// configuration and doesn't need any wallet instance yet.
|
||||
func NewPartialChainControl(cfg *Config) (*PartialChainControl, func(), error) {
|
||||
// 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.
|
||||
homeChainConfig := cfg.Bitcoin
|
||||
if cfg.PrimaryChain() == LitecoinChain {
|
||||
homeChainConfig = cfg.Litecoin
|
||||
}
|
||||
log.Infof("Primary chain is set to: %v",
|
||||
cfg.PrimaryChain())
|
||||
log.Infof("Primary chain is set to: %v", cfg.PrimaryChain())
|
||||
|
||||
cc := &ChainControl{}
|
||||
cc := &PartialChainControl{
|
||||
Cfg: cfg,
|
||||
}
|
||||
|
||||
switch cfg.PrimaryChain() {
|
||||
case BitcoinChain:
|
||||
|
@ -288,20 +290,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
"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
|
||||
|
||||
heightHintCacheConfig := chainntnfs.CacheConfig{
|
||||
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
|
||||
// the neutrino light client.
|
||||
cc.ChainNotifier = neutrinonotify.New(
|
||||
cfg.NeutrinoCS, hintCache, hintCache, blockCache,
|
||||
cfg.NeutrinoCS, hintCache, hintCache, cfg.BlockCache,
|
||||
)
|
||||
cc.ChainView, err = chainview.NewCfFilteredChainView(
|
||||
cfg.NeutrinoCS, blockCache,
|
||||
cfg.NeutrinoCS, cfg.BlockCache,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -347,13 +336,13 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
cfg.FeeURL = cfg.NeutrinoMode.FeeURL
|
||||
}
|
||||
|
||||
walletConfig.ChainSource = chain.NewNeutrinoClient(
|
||||
cc.ChainSource = chain.NewNeutrinoClient(
|
||||
cfg.ActiveNetParams.Params, cfg.NeutrinoCS,
|
||||
)
|
||||
|
||||
// Get our best block as a health check.
|
||||
cc.HealthCheck = func() error {
|
||||
_, _, err := walletConfig.ChainSource.GetBestBlock()
|
||||
_, _, err := cc.ChainSource.GetBestBlock()
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -432,12 +421,12 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
|
||||
cc.ChainNotifier = bitcoindnotify.New(
|
||||
bitcoindConn, cfg.ActiveNetParams.Params, hintCache,
|
||||
hintCache, blockCache,
|
||||
hintCache, cfg.BlockCache,
|
||||
)
|
||||
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
|
||||
// proper fee estimator for testnet.
|
||||
|
@ -564,7 +553,7 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
}
|
||||
cc.ChainNotifier, err = btcdnotify.New(
|
||||
rpcConfig, cfg.ActiveNetParams.Params, hintCache,
|
||||
hintCache, blockCache,
|
||||
hintCache, cfg.BlockCache,
|
||||
)
|
||||
if err != nil {
|
||||
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
|
||||
// used within the routing layer.
|
||||
cc.ChainView, err = chainview.NewBtcdFilteredChainView(
|
||||
*rpcConfig, blockCache,
|
||||
*rpcConfig, cfg.BlockCache,
|
||||
)
|
||||
if err != nil {
|
||||
log.Errorf("unable to create chain view: %v", err)
|
||||
|
@ -588,11 +577,11 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
walletConfig.ChainSource = chainRPC
|
||||
cc.ChainSource = chainRPC
|
||||
|
||||
// Use a query for our best block as a health check.
|
||||
cc.HealthCheck = func() error {
|
||||
_, _, err := walletConfig.ChainSource.GetBestBlock()
|
||||
_, _, err := cc.ChainSource.GetBestBlock()
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -648,12 +637,6 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
}
|
||||
|
||||
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 err := cc.FeeEstimator.Stop(); err != nil {
|
||||
log.Errorf("Failed to stop feeEstimator: %v", err)
|
||||
|
@ -666,7 +649,37 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
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 {
|
||||
fmt.Printf("unable to create wallet controller: %v\n", err)
|
||||
return nil, ccCleanup, err
|
||||
|
@ -677,29 +690,23 @@ func NewChainControl(cfg *Config, blockCache *blockcache.BlockCache) (
|
|||
cc.ChainIO = wc
|
||||
cc.Wc = wc
|
||||
|
||||
// Select the default channel constraints for the primary chain.
|
||||
channelConstraints := GenDefaultBtcConstraints()
|
||||
if cfg.PrimaryChain() == LitecoinChain {
|
||||
channelConstraints = DefaultLtcChannelConstraints
|
||||
}
|
||||
|
||||
keyRing := keychain.NewBtcWalletKeyRing(
|
||||
wc.InternalWallet(), cfg.ActiveNetParams.CoinType,
|
||||
wc.InternalWallet(), walletConfig.CoinType,
|
||||
)
|
||||
cc.KeyRing = keyRing
|
||||
|
||||
// Create, and start the lnwallet, which handles the core payment
|
||||
// channel logic, and exposes control via proxy state machines.
|
||||
walletCfg := lnwallet.Config{
|
||||
Database: cfg.ChanStateDB,
|
||||
Database: pcc.Cfg.ChanStateDB,
|
||||
Notifier: cc.ChainNotifier,
|
||||
WalletController: wc,
|
||||
Signer: cc.Signer,
|
||||
FeeEstimator: cc.FeeEstimator,
|
||||
SecretKeyRing: keyRing,
|
||||
ChainIO: cc.ChainIO,
|
||||
DefaultConstraints: channelConstraints,
|
||||
NetParams: *cfg.ActiveNetParams.Params,
|
||||
DefaultConstraints: cc.ChannelConstraints,
|
||||
NetParams: *walletConfig.NetParams,
|
||||
}
|
||||
lnWallet, err := lnwallet.NewLightningWallet(walletCfg)
|
||||
if err != nil {
|
||||
|
|
|
@ -31,11 +31,12 @@ func main() {
|
|||
// Help was requested, exit normally.
|
||||
os.Exit(0)
|
||||
}
|
||||
implCfg := loadedConfig.ImplementationConfig(shutdownInterceptor)
|
||||
|
||||
// Call the "real" main in a nested manner so the defers will properly
|
||||
// be executed in the case of a graceful shutdown.
|
||||
if err = lnd.Main(
|
||||
loadedConfig, lnd.ListenerCfg{}, shutdownInterceptor,
|
||||
loadedConfig, lnd.ListenerCfg{}, implCfg, shutdownInterceptor,
|
||||
); err != nil {
|
||||
_, _ = fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
|
|
15
config.go
15
config.go
|
@ -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
|
||||
// passed path, cleans the result, and returns it.
|
||||
// This function is taken from https://github.com/btcsuite/btcd
|
||||
|
|
1100
config_builder.go
Normal file
1100
config_builder.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -15,6 +15,7 @@ import (
|
|||
"github.com/lightningnetwork/lnd/batch"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnpeer"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
|
@ -316,6 +317,10 @@ type AuthenticatedGossiper struct {
|
|||
// selfKey is the identity public key of the backing Lightning node.
|
||||
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
|
||||
// goroutine per channel ID. This is done to ensure that when
|
||||
// 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
|
||||
// passed configuration parameters.
|
||||
func New(cfg Config, selfKey *btcec.PublicKey) *AuthenticatedGossiper {
|
||||
func New(cfg Config, selfKeyDesc *keychain.KeyDescriptor) *AuthenticatedGossiper {
|
||||
gossiper := &AuthenticatedGossiper{
|
||||
selfKey: selfKey,
|
||||
selfKey: selfKeyDesc.PubKey,
|
||||
selfKeyLoc: selfKeyDesc.KeyLocator,
|
||||
cfg: &cfg,
|
||||
networkMsgs: make(chan *networkMsg),
|
||||
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
|
||||
// announcement itself and update the timestamp to ensure it propagate.
|
||||
err := netann.SignChannelUpdate(
|
||||
d.cfg.AnnSigner, d.selfKey, chanUpdate,
|
||||
d.cfg.AnnSigner, d.selfKeyLoc, chanUpdate,
|
||||
netann.ChanUpdSetTimestamp,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/lightningnetwork/lnd/batch"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/kvdb"
|
||||
"github.com/lightningnetwork/lnd/lnpeer"
|
||||
"github.com/lightningnetwork/lnd/lntest/mock"
|
||||
|
@ -46,11 +47,15 @@ var (
|
|||
R: new(big.Int),
|
||||
S: new(big.Int),
|
||||
}
|
||||
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
||||
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
||||
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
||||
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
||||
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
|
||||
|
||||
selfKeyPriv, _ = btcec.NewPrivateKey(btcec.S256())
|
||||
selfKeyPub = selfKeyPriv.PubKey()
|
||||
selfKeyDesc = &keychain.KeyDescriptor{
|
||||
PubKey: selfKeyPriv.PubKey(),
|
||||
KeyLocator: testKeyLoc,
|
||||
}
|
||||
|
||||
bitcoinKeyPriv1, _ = btcec.NewPrivateKey(btcec.S256())
|
||||
bitcoinKeyPub1 = bitcoinKeyPriv1.PubKey()
|
||||
|
@ -568,7 +573,7 @@ func createNodeAnnouncement(priv *btcec.PrivateKey,
|
|||
}
|
||||
|
||||
signer := mock.SingleSigner{Privkey: priv}
|
||||
sig, err := netann.SignAnnouncement(&signer, priv.PubKey(), a)
|
||||
sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -618,9 +623,8 @@ func createUpdateAnnouncement(blockHeight uint32,
|
|||
}
|
||||
|
||||
func signUpdate(nodeKey *btcec.PrivateKey, a *lnwire.ChannelUpdate) error {
|
||||
pub := nodeKey.PubKey()
|
||||
signer := mock.SingleSigner{Privkey: nodeKey}
|
||||
sig, err := netann.SignAnnouncement(&signer, pub, a)
|
||||
sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -667,9 +671,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
|
|||
|
||||
a := createAnnouncementWithoutProof(blockHeight, key1.PubKey(), key2.PubKey(), extraBytes...)
|
||||
|
||||
pub := key1.PubKey()
|
||||
signer := mock.SingleSigner{Privkey: key1}
|
||||
sig, err := netann.SignAnnouncement(&signer, pub, a)
|
||||
sig, err := netann.SignAnnouncement(&signer, testKeyLoc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -678,9 +681,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pub = key2.PubKey()
|
||||
signer = mock.SingleSigner{Privkey: key2}
|
||||
sig, err = netann.SignAnnouncement(&signer, pub, a)
|
||||
sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -689,9 +691,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pub = bitcoinKeyPriv1.PubKey()
|
||||
signer = mock.SingleSigner{Privkey: bitcoinKeyPriv1}
|
||||
sig, err = netann.SignAnnouncement(&signer, pub, a)
|
||||
sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -700,9 +701,8 @@ func createChannelAnnouncement(blockHeight uint32, key1, key2 *btcec.PrivateKey,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
pub = bitcoinKeyPriv2.PubKey()
|
||||
signer = mock.SingleSigner{Privkey: bitcoinKeyPriv2}
|
||||
sig, err = netann.SignAnnouncement(&signer, pub, a)
|
||||
sig, err = netann.SignAnnouncement(&signer, testKeyLoc, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -785,7 +785,7 @@ func createTestCtx(startHeight uint32) (*testCtx, func(), error) {
|
|||
MinimumBatchSize: 10,
|
||||
MaxChannelUpdateBurst: DefaultMaxChannelUpdateBurst,
|
||||
ChannelUpdateInterval: DefaultChannelUpdateInterval,
|
||||
}, selfKeyPub)
|
||||
}, selfKeyDesc)
|
||||
|
||||
if err := gossiper.Start(); err != nil {
|
||||
cleanUpDb()
|
||||
|
@ -1480,7 +1480,10 @@ func TestSignatureAnnouncementRetryAtStartup(t *testing.T) {
|
|||
NumActiveSyncers: 3,
|
||||
MinimumBatchSize: 10,
|
||||
SubBatchDelay: time.Second * 5,
|
||||
}, ctx.gossiper.selfKey)
|
||||
}, &keychain.KeyDescriptor{
|
||||
PubKey: ctx.gossiper.selfKey,
|
||||
KeyLocator: ctx.gossiper.selfKeyLoc,
|
||||
})
|
||||
if err != nil {
|
||||
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
|
||||
// (i.e., an unadvertised channel), followed by a node announcement for
|
||||
// this same channel announcement.
|
||||
chanAnn := createAnnouncementWithoutProof(startingHeight-2, selfKeyPub, remoteKeyPub1)
|
||||
chanAnn := createAnnouncementWithoutProof(
|
||||
startingHeight-2, selfKeyDesc.PubKey, remoteKeyPub1,
|
||||
)
|
||||
pubKey := remoteKeyPriv1.PubKey()
|
||||
|
||||
select {
|
||||
|
@ -3671,8 +3676,12 @@ func TestProcessChannelAnnouncementOptionalMsgFields(t *testing.T) {
|
|||
}
|
||||
defer cleanup()
|
||||
|
||||
chanAnn1 := createAnnouncementWithoutProof(100, selfKeyPub, remoteKeyPub1)
|
||||
chanAnn2 := createAnnouncementWithoutProof(101, selfKeyPub, remoteKeyPub1)
|
||||
chanAnn1 := createAnnouncementWithoutProof(
|
||||
100, selfKeyDesc.PubKey, remoteKeyPub1,
|
||||
)
|
||||
chanAnn2 := createAnnouncementWithoutProof(
|
||||
101, selfKeyDesc.PubKey, remoteKeyPub1,
|
||||
)
|
||||
|
||||
// assertOptionalMsgFields is a helper closure that ensures the optional
|
||||
// message fields were set as intended.
|
||||
|
|
|
@ -353,6 +353,10 @@ you.
|
|||
* [Only upload itest logs on failure, fix more
|
||||
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
|
||||
|
||||
* [Ensure single writer for legacy
|
||||
|
|
|
@ -294,6 +294,10 @@ type Config struct {
|
|||
// Lightning Network.
|
||||
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
|
||||
// funds from on-chain transaction outputs into Lightning channels.
|
||||
Wallet *lnwallet.LightningWallet
|
||||
|
@ -322,8 +326,8 @@ type Config struct {
|
|||
//
|
||||
// TODO(roasbeef): should instead pass on this responsibility to a
|
||||
// distinct sub-system?
|
||||
SignMessage func(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error)
|
||||
SignMessage func(keyLoc keychain.KeyLocator,
|
||||
msg []byte) (*btcec.Signature, error)
|
||||
|
||||
// CurrentNodeAnnouncement should return the latest, fully signed node
|
||||
// announcement from the backing Lightning Network node.
|
||||
|
@ -2523,7 +2527,7 @@ func (f *Manager) addToRouterGraph(completeChan *channeldb.OpenChannel,
|
|||
|
||||
ann, err := f.newChanAnnouncement(
|
||||
f.cfg.IDKey, completeChan.IdentityPub,
|
||||
completeChan.LocalChanCfg.MultiSigKey.PubKey,
|
||||
&completeChan.LocalChanCfg.MultiSigKey,
|
||||
completeChan.RemoteChanCfg.MultiSigKey.PubKey, *shortChanID,
|
||||
chanID, fwdMinHTLC, fwdMaxHTLC,
|
||||
)
|
||||
|
@ -2686,7 +2690,7 @@ func (f *Manager) annAfterSixConfs(completeChan *channeldb.OpenChannel,
|
|||
// public and usable for other nodes for routing.
|
||||
err = f.announceChannel(
|
||||
f.cfg.IDKey, completeChan.IdentityPub,
|
||||
completeChan.LocalChanCfg.MultiSigKey.PubKey,
|
||||
&completeChan.LocalChanCfg.MultiSigKey,
|
||||
completeChan.RemoteChanCfg.MultiSigKey.PubKey,
|
||||
*shortChanID, chanID,
|
||||
)
|
||||
|
@ -2826,10 +2830,11 @@ type chanAnnouncement struct {
|
|||
// 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
|
||||
// channel.
|
||||
func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
|
||||
localFundingKey, remoteFundingKey *btcec.PublicKey,
|
||||
shortChanID lnwire.ShortChannelID, chanID lnwire.ChannelID,
|
||||
fwdMinHTLC, fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) {
|
||||
func (f *Manager) newChanAnnouncement(localPubKey,
|
||||
remotePubKey *btcec.PublicKey, localFundingKey *keychain.KeyDescriptor,
|
||||
remoteFundingKey *btcec.PublicKey, shortChanID lnwire.ShortChannelID,
|
||||
chanID lnwire.ChannelID, fwdMinHTLC,
|
||||
fwdMaxHTLC lnwire.MilliSatoshi) (*chanAnnouncement, error) {
|
||||
|
||||
chainHash := *f.cfg.Wallet.Cfg.NetParams.GenesisHash
|
||||
|
||||
|
@ -2857,7 +2862,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
|
|||
if bytes.Compare(selfBytes, remoteBytes) == -1 {
|
||||
copy(chanAnn.NodeID1[:], localPubKey.SerializeCompressed())
|
||||
copy(chanAnn.NodeID2[:], remotePubKey.SerializeCompressed())
|
||||
copy(chanAnn.BitcoinKey1[:], localFundingKey.SerializeCompressed())
|
||||
copy(chanAnn.BitcoinKey1[:], localFundingKey.PubKey.SerializeCompressed())
|
||||
copy(chanAnn.BitcoinKey2[:], remoteFundingKey.SerializeCompressed())
|
||||
|
||||
// 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.NodeID2[:], localPubKey.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
|
||||
// indicate the "direction" of the update.
|
||||
|
@ -2906,7 +2911,7 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err := f.cfg.SignMessage(f.cfg.IDKey, chanUpdateMsg)
|
||||
sig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanUpdateMsg)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("unable to generate channel "+
|
||||
"update announcement signature: %v", err)
|
||||
|
@ -2928,12 +2933,14 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nodeSig, err := f.cfg.SignMessage(f.cfg.IDKey, chanAnnMsg)
|
||||
nodeSig, err := f.cfg.SignMessage(f.cfg.IDKeyLoc, chanAnnMsg)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("unable to generate node "+
|
||||
"signature for channel announcement: %v", err)
|
||||
}
|
||||
bitcoinSig, err := f.cfg.SignMessage(localFundingKey, chanAnnMsg)
|
||||
bitcoinSig, err := f.cfg.SignMessage(
|
||||
localFundingKey.KeyLocator, chanAnnMsg,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("unable to generate bitcoin "+
|
||||
"signature for node public key: %v", err)
|
||||
|
@ -2969,7 +2976,8 @@ func (f *Manager) newChanAnnouncement(localPubKey, remotePubKey,
|
|||
// the network during its next trickle.
|
||||
// This method is synchronous and will return when all the network requests
|
||||
// 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,
|
||||
chanID lnwire.ChannelID) error {
|
||||
|
||||
|
|
|
@ -110,6 +110,8 @@ var (
|
|||
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
||||
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
||||
|
||||
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
|
||||
|
||||
fundingNetParams = chainreg.BitcoinTestNetParams
|
||||
)
|
||||
|
||||
|
@ -355,11 +357,12 @@ func createTestFundingManager(t *testing.T, privKey *btcec.PrivateKey,
|
|||
|
||||
fundingCfg := Config{
|
||||
IDKey: privKey.PubKey(),
|
||||
IDKeyLoc: testKeyLoc,
|
||||
Wallet: lnw,
|
||||
Notifier: chainNotifier,
|
||||
FeeEstimator: estimator,
|
||||
SignMessage: func(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
SignMessage: func(_ keychain.KeyLocator,
|
||||
_ []byte) (*btcec.Signature, error) {
|
||||
|
||||
return testSig, nil
|
||||
},
|
||||
|
@ -502,11 +505,13 @@ func recreateAliceFundingManager(t *testing.T, alice *testNode) {
|
|||
|
||||
f, err := NewFundingManager(Config{
|
||||
IDKey: oldCfg.IDKey,
|
||||
IDKeyLoc: oldCfg.IDKeyLoc,
|
||||
Wallet: oldCfg.Wallet,
|
||||
Notifier: oldCfg.Notifier,
|
||||
FeeEstimator: oldCfg.FeeEstimator,
|
||||
SignMessage: func(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
SignMessage: func(_ keychain.KeyLocator,
|
||||
_ []byte) (*btcec.Signature, error) {
|
||||
|
||||
return testSig, nil
|
||||
},
|
||||
SendAnnouncement: func(msg lnwire.Message,
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lightningnetwork/lnd/zpay32"
|
||||
)
|
||||
|
||||
|
@ -31,9 +32,11 @@ func Fuzz_encode(data []byte) int {
|
|||
// Then, initialize the testMessageSigner so we can encode out
|
||||
// invoices with this private key.
|
||||
testMessageSigner := zpay32.MessageSigner{
|
||||
SignCompact: func(hash []byte) ([]byte, error) {
|
||||
sig, err := btcec.SignCompact(btcec.S256(),
|
||||
testPrivKey, hash, true)
|
||||
SignCompact: func(msg []byte) ([]byte, error) {
|
||||
hash := chainhash.HashB(msg)
|
||||
sig, err := btcec.SignCompact(
|
||||
btcec.S256(), testPrivKey, hash, true,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't sign the "+
|
||||
"message: %v", err)
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/clock"
|
||||
|
@ -80,8 +81,11 @@ var (
|
|||
testNetParams = &chaincfg.MainNetParams
|
||||
|
||||
testMessageSigner = zpay32.MessageSigner{
|
||||
SignCompact: func(hash []byte) ([]byte, error) {
|
||||
sig, err := btcec.SignCompact(btcec.S256(), testPrivKey, hash, true)
|
||||
SignCompact: func(msg []byte) ([]byte, error) {
|
||||
hash := chainhash.HashB(msg)
|
||||
sig, err := btcec.SignCompact(
|
||||
btcec.S256(), testPrivKey, hash, true,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't sign the message: %v", err)
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/wallet"
|
||||
"github.com/btcsuite/btcwallet/walletdb"
|
||||
|
@ -390,31 +391,49 @@ func (b *BtcWalletKeyRing) ECDH(keyDesc KeyDescriptor,
|
|||
return h, nil
|
||||
}
|
||||
|
||||
// SignDigest signs the given SHA256 message digest with the private key
|
||||
// described in the key descriptor.
|
||||
// SignMessage signs the given message, single or double SHA256 hashing it
|
||||
// first, with the private key described in the key locator.
|
||||
//
|
||||
// NOTE: This is part of the keychain.DigestSignerRing interface.
|
||||
func (b *BtcWalletKeyRing) SignDigest(keyDesc KeyDescriptor,
|
||||
digest [32]byte) (*btcec.Signature, error) {
|
||||
// NOTE: This is part of the keychain.MessageSignerRing interface.
|
||||
func (b *BtcWalletKeyRing) SignMessage(keyLoc KeyLocator,
|
||||
msg []byte, doubleHash bool) (*btcec.Signature, error) {
|
||||
|
||||
privKey, err := b.DerivePrivKey(keyDesc)
|
||||
privKey, err := b.DerivePrivKey(KeyDescriptor{
|
||||
KeyLocator: keyLoc,
|
||||
})
|
||||
if err != nil {
|
||||
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
|
||||
// described in the key descriptor and returns the signature in the compact,
|
||||
// public key recoverable format.
|
||||
// SignMessageCompact signs the given message, single or double SHA256 hashing
|
||||
// it first, with the private key described in the key locator and returns
|
||||
// the signature in the compact, public key recoverable format.
|
||||
//
|
||||
// NOTE: This is part of the keychain.DigestSignerRing interface.
|
||||
func (b *BtcWalletKeyRing) SignDigestCompact(keyDesc KeyDescriptor,
|
||||
digest [32]byte) ([]byte, error) {
|
||||
// NOTE: This is part of the keychain.MessageSignerRing interface.
|
||||
func (b *BtcWalletKeyRing) SignMessageCompact(keyLoc KeyLocator,
|
||||
msg []byte, doubleHash bool) ([]byte, error) {
|
||||
|
||||
privKey, err := b.DerivePrivKey(keyDesc)
|
||||
privKey, err := b.DerivePrivKey(KeyDescriptor{
|
||||
KeyLocator: keyLoc,
|
||||
})
|
||||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -178,7 +178,7 @@ type SecretKeyRing interface {
|
|||
|
||||
ECDHRing
|
||||
|
||||
DigestSignerRing
|
||||
MessageSignerRing
|
||||
|
||||
// DerivePrivKey attempts to derive the private key that corresponds to
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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.
|
||||
type DigestSignerRing interface {
|
||||
// SignDigest signs the given SHA256 message digest with the private key
|
||||
// described in the key descriptor.
|
||||
SignDigest(keyDesc KeyDescriptor, digest [32]byte) (*btcec.Signature,
|
||||
error)
|
||||
type MessageSignerRing interface {
|
||||
// SignMessage signs the given message, single or double SHA256 hashing
|
||||
// it first, with the private key described in the key locator.
|
||||
SignMessage(keyLoc KeyLocator, msg []byte,
|
||||
doubleHash bool) (*btcec.Signature, error)
|
||||
|
||||
// SignDigestCompact signs the given SHA256 message digest with the
|
||||
// private key described in the key descriptor and returns the signature
|
||||
// in the compact, public key recoverable format.
|
||||
SignDigestCompact(keyDesc KeyDescriptor, digest [32]byte) ([]byte, error)
|
||||
// SignMessageCompact signs the given message, single or double SHA256
|
||||
// hashing it first, with the private key described in the key locator
|
||||
// and returns the signature in the compact, public key recoverable
|
||||
// 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
|
||||
// single, specific private key.
|
||||
type SingleKeyDigestSigner interface {
|
||||
type SingleKeyMessageSigner interface {
|
||||
// PubKey returns the public key of the wrapped private key.
|
||||
PubKey() *btcec.PublicKey
|
||||
|
||||
// SignDigest signs the given SHA256 message digest with the wrapped
|
||||
// private key.
|
||||
SignDigest(digest [32]byte) (*btcec.Signature, error)
|
||||
// KeyLocator returns the locator that describes the wrapped private
|
||||
// key.
|
||||
KeyLocator() KeyLocator
|
||||
|
||||
// SignDigestCompact signs the given SHA256 message digest with the
|
||||
// wrapped private key and returns the signature in the compact, public
|
||||
// key recoverable format.
|
||||
SignDigestCompact(digest [32]byte) ([]byte, error)
|
||||
// SignMessage signs the given message, single or double SHA256 hashing
|
||||
// it first, with the wrapped private key.
|
||||
SignMessage(message []byte, doubleHash bool) (*btcec.Signature, 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
|
||||
|
|
|
@ -1,56 +1,91 @@
|
|||
package keychain
|
||||
|
||||
import "github.com/btcsuite/btcd/btcec"
|
||||
import (
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
)
|
||||
|
||||
func NewPubKeyDigestSigner(keyDesc KeyDescriptor,
|
||||
signer DigestSignerRing) *PubKeyDigestSigner {
|
||||
func NewPubKeyMessageSigner(pubKey *btcec.PublicKey, keyLoc KeyLocator,
|
||||
signer MessageSignerRing) *PubKeyMessageSigner {
|
||||
|
||||
return &PubKeyDigestSigner{
|
||||
keyDesc: keyDesc,
|
||||
return &PubKeyMessageSigner{
|
||||
pubKey: pubKey,
|
||||
keyLoc: keyLoc,
|
||||
digestSigner: signer,
|
||||
}
|
||||
}
|
||||
|
||||
type PubKeyDigestSigner struct {
|
||||
keyDesc KeyDescriptor
|
||||
digestSigner DigestSignerRing
|
||||
type PubKeyMessageSigner struct {
|
||||
pubKey *btcec.PublicKey
|
||||
keyLoc KeyLocator
|
||||
digestSigner MessageSignerRing
|
||||
}
|
||||
|
||||
func (p *PubKeyDigestSigner) PubKey() *btcec.PublicKey {
|
||||
return p.keyDesc.PubKey
|
||||
func (p *PubKeyMessageSigner) PubKey() *btcec.PublicKey {
|
||||
return p.pubKey
|
||||
}
|
||||
|
||||
func (p *PubKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature,
|
||||
error) {
|
||||
|
||||
return p.digestSigner.SignDigest(p.keyDesc, digest)
|
||||
func (p *PubKeyMessageSigner) KeyLocator() KeyLocator {
|
||||
return p.keyLoc
|
||||
}
|
||||
|
||||
func (p *PubKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte,
|
||||
error) {
|
||||
func (p *PubKeyMessageSigner) SignMessage(message []byte,
|
||||
doubleHash bool) (*btcec.Signature, error) {
|
||||
|
||||
return p.digestSigner.SignDigestCompact(p.keyDesc, digest)
|
||||
return p.digestSigner.SignMessage(p.keyLoc, message, doubleHash)
|
||||
}
|
||||
|
||||
type PrivKeyDigestSigner struct {
|
||||
PrivKey *btcec.PrivateKey
|
||||
func (p *PubKeyMessageSigner) SignMessageCompact(msg []byte,
|
||||
doubleHash bool) ([]byte, error) {
|
||||
|
||||
return p.digestSigner.SignMessageCompact(p.keyLoc, msg, doubleHash)
|
||||
}
|
||||
|
||||
func (p *PrivKeyDigestSigner) PubKey() *btcec.PublicKey {
|
||||
return p.PrivKey.PubKey()
|
||||
func NewPrivKeyMessageSigner(privKey *btcec.PrivateKey,
|
||||
keyLoc KeyLocator) *PrivKeyMessageSigner {
|
||||
|
||||
return &PrivKeyMessageSigner{
|
||||
privKey: privKey,
|
||||
keyLoc: keyLoc,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *PrivKeyDigestSigner) SignDigest(digest [32]byte) (*btcec.Signature,
|
||||
error) {
|
||||
|
||||
return p.PrivKey.Sign(digest[:])
|
||||
type PrivKeyMessageSigner struct {
|
||||
keyLoc KeyLocator
|
||||
privKey *btcec.PrivateKey
|
||||
}
|
||||
|
||||
func (p *PrivKeyDigestSigner) SignDigestCompact(digest [32]byte) ([]byte,
|
||||
error) {
|
||||
|
||||
return btcec.SignCompact(btcec.S256(), p.PrivKey, digest[:], true)
|
||||
func (p *PrivKeyMessageSigner) PubKey() *btcec.PublicKey {
|
||||
return p.privKey.PubKey()
|
||||
}
|
||||
|
||||
var _ SingleKeyDigestSigner = (*PubKeyDigestSigner)(nil)
|
||||
var _ SingleKeyDigestSigner = (*PrivKeyDigestSigner)(nil)
|
||||
func (p *PrivKeyMessageSigner) KeyLocator() KeyLocator {
|
||||
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)
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg"
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/btcsuite/btcutil"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
|
@ -426,14 +425,11 @@ func AddInvoice(ctx context.Context, cfg *AddInvoiceConfig,
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
payReqString, err := payReq.Encode(
|
||||
zpay32.MessageSigner{
|
||||
SignCompact: func(msg []byte) ([]byte, error) {
|
||||
hash := chainhash.HashB(msg)
|
||||
return cfg.NodeSigner.SignDigestCompact(hash)
|
||||
},
|
||||
payReqString, err := payReq.Encode(zpay32.MessageSigner{
|
||||
SignCompact: func(msg []byte) ([]byte, error) {
|
||||
return cfg.NodeSigner.SignMessageCompact(msg, false)
|
||||
},
|
||||
)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1086,6 +1086,12 @@ message SignMessageRequest {
|
|||
base64.
|
||||
*/
|
||||
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 {
|
||||
// The signature for the given message
|
||||
|
|
|
@ -6187,6 +6187,10 @@
|
|||
"type": "string",
|
||||
"format": "byte",
|
||||
"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."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -548,6 +548,8 @@ type SignMessageReq struct {
|
|||
Msg []byte `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
|
||||
// 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"`
|
||||
// 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() {
|
||||
|
@ -596,6 +598,13 @@ func (x *SignMessageReq) GetKeyLoc() *KeyLocator {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (x *SignMessageReq) GetDoubleHash() bool {
|
||||
if x != nil {
|
||||
return x.DoubleHash
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type SignMessageResp struct {
|
||||
state protoimpl.MessageState
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74, 0x75,
|
||||
0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
|
||||
0x75, 0x72, 0x65, 0x22, 0x5a, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67,
|
||||
0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69,
|
||||
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65,
|
||||
0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x22,
|
||||
0x29, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65,
|
||||
0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0xa2, 0x01, 0x0a, 0x10, 0x53,
|
||||
0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
|
||||
0x29, 0x0a, 0x10, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75, 0x62,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x70, 0x68, 0x65, 0x6d,
|
||||
0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x30, 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, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f, 0x72,
|
||||
0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x12, 0x31, 0x0a, 0x08,
|
||||
0x6b, 0x65, 0x79, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16,
|
||||
0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63,
|
||||
0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63, 0x22,
|
||||
0x32, 0x0a, 0x11, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70,
|
||||
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64,
|
||||
0x4b, 0x65, 0x79, 0x32, 0xd4, 0x02, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12, 0x34,
|
||||
0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x61, 0x77, 0x12,
|
||||
0x10, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65,
|
||||
0x71, 0x1a, 0x11, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e,
|
||||
0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x49,
|
||||
0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x10, 0x2e, 0x73, 0x69, 0x67,
|
||||
0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e, 0x73,
|
||||
0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69,
|
||||
0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e,
|
||||
0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x18,
|
||||
0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73,
|
||||
0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, 0x0d, 0x56, 0x65, 0x72, 0x69,
|
||||
0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e,
|
||||
0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56,
|
||||
0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70,
|
||||
0x12, 0x48, 0x0a, 0x0f, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64,
|
||||
0x4b, 0x65, 0x79, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x68,
|
||||
0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a,
|
||||
0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b,
|
||||
0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69,
|
||||
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e, 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,
|
||||
0x6f, 0x63, 0x12, 0x1f, 0x0a, 0x0b, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x68, 0x61, 0x73,
|
||||
0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x48,
|
||||
0x61, 0x73, 0x68, 0x22, 0x2f, 0x0a, 0x0f, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x74,
|
||||
0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x69, 0x67, 0x6e, 0x61,
|
||||
0x74, 0x75, 0x72, 0x65, 0x22, 0x5a, 0x0a, 0x10, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x69,
|
||||
0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73,
|
||||
0x69, 0x67, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x75, 0x62, 0x6b,
|
||||
0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x70, 0x75, 0x62, 0x6b, 0x65, 0x79,
|
||||
0x22, 0x29, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67,
|
||||
0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x22, 0xa2, 0x01, 0x0a, 0x10,
|
||||
0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x12, 0x29, 0x0a, 0x10, 0x65, 0x70, 0x68, 0x65, 0x6d, 0x65, 0x72, 0x61, 0x6c, 0x5f, 0x70, 0x75,
|
||||
0x62, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x70, 0x68, 0x65,
|
||||
0x6d, 0x65, 0x72, 0x61, 0x6c, 0x50, 0x75, 0x62, 0x6b, 0x65, 0x79, 0x12, 0x30, 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, 0x4b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x6f,
|
||||
0x72, 0x42, 0x02, 0x18, 0x01, 0x52, 0x06, 0x6b, 0x65, 0x79, 0x4c, 0x6f, 0x63, 0x12, 0x31, 0x0a,
|
||||
0x08, 0x6b, 0x65, 0x79, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x16, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x4b, 0x65, 0x79, 0x44, 0x65, 0x73,
|
||||
0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x44, 0x65, 0x73, 0x63,
|
||||
0x22, 0x32, 0x0a, 0x11, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5f,
|
||||
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x68, 0x61, 0x72, 0x65,
|
||||
0x64, 0x4b, 0x65, 0x79, 0x32, 0xd4, 0x02, 0x0a, 0x06, 0x53, 0x69, 0x67, 0x6e, 0x65, 0x72, 0x12,
|
||||
0x34, 0x0a, 0x0d, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x52, 0x61, 0x77,
|
||||
0x12, 0x10, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52,
|
||||
0x65, 0x71, 0x1a, 0x11, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67,
|
||||
0x6e, 0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65,
|
||||
0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x10, 0x2e, 0x73, 0x69,
|
||||
0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x52, 0x65, 0x71, 0x1a, 0x18, 0x2e,
|
||||
0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x53, 0x63, 0x72,
|
||||
0x69, 0x70, 0x74, 0x52, 0x65, 0x73, 0x70, 0x12, 0x40, 0x0a, 0x0b, 0x53, 0x69, 0x67, 0x6e, 0x4d,
|
||||
0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x17, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63,
|
||||
0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x1a,
|
||||
0x18, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x69, 0x67, 0x6e, 0x4d, 0x65,
|
||||
0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x12, 0x46, 0x0a, 0x0d, 0x56, 0x65, 0x72,
|
||||
0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67,
|
||||
0x6e, 0x72, 0x70, 0x63, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61,
|
||||
0x67, 0x65, 0x52, 0x65, 0x71, 0x1a, 0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e,
|
||||
0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73,
|
||||
0x70, 0x12, 0x48, 0x0a, 0x0f, 0x44, 0x65, 0x72, 0x69, 0x76, 0x65, 0x53, 0x68, 0x61, 0x72, 0x65,
|
||||
0x64, 0x4b, 0x65, 0x79, 0x12, 0x19, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53,
|
||||
0x68, 0x61, 0x72, 0x65, 0x64, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x1a, 0x2e, 0x73, 0x69, 0x67, 0x6e, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x68, 0x61, 0x72, 0x65, 0x64,
|
||||
0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x2f, 0x5a, 0x2d, 0x67,
|
||||
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x6e,
|
||||
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 (
|
||||
|
|
|
@ -190,6 +190,9 @@ message SignMessageReq {
|
|||
|
||||
// The key locator that identifies which key to use for signing.
|
||||
KeyLocator key_loc = 2;
|
||||
|
||||
// Double-SHA256 hash instead of just the default single round.
|
||||
bool double_hash = 3;
|
||||
}
|
||||
message SignMessageResp {
|
||||
/*
|
||||
|
|
|
@ -354,6 +354,10 @@
|
|||
"key_loc": {
|
||||
"$ref": "#/definitions/signrpcKeyLocator",
|
||||
"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."
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -446,7 +446,7 @@ func (s *Server) ComputeInputScript(ctx context.Context,
|
|||
|
||||
// SignMessage signs a message with the key specified in the key locator. The
|
||||
// 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) {
|
||||
|
||||
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.
|
||||
keyDescriptor := keychain.KeyDescriptor{
|
||||
KeyLocator: keychain.KeyLocator{
|
||||
Family: keychain.KeyFamily(in.KeyLoc.KeyFamily),
|
||||
Index: uint32(in.KeyLoc.KeyIndex),
|
||||
},
|
||||
keyLocator := keychain.KeyLocator{
|
||||
Family: keychain.KeyFamily(in.KeyLoc.KeyFamily),
|
||||
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
|
||||
// format after.
|
||||
sig, err := s.cfg.KeyRing.SignDigest(keyDescriptor, digest)
|
||||
sig, err := s.cfg.KeyRing.SignMessage(
|
||||
keyLocator, in.Msg, in.DoubleHash,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't sign the hash: %v", err)
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package mock
|
|||
|
||||
import (
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
|
||||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
)
|
||||
|
||||
|
@ -12,8 +12,8 @@ type SecretKeyRing struct {
|
|||
}
|
||||
|
||||
// DeriveNextKey currently returns dummy values.
|
||||
func (s *SecretKeyRing) DeriveNextKey(keyFam keychain.KeyFamily) (
|
||||
keychain.KeyDescriptor, error) {
|
||||
func (s *SecretKeyRing) DeriveNextKey(
|
||||
_ keychain.KeyFamily) (keychain.KeyDescriptor, error) {
|
||||
|
||||
return keychain.KeyDescriptor{
|
||||
PubKey: s.RootKey.PubKey(),
|
||||
|
@ -21,36 +21,50 @@ func (s *SecretKeyRing) DeriveNextKey(keyFam keychain.KeyFamily) (
|
|||
}
|
||||
|
||||
// DeriveKey currently returns dummy values.
|
||||
func (s *SecretKeyRing) DeriveKey(keyLoc keychain.KeyLocator) (keychain.KeyDescriptor,
|
||||
error) {
|
||||
func (s *SecretKeyRing) DeriveKey(
|
||||
_ keychain.KeyLocator) (keychain.KeyDescriptor, error) {
|
||||
|
||||
return keychain.KeyDescriptor{
|
||||
PubKey: s.RootKey.PubKey(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// DerivePrivKey currently returns dummy values.
|
||||
func (s *SecretKeyRing) DerivePrivKey(keyDesc keychain.KeyDescriptor) (*btcec.PrivateKey,
|
||||
error) {
|
||||
func (s *SecretKeyRing) DerivePrivKey(
|
||||
_ keychain.KeyDescriptor) (*btcec.PrivateKey, error) {
|
||||
|
||||
return s.RootKey, nil
|
||||
}
|
||||
|
||||
// ECDH currently returns dummy values.
|
||||
func (s *SecretKeyRing) ECDH(_ keychain.KeyDescriptor, pubKey *btcec.PublicKey) ([32]byte,
|
||||
error) {
|
||||
func (s *SecretKeyRing) ECDH(_ keychain.KeyDescriptor,
|
||||
_ *btcec.PublicKey) ([32]byte, error) {
|
||||
|
||||
return [32]byte{}, nil
|
||||
}
|
||||
|
||||
// SignDigest signs the passed digest and ignores the KeyDescriptor.
|
||||
func (s *SecretKeyRing) SignDigest(_ keychain.KeyDescriptor,
|
||||
digest [32]byte) (*btcec.Signature, error) {
|
||||
// SignMessage signs the passed message and ignores the KeyDescriptor.
|
||||
func (s *SecretKeyRing) SignMessage(_ keychain.KeyLocator,
|
||||
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.
|
||||
func (s *SecretKeyRing) SignDigestCompact(_ keychain.KeyDescriptor,
|
||||
digest [32]byte) ([]byte, error) {
|
||||
// SignMessageCompact signs the passed message.
|
||||
func (s *SecretKeyRing) SignMessageCompact(_ keychain.KeyLocator,
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -7,8 +7,12 @@ import (
|
|||
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
||||
"github.com/btcsuite/btcd/txscript"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
)
|
||||
|
||||
var (
|
||||
idKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
|
||||
)
|
||||
|
||||
// DummySignature is a dummy Signature implementation.
|
||||
|
@ -46,6 +50,7 @@ func (d *DummySigner) ComputeInputScript(tx *wire.MsgTx,
|
|||
// everything with a single private key.
|
||||
type SingleSigner struct {
|
||||
Privkey *btcec.PrivateKey
|
||||
KeyLoc keychain.KeyLocator
|
||||
}
|
||||
|
||||
// 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
|
||||
// with the stored private key if the public key matches the private key.
|
||||
func (s *SingleSigner) SignMessage(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
func (s *SingleSigner) SignMessage(keyLoc keychain.KeyLocator,
|
||||
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")
|
||||
}
|
||||
|
||||
|
|
|
@ -126,11 +126,13 @@ func (b *BtcWallet) deriveKeyByLocator(keyLoc keychain.KeyLocator) (*btcec.Priva
|
|||
|
||||
// fetchPrivKey attempts to retrieve the raw private key corresponding to the
|
||||
// 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
|
||||
// directly derive the keys raw.
|
||||
emptyLocator := keyDesc.KeyLocator.IsEmpty()
|
||||
if !emptyLocator {
|
||||
if !emptyLocator || keyDesc.PubKey == nil {
|
||||
return b.deriveKeyByLocator(keyDesc.KeyLocator)
|
||||
}
|
||||
|
||||
|
@ -259,18 +261,18 @@ func (b *BtcWallet) ComputeInputScript(tx *wire.MsgTx,
|
|||
var _ input.Signer = (*BtcWallet)(nil)
|
||||
|
||||
// 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
|
||||
// double SHA-256 of the passed message.
|
||||
//
|
||||
// NOTE: This is a part of the MessageSigner interface.
|
||||
func (b *BtcWallet) SignMessage(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
func (b *BtcWallet) SignMessage(keyLoc keychain.KeyLocator,
|
||||
msg []byte) (*btcec.Signature, error) {
|
||||
|
||||
// First attempt to fetch the private key which corresponds to the
|
||||
// specified public key.
|
||||
privKey, err := b.fetchPrivKey(&keychain.KeyDescriptor{
|
||||
PubKey: pubKey,
|
||||
KeyLocator: keyLoc,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -15,7 +15,7 @@ import (
|
|||
"github.com/btcsuite/btcwallet/waddrmgr"
|
||||
"github.com/btcsuite/btcwallet/wallet/txauthor"
|
||||
"github.com/btcsuite/btcwallet/wtxmgr"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet/chainfee"
|
||||
)
|
||||
|
||||
|
@ -440,10 +440,11 @@ type BlockChainIO interface {
|
|||
// to attest to some message.
|
||||
type MessageSigner interface {
|
||||
// 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 be found, then an error will be returned. The actual
|
||||
// digest signed is the double SHA-256 of the passed message.
|
||||
SignMessage(pubKey *btcec.PublicKey, msg []byte) (input.Signature, error)
|
||||
// described in the key locator. If the target private key is unable to
|
||||
// be found, then an error will be returned. The actual digest signed is
|
||||
// the double SHA-256 of the passed message.
|
||||
SignMessage(keyLoc keychain.KeyLocator, msg []byte) (*btcec.Signature,
|
||||
error)
|
||||
}
|
||||
|
||||
// WalletDriver represents a "driver" for a particular concrete
|
||||
|
|
|
@ -70,6 +70,12 @@ func NewSigFromSignature(e input.Signature) (Sig, error) {
|
|||
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.
|
||||
return NewSigFromRawSignature(e.Serialize())
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ func Start(extraArgs string, rpcReady Callback) {
|
|||
Ready: rpcListening,
|
||||
}},
|
||||
}
|
||||
implCfg := loadedConfig.ImplementationConfig(shutdownInterceptor)
|
||||
|
||||
// Call the "real" main in a nested manner so the defers will properly
|
||||
// be executed in the case of a graceful shutdown.
|
||||
|
@ -107,7 +108,7 @@ func Start(extraArgs string, rpcReady Callback) {
|
|||
defer close(quit)
|
||||
|
||||
if err := lnd.Main(
|
||||
loadedConfig, cfg, shutdownInterceptor,
|
||||
loadedConfig, cfg, implCfg, shutdownInterceptor,
|
||||
); err != nil {
|
||||
if e, ok := err.(*flags.Error); ok &&
|
||||
e.Type == flags.ErrHelp {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
@ -43,6 +44,10 @@ type ChanStatusConfig struct {
|
|||
// OurPubKey is the public key identifying this node on the network.
|
||||
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 lnwallet.MessageSigner
|
||||
|
||||
|
@ -621,7 +626,7 @@ func (m *ChanStatusManager) signAndSendNextUpdate(outpoint wire.OutPoint,
|
|||
}
|
||||
|
||||
err = SignChannelUpdate(
|
||||
m.cfg.MessageSigner, m.cfg.OurPubKey, chanUpdate,
|
||||
m.cfg.MessageSigner, m.cfg.OurKeyLoc, chanUpdate,
|
||||
ChanUpdSetDisable(disabled), ChanUpdSetTimestamp,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -19,6 +19,10 @@ import (
|
|||
"github.com/lightningnetwork/lnd/netann"
|
||||
)
|
||||
|
||||
var (
|
||||
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
|
||||
)
|
||||
|
||||
// randOutpoint creates a random wire.Outpoint.
|
||||
func randOutpoint(t *testing.T) wire.OutPoint {
|
||||
t.Helper()
|
||||
|
@ -310,7 +314,7 @@ func newManagerCfg(t *testing.T, numChannels int,
|
|||
if err != nil {
|
||||
t.Fatalf("unable to generate key pair: %v", err)
|
||||
}
|
||||
privKeySigner := &keychain.PrivKeyDigestSigner{PrivKey: privKey}
|
||||
privKeySigner := keychain.NewPrivKeyMessageSigner(privKey, testKeyLoc)
|
||||
|
||||
graph := newMockGraph(
|
||||
t, numChannels, startEnabled, startEnabled, privKey.PubKey(),
|
||||
|
@ -322,6 +326,7 @@ func newManagerCfg(t *testing.T, numChannels int,
|
|||
ChanEnableTimeout: 500 * time.Millisecond,
|
||||
ChanDisableTimeout: time.Second,
|
||||
OurPubKey: privKey.PubKey(),
|
||||
OurKeyLoc: testKeyLoc,
|
||||
MessageSigner: netann.NewNodeSigner(privKeySigner),
|
||||
IsChannelActive: htlcSwitch.HasActiveLink,
|
||||
ApplyChannelUpdate: graph.ApplyChannelUpdate,
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
@ -55,7 +56,7 @@ func ChanUpdSetTimestamp(update *lnwire.ChannelUpdate) {
|
|||
// monotonically increase from the prior.
|
||||
//
|
||||
// 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 {
|
||||
|
||||
// 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.
|
||||
sig, err := SignAnnouncement(signer, pubKey, update)
|
||||
sig, err := SignAnnouncement(signer, keyLoc, update)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
|
@ -18,8 +17,8 @@ type mockSigner struct {
|
|||
err error
|
||||
}
|
||||
|
||||
func (m *mockSigner) SignMessage(pk *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
func (m *mockSigner) SignMessage(_ keychain.KeyLocator,
|
||||
_ []byte) (*btcec.Signature, error) {
|
||||
|
||||
if m.err != nil {
|
||||
return nil, m.err
|
||||
|
@ -32,7 +31,7 @@ var _ lnwallet.MessageSigner = (*mockSigner)(nil)
|
|||
|
||||
var (
|
||||
privKey, _ = btcec.NewPrivateKey(btcec.S256())
|
||||
privKeySigner = &keychain.PrivKeyDigestSigner{PrivKey: privKey}
|
||||
privKeySigner = keychain.NewPrivKeyMessageSigner(privKey, testKeyLoc)
|
||||
|
||||
pubKey = privKey.PubKey()
|
||||
|
||||
|
@ -130,7 +129,7 @@ func TestUpdateDisableFlag(t *testing.T) {
|
|||
// Attempt to update and sign the new update, specifying
|
||||
// disabled or enabled as prescribed in the test case.
|
||||
err := netann.SignChannelUpdate(
|
||||
tc.signer, pubKey, newUpdate,
|
||||
tc.signer, testKeyLoc, newUpdate,
|
||||
netann.ChanUpdSetDisable(tc.disable),
|
||||
netann.ChanUpdSetTimestamp,
|
||||
)
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"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
|
||||
// not monotonically increase from the prior.
|
||||
func SignNodeAnnouncement(signer lnwallet.MessageSigner,
|
||||
pubKey *btcec.PublicKey, nodeAnn *lnwire.NodeAnnouncement,
|
||||
keyLoc keychain.KeyLocator, nodeAnn *lnwire.NodeAnnouncement,
|
||||
mods ...NodeAnnModifier) error {
|
||||
|
||||
// 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.
|
||||
sig, err := SignAnnouncement(signer, pubKey, nodeAnn)
|
||||
sig, err := SignAnnouncement(signer, keyLoc, nodeAnn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@ import (
|
|||
"fmt"
|
||||
|
||||
"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/lnwallet"
|
||||
)
|
||||
|
@ -13,33 +11,31 @@ import (
|
|||
// NodeSigner is an implementation of the MessageSigner interface backed by the
|
||||
// identity private key of running lnd node.
|
||||
type NodeSigner struct {
|
||||
keySigner keychain.SingleKeyDigestSigner
|
||||
keySigner keychain.SingleKeyMessageSigner
|
||||
}
|
||||
|
||||
// NewNodeSigner creates a new instance of the NodeSigner backed by the target
|
||||
// private key.
|
||||
func NewNodeSigner(keySigner keychain.SingleKeyDigestSigner) *NodeSigner {
|
||||
func NewNodeSigner(keySigner keychain.SingleKeyMessageSigner) *NodeSigner {
|
||||
return &NodeSigner{
|
||||
keySigner: keySigner,
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// private key, then an error will be returned.
|
||||
func (n *NodeSigner) SignMessage(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
// resident node's private key described in the key locator. If the target key
|
||||
// locator is _not_ the node's private key, then an error will be returned.
|
||||
func (n *NodeSigner) SignMessage(keyLoc keychain.KeyLocator,
|
||||
msg []byte) (*btcec.Signature, error) {
|
||||
|
||||
// If this isn't our identity public key, then we'll exit early with an
|
||||
// error as we can't sign with this key.
|
||||
if !pubKey.IsEqual(n.keySigner.PubKey()) {
|
||||
return nil, fmt.Errorf("unknown public key")
|
||||
if keyLoc != n.keySigner.KeyLocator() {
|
||||
return nil, fmt.Errorf("unknown public key locator")
|
||||
}
|
||||
|
||||
// Otherwise, we'll sign the dsha256 of the target message.
|
||||
var digest [32]byte
|
||||
copy(digest[:], chainhash.DoubleHashB(msg))
|
||||
sig, err := n.keySigner.SignDigest(digest)
|
||||
// Otherwise, we'll sign the double-sha256 of the target message.
|
||||
sig, err := n.keySigner.SignMessage(msg, true)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
// SignCompact signs a double-sha256 digest of the msg parameter under the
|
||||
// resident node's private key. The returned signature is a pubkey-recoverable
|
||||
// signature.
|
||||
func (n *NodeSigner) SignCompact(msg []byte) ([]byte, error) {
|
||||
// We'll sign the dsha256 of the target message.
|
||||
digest := chainhash.DoubleHashB(msg)
|
||||
// SignMessageCompact signs a single or double sha256 digest of the msg
|
||||
// parameter under the resident node's private key. The returned signature is a
|
||||
// pubkey-recoverable signature.
|
||||
func (n *NodeSigner) SignMessageCompact(msg []byte, doubleHash bool) ([]byte,
|
||||
error) {
|
||||
|
||||
return n.SignDigestCompact(digest)
|
||||
}
|
||||
|
||||
// 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
|
||||
return n.keySigner.SignMessageCompact(msg, doubleHash)
|
||||
}
|
||||
|
||||
// A compile time check to ensure that NodeSigner implements the MessageSigner
|
||||
|
|
|
@ -3,15 +3,15 @@ package netann
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec"
|
||||
"github.com/lightningnetwork/lnd/input"
|
||||
"github.com/lightningnetwork/lnd/keychain"
|
||||
"github.com/lightningnetwork/lnd/lnwallet"
|
||||
"github.com/lightningnetwork/lnd/lnwire"
|
||||
)
|
||||
|
||||
// SignAnnouncement signs any type of gossip message that is announced on the
|
||||
// network.
|
||||
func SignAnnouncement(signer lnwallet.MessageSigner, pubKey *btcec.PublicKey,
|
||||
func SignAnnouncement(signer lnwallet.MessageSigner, keyLoc keychain.KeyLocator,
|
||||
msg lnwire.Message) (input.Signature, error) {
|
||||
|
||||
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 signer.SignMessage(pubKey, data)
|
||||
return signer.SignMessage(keyLoc, data)
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ const (
|
|||
var (
|
||||
// Just use some arbitrary bytes as delivery script.
|
||||
dummyDeliveryScript = channels.AlicesPrivKey
|
||||
|
||||
testKeyLoc = keychain.KeyLocator{Family: keychain.KeyFamilyNodeKey}
|
||||
)
|
||||
|
||||
// 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) (
|
||||
*Brontide, *lnwallet.LightningChannel, func(), error) {
|
||||
|
||||
nodeKeyLocator := keychain.KeyLocator{
|
||||
Family: keychain.KeyFamilyNodeKey,
|
||||
}
|
||||
aliceKeyPriv, aliceKeyPub := btcec.PrivKeyFromBytes(
|
||||
btcec.S256(), channels.AlicesPrivKey,
|
||||
)
|
||||
aliceKeySigner := &keychain.PrivKeyDigestSigner{PrivKey: aliceKeyPriv}
|
||||
aliceKeySigner := keychain.NewPrivKeyMessageSigner(
|
||||
aliceKeyPriv, nodeKeyLocator,
|
||||
)
|
||||
bobKeyPriv, bobKeyPub := btcec.PrivKeyFromBytes(
|
||||
btcec.S256(), channels.BobsPrivKey,
|
||||
)
|
||||
|
@ -325,6 +332,7 @@ func createTestPeer(notifier chainntnfs.ChainNotifier,
|
|||
Graph: dbAlice.ChannelGraph(),
|
||||
MessageSigner: nodeSignerAlice,
|
||||
OurPubKey: aliceKeyPub,
|
||||
OurKeyLoc: testKeyLoc,
|
||||
IsChannelActive: func(lnwire.ChannelID) bool { return true },
|
||||
ApplyChannelUpdate: func(*lnwire.ChannelUpdate) error { return nil },
|
||||
})
|
||||
|
|
4
pilot.go
4
pilot.go
|
@ -137,7 +137,7 @@ var _ autopilot.ChannelController = (*chanController)(nil)
|
|||
// interfaces needed to drive it won't be launched before the Manager's
|
||||
// StartAgent method is called.
|
||||
func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
|
||||
chainCfg *lncfg.Chain, netParams chainreg.BitcoinNetParams) (
|
||||
minHTLCIn lnwire.MilliSatoshi, netParams chainreg.BitcoinNetParams) (
|
||||
*autopilot.ManagerCfg, error) {
|
||||
|
||||
atplLog.Infof("Instantiating autopilot with active=%v, "+
|
||||
|
@ -177,7 +177,7 @@ func initAutoPilot(svr *server, cfg *lncfg.AutoPilot,
|
|||
private: cfg.Private,
|
||||
minConfs: cfg.MinConfs,
|
||||
confTarget: cfg.ConfTarget,
|
||||
chanMinHtlcIn: chainCfg.MinHTLCIn,
|
||||
chanMinHtlcIn: minHTLCIn,
|
||||
netParams: netParams,
|
||||
},
|
||||
WalletBalance: func() (btcutil.Amount, error) {
|
||||
|
|
|
@ -386,6 +386,15 @@ func (r *InterceptorChain) AddMacaroonService(svc *macaroons.Service) {
|
|||
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.
|
||||
func (r *InterceptorChain) AddPermission(method string, ops []bakery.Op) error {
|
||||
r.Lock()
|
||||
|
|
88
rpcserver.go
88
rpcserver.go
|
@ -611,16 +611,12 @@ type rpcServer struct {
|
|||
// selfNode is our own pubkey.
|
||||
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
|
||||
|
||||
// extSubserverCfg is optional and specifies the registration
|
||||
// callback and permissions to register external gRPC subservers.
|
||||
extSubserverCfg *RPCSubserverConfig
|
||||
|
||||
// extRestRegistrar is optional and specifies the registration
|
||||
// callback to register external REST subservers.
|
||||
extRestRegistrar RestRegistrar
|
||||
// implCfg is the configuration for some of the interfaces that can be
|
||||
// provided externally.
|
||||
implCfg *ImplementationCfg
|
||||
|
||||
// interceptor is used to be able to request a shutdown
|
||||
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
|
||||
// be used to register the LightningService with the gRPC server.
|
||||
func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain,
|
||||
extSubserverCfg *RPCSubserverConfig,
|
||||
extRestRegistrar RestRegistrar,
|
||||
interceptor signal.Interceptor) *rpcServer {
|
||||
implCfg *ImplementationCfg, interceptor signal.Interceptor) *rpcServer {
|
||||
|
||||
// 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
|
||||
|
@ -654,8 +648,7 @@ func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain,
|
|||
cfg: cfg,
|
||||
subGrpcHandlers: subServerHandlers,
|
||||
interceptorChain: interceptorChain,
|
||||
extSubserverCfg: extSubserverCfg,
|
||||
extRestRegistrar: extRestRegistrar,
|
||||
implCfg: implCfg,
|
||||
quit: make(chan struct{}, 1),
|
||||
interceptor: interceptor,
|
||||
}
|
||||
|
@ -785,30 +778,22 @@ func (r *rpcServer) addDeps(s *server, macService *macaroons.Service,
|
|||
|
||||
// External subserver possibly need to register their own permissions
|
||||
// and macaroon validator.
|
||||
if r.extSubserverCfg != nil {
|
||||
macValidator := r.extSubserverCfg.MacaroonValidator
|
||||
for method, ops := range r.extSubserverCfg.Permissions {
|
||||
err := r.interceptorChain.AddPermission(method, ops)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for method, ops := range r.implCfg.ExternalValidator.Permissions() {
|
||||
err := r.interceptorChain.AddPermission(method, ops)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Give the external subservers the possibility
|
||||
// to also use their own validator to check any
|
||||
// macaroons attached to calls to this method.
|
||||
// This allows them to have their own root key
|
||||
// ID database and permission entities.
|
||||
if macValidator != nil {
|
||||
err := macService.RegisterExternalValidator(
|
||||
method, macValidator,
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could "+
|
||||
"not register "+
|
||||
"external macaroon "+
|
||||
"validator: %v", err)
|
||||
}
|
||||
}
|
||||
// Give the external subservers the possibility to also use
|
||||
// their own validator to check any macaroons attached to calls
|
||||
// to this method. This allows them to have their own root key
|
||||
// ID database and permission entities.
|
||||
err = macService.RegisterExternalValidator(
|
||||
method, r.implCfg.ExternalValidator,
|
||||
)
|
||||
if err != nil {
|
||||
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
|
||||
// server instance so all of them can be exposed on the same
|
||||
// port/listener.
|
||||
if r.extSubserverCfg != nil && r.extSubserverCfg.Registrar != nil {
|
||||
registerer := r.extSubserverCfg.Registrar
|
||||
err := registerer.RegisterGrpcSubserver(grpcServer)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering external gRPC "+
|
||||
"subserver: %v", err)
|
||||
}
|
||||
err := r.implCfg.RegisterGrpcSubserver(grpcServer)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering external gRPC "+
|
||||
"subserver: %v", err)
|
||||
}
|
||||
|
||||
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
|
||||
// external subservers a chance to register their own REST proxy stub
|
||||
// with our mux instance.
|
||||
if r.extRestRegistrar != nil {
|
||||
err := r.extRestRegistrar.RegisterRestSubserver(
|
||||
restCtx, restMux, restProxyDest, restDialOpts,
|
||||
)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering "+
|
||||
"external REST subserver: %v", err)
|
||||
}
|
||||
err = r.implCfg.RegisterRestSubserver(
|
||||
restCtx, restMux, restProxyDest, restDialOpts,
|
||||
)
|
||||
if err != nil {
|
||||
rpcsLog.Errorf("error registering external REST subserver: %v",
|
||||
err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1522,7 +1502,7 @@ var (
|
|||
// SignMessage signs a message with the resident node's private key. The
|
||||
// returned signature string is zbase32 encoded and pubkey recoverable, meaning
|
||||
// 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) {
|
||||
|
||||
if in.Msg == nil {
|
||||
|
@ -1530,7 +1510,9 @@ func (r *rpcServer) SignMessage(ctx context.Context,
|
|||
}
|
||||
|
||||
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 {
|
||||
return nil, err
|
||||
}
|
||||
|
|
97
server.go
97
server.go
|
@ -157,6 +157,9 @@ type server struct {
|
|||
// to authenticate any incoming connections.
|
||||
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
|
||||
// that's backed by the identity private key of the running lnd node.
|
||||
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
|
||||
// passed listener address.
|
||||
func newServer(cfg *Config, listenAddrs []net.Addr,
|
||||
dbs *databaseInstances, cc *chainreg.ChainControl,
|
||||
dbs *DatabaseInstances, cc *chainreg.ChainControl,
|
||||
nodeKeyDesc *keychain.KeyDescriptor,
|
||||
chansToRestore walletunlocker.ChannelsToRecover,
|
||||
chanPredicate chanacceptor.ChannelAcceptor,
|
||||
torController *tor.Controller) (*server, error) {
|
||||
|
||||
var (
|
||||
err error
|
||||
nodeKeyECDH = keychain.NewPubKeyECDH(*nodeKeyDesc, cc.KeyRing)
|
||||
nodeKeySigner = keychain.NewPubKeyDigestSigner(
|
||||
*nodeKeyDesc, cc.KeyRing,
|
||||
err error
|
||||
nodeKeyECDH = keychain.NewPubKeyECDH(*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
|
||||
copy(serializedPubKey[:], nodeKeyECDH.PubKey().SerializeCompressed())
|
||||
copy(serializedPubKey[:], nodeKeyDesc.PubKey.SerializeCompressed())
|
||||
|
||||
// Initialize the sphinx router.
|
||||
replayLog := htlcswitch.NewDecayedLog(
|
||||
dbs.decayedLogDB, cc.ChainNotifier,
|
||||
dbs.DecayedLogDB, cc.ChainNotifier,
|
||||
)
|
||||
sphinxRouter := sphinx.NewRouter(
|
||||
nodeKeyECDH, cfg.ActiveNetParams.Params, replayLog,
|
||||
|
@ -521,10 +527,10 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
|
||||
s := &server{
|
||||
cfg: cfg,
|
||||
graphDB: dbs.graphDB.ChannelGraph(),
|
||||
chanStateDB: dbs.chanStateDB.ChannelStateDB(),
|
||||
addrSource: dbs.chanStateDB,
|
||||
miscDB: dbs.chanStateDB,
|
||||
graphDB: dbs.GraphDB.ChannelGraph(),
|
||||
chanStateDB: dbs.ChanStateDB.ChannelStateDB(),
|
||||
addrSource: dbs.ChanStateDB,
|
||||
miscDB: dbs.ChanStateDB,
|
||||
cc: cc,
|
||||
sigPool: lnwallet.NewSigPool(cfg.Workers.Sig, cc.Signer),
|
||||
writePool: writePool,
|
||||
|
@ -532,11 +538,12 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
chansToRestore: chansToRestore,
|
||||
|
||||
channelNotifier: channelnotifier.New(
|
||||
dbs.chanStateDB.ChannelStateDB(),
|
||||
dbs.ChanStateDB.ChannelStateDB(),
|
||||
),
|
||||
|
||||
identityECDH: nodeKeyECDH,
|
||||
nodeSigner: netann.NewNodeSigner(nodeKeySigner),
|
||||
identityECDH: nodeKeyECDH,
|
||||
identityKeyLoc: nodeKeyDesc.KeyLocator,
|
||||
nodeSigner: netann.NewNodeSigner(nodeKeySigner),
|
||||
|
||||
listenAddrs: listenAddrs,
|
||||
|
||||
|
@ -566,7 +573,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
}
|
||||
|
||||
s.witnessBeacon = &preimageBeacon{
|
||||
wCache: dbs.chanStateDB.NewWitnessCache(),
|
||||
wCache: dbs.ChanStateDB.NewWitnessCache(),
|
||||
subscribers: make(map[uint64]*preimageSubscriber),
|
||||
}
|
||||
|
||||
|
@ -580,7 +587,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
uint32(currentHeight), currentHash, cc.ChainNotifier,
|
||||
)
|
||||
s.invoices = invoices.NewRegistry(
|
||||
dbs.chanStateDB, expiryWatcher, ®istryConfig,
|
||||
dbs.ChanStateDB, expiryWatcher, ®istryConfig,
|
||||
)
|
||||
|
||||
s.htlcNotifier = htlcswitch.NewHtlcNotifier(time.Now)
|
||||
|
@ -589,7 +596,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
thresholdMSats := lnwire.NewMSatFromSatoshis(thresholdSats)
|
||||
|
||||
s.htlcSwitch, err = htlcswitch.New(htlcswitch.Config{
|
||||
DB: dbs.chanStateDB,
|
||||
DB: dbs.ChanStateDB,
|
||||
FetchAllOpenChannels: s.chanStateDB.FetchAllOpenChannels,
|
||||
FetchClosedChannels: s.chanStateDB.FetchClosedChannels,
|
||||
LocalChannelClose: func(pubKey []byte,
|
||||
|
@ -606,7 +613,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
|
||||
peer.HandleLocalCloseChanReqs(request)
|
||||
},
|
||||
FwdingLog: dbs.chanStateDB.ForwardingLog(),
|
||||
FwdingLog: dbs.ChanStateDB.ForwardingLog(),
|
||||
SwitchPackager: channeldb.NewSwitchPackager(),
|
||||
ExtractErrorEncrypter: s.sphinx.ExtractErrorEncrypter,
|
||||
FetchLastChannelUpdate: s.fetchLastChanUpdate(),
|
||||
|
@ -630,12 +637,13 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
ChanStatusSampleInterval: cfg.ChanStatusSampleInterval,
|
||||
ChanEnableTimeout: cfg.ChanEnableTimeout,
|
||||
ChanDisableTimeout: cfg.ChanDisableTimeout,
|
||||
OurPubKey: nodeKeyECDH.PubKey(),
|
||||
OurPubKey: nodeKeyDesc.PubKey,
|
||||
OurKeyLoc: nodeKeyDesc.KeyLocator,
|
||||
MessageSigner: s.nodeSigner,
|
||||
IsChannelActive: s.htlcSwitch.HasActiveLink,
|
||||
ApplyChannelUpdate: s.applyChannelUpdate,
|
||||
DB: s.chanStateDB,
|
||||
Graph: dbs.graphDB.ChannelGraph(),
|
||||
Graph: dbs.GraphDB.ChannelGraph(),
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
||||
// 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),
|
||||
Color: color,
|
||||
}
|
||||
copy(selfNode.PubKeyBytes[:], nodeKeyECDH.PubKey().SerializeCompressed())
|
||||
copy(selfNode.PubKeyBytes[:], nodeKeyDesc.PubKey.SerializeCompressed())
|
||||
|
||||
// Based on the disk representation of the node announcement generated
|
||||
// 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
|
||||
// authenticate the message on the network.
|
||||
authSig, err := netann.SignAnnouncement(
|
||||
s.nodeSigner, nodeKeyECDH.PubKey(), nodeAnn,
|
||||
s.nodeSigner, nodeKeyDesc.KeyLocator, nodeAnn,
|
||||
)
|
||||
if err != nil {
|
||||
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
|
||||
// can generate unique payment IDs.
|
||||
sequencer, err := htlcswitch.NewPersistentSequencer(dbs.chanStateDB)
|
||||
sequencer, err := htlcswitch.NewPersistentSequencer(dbs.ChanStateDB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -839,7 +847,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
}
|
||||
|
||||
s.missionControl, err = routing.NewMissionControl(
|
||||
dbs.chanStateDB, selfNode.PubKeyBytes,
|
||||
dbs.ChanStateDB, selfNode.PubKeyBytes,
|
||||
&routing.MissionControlConfig{
|
||||
ProbabilityEstimatorCfg: estimatorCfg,
|
||||
MaxMcHistory: routingConfig.MaxMcHistory,
|
||||
|
@ -876,7 +884,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
PathFindingConfig: pathFindingConfig,
|
||||
}
|
||||
|
||||
paymentControl := channeldb.NewPaymentControl(dbs.chanStateDB)
|
||||
paymentControl := channeldb.NewPaymentControl(dbs.ChanStateDB)
|
||||
|
||||
s.controlTower = routing.NewControlTower(paymentControl)
|
||||
|
||||
|
@ -906,11 +914,11 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
}
|
||||
|
||||
chanSeries := discovery.NewChanSeries(s.graphDB)
|
||||
gossipMessageStore, err := discovery.NewMessageStore(dbs.chanStateDB)
|
||||
gossipMessageStore, err := discovery.NewMessageStore(dbs.ChanStateDB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
waitingProofStore, err := channeldb.NewWaitingProofStore(dbs.chanStateDB)
|
||||
waitingProofStore, err := channeldb.NewWaitingProofStore(dbs.ChanStateDB)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -942,9 +950,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
PinnedSyncers: cfg.Gossip.PinnedSyncers,
|
||||
MaxChannelUpdateBurst: cfg.Gossip.MaxChannelUpdateBurst,
|
||||
ChannelUpdateInterval: cfg.Gossip.ChannelUpdateInterval,
|
||||
},
|
||||
nodeKeyECDH.PubKey(),
|
||||
)
|
||||
}, nodeKeyDesc)
|
||||
|
||||
s.localChanMgr = &localchans.Manager{
|
||||
ForAllOutgoingChannels: s.chanRouter.ForAllOutgoingChannels,
|
||||
|
@ -954,7 +960,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
}
|
||||
|
||||
utxnStore, err := contractcourt.NewNurseryStore(
|
||||
s.cfg.ActiveNetParams.GenesisHash, dbs.chanStateDB,
|
||||
s.cfg.ActiveNetParams.GenesisHash, dbs.ChanStateDB,
|
||||
)
|
||||
if err != nil {
|
||||
srvrLog.Errorf("unable to create nursery store: %v", err)
|
||||
|
@ -965,7 +971,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
sweep.DefaultBatchWindowDuration)
|
||||
|
||||
sweeperStore, err := sweep.NewSweeperStore(
|
||||
dbs.chanStateDB, s.cfg.ActiveNetParams.GenesisHash,
|
||||
dbs.ChanStateDB, s.cfg.ActiveNetParams.GenesisHash,
|
||||
)
|
||||
if err != nil {
|
||||
srvrLog.Errorf("unable to create sweeper store: %v", err)
|
||||
|
@ -1115,7 +1121,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
PaymentsExpirationGracePeriod: cfg.PaymentsExpirationGracePeriod,
|
||||
IsForwardedHTLC: s.htlcSwitch.IsForwardedHTLC,
|
||||
Clock: clock.NewDefaultClock(),
|
||||
}, dbs.chanStateDB)
|
||||
}, dbs.ChanStateDB)
|
||||
|
||||
s.breachArbiter = contractcourt.NewBreachArbiter(&contractcourt.BreachConfig{
|
||||
CloseLink: closeLink,
|
||||
|
@ -1127,7 +1133,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
ContractBreaches: contractBreaches,
|
||||
Signer: cc.Wallet.Cfg.Signer,
|
||||
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{
|
||||
NoWumboChans: !cfg.ProtocolOptions.Wumbo(),
|
||||
IDKey: nodeKeyECDH.PubKey(),
|
||||
IDKey: nodeKeyDesc.PubKey,
|
||||
IDKeyLoc: nodeKeyDesc.KeyLocator,
|
||||
Wallet: cc.Wallet,
|
||||
PublishTransaction: cc.Wallet.PublishTransaction,
|
||||
UpdateLabel: func(hash chainhash.Hash, label string) error {
|
||||
|
@ -1158,15 +1165,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
},
|
||||
Notifier: cc.ChainNotifier,
|
||||
FeeEstimator: cc.FeeEstimator,
|
||||
SignMessage: func(pubKey *btcec.PublicKey,
|
||||
msg []byte) (input.Signature, error) {
|
||||
|
||||
if pubKey.IsEqual(nodeKeyECDH.PubKey()) {
|
||||
return s.nodeSigner.SignMessage(pubKey, msg)
|
||||
}
|
||||
|
||||
return cc.MsgSigner.SignMessage(pubKey, msg)
|
||||
},
|
||||
SignMessage: cc.MsgSigner.SignMessage,
|
||||
CurrentNodeAnnouncement: func() (lnwire.NodeAnnouncement, error) {
|
||||
return s.genNodeAnnouncement(true)
|
||||
},
|
||||
|
@ -1348,7 +1347,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
// static backup of the latest channel state.
|
||||
chanNotifier := &channelNotifier{
|
||||
chanNotifier: s.channelNotifier,
|
||||
addrs: dbs.chanStateDB,
|
||||
addrs: dbs.ChanStateDB,
|
||||
}
|
||||
backupFile := chanbackup.NewMultiFile(cfg.BackupFilePath)
|
||||
startingChans, err := chanbackup.FetchStaticChanBackups(
|
||||
|
@ -1416,7 +1415,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
SecretKeyRing: s.cc.KeyRing,
|
||||
Dial: cfg.net.Dial,
|
||||
AuthDial: authDial,
|
||||
DB: dbs.towerClientDB,
|
||||
DB: dbs.TowerClientDB,
|
||||
Policy: policy,
|
||||
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
||||
MinBackoff: 10 * time.Second,
|
||||
|
@ -1439,7 +1438,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
|
|||
SecretKeyRing: s.cc.KeyRing,
|
||||
Dial: cfg.net.Dial,
|
||||
AuthDial: authDial,
|
||||
DB: dbs.towerClientDB,
|
||||
DB: dbs.TowerClientDB,
|
||||
Policy: anchorPolicy,
|
||||
ChainHash: *s.cfg.ActiveNetParams.GenesisHash,
|
||||
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
|
||||
// modifiers.
|
||||
err := netann.SignNodeAnnouncement(
|
||||
s.nodeSigner, s.identityECDH.PubKey(), s.currentNodeAnn,
|
||||
s.nodeSigner, s.identityKeyLoc, s.currentNodeAnn,
|
||||
modifiers...,
|
||||
)
|
||||
if err != nil {
|
||||
|
|
|
@ -27,6 +27,45 @@ var (
|
|||
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
|
||||
// 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.
|
||||
|
|
|
@ -102,8 +102,10 @@ var (
|
|||
|
||||
testMessageSigner = MessageSigner{
|
||||
SignCompact: func(msg []byte) ([]byte, error) {
|
||||
sig, err := btcec.SignCompact(btcec.S256(),
|
||||
testPrivKey, chainhash.HashB(msg), true)
|
||||
hash := chainhash.HashB(msg)
|
||||
sig, err := btcec.SignCompact(
|
||||
btcec.S256(), testPrivKey, hash, true,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("can't sign the "+
|
||||
"message: %v", err)
|
||||
|
|
Loading…
Add table
Reference in a new issue