Move services to status-node
Move all the services to status-node, as some of them were there, some of them were in the geth backend and scattered around.
This commit is contained in:
parent
36430257fd
commit
4b0daeb47b
|
@ -10,7 +10,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/pborman/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore"
|
gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
@ -206,12 +206,16 @@ func (m *Manager) SetAccountAddresses(main types.Address, secondary ...types.Add
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetChatAccount initializes selectedChatAccount with privKey
|
// SetChatAccount initializes selectedChatAccount with privKey
|
||||||
func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) {
|
func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) error {
|
||||||
m.mu.Lock()
|
m.mu.Lock()
|
||||||
defer m.mu.Unlock()
|
defer m.mu.Unlock()
|
||||||
|
|
||||||
address := crypto.PubkeyToAddress(privKey.PublicKey)
|
address := crypto.PubkeyToAddress(privKey.PublicKey)
|
||||||
id := uuid.NewRandom()
|
id, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
key := &types.Key{
|
key := &types.Key{
|
||||||
ID: id,
|
ID: id,
|
||||||
Address: address,
|
Address: address,
|
||||||
|
@ -222,6 +226,7 @@ func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) {
|
||||||
Address: address,
|
Address: address,
|
||||||
AccountKey: key,
|
AccountKey: key,
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MainAccountAddress returns currently selected watch addresses.
|
// MainAccountAddress returns currently selected watch addresses.
|
||||||
|
|
|
@ -35,7 +35,6 @@ type StatusBackend interface {
|
||||||
|
|
||||||
CallPrivateRPC(inputJSON string) (string, error)
|
CallPrivateRPC(inputJSON string) (string, error)
|
||||||
CallRPC(inputJSON string) (string, error)
|
CallRPC(inputJSON string) (string, error)
|
||||||
GetNodesFromContract(rpcEndpoint string, contractAddress string) ([]string, error)
|
|
||||||
HashTransaction(sendArgs transactions.SendTxArgs) (transactions.SendTxArgs, types.Hash, error)
|
HashTransaction(sendArgs transactions.SendTxArgs) (transactions.SendTxArgs, types.Hash, error)
|
||||||
HashTypedData(typed typeddata.TypedData) (types.Hash, error)
|
HashTypedData(typed typeddata.TypedData) (types.Hash, error)
|
||||||
HashTypedDataV4(typed signercore.TypedData) (types.Hash, error)
|
HashTypedDataV4(typed signercore.TypedData) (types.Hash, error)
|
||||||
|
|
|
@ -11,18 +11,13 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
ethcrypto "github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
|
||||||
"github.com/ethereum/go-ethereum/event"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
gethnode "github.com/ethereum/go-ethereum/node"
|
|
||||||
signercore "github.com/ethereum/go-ethereum/signer/core"
|
signercore "github.com/ethereum/go-ethereum/signer/core"
|
||||||
|
|
||||||
"github.com/status-im/status-go/account"
|
"github.com/status-im/status-go/account"
|
||||||
"github.com/status-im/status-go/appdatabase"
|
"github.com/status-im/status-go/appdatabase"
|
||||||
"github.com/status-im/status-go/appmetrics"
|
|
||||||
"github.com/status-im/status-go/connection"
|
"github.com/status-im/status-go/connection"
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
@ -32,19 +27,8 @@ import (
|
||||||
"github.com/status-im/status-go/node"
|
"github.com/status-im/status-go/node"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/rpc"
|
"github.com/status-im/status-go/rpc"
|
||||||
accountssvc "github.com/status-im/status-go/services/accounts"
|
|
||||||
appmetricsservice "github.com/status-im/status-go/services/appmetrics"
|
|
||||||
"github.com/status-im/status-go/services/browsers"
|
|
||||||
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
|
||||||
"github.com/status-im/status-go/services/mailservers"
|
|
||||||
"github.com/status-im/status-go/services/permissions"
|
|
||||||
"github.com/status-im/status-go/services/personal"
|
"github.com/status-im/status-go/services/personal"
|
||||||
"github.com/status-im/status-go/services/rpcfilters"
|
|
||||||
"github.com/status-im/status-go/services/rpcstats"
|
|
||||||
"github.com/status-im/status-go/services/subscriptions"
|
|
||||||
"github.com/status-im/status-go/services/typeddata"
|
"github.com/status-im/status-go/services/typeddata"
|
||||||
"github.com/status-im/status-go/services/wakuext"
|
|
||||||
"github.com/status-im/status-go/services/wallet"
|
|
||||||
"github.com/status-im/status-go/signal"
|
"github.com/status-im/status-go/signal"
|
||||||
"github.com/status-im/status-go/transactions"
|
"github.com/status-im/status-go/transactions"
|
||||||
)
|
)
|
||||||
|
@ -58,8 +42,6 @@ var (
|
||||||
ErrWhisperClearIdentitiesFailure = errors.New("failed to clear whisper identities")
|
ErrWhisperClearIdentitiesFailure = errors.New("failed to clear whisper identities")
|
||||||
// ErrWhisperIdentityInjectionFailure injecting whisper identities has failed.
|
// ErrWhisperIdentityInjectionFailure injecting whisper identities has failed.
|
||||||
ErrWhisperIdentityInjectionFailure = errors.New("failed to inject identity into Whisper")
|
ErrWhisperIdentityInjectionFailure = errors.New("failed to inject identity into Whisper")
|
||||||
// ErrWakuClearIdentitiesFailure clearing whisper identities has failed.
|
|
||||||
ErrWakuClearIdentitiesFailure = errors.New("failed to clear waku identities")
|
|
||||||
// ErrWakuIdentityInjectionFailure injecting whisper identities has failed.
|
// ErrWakuIdentityInjectionFailure injecting whisper identities has failed.
|
||||||
ErrWakuIdentityInjectionFailure = errors.New("failed to inject identity into waku")
|
ErrWakuIdentityInjectionFailure = errors.New("failed to inject identity into waku")
|
||||||
// ErrUnsupportedRPCMethod is for methods not supported by the RPC interface
|
// ErrUnsupportedRPCMethod is for methods not supported by the RPC interface
|
||||||
|
@ -81,7 +63,6 @@ type GethStatusBackend struct {
|
||||||
appDB *sql.DB
|
appDB *sql.DB
|
||||||
statusNode *node.StatusNode
|
statusNode *node.StatusNode
|
||||||
personalAPI *personal.PublicAPI
|
personalAPI *personal.PublicAPI
|
||||||
rpcFilters *rpcfilters.Service
|
|
||||||
multiaccountsDB *multiaccounts.Database
|
multiaccountsDB *multiaccounts.Database
|
||||||
account *multiaccounts.Account
|
account *multiaccounts.Account
|
||||||
accountManager *account.GethManager
|
accountManager *account.GethManager
|
||||||
|
@ -91,6 +72,7 @@ type GethStatusBackend struct {
|
||||||
selectedAccountKeyID string
|
selectedAccountKeyID string
|
||||||
log log.Logger
|
log log.Logger
|
||||||
allowAllRPC bool // used only for tests, disables api method restrictions
|
allowAllRPC bool // used only for tests, disables api method restrictions
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGethStatusBackend create a new GethStatusBackend instance
|
// NewGethStatusBackend create a new GethStatusBackend instance
|
||||||
|
@ -101,14 +83,12 @@ func NewGethStatusBackend() *GethStatusBackend {
|
||||||
accountManager := account.NewGethManager()
|
accountManager := account.NewGethManager()
|
||||||
transactor := transactions.NewTransactor()
|
transactor := transactions.NewTransactor()
|
||||||
personalAPI := personal.NewAPI()
|
personalAPI := personal.NewAPI()
|
||||||
rpcFilters := rpcfilters.New(statusNode)
|
|
||||||
|
|
||||||
return &GethStatusBackend{
|
return &GethStatusBackend{
|
||||||
statusNode: statusNode,
|
statusNode: statusNode,
|
||||||
accountManager: accountManager,
|
accountManager: accountManager,
|
||||||
transactor: transactor,
|
transactor: transactor,
|
||||||
personalAPI: personalAPI,
|
personalAPI: personalAPI,
|
||||||
rpcFilters: rpcFilters,
|
|
||||||
log: log.New("package", "status-go/api.GethStatusBackend"),
|
log: log.New("package", "status-go/api.GethStatusBackend"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,10 +122,12 @@ func (b *GethStatusBackend) IsNodeRunning() bool {
|
||||||
func (b *GethStatusBackend) StartNode(config *params.NodeConfig) error {
|
func (b *GethStatusBackend) StartNode(config *params.NodeConfig) error {
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
log.Info("STARTING NODE")
|
||||||
if err := b.startNode(config); err != nil {
|
if err := b.startNode(config); err != nil {
|
||||||
signal.SendNodeCrashed(err)
|
signal.SendNodeCrashed(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Info("STARTED NODE")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,6 +149,7 @@ func (b *GethStatusBackend) OpenAccounts() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b.multiaccountsDB = db
|
b.multiaccountsDB = db
|
||||||
|
b.statusNode.SetMultiaccountsDB(db)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +234,7 @@ func (b *GethStatusBackend) ensureAppDBOpened(account multiaccounts.Account, pas
|
||||||
b.log.Error("failed to initialize db", "err", err)
|
b.log.Error("failed to initialize db", "err", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
b.statusNode.SetAppDB(b.appDB)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,14 +487,17 @@ func (b *GethStatusBackend) StartNodeWithAccountAndConfig(
|
||||||
nodecfg *params.NodeConfig,
|
nodecfg *params.NodeConfig,
|
||||||
subaccs []accounts.Account,
|
subaccs []accounts.Account,
|
||||||
) error {
|
) error {
|
||||||
|
log.Info("STARTING 1 NODE")
|
||||||
err := b.SaveAccount(account)
|
err := b.SaveAccount(account)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Info("STARTING 2 NODE")
|
||||||
err = b.ensureAppDBOpened(account, password)
|
err = b.ensureAppDBOpened(account, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Info("STARTING 3 NODE")
|
||||||
err = b.saveAccountsAndSettings(settings, nodecfg, subaccs)
|
err = b.saveAccountsAndSettings(settings, nodecfg, subaccs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -565,66 +552,6 @@ func (b *GethStatusBackend) GetNodeConfig() (*params.NodeConfig, error) {
|
||||||
return b.loadNodeConfig()
|
return b.loadNodeConfig()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) rpcFiltersService() gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return rpcfilters.New(b.statusNode), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) subscriptionService() gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return subscriptions.New(func() *rpc.Client { return b.statusNode.RPCPrivateClient() }), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) rpcStatsService() gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return rpcstats.New(), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) accountsService(accountsFeed *event.Feed) gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return accountssvc.NewService(accounts.NewDB(b.appDB), b.multiaccountsDB, b.accountManager.Manager, accountsFeed), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) browsersService() gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return browsers.NewService(browsers.NewDB(b.appDB)), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) permissionsService() gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return permissions.NewService(permissions.NewDB(b.appDB)), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) mailserversService() gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return mailservers.NewService(mailservers.NewDB(b.appDB)), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) appmetricsService() gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return appmetricsservice.NewService(appmetrics.NewDB(b.appDB)), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) walletService(network uint64, accountsFeed *event.Feed) gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return wallet.NewService(wallet.NewDB(b.appDB, network), accountsFeed), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) localNotificationsService(network uint64) gethnode.ServiceConstructor {
|
|
||||||
return func(*gethnode.ServiceContext) (gethnode.Service, error) {
|
|
||||||
return localnotifications.NewService(b.appDB, network), nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
|
func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
|
@ -644,26 +571,12 @@ func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
|
||||||
if err := config.Validate(); err != nil {
|
if err := config.Validate(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
accountsFeed := &event.Feed{}
|
|
||||||
services := []gethnode.ServiceConstructor{}
|
|
||||||
services = appendIf(config.UpstreamConfig.Enabled, services, b.rpcFiltersService())
|
|
||||||
services = append(services, b.subscriptionService())
|
|
||||||
services = append(services, b.rpcStatsService())
|
|
||||||
services = append(services, b.appmetricsService())
|
|
||||||
services = appendIf(b.appDB != nil && b.multiaccountsDB != nil, services, b.accountsService(accountsFeed))
|
|
||||||
services = appendIf(config.BrowsersConfig.Enabled, services, b.browsersService())
|
|
||||||
services = appendIf(config.PermissionsConfig.Enabled, services, b.permissionsService())
|
|
||||||
services = appendIf(config.MailserversConfig.Enabled, services, b.mailserversService())
|
|
||||||
services = appendIf(config.WalletConfig.Enabled, services, b.walletService(config.NetworkID, accountsFeed))
|
|
||||||
// We ignore for now local notifications flag as users who are upgrading have no mean to enable it
|
|
||||||
services = append(services, b.localNotificationsService(config.NetworkID))
|
|
||||||
|
|
||||||
manager := b.accountManager.GetManager()
|
manager := b.accountManager.GetManager()
|
||||||
if manager == nil {
|
if manager == nil {
|
||||||
return errors.New("ethereum accounts.Manager is nil")
|
return errors.New("ethereum accounts.Manager is nil")
|
||||||
}
|
}
|
||||||
if err = b.statusNode.StartWithOptions(config, node.StartOptions{
|
if err = b.statusNode.StartWithOptions(config, node.StartOptions{
|
||||||
Services: services,
|
|
||||||
// The peers discovery protocols are started manually after
|
// The peers discovery protocols are started manually after
|
||||||
// `node.ready` signal is sent.
|
// `node.ready` signal is sent.
|
||||||
// It was discussed in https://github.com/status-im/status-go/pull/1333.
|
// It was discussed in https://github.com/status-im/status-go/pull/1333.
|
||||||
|
@ -672,13 +585,7 @@ func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if config.WalletConfig.Enabled {
|
|
||||||
walletService, err := b.statusNode.WalletService()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
walletService.SetClient(b.statusNode.RPCClient().Ethclient())
|
|
||||||
}
|
|
||||||
signal.SendNodeStarted()
|
signal.SendNodeStarted()
|
||||||
|
|
||||||
b.transactor.SetNetworkID(config.NetworkID)
|
b.transactor.SetNetworkID(config.NetworkID)
|
||||||
|
@ -691,14 +598,6 @@ func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
|
||||||
}
|
}
|
||||||
b.log.Info("Handlers registered")
|
b.log.Info("Handlers registered")
|
||||||
|
|
||||||
if st, err := b.statusNode.StatusService(); err == nil {
|
|
||||||
st.SetAccountManager(b.accountManager)
|
|
||||||
}
|
|
||||||
|
|
||||||
if st, err := b.statusNode.PeerService(); err == nil {
|
|
||||||
st.SetDiscoverer(b.StatusNode())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle a case when a node is stopped and resumed.
|
// Handle a case when a node is stopped and resumed.
|
||||||
// If there is no account selected, an error is returned.
|
// If there is no account selected, an error is returned.
|
||||||
if _, err := b.accountManager.SelectedChatAccount(); err == nil {
|
if _, err := b.accountManager.SelectedChatAccount(); err == nil {
|
||||||
|
@ -796,7 +695,7 @@ func (b *GethStatusBackend) SendTransaction(sendArgs transactions.SendTxArgs, pa
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go b.rpcFilters.TriggerTransactionSentToUpstreamEvent(hash)
|
go b.statusNode.RPCFiltersService().TriggerTransactionSentToUpstreamEvent(hash)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -807,7 +706,7 @@ func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.S
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
go b.rpcFilters.TriggerTransactionSentToUpstreamEvent(hash)
|
go b.statusNode.RPCFiltersService().TriggerTransactionSentToUpstreamEvent(hash)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -964,10 +863,7 @@ func (b *GethStatusBackend) ConnectionChange(typ string, expensive bool) {
|
||||||
b.log.Info("Network state change", "old", b.connectionState, "new", state)
|
b.log.Info("Network state change", "old", b.connectionState, "new", state)
|
||||||
|
|
||||||
b.connectionState = state
|
b.connectionState = state
|
||||||
err := b.statusNode.ConnectionChanged(state)
|
b.statusNode.ConnectionChanged(state)
|
||||||
if err != nil {
|
|
||||||
b.log.Error("failed to notify of connection changed", "err", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// logic of handling state changes here
|
// logic of handling state changes here
|
||||||
// restart node? force peers reconnect? etc
|
// restart node? force peers reconnect? etc
|
||||||
|
@ -990,54 +886,18 @@ func (b *GethStatusBackend) AppStateChange(state string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) StopLocalNotifications() error {
|
func (b *GethStatusBackend) StopLocalNotifications() error {
|
||||||
localPN, err := b.statusNode.LocalNotificationsService()
|
if b.statusNode == nil {
|
||||||
if err != nil {
|
|
||||||
b.log.Error("Retrieving of LocalNotifications service failed on StopLocalNotifications", "error", err)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return b.statusNode.StopLocalNotifications()
|
||||||
if localPN.IsStarted() {
|
|
||||||
err = localPN.Stop()
|
|
||||||
if err != nil {
|
|
||||||
b.log.Error("LocalNotifications service stop failed on StopLocalNotifications", "error", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) StartLocalNotifications() error {
|
func (b *GethStatusBackend) StartLocalNotifications() error {
|
||||||
localPN, err := b.statusNode.LocalNotificationsService()
|
if b.statusNode == nil {
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
b.log.Error("Retrieving of local notifications service failed on StartLocalNotifications", "error", err)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return b.statusNode.StartLocalNotifications()
|
||||||
|
|
||||||
wallet, err := b.statusNode.WalletService()
|
|
||||||
if err != nil {
|
|
||||||
b.log.Error("Retrieving of wallet service failed on StartLocalNotifications", "error", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if !localPN.IsStarted() {
|
|
||||||
err = localPN.Start(b.statusNode.Server())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
b.log.Error("LocalNotifications service start failed on StartLocalNotifications", "error", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = localPN.SubscribeWallet(wallet.GetFeed())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
b.log.Error("LocalNotifications service could not subscribe to wallet on StartLocalNotifications", "error", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logout clears whisper identities.
|
// Logout clears whisper identities.
|
||||||
|
@ -1061,34 +921,11 @@ func (b *GethStatusBackend) Logout() error {
|
||||||
|
|
||||||
// cleanupServices stops parts of services that doesn't managed by a node and removes injected data from services.
|
// cleanupServices stops parts of services that doesn't managed by a node and removes injected data from services.
|
||||||
func (b *GethStatusBackend) cleanupServices() error {
|
func (b *GethStatusBackend) cleanupServices() error {
|
||||||
wakuService, err := b.statusNode.WakuService()
|
b.selectedAccountKeyID = ""
|
||||||
switch err {
|
if b.statusNode == nil {
|
||||||
case node.ErrServiceUnknown: // Waku was never registered
|
return nil
|
||||||
case nil:
|
|
||||||
if err := wakuService.DeleteKeyPairs(); err != nil {
|
|
||||||
return fmt.Errorf("%s: %v", ErrWakuClearIdentitiesFailure, err)
|
|
||||||
}
|
|
||||||
b.selectedAccountKeyID = ""
|
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
return b.statusNode.Cleanup()
|
||||||
if b.statusNode.Config().WalletConfig.Enabled {
|
|
||||||
wallet, err := b.statusNode.WalletService()
|
|
||||||
switch err {
|
|
||||||
case node.ErrServiceUnknown:
|
|
||||||
case nil:
|
|
||||||
if wallet.IsStarted() {
|
|
||||||
err = wallet.Stop()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *GethStatusBackend) closeAppDB() error {
|
func (b *GethStatusBackend) closeAppDB() error {
|
||||||
|
@ -1135,9 +972,6 @@ func (b *GethStatusBackend) GetActiveAccount() (*multiaccounts.Account, error) {
|
||||||
|
|
||||||
return b.account, nil
|
return b.account, nil
|
||||||
}
|
}
|
||||||
func (b *GethStatusBackend) WakuExtService() (*wakuext.Service, error) {
|
|
||||||
return b.statusNode.WakuExtService()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
||||||
chatAccount, err := b.accountManager.SelectedChatAccount()
|
chatAccount, err := b.accountManager.SelectedChatAccount()
|
||||||
|
@ -1152,11 +986,9 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
wakuService, err := b.statusNode.WakuService()
|
wakuService := b.statusNode.WakuService()
|
||||||
|
|
||||||
switch err {
|
if wakuService != nil {
|
||||||
case node.ErrServiceUnknown: // Waku was never registered
|
|
||||||
case nil:
|
|
||||||
if err := wakuService.DeleteKeyPairs(); err != nil { // err is not possible; method return value is incorrect
|
if err := wakuService.DeleteKeyPairs(); err != nil { // err is not possible; method return value is incorrect
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1164,29 +996,21 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrWakuIdentityInjectionFailure
|
return ErrWakuIdentityInjectionFailure
|
||||||
}
|
}
|
||||||
default:
|
st := b.statusNode.WakuExtService()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if wakuService != nil {
|
if st != nil {
|
||||||
st, err := b.statusNode.WakuExtService()
|
if err := st.InitProtocol(identity, b.appDB, b.multiaccountsDB, acc, logutils.ZapLogger()); err != nil {
|
||||||
if err != nil {
|
return err
|
||||||
return err
|
}
|
||||||
|
// Set initial connection state
|
||||||
|
st.ConnectionChanged(b.connectionState)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := st.InitProtocol(identity, b.appDB, b.multiaccountsDB, acc, logutils.ZapLogger()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set initial connection state
|
|
||||||
st.ConnectionChanged(b.connectionState)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wakuV2Service, err := b.statusNode.WakuV2Service()
|
wakuV2Service := b.statusNode.WakuV2Service()
|
||||||
|
|
||||||
switch err {
|
if wakuV2Service != nil {
|
||||||
case node.ErrServiceUnknown: // WakuV2 was never registered
|
|
||||||
case nil:
|
|
||||||
if err := wakuV2Service.DeleteKeyPairs(); err != nil { // err is not possible; method return value is incorrect
|
if err := wakuV2Service.DeleteKeyPairs(); err != nil { // err is not possible; method return value is incorrect
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1194,15 +1018,7 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrWakuIdentityInjectionFailure
|
return ErrWakuIdentityInjectionFailure
|
||||||
}
|
}
|
||||||
default:
|
st := b.statusNode.WakuV2ExtService()
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if wakuV2Service != nil {
|
|
||||||
st, err := b.statusNode.WakuV2ExtService()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := st.InitProtocol(identity, b.appDB, b.multiaccountsDB, acc, logutils.ZapLogger()); err != nil {
|
if err := st.InitProtocol(identity, b.appDB, b.multiaccountsDB, acc, logutils.ZapLogger()); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1212,13 +1028,6 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendIf(condition bool, services []gethnode.ServiceConstructor, service gethnode.ServiceConstructor) []gethnode.ServiceConstructor {
|
|
||||||
if !condition {
|
|
||||||
return services
|
|
||||||
}
|
|
||||||
return append(services, service)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractGroupMembershipSignatures extract signatures from tuples of content/signature
|
// ExtractGroupMembershipSignatures extract signatures from tuples of content/signature
|
||||||
func (b *GethStatusBackend) ExtractGroupMembershipSignatures(signaturePairs [][2]string) ([]string, error) {
|
func (b *GethStatusBackend) ExtractGroupMembershipSignatures(signaturePairs [][2]string) ([]string, error) {
|
||||||
return crypto.ExtractSignatures(signaturePairs)
|
return crypto.ExtractSignatures(signaturePairs)
|
||||||
|
|
|
@ -140,13 +140,13 @@ func main() {
|
||||||
backend := api.NewGethStatusBackend()
|
backend := api.NewGethStatusBackend()
|
||||||
err = ImportAccount(*seedPhrase, backend)
|
err = ImportAccount(*seedPhrase, backend)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed", "err", err)
|
logger.Error("failed import account", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
wakuextservice, err := backend.WakuExtService()
|
wakuextservice := backend.StatusNode().WakuExtService()
|
||||||
if err != nil {
|
if wakuextservice == nil {
|
||||||
logger.Error("failed", "err", err)
|
logger.Error("wakuext not available")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,14 +165,14 @@ func main() {
|
||||||
for i := 0; i < *nAddedContacts; i++ {
|
for i := 0; i < *nAddedContacts; i++ {
|
||||||
key, err := crypto.GenerateKey()
|
key, err := crypto.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed", err)
|
logger.Error("failed generate key", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
keyString := common.PubkeyToHex(&key.PublicKey)
|
keyString := common.PubkeyToHex(&key.PublicKey)
|
||||||
_, err = wakuext.AddContact(context.Background(), keyString)
|
_, err = wakuext.AddContact(context.Background(), keyString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed", "err", err)
|
logger.Error("failed Add contact", "err", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,6 +253,11 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
url := "enode://30211cbd81c25f07b03a0196d56e6ce4604bb13db773ff1c0ea2253547fafd6c06eae6ad3533e2ba39d59564cfbdbb5e2ce7c137a5ebb85e99dcfc7a75f99f55@23.236.58.92:443"
|
||||||
|
fmt.Println("UPDATING")
|
||||||
|
wakuext.UpdateMailservers([]string{url})
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
fmt.Println("UPDATED")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -427,21 +432,25 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
||||||
manager.InitKeystore("./tmp")
|
manager.InitKeystore("./tmp")
|
||||||
err := backend.OpenAccounts()
|
err := backend.OpenAccounts()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error("failed open accounts", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
generator := manager.AccountsGenerator()
|
generator := manager.AccountsGenerator()
|
||||||
generatedAccountInfo, err := generator.ImportMnemonic(seedPhrase, "")
|
generatedAccountInfo, err := generator.ImportMnemonic(seedPhrase, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error("import mnemonic", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
derivedAddresses, err := generator.DeriveAddresses(generatedAccountInfo.ID, paths)
|
derivedAddresses, err := generator.DeriveAddresses(generatedAccountInfo.ID, paths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error("deriver addressess", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = generator.StoreDerivedAccounts(generatedAccountInfo.ID, "", paths)
|
_, err = generator.StoreDerivedAccounts(generatedAccountInfo.ID, "", paths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error("store addressess", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -450,11 +459,13 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
||||||
}
|
}
|
||||||
settings, err := defaultSettings(generatedAccountInfo, derivedAddresses, &seedPhrase)
|
settings, err := defaultSettings(generatedAccountInfo, derivedAddresses, &seedPhrase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error("default settings", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeConfig, err := defaultNodeConfig(settings.InstallationID)
|
nodeConfig, err := defaultNodeConfig(settings.InstallationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
logger.Error("node config", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -477,8 +488,15 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
||||||
Path: pathDefaultChat,
|
Path: pathDefaultChat,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Println(nodeConfig)
|
||||||
accounts := []accounts.Account{walletAccount, chatAccount}
|
accounts := []accounts.Account{walletAccount, chatAccount}
|
||||||
return backend.StartNodeWithAccountAndConfig(account, "", *settings, nodeConfig, accounts)
|
err = backend.StartNodeWithAccountAndConfig(account, "", *settings, nodeConfig, accounts)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error("start node", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
|
@ -486,7 +504,7 @@ var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
||||||
func buildMessage(chat *protocol.Chat, count int) *common.Message {
|
func buildMessage(chat *protocol.Chat, count int) *common.Message {
|
||||||
key, err := crypto.GenerateKey()
|
key, err := crypto.GenerateKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed", err)
|
logger.Error("failed build message", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
#/bin/bash
|
||||||
|
go build -mod=vendor
|
||||||
|
rm ./tmp -rf
|
||||||
|
./populate-db --added-contacts 1 --contacts 2 --public-chats 1 --one-to-one-chats 4 --number-of-messages 2 --seed-phrase "wolf uncover ancient kiss deer blossom blind expose estate average cancel kiss"
|
|
@ -3,8 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/status-im/status-go/node"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc) {
|
func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc) {
|
||||||
|
@ -14,41 +12,3 @@ func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc)
|
||||||
|
|
||||||
return context.WithTimeout(context.Background(), time.Duration(timeout)*time.Minute)
|
return context.WithTimeout(context.Background(), time.Duration(timeout)*time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncAndStopNode tries to sync the blockchain and stop the node.
|
|
||||||
// It returns an exit code (`0` if successful or `1` in case of error)
|
|
||||||
// that can be used in `os.Exit` to exit immediately when the function returns.
|
|
||||||
// The special exit code `-1` is used if execution was interrupted.
|
|
||||||
func syncAndStopNode(interruptCh <-chan struct{}, statusNode *node.StatusNode, timeout int) (exitCode int) {
|
|
||||||
|
|
||||||
logger.Info("syncAndStopNode: node will synchronize the chain and exit", "timeoutInMins", timeout)
|
|
||||||
|
|
||||||
ctx, cancel := createContextFromTimeout(timeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
doneSync := make(chan struct{})
|
|
||||||
errSync := make(chan error)
|
|
||||||
go func() {
|
|
||||||
if err := statusNode.EnsureSync(ctx); err != nil {
|
|
||||||
errSync <- err
|
|
||||||
}
|
|
||||||
close(doneSync)
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case err := <-errSync:
|
|
||||||
logger.Error("syncAndStopNode: failed to sync the chain", "error", err)
|
|
||||||
exitCode = 1
|
|
||||||
case <-doneSync:
|
|
||||||
case <-interruptCh:
|
|
||||||
// cancel context and return immediately if interrupted
|
|
||||||
// `-1` is used as a special exit code to denote interruption
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := statusNode.Stop(); err != nil {
|
|
||||||
logger.Error("syncAndStopNode: failed to stop the node", "error", err)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
|
@ -71,8 +71,6 @@ var (
|
||||||
// don't change the name of this flag, https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L41
|
// don't change the name of this flag, https://github.com/ethereum/go-ethereum/blob/master/metrics/metrics.go#L41
|
||||||
metricsEnabled = flag.Bool("metrics", false, "Expose ethereum metrics with debug_metrics jsonrpc call")
|
metricsEnabled = flag.Bool("metrics", false, "Expose ethereum metrics with debug_metrics jsonrpc call")
|
||||||
metricsPort = flag.Int("metrics-port", 9305, "Port for the Prometheus /metrics endpoint")
|
metricsPort = flag.Int("metrics-port", 9305, "Port for the Prometheus /metrics endpoint")
|
||||||
|
|
||||||
syncAndExit = flag.Int("sync-and-exit", -1, "Timeout in minutes for blockchain sync and exit, zero means no timeout unless sync is finished")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// All general log messages in this package should be routed through this logger.
|
// All general log messages in this package should be routed through this logger.
|
||||||
|
@ -182,20 +180,6 @@ func main() {
|
||||||
profiling.NewProfiler(*pprofPort).Go()
|
profiling.NewProfiler(*pprofPort).Go()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sync blockchain and stop.
|
|
||||||
if *syncAndExit >= 0 {
|
|
||||||
exitCode := syncAndStopNode(interruptCh, backend.StatusNode(), *syncAndExit)
|
|
||||||
// Call was interrupted. Wait for graceful shutdown.
|
|
||||||
if exitCode == -1 {
|
|
||||||
if gethNode := backend.StatusNode().GethNode(); gethNode != nil {
|
|
||||||
gethNode.Wait()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Otherwise, exit immediately with a returned exit code.
|
|
||||||
os.Exit(exitCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.PushNotificationServerConfig.Enabled {
|
if config.PushNotificationServerConfig.Enabled {
|
||||||
if config.NodeKey == "" {
|
if config.NodeKey == "" {
|
||||||
logger.Error("node key needs to be set if running a push notification server")
|
logger.Error("node key needs to be set if running a push notification server")
|
||||||
|
@ -227,7 +211,7 @@ func main() {
|
||||||
protocol.WithDatabase(db),
|
protocol.WithDatabase(db),
|
||||||
}
|
}
|
||||||
|
|
||||||
messenger, err := protocol.NewMessenger(identity, gethbridge.NewNodeBridge(backend.StatusNode().GethNode()), installationID.String(), options...)
|
messenger, err := protocol.NewMessenger(identity, gethbridge.NewNodeBridge(backend.StatusNode().GethNode(), backend.StatusNode().WakuService(), backend.StatusNode().WakuV2Service()), installationID.String(), options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error("failed to create messenger", "error", err)
|
logger.Error("failed to create messenger", "error", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -3,8 +3,6 @@ package main
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/status-im/status-go/node"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc) {
|
func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc) {
|
||||||
|
@ -14,41 +12,3 @@ func createContextFromTimeout(timeout int) (context.Context, context.CancelFunc)
|
||||||
|
|
||||||
return context.WithTimeout(context.Background(), time.Duration(timeout)*time.Minute)
|
return context.WithTimeout(context.Background(), time.Duration(timeout)*time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
// syncAndStopNode tries to sync the blockchain and stop the node.
|
|
||||||
// It returns an exit code (`0` if successful or `1` in case of error)
|
|
||||||
// that can be used in `os.Exit` to exit immediately when the function returns.
|
|
||||||
// The special exit code `-1` is used if execution was interrupted.
|
|
||||||
func syncAndStopNode(interruptCh <-chan struct{}, statusNode *node.StatusNode, timeout int) (exitCode int) {
|
|
||||||
|
|
||||||
logger.Info("syncAndStopNode: node will synchronize the chain and exit", "timeoutInMins", timeout)
|
|
||||||
|
|
||||||
ctx, cancel := createContextFromTimeout(timeout)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
doneSync := make(chan struct{})
|
|
||||||
errSync := make(chan error)
|
|
||||||
go func() {
|
|
||||||
if err := statusNode.EnsureSync(ctx); err != nil {
|
|
||||||
errSync <- err
|
|
||||||
}
|
|
||||||
close(doneSync)
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case err := <-errSync:
|
|
||||||
logger.Error("syncAndStopNode: failed to sync the chain", "error", err)
|
|
||||||
exitCode = 1
|
|
||||||
case <-doneSync:
|
|
||||||
case <-interruptCh:
|
|
||||||
// cancel context and return immediately if interrupted
|
|
||||||
// `-1` is used as a special exit code to denote interruption
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := statusNode.Stop(); err != nil {
|
|
||||||
logger.Error("syncAndStopNode: failed to stop the node", "error", err)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StatusService interface {
|
||||||
|
Start() error
|
||||||
|
Stop() error
|
||||||
|
Protocols() []p2p.Protocol
|
||||||
|
APIs() []rpc.API
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
package gethbridge
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"errors"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/extkeys"
|
||||||
|
)
|
||||||
|
|
||||||
|
type gethKeyStoreAdapter struct {
|
||||||
|
keystore *keystore.KeyStore
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapKeyStore creates a types.KeyStore wrapper over a keystore.KeyStore object
|
||||||
|
func WrapKeyStore(keystore *keystore.KeyStore) types.KeyStore {
|
||||||
|
return &gethKeyStoreAdapter{keystore: keystore}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gethKeyStoreAdapter) ImportECDSA(priv *ecdsa.PrivateKey, passphrase string) (types.Account, error) {
|
||||||
|
gethAccount, err := k.keystore.ImportECDSA(priv, passphrase)
|
||||||
|
return accountFrom(gethAccount), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gethKeyStoreAdapter) ImportSingleExtendedKey(extKey *extkeys.ExtendedKey, passphrase string) (types.Account, error) {
|
||||||
|
gethAccount, err := k.keystore.ImportSingleExtendedKey(extKey, passphrase)
|
||||||
|
return accountFrom(gethAccount), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gethKeyStoreAdapter) ImportExtendedKeyForPurpose(keyPurpose extkeys.KeyPurpose, extKey *extkeys.ExtendedKey, passphrase string) (types.Account, error) {
|
||||||
|
gethAccount, err := k.keystore.ImportExtendedKeyForPurpose(keyPurpose, extKey, passphrase)
|
||||||
|
return accountFrom(gethAccount), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gethKeyStoreAdapter) AccountDecryptedKey(a types.Account, auth string) (types.Account, *types.Key, error) {
|
||||||
|
gethAccount, err := gethAccountFrom(a)
|
||||||
|
if err != nil {
|
||||||
|
return types.Account{}, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var gethKey *keystore.Key
|
||||||
|
gethAccount, gethKey, err = k.keystore.AccountDecryptedKey(gethAccount, auth)
|
||||||
|
return accountFrom(gethAccount), keyFrom(gethKey), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k *gethKeyStoreAdapter) Delete(a types.Account, auth string) error {
|
||||||
|
gethAccount, err := gethAccountFrom(a)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return k.keystore.Delete(gethAccount, auth)
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseGethURL converts a user supplied URL into the accounts specific structure.
|
||||||
|
func parseGethURL(url string) (accounts.URL, error) {
|
||||||
|
parts := strings.Split(url, "://")
|
||||||
|
if len(parts) != 2 || parts[0] == "" {
|
||||||
|
return accounts.URL{}, errors.New("protocol scheme missing")
|
||||||
|
}
|
||||||
|
return accounts.URL{
|
||||||
|
Scheme: parts[0],
|
||||||
|
Path: parts[1],
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func gethAccountFrom(account types.Account) (accounts.Account, error) {
|
||||||
|
var (
|
||||||
|
gethAccount accounts.Account
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
gethAccount.Address = common.Address(account.Address)
|
||||||
|
if account.URL != "" {
|
||||||
|
gethAccount.URL, err = parseGethURL(account.URL)
|
||||||
|
}
|
||||||
|
return gethAccount, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func accountFrom(gethAccount accounts.Account) types.Account {
|
||||||
|
return types.Account{
|
||||||
|
Address: types.Address(gethAccount.Address),
|
||||||
|
URL: gethAccount.URL.String(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func keyFrom(k *keystore.Key) *types.Key {
|
||||||
|
if k == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &types.Key{
|
||||||
|
ID: k.Id,
|
||||||
|
Address: types.Address(k.Address),
|
||||||
|
PrivateKey: k.PrivateKey,
|
||||||
|
ExtendedKey: k.ExtendedKey,
|
||||||
|
SubAccountIndex: k.SubAccountIndex,
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,10 +18,12 @@ import (
|
||||||
|
|
||||||
type gethNodeWrapper struct {
|
type gethNodeWrapper struct {
|
||||||
stack *node.Node
|
stack *node.Node
|
||||||
|
waku1 *waku.Waku
|
||||||
|
waku2 *wakuv2.Waku
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNodeBridge(stack *node.Node) types.Node {
|
func NewNodeBridge(stack *node.Node, waku1 *waku.Waku, waku2 *wakuv2.Waku) types.Node {
|
||||||
return &gethNodeWrapper{stack: stack}
|
return &gethNodeWrapper{stack: stack, waku1: waku1, waku2: waku2}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *gethNodeWrapper) Poll() {
|
func (w *gethNodeWrapper) Poll() {
|
||||||
|
@ -32,50 +34,28 @@ func (w *gethNodeWrapper) NewENSVerifier(logger *zap.Logger) enstypes.ENSVerifie
|
||||||
return gethens.NewVerifier(logger)
|
return gethens.NewVerifier(logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *gethNodeWrapper) SetWaku1(waku *waku.Waku) {
|
||||||
|
w.waku1 = waku
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *gethNodeWrapper) SetWaku2(waku *wakuv2.Waku) {
|
||||||
|
w.waku2 = waku
|
||||||
|
}
|
||||||
|
|
||||||
func (w *gethNodeWrapper) GetWaku(ctx interface{}) (types.Waku, error) {
|
func (w *gethNodeWrapper) GetWaku(ctx interface{}) (types.Waku, error) {
|
||||||
var nativeWaku *waku.Waku
|
if w.waku1 == nil {
|
||||||
if ctx == nil || ctx == w {
|
|
||||||
err := w.stack.Service(&nativeWaku)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch serviceProvider := ctx.(type) {
|
|
||||||
case *node.ServiceContext:
|
|
||||||
err := serviceProvider.Service(&nativeWaku)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nativeWaku == nil {
|
|
||||||
return nil, errors.New("waku service is not available")
|
return nil, errors.New("waku service is not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewGethWakuWrapper(nativeWaku), nil
|
return NewGethWakuWrapper(w.waku1), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *gethNodeWrapper) GetWakuV2(ctx interface{}) (types.Waku, error) {
|
func (w *gethNodeWrapper) GetWakuV2(ctx interface{}) (types.Waku, error) {
|
||||||
var nativeWaku *wakuv2.Waku
|
if w.waku2 == nil {
|
||||||
if ctx == nil || ctx == w {
|
|
||||||
err := w.stack.Service(&nativeWaku)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch serviceProvider := ctx.(type) {
|
|
||||||
case *node.ServiceContext:
|
|
||||||
err := serviceProvider.Service(&nativeWaku)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nativeWaku == nil {
|
|
||||||
return nil, errors.New("waku service is not available")
|
return nil, errors.New("waku service is not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
return NewGethWakuV2Wrapper(nativeWaku), nil
|
return NewGethWakuV2Wrapper(w.waku2), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *gethNodeWrapper) AddPeer(url string) error {
|
func (w *gethNodeWrapper) AddPeer(url string) error {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pborman/uuid"
|
"github.com/google/uuid"
|
||||||
"golang.org/x/crypto/pbkdf2"
|
"golang.org/x/crypto/pbkdf2"
|
||||||
"golang.org/x/crypto/scrypt"
|
"golang.org/x/crypto/scrypt"
|
||||||
|
|
||||||
|
@ -107,8 +107,13 @@ func DecryptKey(keyjson []byte, auth string) (*types.Key, error) {
|
||||||
}
|
}
|
||||||
key := crypto.ToECDSAUnsafe(keyBytes)
|
key := crypto.ToECDSAUnsafe(keyBytes)
|
||||||
|
|
||||||
|
id, err := uuid.FromBytes(keyId)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &types.Key{
|
return &types.Key{
|
||||||
ID: uuid.UUID(keyId),
|
ID: id,
|
||||||
Address: crypto.PubkeyToAddress(key.PublicKey),
|
Address: crypto.PubkeyToAddress(key.PublicKey),
|
||||||
PrivateKey: key,
|
PrivateKey: key,
|
||||||
ExtendedKey: extKey,
|
ExtendedKey: extKey,
|
||||||
|
@ -156,7 +161,11 @@ func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byt
|
||||||
if keyProtected.Version != version {
|
if keyProtected.Version != version {
|
||||||
return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
|
return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
|
||||||
}
|
}
|
||||||
keyId = uuid.Parse(keyProtected.Id)
|
id, err := uuid.Parse(keyProtected.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
keyId = id[:]
|
||||||
plainText, err := DecryptDataV3(keyProtected.Crypto, auth)
|
plainText, err := DecryptDataV3(keyProtected.Crypto, auth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -165,7 +174,12 @@ func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byt
|
||||||
}
|
}
|
||||||
|
|
||||||
func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
|
func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
|
||||||
keyId = uuid.Parse(keyProtected.Id)
|
id, err := uuid.Parse(keyProtected.Id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
keyId = id[:]
|
||||||
|
|
||||||
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
|
mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -329,8 +343,7 @@ func pkcs7Unpad(in []byte) []byte {
|
||||||
return in[:len(in)-int(padding)]
|
return in[:len(in)-int(padding)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RawKeyToCryptoJSON(rawKeyFile []byte) (cj CryptoJSON, e error) {
|
||||||
func RawKeyToCryptoJSON(rawKeyFile []byte) (cj CryptoJSON, e error){
|
|
||||||
var keyJSON encryptedKeyJSONV3
|
var keyJSON encryptedKeyJSONV3
|
||||||
if e := json.Unmarshal(rawKeyFile, &keyJSON); e != nil {
|
if e := json.Unmarshal(rawKeyFile, &keyJSON); e != nil {
|
||||||
return cj, fmt.Errorf("failed to read key file: %s", e)
|
return cj, fmt.Errorf("failed to read key file: %s", e)
|
||||||
|
|
|
@ -3,7 +3,7 @@ package types
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
|
||||||
"github.com/pborman/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
"github.com/status-im/status-go/extkeys"
|
"github.com/status-im/status-go/extkeys"
|
||||||
)
|
)
|
||||||
|
|
|
@ -516,27 +516,6 @@ func makeJSONResponse(err error) string {
|
||||||
return string(outBytes)
|
return string(outBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNodesFromContract returns a list of nodes from a given contract
|
|
||||||
//export GetNodesFromContract
|
|
||||||
func GetNodesFromContract(rpcEndpoint string, contractAddress string) string {
|
|
||||||
nodes, err := statusBackend.GetNodesFromContract(
|
|
||||||
rpcEndpoint,
|
|
||||||
contractAddress,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
return makeJSONResponse(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(struct {
|
|
||||||
Nodes []string `json:"result"`
|
|
||||||
}{Nodes: nodes})
|
|
||||||
if err != nil {
|
|
||||||
return makeJSONResponse(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddPeer adds an enode as a peer.
|
// AddPeer adds an enode as a peer.
|
||||||
func AddPeer(enode string) string {
|
func AddPeer(enode string) string {
|
||||||
err := statusBackend.StatusNode().AddPeer(enode)
|
err := statusBackend.StatusNode().AddPeer(enode)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package node
|
package node
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
@ -16,27 +16,36 @@ import (
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/les"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/account"
|
||||||
"github.com/status-im/status-go/connection"
|
"github.com/status-im/status-go/connection"
|
||||||
"github.com/status-im/status-go/db"
|
"github.com/status-im/status-go/db"
|
||||||
"github.com/status-im/status-go/discovery"
|
"github.com/status-im/status-go/discovery"
|
||||||
|
"github.com/status-im/status-go/multiaccounts"
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/peers"
|
"github.com/status-im/status-go/peers"
|
||||||
"github.com/status-im/status-go/rpc"
|
"github.com/status-im/status-go/rpc"
|
||||||
|
accountssvc "github.com/status-im/status-go/services/accounts"
|
||||||
|
appmetricsservice "github.com/status-im/status-go/services/appmetrics"
|
||||||
"github.com/status-im/status-go/services/browsers"
|
"github.com/status-im/status-go/services/browsers"
|
||||||
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
||||||
|
"github.com/status-im/status-go/services/mailservers"
|
||||||
|
"github.com/status-im/status-go/services/nodebridge"
|
||||||
"github.com/status-im/status-go/services/peer"
|
"github.com/status-im/status-go/services/peer"
|
||||||
"github.com/status-im/status-go/services/permissions"
|
"github.com/status-im/status-go/services/permissions"
|
||||||
"github.com/status-im/status-go/services/status"
|
"github.com/status-im/status-go/services/personal"
|
||||||
|
"github.com/status-im/status-go/services/rpcfilters"
|
||||||
|
"github.com/status-im/status-go/services/rpcstats"
|
||||||
|
"github.com/status-im/status-go/services/subscriptions"
|
||||||
"github.com/status-im/status-go/services/wakuext"
|
"github.com/status-im/status-go/services/wakuext"
|
||||||
"github.com/status-im/status-go/services/wakuv2ext"
|
"github.com/status-im/status-go/services/wakuv2ext"
|
||||||
"github.com/status-im/status-go/services/wallet"
|
"github.com/status-im/status-go/services/wallet"
|
||||||
|
"github.com/status-im/status-go/timesource"
|
||||||
"github.com/status-im/status-go/waku"
|
"github.com/status-im/status-go/waku"
|
||||||
"github.com/status-im/status-go/wakuv2"
|
"github.com/status-im/status-go/wakuv2"
|
||||||
)
|
)
|
||||||
|
@ -59,6 +68,9 @@ var (
|
||||||
type StatusNode struct {
|
type StatusNode struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
|
appDB *sql.DB
|
||||||
|
multiaccountsDB *multiaccounts.Database
|
||||||
|
|
||||||
config *params.NodeConfig // Status node configuration
|
config *params.NodeConfig // Status node configuration
|
||||||
gethNode *node.Node // reference to Geth P2P stack/node
|
gethNode *node.Node // reference to Geth P2P stack/node
|
||||||
rpcClient *rpc.Client // reference to public RPC client
|
rpcClient *rpc.Client // reference to public RPC client
|
||||||
|
@ -70,12 +82,37 @@ type StatusNode struct {
|
||||||
db *leveldb.DB // used as a cache for PeerPool
|
db *leveldb.DB // used as a cache for PeerPool
|
||||||
|
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
|
||||||
|
gethAccountManager *account.GethManager
|
||||||
|
accountsManager *accounts.Manager
|
||||||
|
|
||||||
|
// services
|
||||||
|
// Not sure whether we can use the one that has already be initalized above
|
||||||
|
rpcFiltersSrvc *rpcfilters.Service
|
||||||
|
subscriptionsSrvc *subscriptions.Service
|
||||||
|
rpcStatsSrvc *rpcstats.Service
|
||||||
|
accountsSrvc *accountssvc.Service
|
||||||
|
browsersSrvc *browsers.Service
|
||||||
|
nodeBridgeSrvc *nodebridge.NodeService
|
||||||
|
permissionsSrvc *permissions.Service
|
||||||
|
mailserversSrvc *mailservers.Service
|
||||||
|
appMetricsSrvc *appmetricsservice.Service
|
||||||
|
walletSrvc *wallet.Service
|
||||||
|
peerSrvc *peer.Service
|
||||||
|
localNotificationsSrvc *localnotifications.Service
|
||||||
|
personalSrvc *personal.Service
|
||||||
|
timeSourceSrvc *timesource.NTPTimeSource
|
||||||
|
wakuSrvc *waku.Waku
|
||||||
|
wakuExtSrvc *wakuext.Service
|
||||||
|
wakuV2Srvc *wakuv2.Waku
|
||||||
|
wakuV2ExtSrvc *wakuv2ext.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
// New makes new instance of StatusNode.
|
// New makes new instance of StatusNode.
|
||||||
func New() *StatusNode {
|
func New() *StatusNode {
|
||||||
return &StatusNode{
|
return &StatusNode{
|
||||||
log: log.New("package", "status-go/node.StatusNode"),
|
gethAccountManager: account.NewGethManager(),
|
||||||
|
log: log.New("package", "status-go/node.StatusNode"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,9 +146,9 @@ func (n *StatusNode) Server() *p2p.Server {
|
||||||
|
|
||||||
// Start starts current StatusNode, failing if it's already started.
|
// Start starts current StatusNode, failing if it's already started.
|
||||||
// It accepts a list of services that should be added to the node.
|
// It accepts a list of services that should be added to the node.
|
||||||
func (n *StatusNode) Start(config *params.NodeConfig, accs *accounts.Manager, services ...node.ServiceConstructor) error {
|
func (n *StatusNode) Start(config *params.NodeConfig, accs *accounts.Manager) error {
|
||||||
|
n.accountsManager = accs
|
||||||
return n.StartWithOptions(config, StartOptions{
|
return n.StartWithOptions(config, StartOptions{
|
||||||
Services: services,
|
|
||||||
StartDiscovery: true,
|
StartDiscovery: true,
|
||||||
AccountsManager: accs,
|
AccountsManager: accs,
|
||||||
})
|
})
|
||||||
|
@ -119,7 +156,6 @@ func (n *StatusNode) Start(config *params.NodeConfig, accs *accounts.Manager, se
|
||||||
|
|
||||||
// StartOptions allows to control some parameters of Start() method.
|
// StartOptions allows to control some parameters of Start() method.
|
||||||
type StartOptions struct {
|
type StartOptions struct {
|
||||||
Services []node.ServiceConstructor
|
|
||||||
StartDiscovery bool
|
StartDiscovery bool
|
||||||
AccountsManager *accounts.Manager
|
AccountsManager *accounts.Manager
|
||||||
}
|
}
|
||||||
|
@ -135,6 +171,8 @@ func (n *StatusNode) StartWithOptions(config *params.NodeConfig, options StartOp
|
||||||
return ErrNodeRunning
|
return ErrNodeRunning
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n.accountsManager = options.AccountsManager
|
||||||
|
|
||||||
n.log.Debug("starting with options", "ClusterConfig", config.ClusterConfig)
|
n.log.Debug("starting with options", "ClusterConfig", config.ClusterConfig)
|
||||||
|
|
||||||
db, err := db.Create(config.DataDir, params.StatusDatabase)
|
db, err := db.Create(config.DataDir, params.StatusDatabase)
|
||||||
|
@ -143,9 +181,11 @@ func (n *StatusNode) StartWithOptions(config *params.NodeConfig, options StartOp
|
||||||
}
|
}
|
||||||
|
|
||||||
n.db = db
|
n.db = db
|
||||||
|
n.log.Info("starting with db")
|
||||||
|
|
||||||
err = n.startWithDB(config, options.AccountsManager, db, options.Services)
|
err = n.startWithDB(config, options.AccountsManager, db)
|
||||||
|
|
||||||
|
n.log.Info("started with db")
|
||||||
// continue only if there was no error when starting node with a db
|
// continue only if there was no error when starting node with a db
|
||||||
if err == nil && options.StartDiscovery && n.discoveryEnabled() {
|
if err == nil && options.StartDiscovery && n.discoveryEnabled() {
|
||||||
err = n.startDiscovery()
|
err = n.startDiscovery()
|
||||||
|
@ -162,21 +202,22 @@ func (n *StatusNode) StartWithOptions(config *params.NodeConfig, options StartOp
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *StatusNode) startWithDB(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB, services []node.ServiceConstructor) error {
|
func (n *StatusNode) startWithDB(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) error {
|
||||||
if err := n.createNode(config, accs, db); err != nil {
|
if err := n.createNode(config, accs, db); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
n.config = config
|
n.config = config
|
||||||
|
n.log.Info("starting geth node")
|
||||||
|
|
||||||
if err := n.startGethNode(services); err != nil {
|
n.log.Info("setting up rpc client")
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := n.setupRPCClient(); err != nil {
|
if err := n.setupRPCClient(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
if err := n.initServices(config); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return n.startGethNode()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *StatusNode) createNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) (err error) {
|
func (n *StatusNode) createNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) (err error) {
|
||||||
|
@ -185,19 +226,13 @@ func (n *StatusNode) createNode(config *params.NodeConfig, accs *accounts.Manage
|
||||||
}
|
}
|
||||||
|
|
||||||
// startGethNode starts current StatusNode, will fail if it's already started.
|
// startGethNode starts current StatusNode, will fail if it's already started.
|
||||||
func (n *StatusNode) startGethNode(services []node.ServiceConstructor) error {
|
func (n *StatusNode) startGethNode() error {
|
||||||
for _, service := range services {
|
|
||||||
if err := n.gethNode.Register(service); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.gethNode.Start()
|
return n.gethNode.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *StatusNode) setupRPCClient() (err error) {
|
func (n *StatusNode) setupRPCClient() (err error) {
|
||||||
// setup public RPC client
|
// setup public RPC client
|
||||||
gethNodeClient, err := n.gethNode.AttachPublic()
|
gethNodeClient, err := n.gethNode.Attach()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -315,8 +350,6 @@ func (n *StatusNode) startDiscovery() error {
|
||||||
options.AllowStop = len(n.config.RegisterTopics) == 0
|
options.AllowStop = len(n.config.RegisterTopics) == 0
|
||||||
options.TrustedMailServers = parseNodesToNodeID(n.config.ClusterConfig.TrustedMailServers)
|
options.TrustedMailServers = parseNodesToNodeID(n.config.ClusterConfig.TrustedMailServers)
|
||||||
|
|
||||||
options.MailServerRegistryAddress = n.config.MailServerRegistryAddress
|
|
||||||
|
|
||||||
n.peerPool = peers.NewPeerPool(
|
n.peerPool = peers.NewPeerPool(
|
||||||
n.discovery,
|
n.discovery,
|
||||||
n.config.RequireTopics,
|
n.config.RequireTopics,
|
||||||
|
@ -355,7 +388,7 @@ func (n *StatusNode) stop() error {
|
||||||
n.discovery = nil
|
n.discovery = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := n.gethNode.Stop(); err != nil {
|
if err := n.gethNode.Close(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,163 +553,12 @@ func (n *StatusNode) PeerCount() int {
|
||||||
return n.gethNode.Server().PeerCount()
|
return n.gethNode.Server().PeerCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
// gethService is a wrapper for gethNode.Service which retrieves a currently
|
func (n *StatusNode) ConnectionChanged(state connection.State) {
|
||||||
// running service registered of a specific type.
|
if n.wakuExtSrvc == nil {
|
||||||
func (n *StatusNode) gethService(serviceInstance interface{}) error {
|
return
|
||||||
if !n.isRunning() {
|
|
||||||
return ErrNoRunningNode
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := n.gethNode.Service(serviceInstance); err != nil {
|
n.wakuExtSrvc.ConnectionChanged(state)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LightEthereumService exposes reference to LES service running on top of the node
|
|
||||||
func (n *StatusNode) LightEthereumService() (l *les.LightEthereum, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
|
|
||||||
err = n.gethService(&l)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// StatusService exposes reference to status service running on top of the node
|
|
||||||
func (n *StatusNode) StatusService() (st *status.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
|
|
||||||
err = n.gethService(&st)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerService exposes reference to peer service running on top of the node.
|
|
||||||
func (n *StatusNode) PeerService() (st *peer.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
|
|
||||||
err = n.gethService(&st)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WakuService exposes reference to Waku service running on top of the node
|
|
||||||
func (n *StatusNode) WakuService() (w *waku.Waku, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
|
|
||||||
err = n.gethService(&w)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WakuV2Service exposes reference to Whisper service running on top of the node
|
|
||||||
func (n *StatusNode) WakuV2Service() (w *wakuv2.Waku, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
|
|
||||||
err = n.gethService(&w)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WakuExtService exposes reference to shh extension service running on top of the node
|
|
||||||
func (n *StatusNode) WakuExtService() (s *wakuext.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
|
|
||||||
err = n.gethService(&s)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *StatusNode) ConnectionChanged(state connection.State) error {
|
|
||||||
service, err := n.WakuExtService()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
service.ConnectionChanged(state)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WakuV2ExtService exposes reference to waku v2 extension service running on top of the node
|
|
||||||
func (n *StatusNode) WakuV2ExtService() (s *wakuv2ext.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
|
|
||||||
err = n.gethService(&s)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WalletService returns wallet.Service instance if it was started.
|
|
||||||
func (n *StatusNode) WalletService() (s *wallet.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
err = n.gethService(&s)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// LocalNotificationsService returns localnotifications.Service instance if it was started.
|
|
||||||
func (n *StatusNode) LocalNotificationsService() (s *localnotifications.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
err = n.gethService(&s)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// BrowsersService returns browsers.Service instance if it was started.
|
|
||||||
func (n *StatusNode) BrowsersService() (s *browsers.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
err = n.gethService(&s)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// PermissionsService returns browsers.Service instance if it was started.
|
|
||||||
func (n *StatusNode) PermissionsService() (s *permissions.Service, err error) {
|
|
||||||
n.mu.RLock()
|
|
||||||
defer n.mu.RUnlock()
|
|
||||||
err = n.gethService(&s)
|
|
||||||
if err == node.ErrServiceUnknown {
|
|
||||||
err = ErrServiceUnknown
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccountManager exposes reference to node's accounts manager
|
// AccountManager exposes reference to node's accounts manager
|
||||||
|
@ -735,67 +617,6 @@ func (n *StatusNode) ChaosModeCheckRPCClientsUpstreamURL(on bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnsureSync waits until blockchain synchronization
|
|
||||||
// is complete and returns.
|
|
||||||
func (n *StatusNode) EnsureSync(ctx context.Context) error {
|
|
||||||
// Don't wait for any blockchain sync for the
|
|
||||||
// local private chain as blocks are never mined.
|
|
||||||
if n.config.NetworkID == 0 || n.config.NetworkID == params.StatusChainNetworkID {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return n.ensureSync(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n *StatusNode) ensureSync(ctx context.Context) error {
|
|
||||||
les, err := n.LightEthereumService()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to get LES service: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
downloader := les.Downloader()
|
|
||||||
if downloader == nil {
|
|
||||||
return errors.New("LightEthereumService downloader is nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
progress := downloader.Progress()
|
|
||||||
if n.PeerCount() > 0 && progress.CurrentBlock >= progress.HighestBlock {
|
|
||||||
n.log.Debug("Synchronization completed", "current block", progress.CurrentBlock, "highest block", progress.HighestBlock)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
ticker := time.NewTicker(tickerResolution)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
progressTicker := time.NewTicker(time.Minute)
|
|
||||||
defer progressTicker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ctx.Done():
|
|
||||||
return errors.New("timeout during node synchronization")
|
|
||||||
case <-ticker.C:
|
|
||||||
if n.PeerCount() == 0 {
|
|
||||||
n.log.Debug("No established connections with any peers, continue waiting for a sync")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if downloader.Synchronising() {
|
|
||||||
n.log.Debug("Synchronization is in progress")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
progress = downloader.Progress()
|
|
||||||
if progress.CurrentBlock >= progress.HighestBlock {
|
|
||||||
n.log.Info("Synchronization completed", "current block", progress.CurrentBlock, "highest block", progress.HighestBlock)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
n.log.Debug("Synchronization is not finished", "current", progress.CurrentBlock, "highest", progress.HighestBlock)
|
|
||||||
case <-progressTicker.C:
|
|
||||||
progress = downloader.Progress()
|
|
||||||
n.log.Warn("Synchronization is not finished", "current", progress.CurrentBlock, "highest", progress.HighestBlock)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Discover sets up the discovery for a specific topic.
|
// Discover sets up the discovery for a specific topic.
|
||||||
func (n *StatusNode) Discover(topic string, max, min int) (err error) {
|
func (n *StatusNode) Discover(topic string, max, min int) (err error) {
|
||||||
if n.peerPool == nil {
|
if n.peerPool == nil {
|
||||||
|
@ -806,3 +627,11 @@ func (n *StatusNode) Discover(topic string, max, min int) (err error) {
|
||||||
Min: min,
|
Min: min,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n *StatusNode) SetAppDB(db *sql.DB) {
|
||||||
|
n.appDB = db
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *StatusNode) SetMultiaccountsDB(db *multiaccounts.Database) {
|
||||||
|
n.multiaccountsDB = db
|
||||||
|
}
|
||||||
|
|
|
@ -6,17 +6,11 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
|
||||||
|
|
||||||
logging "github.com/ipfs/go-log"
|
|
||||||
|
|
||||||
"github.com/syndtr/goleveldb/leveldb"
|
"github.com/syndtr/goleveldb/leveldb"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
||||||
"github.com/ethereum/go-ethereum/les"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
@ -24,22 +18,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
|
|
||||||
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
"github.com/status-im/status-go/logutils"
|
|
||||||
"github.com/status-im/status-go/mailserver"
|
|
||||||
"github.com/status-im/status-go/params"
|
"github.com/status-im/status-go/params"
|
||||||
"github.com/status-im/status-go/services/ext"
|
|
||||||
"github.com/status-im/status-go/services/nodebridge"
|
|
||||||
"github.com/status-im/status-go/services/peer"
|
|
||||||
"github.com/status-im/status-go/services/personal"
|
|
||||||
"github.com/status-im/status-go/services/wakuext"
|
|
||||||
"github.com/status-im/status-go/services/wakuv2ext"
|
|
||||||
"github.com/status-im/status-go/static"
|
"github.com/status-im/status-go/static"
|
||||||
"github.com/status-im/status-go/timesource"
|
|
||||||
"github.com/status-im/status-go/waku"
|
|
||||||
wakucommon "github.com/status-im/status-go/waku/common"
|
|
||||||
"github.com/status-im/status-go/wakuv2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errors related to node and services creation.
|
// Errors related to node and services creation.
|
||||||
|
@ -83,77 +64,9 @@ func MakeNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB)
|
||||||
return nil, fmt.Errorf(ErrNodeMakeFailureFormat, err.Error())
|
return nil, fmt.Errorf(ErrNodeMakeFailureFormat, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
err = activateServices(stack, config, accs, db)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return stack, nil
|
return stack, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func activateServices(stack *node.Node, config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) error {
|
|
||||||
if config.EnableNTPSync {
|
|
||||||
err := stack.Register(func(*node.ServiceContext) (node.Service, error) {
|
|
||||||
return timesource.Default(), nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to register NTP time source: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// start Ethereum service if we are not expected to use an upstream server
|
|
||||||
if !config.UpstreamConfig.Enabled {
|
|
||||||
if err := activateLightEthService(stack, accs, config); err != nil {
|
|
||||||
return fmt.Errorf("%v: %v", ErrLightEthRegistrationFailure, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if config.LightEthConfig.Enabled {
|
|
||||||
return ErrLightEthRegistrationFailureUpstreamEnabled
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("LES protocol is disabled")
|
|
||||||
|
|
||||||
// `personal_sign` and `personal_ecRecover` methods are important to
|
|
||||||
// keep DApps working.
|
|
||||||
// Usually, they are provided by an ETH or a LES service, but when using
|
|
||||||
// upstream, we don't start any of these, so we need to start our own
|
|
||||||
// implementation.
|
|
||||||
if err := activatePersonalService(stack, accs, config); err != nil {
|
|
||||||
return fmt.Errorf("%v: %v", ErrPersonalServiceRegistrationFailure, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := activateNodeServices(stack, config, db); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func activateNodeServices(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) error {
|
|
||||||
// Register eth-node node bridge
|
|
||||||
err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
return &nodebridge.NodeService{Node: gethbridge.NewNodeBridge(stack)}, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to register NodeBridge: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// start Waku service
|
|
||||||
if err := activateWakuService(stack, config, db); err != nil {
|
|
||||||
return fmt.Errorf("%v: %v", ErrWakuServiceRegistrationFailure, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := activateWakuV2Service(stack, config, db); err != nil {
|
|
||||||
return fmt.Errorf("%v: %v", ErrWakuV2ServiceRegistrationFailure, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// start peer service
|
|
||||||
if err := activatePeerService(stack); err != nil {
|
|
||||||
return fmt.Errorf("%v: %v", ErrPeerServiceRegistrationFailure, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// newGethNodeConfig returns default stack configuration for mobile client node
|
// newGethNodeConfig returns default stack configuration for mobile client node
|
||||||
func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
|
func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
|
||||||
nc := &node.Config{
|
nc := &node.Config{
|
||||||
|
@ -164,11 +77,12 @@ func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
|
||||||
Name: config.Name,
|
Name: config.Name,
|
||||||
Version: config.Version,
|
Version: config.Version,
|
||||||
P2P: p2p.Config{
|
P2P: p2p.Config{
|
||||||
NoDiscovery: true, // we always use only v5 server
|
NoDiscovery: true, // we always use only v5 server
|
||||||
ListenAddr: config.ListenAddr,
|
ListenAddr: config.ListenAddr,
|
||||||
NAT: nat.Any(),
|
NAT: nat.Any(),
|
||||||
MaxPeers: config.MaxPeers,
|
// FIX ME: don't hardcode
|
||||||
MaxPendingPeers: config.MaxPendingPeers,
|
MaxPeers: 200,
|
||||||
|
MaxPendingPeers: 200,
|
||||||
},
|
},
|
||||||
HTTPModules: config.FormatAPIModules(),
|
HTTPModules: config.FormatAPIModules(),
|
||||||
}
|
}
|
||||||
|
@ -214,7 +128,7 @@ func calculateGenesis(networkID uint64) (*core.Genesis, error) {
|
||||||
case params.MainNetworkID:
|
case params.MainNetworkID:
|
||||||
genesis = core.DefaultGenesisBlock()
|
genesis = core.DefaultGenesisBlock()
|
||||||
case params.RopstenNetworkID:
|
case params.RopstenNetworkID:
|
||||||
genesis = core.DefaultTestnetGenesisBlock()
|
genesis = core.DefaultRopstenGenesisBlock()
|
||||||
case params.RinkebyNetworkID:
|
case params.RinkebyNetworkID:
|
||||||
genesis = core.DefaultRinkebyGenesisBlock()
|
genesis = core.DefaultRinkebyGenesisBlock()
|
||||||
case params.GoerliNetworkID:
|
case params.GoerliNetworkID:
|
||||||
|
@ -246,191 +160,6 @@ func defaultStatusChainGenesisBlock() (*core.Genesis, error) {
|
||||||
return genesis, nil
|
return genesis, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// activateLightEthService configures and registers the eth.Ethereum service with a given node.
|
|
||||||
func activateLightEthService(stack *node.Node, accs *accounts.Manager, config *params.NodeConfig) error {
|
|
||||||
if !config.LightEthConfig.Enabled {
|
|
||||||
logger.Info("LES protocol is disabled")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
genesis, err := calculateGenesis(config.NetworkID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ethConf := eth.DefaultConfig
|
|
||||||
ethConf.Genesis = genesis
|
|
||||||
ethConf.SyncMode = downloader.LightSync
|
|
||||||
ethConf.NetworkId = config.NetworkID
|
|
||||||
ethConf.DatabaseCache = config.LightEthConfig.DatabaseCache
|
|
||||||
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
// NOTE(dshulyak) here we set our instance of the accounts manager.
|
|
||||||
// without sharing same instance selected account won't be visible for personal_* methods.
|
|
||||||
nctx := &node.ServiceContext{}
|
|
||||||
*nctx = *ctx
|
|
||||||
nctx.AccountManager = accs
|
|
||||||
return les.New(nctx, ðConf)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func activatePersonalService(stack *node.Node, accs *accounts.Manager, config *params.NodeConfig) error {
|
|
||||||
return stack.Register(func(*node.ServiceContext) (node.Service, error) {
|
|
||||||
svc := personal.New(accs)
|
|
||||||
return svc, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func activatePeerService(stack *node.Node) error {
|
|
||||||
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
svc := peer.New()
|
|
||||||
return svc, nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func registerWakuMailServer(wakuService *waku.Waku, config *params.WakuConfig) (err error) {
|
|
||||||
var mailServer mailserver.WakuMailServer
|
|
||||||
wakuService.RegisterMailServer(&mailServer)
|
|
||||||
|
|
||||||
return mailServer.Init(wakuService, config)
|
|
||||||
}
|
|
||||||
|
|
||||||
// activateWakuService configures Waku and adds it to the given node.
|
|
||||||
func activateWakuService(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) (err error) {
|
|
||||||
if !config.WakuConfig.Enabled {
|
|
||||||
logger.Info("Waku protocol is disabled")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
return createWakuService(ctx, &config.WakuConfig, &config.ClusterConfig)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Register Whisper eth-node bridge
|
|
||||||
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
var ethnode *nodebridge.NodeService
|
|
||||||
if err := ctx.Service(ðnode); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
w, err := ethnode.Node.GetWaku(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &nodebridge.WakuService{Waku: w}, nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(dshulyak) add a config option to enable it by default, but disable if app is started from statusd
|
|
||||||
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
var ethnode *nodebridge.NodeService
|
|
||||||
if err := ctx.Service(ðnode); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return wakuext.New(config.ShhextConfig, ethnode.Node, ctx, ext.EnvelopeSignalHandler{}, db), nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// activateWakuV2Service configures WakuV2 and adds it to the given node.
|
|
||||||
func activateWakuV2Service(stack *node.Node, config *params.NodeConfig, db *leveldb.DB) (err error) {
|
|
||||||
if !config.WakuV2Config.Enabled {
|
|
||||||
logger.Info("WakuV2 protocol is disabled")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
return createWakuV2Service(ctx, config.NodeKey, &config.WakuV2Config, &config.ClusterConfig)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
|
||||||
var ethnode *nodebridge.NodeService
|
|
||||||
if err := ctx.Service(ðnode); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return wakuv2ext.New(config.ShhextConfig, ethnode.Node, ctx, ext.EnvelopeSignalHandler{}, db), nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func createWakuService(ctx *node.ServiceContext, wakuCfg *params.WakuConfig, clusterCfg *params.ClusterConfig) (*waku.Waku, error) {
|
|
||||||
cfg := &waku.Config{
|
|
||||||
MaxMessageSize: wakucommon.DefaultMaxMessageSize,
|
|
||||||
BloomFilterMode: wakuCfg.BloomFilterMode,
|
|
||||||
FullNode: wakuCfg.FullNode,
|
|
||||||
SoftBlacklistedPeerIDs: wakuCfg.SoftBlacklistedPeerIDs,
|
|
||||||
MinimumAcceptedPoW: params.WakuMinimumPoW,
|
|
||||||
EnableConfirmations: wakuCfg.EnableConfirmations,
|
|
||||||
}
|
|
||||||
|
|
||||||
if wakuCfg.MaxMessageSize > 0 {
|
|
||||||
cfg.MaxMessageSize = wakuCfg.MaxMessageSize
|
|
||||||
}
|
|
||||||
if wakuCfg.MinimumPoW > 0 {
|
|
||||||
cfg.MinimumAcceptedPoW = wakuCfg.MinimumPoW
|
|
||||||
}
|
|
||||||
|
|
||||||
w := waku.New(cfg, logutils.ZapLogger())
|
|
||||||
|
|
||||||
if wakuCfg.EnableRateLimiter {
|
|
||||||
r := wakuRateLimiter(wakuCfg, clusterCfg)
|
|
||||||
w.RegisterRateLimiter(r)
|
|
||||||
}
|
|
||||||
|
|
||||||
if timesource, err := timeSource(ctx); err == nil {
|
|
||||||
w.SetTimeSource(timesource)
|
|
||||||
}
|
|
||||||
|
|
||||||
// enable mail service
|
|
||||||
if wakuCfg.EnableMailServer {
|
|
||||||
if err := registerWakuMailServer(w, wakuCfg); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to register WakuMailServer: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if wakuCfg.LightClient {
|
|
||||||
emptyBloomFilter := make([]byte, 64)
|
|
||||||
if err := w.SetBloomFilter(emptyBloomFilter); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createWakuV2Service(ctx *node.ServiceContext, nodeKey string, wakuCfg *params.WakuV2Config, clusterCfg *params.ClusterConfig) (*wakuv2.Waku, error) {
|
|
||||||
cfg := &wakuv2.Config{
|
|
||||||
MaxMessageSize: wakucommon.DefaultMaxMessageSize,
|
|
||||||
SoftBlacklistedPeerIDs: wakuCfg.SoftBlacklistedPeerIDs,
|
|
||||||
Host: wakuCfg.Host,
|
|
||||||
Port: wakuCfg.Port,
|
|
||||||
BootNodes: clusterCfg.WakuNodes,
|
|
||||||
StoreNodes: clusterCfg.WakuStoreNodes,
|
|
||||||
}
|
|
||||||
|
|
||||||
if wakuCfg.MaxMessageSize > 0 {
|
|
||||||
cfg.MaxMessageSize = wakuCfg.MaxMessageSize
|
|
||||||
}
|
|
||||||
|
|
||||||
lvl, err := logging.LevelFromString("info")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
logging.SetAllLoggers(lvl)
|
|
||||||
|
|
||||||
w, err := wakuv2.New(nodeKey, cfg, logutils.ZapLogger())
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return w, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseNodes creates list of enode.Node out of enode strings.
|
// parseNodes creates list of enode.Node out of enode strings.
|
||||||
func parseNodes(enodes []string) []*enode.Node {
|
func parseNodes(enodes []string) []*enode.Node {
|
||||||
var nodes []*enode.Node
|
var nodes []*enode.Node
|
||||||
|
@ -469,6 +198,7 @@ func parseNodesToNodeID(enodes []string) []enode.ID {
|
||||||
return nodeIDs
|
return nodeIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// timeSource get timeSource to be used by whisper
|
// timeSource get timeSource to be used by whisper
|
||||||
func timeSource(ctx *node.ServiceContext) (func() time.Time, error) {
|
func timeSource(ctx *node.ServiceContext) (func() time.Time, error) {
|
||||||
var timeSource *timesource.NTPTimeSource
|
var timeSource *timesource.NTPTimeSource
|
||||||
|
@ -476,33 +206,4 @@ func timeSource(ctx *node.ServiceContext) (func() time.Time, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return timeSource.Now, nil
|
return timeSource.Now, nil
|
||||||
}
|
}*/
|
||||||
|
|
||||||
func wakuRateLimiter(wakuCfg *params.WakuConfig, clusterCfg *params.ClusterConfig) *wakucommon.PeerRateLimiter {
|
|
||||||
enodes := append(
|
|
||||||
parseNodes(clusterCfg.StaticNodes),
|
|
||||||
parseNodes(clusterCfg.TrustedMailServers)...,
|
|
||||||
)
|
|
||||||
var (
|
|
||||||
ips []string
|
|
||||||
peerIDs []enode.ID
|
|
||||||
)
|
|
||||||
for _, item := range enodes {
|
|
||||||
ips = append(ips, item.IP().String())
|
|
||||||
peerIDs = append(peerIDs, item.ID())
|
|
||||||
}
|
|
||||||
return wakucommon.NewPeerRateLimiter(
|
|
||||||
&wakucommon.PeerRateLimiterConfig{
|
|
||||||
PacketLimitPerSecIP: wakuCfg.PacketRateLimitIP,
|
|
||||||
PacketLimitPerSecPeerID: wakuCfg.PacketRateLimitPeerID,
|
|
||||||
BytesLimitPerSecIP: wakuCfg.BytesRateLimitIP,
|
|
||||||
BytesLimitPerSecPeerID: wakuCfg.BytesRateLimitPeerID,
|
|
||||||
WhitelistedIPs: ips,
|
|
||||||
WhitelistedPeerIDs: peerIDs,
|
|
||||||
},
|
|
||||||
&wakucommon.MetricsRateLimiterHandler{},
|
|
||||||
&wakucommon.DropPeerRateLimiterHandler{
|
|
||||||
Tolerance: wakuCfg.RateLimitTolerance,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,472 @@
|
||||||
|
package node
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
logging "github.com/ipfs/go-log"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
|
|
||||||
|
"github.com/status-im/status-go/appmetrics"
|
||||||
|
"github.com/status-im/status-go/common"
|
||||||
|
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/logutils"
|
||||||
|
"github.com/status-im/status-go/mailserver"
|
||||||
|
"github.com/status-im/status-go/multiaccounts/accounts"
|
||||||
|
"github.com/status-im/status-go/params"
|
||||||
|
"github.com/status-im/status-go/rpc"
|
||||||
|
accountssvc "github.com/status-im/status-go/services/accounts"
|
||||||
|
appmetricsservice "github.com/status-im/status-go/services/appmetrics"
|
||||||
|
"github.com/status-im/status-go/services/browsers"
|
||||||
|
"github.com/status-im/status-go/services/ext"
|
||||||
|
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
||||||
|
"github.com/status-im/status-go/services/mailservers"
|
||||||
|
"github.com/status-im/status-go/services/nodebridge"
|
||||||
|
"github.com/status-im/status-go/services/peer"
|
||||||
|
"github.com/status-im/status-go/services/permissions"
|
||||||
|
"github.com/status-im/status-go/services/personal"
|
||||||
|
"github.com/status-im/status-go/services/rpcfilters"
|
||||||
|
"github.com/status-im/status-go/services/rpcstats"
|
||||||
|
"github.com/status-im/status-go/services/subscriptions"
|
||||||
|
"github.com/status-im/status-go/services/wakuext"
|
||||||
|
"github.com/status-im/status-go/services/wakuv2ext"
|
||||||
|
"github.com/status-im/status-go/services/wallet"
|
||||||
|
"github.com/status-im/status-go/timesource"
|
||||||
|
"github.com/status-im/status-go/waku"
|
||||||
|
wakucommon "github.com/status-im/status-go/waku/common"
|
||||||
|
"github.com/status-im/status-go/wakuv2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrWakuClearIdentitiesFailure clearing whisper identities has failed.
|
||||||
|
ErrWakuClearIdentitiesFailure = errors.New("failed to clear waku identities")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (b *StatusNode) initServices(config *params.NodeConfig) error {
|
||||||
|
accountsFeed := &event.Feed{}
|
||||||
|
|
||||||
|
services := []common.StatusService{}
|
||||||
|
services = appendIf(config.UpstreamConfig.Enabled, services, b.rpcFiltersService())
|
||||||
|
services = append(services, b.subscriptionService())
|
||||||
|
services = append(services, b.rpcStatsService())
|
||||||
|
services = append(services, b.appmetricsService())
|
||||||
|
services = append(services, b.peerService())
|
||||||
|
services = append(services, b.personalService())
|
||||||
|
services = appendIf(config.EnableNTPSync, services, b.timeSource())
|
||||||
|
services = appendIf(b.appDB != nil && b.multiaccountsDB != nil, services, b.accountsService(accountsFeed))
|
||||||
|
services = appendIf(config.BrowsersConfig.Enabled, services, b.browsersService())
|
||||||
|
services = appendIf(config.PermissionsConfig.Enabled, services, b.permissionsService())
|
||||||
|
services = appendIf(config.MailserversConfig.Enabled, services, b.mailserversService())
|
||||||
|
if config.WakuConfig.Enabled {
|
||||||
|
wakuService, err := b.wakuService(&config.WakuConfig, &config.ClusterConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
services = append(services, wakuService)
|
||||||
|
|
||||||
|
wakuext, err := b.wakuExtService(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.wakuExtSrvc = wakuext
|
||||||
|
|
||||||
|
services = append(services, wakuext)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.WakuV2Config.Enabled {
|
||||||
|
waku2Service, err := b.wakuV2Service(config.NodeKey, &config.WakuV2Config, &config.ClusterConfig)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
services = append(services, waku2Service)
|
||||||
|
|
||||||
|
wakuext, err := b.wakuV2ExtService(config)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
b.wakuV2ExtSrvc = wakuext
|
||||||
|
|
||||||
|
services = append(services, wakuext)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.log.Info("WAKU ENABLED")
|
||||||
|
|
||||||
|
if config.WalletConfig.Enabled {
|
||||||
|
walletService := b.walletService(config.NetworkID, accountsFeed)
|
||||||
|
b.log.Info("SETTING REPC CLIETN")
|
||||||
|
b.walletSrvc.SetClient(b.rpcClient.Ethclient())
|
||||||
|
b.log.Info("SET REPC CLIETN")
|
||||||
|
services = append(services, walletService)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.log.Info("WALLET ENABLED")
|
||||||
|
|
||||||
|
// We ignore for now local notifications flag as users who are upgrading have no mean to enable it
|
||||||
|
services = append(services, b.localNotificationsService(config.NetworkID))
|
||||||
|
|
||||||
|
b.log.Info("SET CLIENT")
|
||||||
|
|
||||||
|
b.peerSrvc.SetDiscoverer(b)
|
||||||
|
|
||||||
|
b.log.Info("SET DISCOVERER")
|
||||||
|
|
||||||
|
for i := range services {
|
||||||
|
b.gethNode.RegisterAPIs(services[i].APIs())
|
||||||
|
b.gethNode.RegisterProtocols(services[i].Protocols())
|
||||||
|
b.gethNode.RegisterLifecycle(services[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) nodeBridge() types.Node {
|
||||||
|
return gethbridge.NewNodeBridge(b.gethNode, b.wakuSrvc, b.wakuV2Srvc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) nodeBridgeService() *nodebridge.NodeService {
|
||||||
|
if b.nodeBridgeSrvc == nil {
|
||||||
|
b.nodeBridgeSrvc = &nodebridge.NodeService{Node: b.nodeBridge()}
|
||||||
|
}
|
||||||
|
return b.nodeBridgeSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) wakuExtService(config *params.NodeConfig) (*wakuext.Service, error) {
|
||||||
|
if b.gethNode == nil {
|
||||||
|
return nil, errors.New("geth node not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.wakuExtSrvc == nil {
|
||||||
|
b.wakuExtSrvc = wakuext.New(config.ShhextConfig, b.nodeBridge(), ext.EnvelopeSignalHandler{}, b.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.wakuExtSrvc.SetP2PServer(b.gethNode.Server())
|
||||||
|
return b.wakuExtSrvc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) wakuV2ExtService(config *params.NodeConfig) (*wakuv2ext.Service, error) {
|
||||||
|
if b.gethNode == nil {
|
||||||
|
return nil, errors.New("geth node not initialized")
|
||||||
|
}
|
||||||
|
if b.wakuV2ExtSrvc == nil {
|
||||||
|
b.wakuV2ExtSrvc = wakuv2ext.New(config.ShhextConfig, b.nodeBridge(), ext.EnvelopeSignalHandler{}, b.db)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.wakuV2ExtSrvc.SetP2PServer(b.gethNode.Server())
|
||||||
|
return b.wakuV2ExtSrvc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) WakuService() *waku.Waku {
|
||||||
|
return b.wakuSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) WakuExtService() *wakuext.Service {
|
||||||
|
return b.wakuExtSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) WakuV2ExtService() *wakuv2ext.Service {
|
||||||
|
return b.wakuV2ExtSrvc
|
||||||
|
}
|
||||||
|
func (b *StatusNode) WakuV2Service() *wakuv2.Waku {
|
||||||
|
return b.wakuV2Srvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) wakuService(wakuCfg *params.WakuConfig, clusterCfg *params.ClusterConfig) (*waku.Waku, error) {
|
||||||
|
if b.wakuSrvc == nil {
|
||||||
|
cfg := &waku.Config{
|
||||||
|
MaxMessageSize: wakucommon.DefaultMaxMessageSize,
|
||||||
|
BloomFilterMode: wakuCfg.BloomFilterMode,
|
||||||
|
FullNode: wakuCfg.FullNode,
|
||||||
|
SoftBlacklistedPeerIDs: wakuCfg.SoftBlacklistedPeerIDs,
|
||||||
|
MinimumAcceptedPoW: params.WakuMinimumPoW,
|
||||||
|
EnableConfirmations: wakuCfg.EnableConfirmations,
|
||||||
|
}
|
||||||
|
|
||||||
|
if wakuCfg.MaxMessageSize > 0 {
|
||||||
|
cfg.MaxMessageSize = wakuCfg.MaxMessageSize
|
||||||
|
}
|
||||||
|
if wakuCfg.MinimumPoW > 0 {
|
||||||
|
cfg.MinimumAcceptedPoW = wakuCfg.MinimumPoW
|
||||||
|
}
|
||||||
|
|
||||||
|
w := waku.New(cfg, logutils.ZapLogger())
|
||||||
|
|
||||||
|
if wakuCfg.EnableRateLimiter {
|
||||||
|
r := wakuRateLimiter(wakuCfg, clusterCfg)
|
||||||
|
w.RegisterRateLimiter(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
if timesource := b.timeSource(); timesource != nil {
|
||||||
|
w.SetTimeSource(timesource.Now)
|
||||||
|
}
|
||||||
|
|
||||||
|
// enable mail service
|
||||||
|
if wakuCfg.EnableMailServer {
|
||||||
|
if err := registerWakuMailServer(w, wakuCfg); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to register WakuMailServer: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if wakuCfg.LightClient {
|
||||||
|
emptyBloomFilter := make([]byte, 64)
|
||||||
|
if err := w.SetBloomFilter(emptyBloomFilter); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
b.wakuSrvc = w
|
||||||
|
}
|
||||||
|
return b.wakuSrvc, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) wakuV2Service(nodeKey string, wakuCfg *params.WakuV2Config, clusterCfg *params.ClusterConfig) (*wakuv2.Waku, error) {
|
||||||
|
if b.wakuV2Srvc == nil {
|
||||||
|
cfg := &wakuv2.Config{
|
||||||
|
MaxMessageSize: wakucommon.DefaultMaxMessageSize,
|
||||||
|
SoftBlacklistedPeerIDs: wakuCfg.SoftBlacklistedPeerIDs,
|
||||||
|
Host: wakuCfg.Host,
|
||||||
|
Port: wakuCfg.Port,
|
||||||
|
BootNodes: clusterCfg.WakuNodes,
|
||||||
|
StoreNodes: clusterCfg.WakuStoreNodes,
|
||||||
|
}
|
||||||
|
|
||||||
|
if wakuCfg.MaxMessageSize > 0 {
|
||||||
|
cfg.MaxMessageSize = wakuCfg.MaxMessageSize
|
||||||
|
}
|
||||||
|
|
||||||
|
lvl, err := logging.LevelFromString("info")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
logging.SetAllLoggers(lvl)
|
||||||
|
|
||||||
|
w, err := wakuv2.New(nodeKey, cfg, logutils.ZapLogger())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
b.wakuV2Srvc = w
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.wakuV2Srvc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func wakuRateLimiter(wakuCfg *params.WakuConfig, clusterCfg *params.ClusterConfig) *wakucommon.PeerRateLimiter {
|
||||||
|
enodes := append(
|
||||||
|
parseNodes(clusterCfg.StaticNodes),
|
||||||
|
parseNodes(clusterCfg.TrustedMailServers)...,
|
||||||
|
)
|
||||||
|
var (
|
||||||
|
ips []string
|
||||||
|
peerIDs []enode.ID
|
||||||
|
)
|
||||||
|
for _, item := range enodes {
|
||||||
|
ips = append(ips, item.IP().String())
|
||||||
|
peerIDs = append(peerIDs, item.ID())
|
||||||
|
}
|
||||||
|
return wakucommon.NewPeerRateLimiter(
|
||||||
|
&wakucommon.PeerRateLimiterConfig{
|
||||||
|
PacketLimitPerSecIP: wakuCfg.PacketRateLimitIP,
|
||||||
|
PacketLimitPerSecPeerID: wakuCfg.PacketRateLimitPeerID,
|
||||||
|
BytesLimitPerSecIP: wakuCfg.BytesRateLimitIP,
|
||||||
|
BytesLimitPerSecPeerID: wakuCfg.BytesRateLimitPeerID,
|
||||||
|
WhitelistedIPs: ips,
|
||||||
|
WhitelistedPeerIDs: peerIDs,
|
||||||
|
},
|
||||||
|
&wakucommon.MetricsRateLimiterHandler{},
|
||||||
|
&wakucommon.DropPeerRateLimiterHandler{
|
||||||
|
Tolerance: wakuCfg.RateLimitTolerance,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) rpcFiltersService() *rpcfilters.Service {
|
||||||
|
if b.rpcFiltersSrvc == nil {
|
||||||
|
b.rpcFiltersSrvc = rpcfilters.New(b)
|
||||||
|
}
|
||||||
|
return b.rpcFiltersSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) subscriptionService() *subscriptions.Service {
|
||||||
|
if b.subscriptionsSrvc == nil {
|
||||||
|
|
||||||
|
b.subscriptionsSrvc = subscriptions.New(func() *rpc.Client { return b.RPCPrivateClient() })
|
||||||
|
}
|
||||||
|
return b.subscriptionsSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) rpcStatsService() *rpcstats.Service {
|
||||||
|
if b.rpcStatsSrvc == nil {
|
||||||
|
b.rpcStatsSrvc = rpcstats.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.rpcStatsSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) accountsService(accountsFeed *event.Feed) *accountssvc.Service {
|
||||||
|
if b.accountsSrvc == nil {
|
||||||
|
b.accountsSrvc = accountssvc.NewService(accounts.NewDB(b.appDB), b.multiaccountsDB, b.gethAccountManager.Manager, accountsFeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return b.accountsSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) browsersService() *browsers.Service {
|
||||||
|
if b.browsersSrvc == nil {
|
||||||
|
b.browsersSrvc = browsers.NewService(browsers.NewDB(b.appDB))
|
||||||
|
}
|
||||||
|
return b.browsersSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) permissionsService() *permissions.Service {
|
||||||
|
if b.permissionsSrvc == nil {
|
||||||
|
b.permissionsSrvc = permissions.NewService(permissions.NewDB(b.appDB))
|
||||||
|
}
|
||||||
|
return b.permissionsSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) mailserversService() *mailservers.Service {
|
||||||
|
if b.mailserversSrvc == nil {
|
||||||
|
|
||||||
|
b.mailserversSrvc = mailservers.NewService(mailservers.NewDB(b.appDB))
|
||||||
|
}
|
||||||
|
return b.mailserversSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) appmetricsService() common.StatusService {
|
||||||
|
if b.appMetricsSrvc == nil {
|
||||||
|
b.appMetricsSrvc = appmetricsservice.NewService(appmetrics.NewDB(b.appDB))
|
||||||
|
}
|
||||||
|
return b.appMetricsSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) walletService(network uint64, accountsFeed *event.Feed) common.StatusService {
|
||||||
|
if b.walletSrvc == nil {
|
||||||
|
b.walletSrvc = wallet.NewService(wallet.NewDB(b.appDB, network), accountsFeed)
|
||||||
|
}
|
||||||
|
return b.walletSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) localNotificationsService(network uint64) *localnotifications.Service {
|
||||||
|
if b.localNotificationsSrvc == nil {
|
||||||
|
b.localNotificationsSrvc = localnotifications.NewService(b.appDB, network)
|
||||||
|
}
|
||||||
|
return b.localNotificationsSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) peerService() *peer.Service {
|
||||||
|
if b.peerSrvc == nil {
|
||||||
|
b.peerSrvc = peer.New()
|
||||||
|
}
|
||||||
|
return b.peerSrvc
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerWakuMailServer(wakuService *waku.Waku, config *params.WakuConfig) (err error) {
|
||||||
|
var mailServer mailserver.WakuMailServer
|
||||||
|
wakuService.RegisterMailServer(&mailServer)
|
||||||
|
|
||||||
|
return mailServer.Init(wakuService, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func appendIf(condition bool, services []common.StatusService, service common.StatusService) []common.StatusService {
|
||||||
|
if !condition {
|
||||||
|
return services
|
||||||
|
}
|
||||||
|
return append(services, service)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) RPCFiltersService() *rpcfilters.Service {
|
||||||
|
return b.rpcFiltersSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) StopLocalNotifications() error {
|
||||||
|
if b.localNotificationsSrvc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.localNotificationsSrvc.IsStarted() {
|
||||||
|
err := b.localNotificationsSrvc.Stop()
|
||||||
|
if err != nil {
|
||||||
|
b.log.Error("LocalNotifications service stop failed on StopLocalNotifications", "error", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) StartLocalNotifications() error {
|
||||||
|
if b.localNotificationsSrvc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.walletSrvc == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if !b.localNotificationsSrvc.IsStarted() {
|
||||||
|
err := b.localNotificationsSrvc.Start()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
b.log.Error("LocalNotifications service start failed on StartLocalNotifications", "error", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := b.localNotificationsSrvc.SubscribeWallet(b.walletSrvc.GetFeed())
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
b.log.Error("LocalNotifications service could not subscribe to wallet on StartLocalNotifications", "error", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// `personal_sign` and `personal_ecRecover` methods are important to
|
||||||
|
// keep DApps working.
|
||||||
|
// Usually, they are provided by an ETH or a LES service, but when using
|
||||||
|
// upstream, we don't start any of these, so we need to start our own
|
||||||
|
// implementation.
|
||||||
|
|
||||||
|
func (b *StatusNode) personalService() *personal.Service {
|
||||||
|
if b.personalSrvc == nil {
|
||||||
|
b.personalSrvc = personal.New(b.accountsManager)
|
||||||
|
}
|
||||||
|
return b.personalSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) timeSource() *timesource.NTPTimeSource {
|
||||||
|
|
||||||
|
if b.timeSourceSrvc == nil {
|
||||||
|
b.timeSourceSrvc = timesource.Default()
|
||||||
|
}
|
||||||
|
return b.timeSourceSrvc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *StatusNode) Cleanup() error {
|
||||||
|
if b.wakuSrvc != nil {
|
||||||
|
if err := b.wakuSrvc.DeleteKeyPairs(); err != nil {
|
||||||
|
return fmt.Errorf("%s: %v", ErrWakuClearIdentitiesFailure, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if b.Config().WalletConfig.Enabled {
|
||||||
|
if b.walletSrvc != nil {
|
||||||
|
if b.walletSrvc.IsStarted() {
|
||||||
|
err := b.walletSrvc.Stop()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
|
@ -17,14 +17,36 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/crypto"
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
"github.com/status-im/status-go/protocol/pushnotificationserver"
|
"github.com/status-im/status-go/protocol/pushnotificationserver"
|
||||||
"github.com/status-im/status-go/static"
|
"github.com/status-im/status-go/static"
|
||||||
wakucommon "github.com/status-im/status-go/waku/common"
|
wakucommon "github.com/status-im/status-go/waku/common"
|
||||||
wakuv2common "github.com/status-im/status-go/wakuv2/common"
|
wakuv2common "github.com/status-im/status-go/wakuv2/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
// LightEthConfig
|
||||||
|
// ----------
|
||||||
|
|
||||||
|
// LightEthConfig holds LES-related configuration
|
||||||
|
// Status nodes are always lightweight clients (due to mobile platform constraints)
|
||||||
|
type LightEthConfig struct {
|
||||||
|
// Enabled flag specifies whether protocol is enabled
|
||||||
|
Enabled bool
|
||||||
|
|
||||||
|
// DatabaseCache is memory (in MBs) allocated to internal caching (min 16MB / database forced)
|
||||||
|
DatabaseCache int
|
||||||
|
|
||||||
|
// TrustedNodes is a list of trusted servers
|
||||||
|
TrustedNodes []string
|
||||||
|
|
||||||
|
//MinTrustedFraction is minimum percentage of connected trusted servers to validate header(1-100)
|
||||||
|
MinTrustedFraction int
|
||||||
|
}
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// DatabaseConfig
|
// DatabaseConfig
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -412,6 +434,9 @@ type NodeConfig struct {
|
||||||
// ClusterConfig extra configuration for supporting cluster peers.
|
// ClusterConfig extra configuration for supporting cluster peers.
|
||||||
ClusterConfig ClusterConfig `json:"ClusterConfig," validate:"structonly"`
|
ClusterConfig ClusterConfig `json:"ClusterConfig," validate:"structonly"`
|
||||||
|
|
||||||
|
// LightEthConfig extra configuration for LES
|
||||||
|
LightEthConfig LightEthConfig `json:"LightEthConfig," validate:"structonly"`
|
||||||
|
|
||||||
// WakuConfig provides a configuration for Waku subprotocol.
|
// WakuConfig provides a configuration for Waku subprotocol.
|
||||||
WakuConfig WakuConfig `json:"WakuConfig" validate:"structonly"`
|
WakuConfig WakuConfig `json:"WakuConfig" validate:"structonly"`
|
||||||
|
|
||||||
|
@ -705,6 +730,9 @@ func (c *NodeConfig) updatePeerLimits() {
|
||||||
if c.NoDiscovery && !c.Rendezvous {
|
if c.NoDiscovery && !c.Rendezvous {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if c.LightEthConfig.Enabled {
|
||||||
|
c.RequireTopics[discv5.Topic(LesTopic(int(c.NetworkID)))] = LesDiscoveryLimits
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewNodeConfig creates new node configuration object with bare-minimum defaults.
|
// NewNodeConfig creates new node configuration object with bare-minimum defaults.
|
||||||
|
@ -739,6 +767,9 @@ func NewNodeConfig(dataDir string, networkID uint64) (*NodeConfig, error) {
|
||||||
UpstreamConfig: UpstreamRPCConfig{
|
UpstreamConfig: UpstreamRPCConfig{
|
||||||
URL: getUpstreamURL(networkID),
|
URL: getUpstreamURL(networkID),
|
||||||
},
|
},
|
||||||
|
LightEthConfig: LightEthConfig{
|
||||||
|
DatabaseCache: 16,
|
||||||
|
},
|
||||||
WakuConfig: WakuConfig{
|
WakuConfig: WakuConfig{
|
||||||
DataDir: wakuDir,
|
DataDir: wakuDir,
|
||||||
MinimumPoW: WakuMinimumPoW,
|
MinimumPoW: WakuMinimumPoW,
|
||||||
|
@ -840,6 +871,10 @@ func (c *NodeConfig) Validate() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.UpstreamConfig.Enabled && c.LightEthConfig.Enabled {
|
||||||
|
return fmt.Errorf("both UpstreamConfig and LightEthConfig are enabled, but they are mutually exclusive")
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.validateChildStructs(validate); err != nil {
|
if err := c.validateChildStructs(validate); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -889,6 +924,9 @@ func (c *NodeConfig) validateChildStructs(validate *validator.Validate) error {
|
||||||
if err := c.ClusterConfig.Validate(validate); err != nil {
|
if err := c.ClusterConfig.Validate(validate); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := c.LightEthConfig.Validate(validate); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := c.SwarmConfig.Validate(validate); err != nil {
|
if err := c.SwarmConfig.Validate(validate); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -928,6 +966,19 @@ func (c *ClusterConfig) Validate(validate *validator.Validate) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate validates the LightEthConfig struct and returns an error if inconsistent values are found
|
||||||
|
func (c *LightEthConfig) Validate(validate *validator.Validate) error {
|
||||||
|
if !c.Enabled {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validate.Struct(c); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Validate validates the SwarmConfig struct and returns an error if inconsistent values are found
|
// Validate validates the SwarmConfig struct and returns an error if inconsistent values are found
|
||||||
func (c *SwarmConfig) Validate(validate *validator.Validate) error {
|
func (c *SwarmConfig) Validate(validate *validator.Validate) error {
|
||||||
if !c.Enabled {
|
if !c.Enabled {
|
||||||
|
@ -995,3 +1046,18 @@ func (c *NodeConfig) FormatAPIModules() []string {
|
||||||
func (c *NodeConfig) AddAPIModule(m string) {
|
func (c *NodeConfig) AddAPIModule(m string) {
|
||||||
c.APIModules = fmt.Sprintf("%s,%s", c.APIModules, m)
|
c.APIModules = fmt.Sprintf("%s,%s", c.APIModules, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LesTopic returns discovery v5 topic derived from genesis of the provided network.
|
||||||
|
// 1 - mainnet, 3 - ropsten, 4 - rinkeby
|
||||||
|
func LesTopic(netid int) string {
|
||||||
|
switch netid {
|
||||||
|
case 1:
|
||||||
|
return LESDiscoveryIdentifier + types.Bytes2Hex(params.MainnetGenesisHash.Bytes()[:8])
|
||||||
|
case 3:
|
||||||
|
return LESDiscoveryIdentifier + types.Bytes2Hex(params.RopstenGenesisHash.Bytes()[:8])
|
||||||
|
case 4:
|
||||||
|
return LESDiscoveryIdentifier + types.Bytes2Hex(params.RinkebyGenesisHash.Bytes()[:8])
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ func (s *PeerPoolSimulationSuite) TestPeerPoolCacheEthV5() {
|
||||||
config := map[discv5.Topic]params.Limits{
|
config := map[discv5.Topic]params.Limits{
|
||||||
topic: params.NewLimits(1, 1),
|
topic: params.NewLimits(1, 1),
|
||||||
}
|
}
|
||||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil, ""}
|
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil}
|
||||||
cache, err := newInMemoryCache()
|
cache, err := newInMemoryCache()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||||
|
@ -177,7 +177,7 @@ func TestPeerPoolMaxPeersOverflow(t *testing.T) {
|
||||||
defer func() { assert.NoError(t, discovery.Stop()) }()
|
defer func() { assert.NoError(t, discovery.Stop()) }()
|
||||||
require.True(t, discovery.Running())
|
require.True(t, discovery.Running())
|
||||||
|
|
||||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, 0, true, 100 * time.Millisecond, nil, ""}
|
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, 0, true, 100 * time.Millisecond, nil}
|
||||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||||
require.NoError(t, pool.Start(peer, nil))
|
require.NoError(t, pool.Start(peer, nil))
|
||||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||||
|
@ -230,7 +230,7 @@ func TestPeerPoolDiscV5Timeout(t *testing.T) {
|
||||||
require.True(t, discovery.Running())
|
require.True(t, discovery.Running())
|
||||||
|
|
||||||
// start PeerPool
|
// start PeerPool
|
||||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, true, 100 * time.Millisecond, nil, ""}
|
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, true, 100 * time.Millisecond, nil}
|
||||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||||
require.NoError(t, pool.Start(server, nil))
|
require.NoError(t, pool.Start(server, nil))
|
||||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||||
|
@ -277,7 +277,7 @@ func TestPeerPoolNotAllowedStopping(t *testing.T) {
|
||||||
require.True(t, discovery.Running())
|
require.True(t, discovery.Running())
|
||||||
|
|
||||||
// start PeerPool
|
// start PeerPool
|
||||||
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, false, 100 * time.Millisecond, nil, ""}
|
poolOpts := &Options{DefaultFastSync, DefaultSlowSync, time.Millisecond * 100, false, 100 * time.Millisecond, nil}
|
||||||
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
pool := NewPeerPool(discovery, nil, nil, poolOpts)
|
||||||
require.NoError(t, pool.Start(server, nil))
|
require.NoError(t, pool.Start(server, nil))
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ func (s *PeerPoolSimulationSuite) TestUpdateTopicLimits() {
|
||||||
config := map[discv5.Topic]params.Limits{
|
config := map[discv5.Topic]params.Limits{
|
||||||
topic: params.NewLimits(1, 1),
|
topic: params.NewLimits(1, 1),
|
||||||
}
|
}
|
||||||
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil, ""}
|
peerPoolOpts := &Options{100 * time.Millisecond, 100 * time.Millisecond, 0, true, 100 * time.Millisecond, nil}
|
||||||
cache, err := newInMemoryCache()
|
cache, err := newInMemoryCache()
|
||||||
s.Require().NoError(err)
|
s.Require().NoError(err)
|
||||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||||
|
@ -373,7 +373,6 @@ func (s *PeerPoolSimulationSuite) TestMailServerPeersDiscovery() {
|
||||||
true,
|
true,
|
||||||
100 * time.Millisecond,
|
100 * time.Millisecond,
|
||||||
[]enode.ID{s.peers[0].Self().ID()},
|
[]enode.ID{s.peers[0].Self().ID()},
|
||||||
"",
|
|
||||||
}
|
}
|
||||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||||
s.Require().NoError(peerPool.Start(s.peers[1], nil))
|
s.Require().NoError(peerPool.Start(s.peers[1], nil))
|
||||||
|
|
|
@ -206,8 +206,7 @@ func NewMessenger(
|
||||||
// Initialize transport layer.
|
// Initialize transport layer.
|
||||||
var transp *transport.Transport
|
var transp *transport.Transport
|
||||||
|
|
||||||
logger.Info("failed to find Whisper service; trying Waku", zap.Error(err))
|
logger.Info("TEST", zap.Any("node", node))
|
||||||
|
|
||||||
if waku, err := node.GetWaku(nil); err == nil && waku != nil {
|
if waku, err := node.GetWaku(nil); err == nil && waku != nil {
|
||||||
transp, err = transport.NewTransport(
|
transp, err = transport.NewTransport(
|
||||||
waku,
|
waku,
|
||||||
|
|
|
@ -24,7 +24,7 @@ type Service struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a service.
|
// Start a service.
|
||||||
func (s *Service) Start(*p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ type Service struct {
|
||||||
db *appmetrics.Database
|
db *appmetrics.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Start(*p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ type Service struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a service.
|
// Start a service.
|
||||||
func (s *Service) Start(*p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ type Service struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that Service implements node.Service interface.
|
// Make sure that Service implements node.Service interface.
|
||||||
var _ node.Service = (*Service)(nil)
|
var _ node.Lifecycle = (*Service)(nil)
|
||||||
|
|
||||||
func New(
|
func New(
|
||||||
config params.ShhextConfig,
|
config params.ShhextConfig,
|
||||||
|
@ -209,7 +209,7 @@ func (c *verifyTransactionClient) TransactionByHash(ctx context.Context, hash ty
|
||||||
return coretypes.Message{}, coretypes.TransactionStatusPending, err
|
return coretypes.Message{}, coretypes.TransactionStatusPending, err
|
||||||
}
|
}
|
||||||
|
|
||||||
message, err := transaction.AsMessage(signer)
|
message, err := transaction.AsMessage(signer, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return coretypes.Message{}, coretypes.TransactionStatusPending, err
|
return coretypes.Message{}, coretypes.TransactionStatusPending, err
|
||||||
}
|
}
|
||||||
|
@ -328,10 +328,15 @@ func (s *Service) APIs() []rpc.API {
|
||||||
panic("this is abstract service, use shhext or wakuext implementation")
|
panic("this is abstract service, use shhext or wakuext implementation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) SetP2PServer(server *p2p.Server) {
|
||||||
|
s.server = server
|
||||||
|
}
|
||||||
|
|
||||||
// Start is run when a service is started.
|
// Start is run when a service is started.
|
||||||
// It does nothing in this case but is required by `node.Service` interface.
|
// It does nothing in this case but is required by `node.Service` interface.
|
||||||
func (s *Service) Start(server *p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
s.server = server
|
// TODO: set server before start
|
||||||
|
// s.server = server
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -153,7 +153,7 @@ func pushMessage(notification *Notification) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start Worker which processes all incoming messages
|
// Start Worker which processes all incoming messages
|
||||||
func (s *Service) Start(_ *p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
s.started = true
|
s.started = true
|
||||||
|
|
||||||
s.transmitter.quit = make(chan struct{})
|
s.transmitter.quit = make(chan struct{})
|
||||||
|
|
|
@ -13,7 +13,7 @@ type Service struct {
|
||||||
db *Database
|
db *Database
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Start(*p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ type Service struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a service.
|
// Start a service.
|
||||||
func (s *Service) Start(*p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Make sure that Service implements node.Service interface.
|
// Make sure that Service implements node.Service interface.
|
||||||
var _ node.Service = (*Service)(nil)
|
var _ node.Lifecycle = (*Service)(nil)
|
||||||
|
|
||||||
// Service represents out own implementation of personal sign operations.
|
// Service represents out own implementation of personal sign operations.
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
@ -40,7 +40,7 @@ func (s *Service) APIs() []rpc.API {
|
||||||
|
|
||||||
// Start is run when a service is started.
|
// Start is run when a service is started.
|
||||||
// It does nothing in this case but is required by `node.Service` interface.
|
// It does nothing in this case but is required by `node.Service` interface.
|
||||||
func (s *Service) Start(server *p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ func (s *Service) Protocols() []p2p.Protocol {
|
||||||
|
|
||||||
// Start is run when a service is started.
|
// Start is run when a service is started.
|
||||||
// It does nothing in this case but is required by `node.Service` interface.
|
// It does nothing in this case but is required by `node.Service` interface.
|
||||||
func (s *Service) Start(server *p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
resetStats()
|
resetStats()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
// Code generated by MockGen. DO NOT EDIT.
|
|
||||||
// Source: services/status/service.go
|
|
||||||
|
|
||||||
// Package status is a generated GoMock package.
|
|
||||||
package status
|
|
||||||
|
|
||||||
import (
|
|
||||||
ecdsa "crypto/ecdsa"
|
|
||||||
reflect "reflect"
|
|
||||||
|
|
||||||
gomock "github.com/golang/mock/gomock"
|
|
||||||
|
|
||||||
account "github.com/status-im/status-go/account"
|
|
||||||
"github.com/status-im/status-go/account/generator"
|
|
||||||
types "github.com/status-im/status-go/eth-node/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// MockWhisperService is a mock of WhisperService interface
|
|
||||||
type MockWhisperService struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockWhisperServiceMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockWhisperServiceMockRecorder is the mock recorder for MockWhisperService
|
|
||||||
type MockWhisperServiceMockRecorder struct {
|
|
||||||
mock *MockWhisperService
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockWhisperService creates a new mock instance
|
|
||||||
func NewMockWhisperService(ctrl *gomock.Controller) *MockWhisperService {
|
|
||||||
mock := &MockWhisperService{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockWhisperServiceMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use
|
|
||||||
func (m *MockWhisperService) EXPECT() *MockWhisperServiceMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddKeyPair mocks base method
|
|
||||||
func (m *MockWhisperService) AddKeyPair(key *ecdsa.PrivateKey) (string, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "AddKeyPair", key)
|
|
||||||
ret0, _ := ret[0].(string)
|
|
||||||
ret1, _ := ret[1].(error)
|
|
||||||
return ret0, ret1
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddKeyPair indicates an expected call of AddKeyPair
|
|
||||||
func (mr *MockWhisperServiceMockRecorder) AddKeyPair(key interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddKeyPair", reflect.TypeOf((*MockWhisperService)(nil).AddKeyPair), key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockAccountManager is a mock of AccountManager interface
|
|
||||||
type MockAccountManager struct {
|
|
||||||
ctrl *gomock.Controller
|
|
||||||
recorder *MockAccountManagerMockRecorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// MockAccountManagerMockRecorder is the mock recorder for MockAccountManager
|
|
||||||
type MockAccountManagerMockRecorder struct {
|
|
||||||
mock *MockAccountManager
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewMockAccountManager creates a new mock instance
|
|
||||||
func NewMockAccountManager(ctrl *gomock.Controller) *MockAccountManager {
|
|
||||||
mock := &MockAccountManager{ctrl: ctrl}
|
|
||||||
mock.recorder = &MockAccountManagerMockRecorder{mock}
|
|
||||||
return mock
|
|
||||||
}
|
|
||||||
|
|
||||||
// EXPECT returns an object that allows the caller to indicate expected use
|
|
||||||
func (m *MockAccountManager) EXPECT() *MockAccountManagerMockRecorder {
|
|
||||||
return m.recorder
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddressToDecryptedAccount mocks base method
|
|
||||||
func (m *MockAccountManager) AddressToDecryptedAccount(arg0, arg1 string) (types.Account, *types.Key, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "AddressToDecryptedAccount", arg0, arg1)
|
|
||||||
ret0, _ := ret[0].(types.Account)
|
|
||||||
ret1, _ := ret[1].(*types.Key)
|
|
||||||
ret2, _ := ret[2].(error)
|
|
||||||
return ret0, ret1, ret2
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddressToDecryptedAccount indicates an expected call of AddressToDecryptedAccount
|
|
||||||
func (mr *MockAccountManagerMockRecorder) AddressToDecryptedAccount(arg0, arg1 interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddressToDecryptedAccount", reflect.TypeOf((*MockAccountManager)(nil).AddressToDecryptedAccount), arg0, arg1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectAccount mocks base method
|
|
||||||
func (m *MockAccountManager) SelectAccount(arg0 account.LoginParams) error {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "SelectAccount", arg0)
|
|
||||||
ret0, _ := ret[0].(error)
|
|
||||||
return ret0
|
|
||||||
}
|
|
||||||
|
|
||||||
// SelectAccount indicates an expected call of SelectAccount
|
|
||||||
func (mr *MockAccountManagerMockRecorder) SelectAccount(arg0 interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SelectAccount", reflect.TypeOf((*MockAccountManager)(nil).SelectAccount), arg0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateAccount mocks base method
|
|
||||||
func (m *MockAccountManager) CreateAccount(password string) (generator.GeneratedAccountInfo, account.Info, string, error) {
|
|
||||||
m.ctrl.T.Helper()
|
|
||||||
ret := m.ctrl.Call(m, "CreateAccount", password)
|
|
||||||
ret0, _ := ret[0].(generator.GeneratedAccountInfo)
|
|
||||||
ret1, _ := ret[1].(account.Info)
|
|
||||||
ret2, _ := ret[2].(string)
|
|
||||||
ret3, _ := ret[3].(error)
|
|
||||||
return ret0, ret1, ret2, ret3
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateAccount indicates an expected call of CreateAccount
|
|
||||||
func (mr *MockAccountManagerMockRecorder) CreateAccount(password interface{}) *gomock.Call {
|
|
||||||
mr.mock.ctrl.T.Helper()
|
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAccount", reflect.TypeOf((*MockAccountManager)(nil).CreateAccount), password)
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
package status
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/account"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PublicAPI represents a set of APIs from the `web3.status` namespace.
|
|
||||||
type PublicAPI struct {
|
|
||||||
s *Service
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAPI creates an instance of the status API.
|
|
||||||
func NewAPI(s *Service) *PublicAPI {
|
|
||||||
return &PublicAPI{s: s}
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoginRequest : json request for status_login.
|
|
||||||
type LoginRequest struct {
|
|
||||||
Addr string `json:"address"`
|
|
||||||
Password string `json:"password"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoginResponse : json response returned by status_login.
|
|
||||||
type LoginResponse struct {
|
|
||||||
AddressKeyID string `json:"address_key_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Login is an implementation of `status_login` or `web3.status.login` API
|
|
||||||
func (api *PublicAPI) Login(context context.Context, req LoginRequest) (res LoginResponse, err error) {
|
|
||||||
_, accountKey, err := api.s.am.AddressToDecryptedAccount(req.Addr, req.Password)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.AddressKeyID, err = api.s.w.AddKeyPair(accountKey.PrivateKey); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
loginParams := account.LoginParams{
|
|
||||||
ChatAddress: types.HexToAddress(req.Addr),
|
|
||||||
Password: req.Password,
|
|
||||||
MainAccount: types.HexToAddress(req.Addr),
|
|
||||||
}
|
|
||||||
if err = api.s.am.SelectAccount(loginParams); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignupRequest : json request for status_signup.
|
|
||||||
type SignupRequest struct {
|
|
||||||
Password string `json:"password"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SignupResponse : json response returned by status_signup.
|
|
||||||
type SignupResponse struct {
|
|
||||||
Address string `json:"address"`
|
|
||||||
Pubkey string `json:"pubkey"`
|
|
||||||
WalletAddress string `json:"walletAddress"`
|
|
||||||
WalletPubkey string `json:"walletPubKey"`
|
|
||||||
ChatAddress string `json:"chatAddress"`
|
|
||||||
ChatPubkey string `json:"chatPubkey"`
|
|
||||||
Mnemonic string `json:"mnemonic"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Signup is an implementation of `status_signup` or `web3.status.signup` API
|
|
||||||
func (api *PublicAPI) Signup(context context.Context, req SignupRequest) (res SignupResponse, err error) {
|
|
||||||
_, accountInfo, mnemonic, err := api.s.am.CreateAccount(req.Password)
|
|
||||||
if err != nil {
|
|
||||||
err = errors.New("could not create the specified account : " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
res.Address = accountInfo.WalletAddress
|
|
||||||
res.Pubkey = accountInfo.WalletPubKey
|
|
||||||
res.WalletAddress = accountInfo.WalletAddress
|
|
||||||
res.WalletPubkey = accountInfo.WalletPubKey
|
|
||||||
res.ChatAddress = accountInfo.ChatAddress
|
|
||||||
res.ChatPubkey = accountInfo.ChatPubKey
|
|
||||||
res.Mnemonic = mnemonic
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateAddressResponse : json response returned by status_createaccount
|
|
||||||
type CreateAddressResponse struct {
|
|
||||||
Address string `json:"address"`
|
|
||||||
Pubkey string `json:"pubkey"`
|
|
||||||
Privkey string `json:"privkey"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateAddress is an implementation of `status_createaccount` or `web3.status.createaccount` API
|
|
||||||
func (api *PublicAPI) CreateAddress(context context.Context) (res CreateAddressResponse, err error) {
|
|
||||||
if res.Address, res.Pubkey, res.Privkey, err = account.CreateAddress(); err != nil {
|
|
||||||
err = fmt.Errorf("could not create an address: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,178 +0,0 @@
|
||||||
package status
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/account/generator"
|
|
||||||
|
|
||||||
"github.com/golang/mock/gomock"
|
|
||||||
"github.com/stretchr/testify/suite"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/account"
|
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestStatusSuite(t *testing.T) {
|
|
||||||
suite.Run(t, new(StatusSuite))
|
|
||||||
}
|
|
||||||
|
|
||||||
type StatusSuite struct {
|
|
||||||
suite.Suite
|
|
||||||
am *MockAccountManager
|
|
||||||
w *MockWhisperService
|
|
||||||
api *PublicAPI
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StatusSuite) SetupTest() {
|
|
||||||
ctrl := gomock.NewController(s.T())
|
|
||||||
s.am = NewMockAccountManager(ctrl)
|
|
||||||
s.w = NewMockWhisperService(ctrl)
|
|
||||||
service := New(s.w)
|
|
||||||
service.SetAccountManager(s.am)
|
|
||||||
|
|
||||||
s.api = NewAPI(service)
|
|
||||||
}
|
|
||||||
|
|
||||||
var logintests = []struct {
|
|
||||||
name string
|
|
||||||
expectedAddressKey string
|
|
||||||
expectedError error
|
|
||||||
prepareExpectations func(*StatusSuite)
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success login",
|
|
||||||
expectedAddressKey: "addressKey",
|
|
||||||
expectedError: nil,
|
|
||||||
prepareExpectations: func(s *StatusSuite) {
|
|
||||||
key := types.Key{
|
|
||||||
PrivateKey: &ecdsa.PrivateKey{},
|
|
||||||
}
|
|
||||||
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(types.Account{}, &key, nil)
|
|
||||||
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("addressKey", nil)
|
|
||||||
|
|
||||||
loginParams := account.LoginParams{
|
|
||||||
MainAccount: types.HexToAddress("0x01"),
|
|
||||||
ChatAddress: types.HexToAddress("0x01"),
|
|
||||||
Password: "password",
|
|
||||||
}
|
|
||||||
s.am.EXPECT().SelectAccount(loginParams).Return(nil)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error when decrypting account from address",
|
|
||||||
expectedAddressKey: "",
|
|
||||||
expectedError: errors.New("foo"),
|
|
||||||
prepareExpectations: func(s *StatusSuite) {
|
|
||||||
key := types.Key{
|
|
||||||
PrivateKey: &ecdsa.PrivateKey{},
|
|
||||||
}
|
|
||||||
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(types.Account{}, &key, errors.New("foo"))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error when adding key pair to whisper",
|
|
||||||
expectedAddressKey: "",
|
|
||||||
expectedError: errors.New("foo"),
|
|
||||||
prepareExpectations: func(s *StatusSuite) {
|
|
||||||
key := types.Key{
|
|
||||||
PrivateKey: &ecdsa.PrivateKey{},
|
|
||||||
}
|
|
||||||
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(types.Account{}, &key, nil)
|
|
||||||
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("", errors.New("foo"))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "error when selecting account",
|
|
||||||
expectedAddressKey: "",
|
|
||||||
expectedError: errors.New("foo"),
|
|
||||||
prepareExpectations: func(s *StatusSuite) {
|
|
||||||
key := types.Key{
|
|
||||||
PrivateKey: &ecdsa.PrivateKey{},
|
|
||||||
}
|
|
||||||
s.am.EXPECT().AddressToDecryptedAccount("0x01", "password").Return(types.Account{}, &key, nil)
|
|
||||||
s.w.EXPECT().AddKeyPair(key.PrivateKey).Return("", nil)
|
|
||||||
|
|
||||||
loginParams := account.LoginParams{
|
|
||||||
MainAccount: types.HexToAddress("0x01"),
|
|
||||||
ChatAddress: types.HexToAddress("0x01"),
|
|
||||||
Password: "password",
|
|
||||||
}
|
|
||||||
s.am.EXPECT().SelectAccount(loginParams).Return(errors.New("foo"))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StatusSuite) TestLogin() {
|
|
||||||
for _, t := range logintests {
|
|
||||||
req := LoginRequest{Addr: "0x01", Password: "password"}
|
|
||||||
|
|
||||||
t.prepareExpectations(s)
|
|
||||||
|
|
||||||
var ctx context.Context
|
|
||||||
res, err := s.api.Login(ctx, req)
|
|
||||||
s.Equal(t.expectedAddressKey, res.AddressKeyID, "failed scenario : "+t.name)
|
|
||||||
s.Equal(t.expectedError, err, "failed scenario : "+t.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var signuptests = []struct {
|
|
||||||
name string
|
|
||||||
expectedResponse SignupResponse
|
|
||||||
expectedError error
|
|
||||||
prepareExpectations func(*StatusSuite)
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "success signup",
|
|
||||||
expectedResponse: SignupResponse{
|
|
||||||
WalletAddress: "addr",
|
|
||||||
WalletPubkey: "pubkey",
|
|
||||||
Mnemonic: "mnemonic",
|
|
||||||
},
|
|
||||||
expectedError: nil,
|
|
||||||
prepareExpectations: func(s *StatusSuite) {
|
|
||||||
mKInfo := generator.GeneratedAccountInfo{
|
|
||||||
IdentifiedAccountInfo: generator.IdentifiedAccountInfo{},
|
|
||||||
Mnemonic: "",
|
|
||||||
}
|
|
||||||
accountInfo := account.Info{
|
|
||||||
WalletAddress: "addr",
|
|
||||||
WalletPubKey: "pubkey",
|
|
||||||
ChatAddress: "addr",
|
|
||||||
ChatPubKey: "pubkey",
|
|
||||||
}
|
|
||||||
s.am.EXPECT().CreateAccount("password").Return(mKInfo, accountInfo, "mnemonic", nil)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "success signup",
|
|
||||||
expectedResponse: SignupResponse{
|
|
||||||
WalletAddress: "",
|
|
||||||
WalletPubkey: "",
|
|
||||||
Mnemonic: "",
|
|
||||||
},
|
|
||||||
expectedError: errors.New("could not create the specified account : foo"),
|
|
||||||
prepareExpectations: func(s *StatusSuite) {
|
|
||||||
mKInfo := generator.GeneratedAccountInfo{
|
|
||||||
IdentifiedAccountInfo: generator.IdentifiedAccountInfo{},
|
|
||||||
Mnemonic: "",
|
|
||||||
}
|
|
||||||
s.am.EXPECT().CreateAccount("password").Return(mKInfo, account.Info{}, "", errors.New("foo"))
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *StatusSuite) TestSignup() {
|
|
||||||
for _, t := range signuptests {
|
|
||||||
t.prepareExpectations(s)
|
|
||||||
|
|
||||||
var ctx context.Context
|
|
||||||
res, err := s.api.Signup(ctx, SignupRequest{Password: "password"})
|
|
||||||
s.Equal(t.expectedResponse.WalletAddress, res.WalletAddress, "failed scenario : "+t.name)
|
|
||||||
s.Equal(t.expectedResponse.WalletPubkey, res.WalletPubkey, "failed scenario : "+t.name)
|
|
||||||
s.Equal(t.expectedResponse.Mnemonic, res.Mnemonic, "failed scenario : "+t.name)
|
|
||||||
s.Equal(t.expectedError, err, "failed scenario : "+t.name)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,74 +0,0 @@
|
||||||
package status
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/node"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/account"
|
|
||||||
"github.com/status-im/status-go/account/generator"
|
|
||||||
"github.com/status-im/status-go/eth-node/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Make sure that Service implements node.Service interface.
|
|
||||||
var _ node.Service = (*Service)(nil)
|
|
||||||
|
|
||||||
// WhisperService whisper interface to add key pairs
|
|
||||||
type WhisperService interface {
|
|
||||||
AddKeyPair(key *ecdsa.PrivateKey) (string, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountManager interface to manage account actions
|
|
||||||
type AccountManager interface {
|
|
||||||
AddressToDecryptedAccount(string, string) (types.Account, *types.Key, error)
|
|
||||||
SelectAccount(account.LoginParams) error
|
|
||||||
CreateAccount(password string) (mkInfo generator.GeneratedAccountInfo, accountInfo account.Info, mnemonic string, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Service represents our own implementation of status status operations.
|
|
||||||
type Service struct {
|
|
||||||
am AccountManager
|
|
||||||
w WhisperService
|
|
||||||
}
|
|
||||||
|
|
||||||
// New returns a new Service.
|
|
||||||
func New(w WhisperService) *Service {
|
|
||||||
return &Service{w: w}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Protocols returns a new protocols list. In this case, there are none.
|
|
||||||
func (s *Service) Protocols() []p2p.Protocol {
|
|
||||||
return []p2p.Protocol{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// APIs returns a list of new APIs.
|
|
||||||
func (s *Service) APIs() []rpc.API {
|
|
||||||
|
|
||||||
return []rpc.API{
|
|
||||||
{
|
|
||||||
Namespace: "status",
|
|
||||||
Version: "1.0",
|
|
||||||
Service: NewAPI(s),
|
|
||||||
Public: false,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetAccountManager sets account manager for the API calls.
|
|
||||||
func (s *Service) SetAccountManager(a AccountManager) {
|
|
||||||
s.am = a
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start is run when a service is started.
|
|
||||||
// It does nothing in this case but is required by `node.Service` interface.
|
|
||||||
func (s *Service) Start(server *p2p.Server) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop is run when a service is stopped.
|
|
||||||
// It does nothing in this case but is required by `node.Service` interface.
|
|
||||||
func (s *Service) Stop() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -15,8 +15,8 @@ type Service struct {
|
||||||
w types.Waku
|
w types.Waku
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config params.ShhextConfig, n types.Node, ctx interface{}, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
func New(config params.ShhextConfig, n types.Node, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
||||||
w, err := n.GetWaku(ctx)
|
w, err := n.GetWaku(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,8 @@ type Service struct {
|
||||||
w types.Waku
|
w types.Waku
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(config params.ShhextConfig, n types.Node, ctx interface{}, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
func New(config params.ShhextConfig, n types.Node, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
||||||
w, err := n.GetWakuV2(ctx)
|
w, err := n.GetWakuV2(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,7 +43,7 @@ type Service struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start signals transmitter.
|
// Start signals transmitter.
|
||||||
func (s *Service) Start(*p2p.Server) error {
|
func (s *Service) Start() error {
|
||||||
s.group = NewGroup(context.Background())
|
s.group = NewGroup(context.Background())
|
||||||
return s.signals.Start()
|
return s.signals.Start()
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,7 +194,7 @@ func (s *NTPTimeSource) StartService() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start runs a goroutine that updates local offset every updatePeriod.
|
// Start runs a goroutine that updates local offset every updatePeriod.
|
||||||
func (s *NTPTimeSource) Start(*p2p.Server) error {
|
func (s *NTPTimeSource) Start() error {
|
||||||
return s.runPeriodically(s.updateOffset)
|
return s.runPeriodically(s.updateOffset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,9 +43,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -203,37 +201,13 @@ func (s *LightEthereum) VfluxRequest(n *enode.Node, reqs vflux.Requests) vflux.R
|
||||||
if !s.udpEnabled {
|
if !s.udpEnabled {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
reqsEnc, _ := rlp.EncodeToBytes(&reqs)
|
return nil
|
||||||
repliesEnc, _ := s.p2pServer.DiscV5.TalkRequest(s.serverPool.DialNode(n), "vfx", reqsEnc)
|
|
||||||
var replies vflux.Replies
|
|
||||||
if len(repliesEnc) == 0 || rlp.DecodeBytes(repliesEnc, &replies) != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return replies
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vfxVersion returns the version number of the "les" service subdomain of the vflux UDP
|
// vfxVersion returns the version number of the "les" service subdomain of the vflux UDP
|
||||||
// service, as advertised in the ENR record
|
// service, as advertised in the ENR record
|
||||||
func (s *LightEthereum) vfxVersion(n *enode.Node) uint {
|
func (s *LightEthereum) vfxVersion(n *enode.Node) uint {
|
||||||
if n.Seq() == 0 {
|
return 0
|
||||||
var err error
|
|
||||||
if !s.udpEnabled {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
if n, err = s.p2pServer.DiscV5.RequestENR(n); n != nil && err == nil && n.Seq() != 0 {
|
|
||||||
s.serverPool.Persist(n)
|
|
||||||
} else {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var les []rlp.RawValue
|
|
||||||
if err := n.Load(enr.WithEntry("les", &les)); err != nil || len(les) < 1 {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
var version uint
|
|
||||||
rlp.DecodeBytes(les[0], &version) // Ignore additional fields (for forward compatibility).
|
|
||||||
return version
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// prenegQuery sends a capacity query to the given server node to determine whether
|
// prenegQuery sends a capacity query to the given server node to determine whether
|
||||||
|
|
|
@ -54,11 +54,6 @@ func (eth *LightEthereum) setupDiscovery() (enode.Iterator, error) {
|
||||||
it.AddSource(dns)
|
it.AddSource(dns)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable DHT.
|
|
||||||
if eth.udpEnabled {
|
|
||||||
it.AddSource(eth.p2pServer.DiscV5.RandomNodes())
|
|
||||||
}
|
|
||||||
|
|
||||||
forkFilter := forkid.NewFilter(eth.blockchain)
|
forkFilter := forkid.NewFilter(eth.blockchain)
|
||||||
iterator := enode.Filter(it, func(n *enode.Node) bool { return nodeIsServer(forkFilter, n) })
|
iterator := enode.Filter(it, func(n *enode.Node) bool { return nodeIsServer(forkFilter, n) })
|
||||||
return iterator, nil
|
return iterator, nil
|
||||||
|
|
|
@ -201,9 +201,10 @@ func (s *LesServer) Start() error {
|
||||||
s.handler.start()
|
s.handler.start()
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go s.capacityManagement()
|
go s.capacityManagement()
|
||||||
if s.p2pSrv.DiscV5 != nil {
|
/*
|
||||||
s.p2pSrv.DiscV5.RegisterTalkHandler("vfx", s.vfluxServer.ServeEncoded)
|
if s.p2pSrv.DiscV5 != nil {
|
||||||
}
|
s.p2pSrv.DiscV5.RegisterTalkHandler("vfx", s.vfluxServer.ServeEncoded)
|
||||||
|
}*/
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -206,6 +206,7 @@ func (d *dialScheduler) removeStatic(n *enode.Node) {
|
||||||
|
|
||||||
// peerAdded updates the peer set.
|
// peerAdded updates the peer set.
|
||||||
func (d *dialScheduler) peerAdded(c *conn) {
|
func (d *dialScheduler) peerAdded(c *conn) {
|
||||||
|
log.Info("PEER added")
|
||||||
select {
|
select {
|
||||||
case d.addPeerCh <- c:
|
case d.addPeerCh <- c:
|
||||||
case <-d.ctx.Done():
|
case <-d.ctx.Done():
|
||||||
|
@ -214,6 +215,7 @@ func (d *dialScheduler) peerAdded(c *conn) {
|
||||||
|
|
||||||
// peerRemoved updates the peer set.
|
// peerRemoved updates the peer set.
|
||||||
func (d *dialScheduler) peerRemoved(c *conn) {
|
func (d *dialScheduler) peerRemoved(c *conn) {
|
||||||
|
log.Info("PEER removed")
|
||||||
select {
|
select {
|
||||||
case d.remPeerCh <- c:
|
case d.remPeerCh <- c:
|
||||||
case <-d.ctx.Done():
|
case <-d.ctx.Done():
|
||||||
|
@ -243,7 +245,7 @@ loop:
|
||||||
select {
|
select {
|
||||||
case node := <-nodesCh:
|
case node := <-nodesCh:
|
||||||
if err := d.checkDial(node); err != nil {
|
if err := d.checkDial(node); err != nil {
|
||||||
d.log.Trace("Discarding dial candidate", "id", node.ID(), "ip", node.IP(), "reason", err)
|
d.log.Info("Discarding dial candidate", "id", node.ID(), "ip", node.IP(), "reason", err)
|
||||||
} else {
|
} else {
|
||||||
d.startDial(newDialTask(node, dynDialedConn))
|
d.startDial(newDialTask(node, dynDialedConn))
|
||||||
}
|
}
|
||||||
|
@ -277,14 +279,22 @@ loop:
|
||||||
case node := <-d.addStaticCh:
|
case node := <-d.addStaticCh:
|
||||||
id := node.ID()
|
id := node.ID()
|
||||||
_, exists := d.static[id]
|
_, exists := d.static[id]
|
||||||
d.log.Trace("Adding static node", "id", id, "ip", node.IP(), "added", !exists)
|
d.log.Info("Adding static node", "id", id, "ip", node.IP(), "added", !exists)
|
||||||
if exists {
|
if exists {
|
||||||
|
d.log.Info("existing, continue")
|
||||||
continue loop
|
continue loop
|
||||||
}
|
}
|
||||||
task := newDialTask(node, staticDialedConn)
|
task := newDialTask(node, staticDialedConn)
|
||||||
|
d.log.Info("new dial task")
|
||||||
d.static[id] = task
|
d.static[id] = task
|
||||||
if d.checkDial(node) == nil {
|
d.log.Info("checking dial")
|
||||||
|
err := d.checkDial(node)
|
||||||
|
d.log.Info("dial checked")
|
||||||
|
if err == nil {
|
||||||
|
d.log.Info("addign to static pool")
|
||||||
d.addToStaticPool(task)
|
d.addToStaticPool(task)
|
||||||
|
} else {
|
||||||
|
d.log.Info("error", "err", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
case node := <-d.remStaticCh:
|
case node := <-d.remStaticCh:
|
||||||
|
@ -376,6 +386,7 @@ func (d *dialScheduler) expireHistory() {
|
||||||
// freeDialSlots returns the number of free dial slots. The result can be negative
|
// freeDialSlots returns the number of free dial slots. The result can be negative
|
||||||
// when peers are connected while their task is still running.
|
// when peers are connected while their task is still running.
|
||||||
func (d *dialScheduler) freeDialSlots() int {
|
func (d *dialScheduler) freeDialSlots() int {
|
||||||
|
log.Info("checkign slots", "max dials", d.maxDialPeers, "dial peers", d.dialPeers)
|
||||||
slots := (d.maxDialPeers - d.dialPeers) * 2
|
slots := (d.maxDialPeers - d.dialPeers) * 2
|
||||||
if slots > d.maxActiveDials {
|
if slots > d.maxActiveDials {
|
||||||
slots = d.maxActiveDials
|
slots = d.maxActiveDials
|
||||||
|
@ -412,7 +423,9 @@ func (d *dialScheduler) checkDial(n *enode.Node) error {
|
||||||
|
|
||||||
// startStaticDials starts n static dial tasks.
|
// startStaticDials starts n static dial tasks.
|
||||||
func (d *dialScheduler) startStaticDials(n int) (started int) {
|
func (d *dialScheduler) startStaticDials(n int) (started int) {
|
||||||
|
log.Info("starting", "n", n)
|
||||||
for started = 0; started < n && len(d.staticPool) > 0; started++ {
|
for started = 0; started < n && len(d.staticPool) > 0; started++ {
|
||||||
|
log.Info("starting static")
|
||||||
idx := d.rand.Intn(len(d.staticPool))
|
idx := d.rand.Intn(len(d.staticPool))
|
||||||
task := d.staticPool[idx]
|
task := d.staticPool[idx]
|
||||||
d.startDial(task)
|
d.startDial(task)
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
This package is an early prototype of Discovery v5. Do not use this code.
|
||||||
|
|
||||||
|
See https://github.com/ethereum/devp2p/blob/master/discv5/discv5.md for the
|
||||||
|
current Discovery v5 specification.
|
|
@ -58,12 +58,11 @@ var (
|
||||||
nodeDBVersionKey = []byte("version") // Version of the database to flush if changes
|
nodeDBVersionKey = []byte("version") // Version of the database to flush if changes
|
||||||
nodeDBItemPrefix = []byte("n:") // Identifier to prefix node entries with
|
nodeDBItemPrefix = []byte("n:") // Identifier to prefix node entries with
|
||||||
|
|
||||||
nodeDBDiscoverRoot = ":discover"
|
nodeDBDiscoverRoot = ":discover"
|
||||||
nodeDBDiscoverPing = nodeDBDiscoverRoot + ":lastping"
|
nodeDBDiscoverPing = nodeDBDiscoverRoot + ":lastping"
|
||||||
nodeDBDiscoverPong = nodeDBDiscoverRoot + ":lastpong"
|
nodeDBDiscoverPong = nodeDBDiscoverRoot + ":lastpong"
|
||||||
nodeDBDiscoverFindFails = nodeDBDiscoverRoot + ":findfail"
|
nodeDBDiscoverFindFails = nodeDBDiscoverRoot + ":findfail"
|
||||||
nodeDBDiscoverLocalEndpoint = nodeDBDiscoverRoot + ":localendpoint"
|
nodeDBTopicRegTickets = ":tickets"
|
||||||
nodeDBTopicRegTickets = ":tickets"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// newNodeDB creates a new node database for storing and retrieving infos about
|
// newNodeDB creates a new node database for storing and retrieving infos about
|
||||||
|
@ -311,20 +310,6 @@ func (db *nodeDB) updateFindFails(id NodeID, fails int) error {
|
||||||
return db.storeInt64(makeKey(id, nodeDBDiscoverFindFails), int64(fails))
|
return db.storeInt64(makeKey(id, nodeDBDiscoverFindFails), int64(fails))
|
||||||
}
|
}
|
||||||
|
|
||||||
// localEndpoint returns the last local endpoint communicated to the
|
|
||||||
// given remote node.
|
|
||||||
func (db *nodeDB) localEndpoint(id NodeID) *rpcEndpoint {
|
|
||||||
var ep rpcEndpoint
|
|
||||||
if err := db.fetchRLP(makeKey(id, nodeDBDiscoverLocalEndpoint), &ep); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return &ep
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *nodeDB) updateLocalEndpoint(id NodeID, ep rpcEndpoint) error {
|
|
||||||
return db.storeRLP(makeKey(id, nodeDBDiscoverLocalEndpoint), &ep)
|
|
||||||
}
|
|
||||||
|
|
||||||
// querySeeds retrieves random nodes to be used as potential seed nodes
|
// querySeeds retrieves random nodes to be used as potential seed nodes
|
||||||
// for bootstrapping.
|
// for bootstrapping.
|
||||||
func (db *nodeDB) querySeeds(n int, maxAge time.Duration) []*Node {
|
func (db *nodeDB) querySeeds(n int, maxAge time.Duration) []*Node {
|
||||||
|
|
|
@ -77,14 +77,6 @@ type Network struct {
|
||||||
nursery []*Node
|
nursery []*Node
|
||||||
nodes map[NodeID]*Node // tracks active nodes with state != known
|
nodes map[NodeID]*Node // tracks active nodes with state != known
|
||||||
timeoutTimers map[timeoutEvent]*time.Timer
|
timeoutTimers map[timeoutEvent]*time.Timer
|
||||||
|
|
||||||
// Revalidation queues.
|
|
||||||
// Nodes put on these queues will be pinged eventually.
|
|
||||||
slowRevalidateQueue []*Node
|
|
||||||
fastRevalidateQueue []*Node
|
|
||||||
|
|
||||||
// Buffers for state transition.
|
|
||||||
sendBuf []*ingressPacket
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// transport is implemented by the UDP transport.
|
// transport is implemented by the UDP transport.
|
||||||
|
@ -104,10 +96,9 @@ type transport interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type findnodeQuery struct {
|
type findnodeQuery struct {
|
||||||
remote *Node
|
remote *Node
|
||||||
target common.Hash
|
target common.Hash
|
||||||
reply chan<- []*Node
|
reply chan<- []*Node
|
||||||
nresults int // counter for received nodes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type topicRegisterReq struct {
|
type topicRegisterReq struct {
|
||||||
|
@ -366,6 +357,8 @@ func (net *Network) loop() {
|
||||||
bucketRefreshTimer = time.NewTimer(bucketRefreshInterval)
|
bucketRefreshTimer = time.NewTimer(bucketRefreshInterval)
|
||||||
refreshDone chan struct{} // closed when the 'refresh' lookup has ended
|
refreshDone chan struct{} // closed when the 'refresh' lookup has ended
|
||||||
)
|
)
|
||||||
|
defer refreshTimer.Stop()
|
||||||
|
defer bucketRefreshTimer.Stop()
|
||||||
|
|
||||||
// Tracking the next ticket to register.
|
// Tracking the next ticket to register.
|
||||||
var (
|
var (
|
||||||
|
@ -402,11 +395,13 @@ func (net *Network) loop() {
|
||||||
searchInfo = make(map[Topic]topicSearchInfo)
|
searchInfo = make(map[Topic]topicSearchInfo)
|
||||||
activeSearchCount int
|
activeSearchCount int
|
||||||
)
|
)
|
||||||
|
defer topicRegisterLookupTick.Stop()
|
||||||
topicSearchLookupDone := make(chan topicSearchResult, 100)
|
topicSearchLookupDone := make(chan topicSearchResult, 100)
|
||||||
topicSearch := make(chan Topic, 100)
|
topicSearch := make(chan Topic, 100)
|
||||||
<-topicRegisterLookupTick.C
|
<-topicRegisterLookupTick.C
|
||||||
|
|
||||||
statsDump := time.NewTicker(10 * time.Second)
|
statsDump := time.NewTicker(10 * time.Second)
|
||||||
|
defer statsDump.Stop()
|
||||||
|
|
||||||
loop:
|
loop:
|
||||||
for {
|
for {
|
||||||
|
@ -646,14 +641,14 @@ loop:
|
||||||
}
|
}
|
||||||
log.Trace("loop stopped")
|
log.Trace("loop stopped")
|
||||||
|
|
||||||
log.Debug(fmt.Sprintf("shutting down"))
|
log.Debug("shutting down")
|
||||||
if net.conn != nil {
|
if net.conn != nil {
|
||||||
net.conn.Close()
|
net.conn.Close()
|
||||||
}
|
}
|
||||||
if refreshDone != nil {
|
// TODO: wait for pending refresh.
|
||||||
// TODO: wait for pending refresh.
|
// if refreshDone != nil {
|
||||||
//<-refreshResults
|
// <-refreshResults
|
||||||
}
|
// }
|
||||||
// Cancel all pending timeouts.
|
// Cancel all pending timeouts.
|
||||||
for _, timer := range net.timeoutTimers {
|
for _, timer := range net.timeoutTimers {
|
||||||
timer.Stop()
|
timer.Stop()
|
||||||
|
@ -1042,6 +1037,9 @@ func (net *Network) handle(n *Node, ev nodeEvent, pkt *ingressPacket) error {
|
||||||
net.db.ensureExpirer()
|
net.db.ensureExpirer()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ev == pongTimeout {
|
||||||
|
n.pingEcho = nil // clean up if pongtimeout
|
||||||
|
}
|
||||||
if n.state == nil {
|
if n.state == nil {
|
||||||
n.state = unknown //???
|
n.state = unknown //???
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,23 +66,6 @@ func (n *Node) addr() *net.UDPAddr {
|
||||||
return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)}
|
return &net.UDPAddr{IP: n.IP, Port: int(n.UDP)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) setAddr(a *net.UDPAddr) {
|
|
||||||
n.IP = a.IP
|
|
||||||
if ipv4 := a.IP.To4(); ipv4 != nil {
|
|
||||||
n.IP = ipv4
|
|
||||||
}
|
|
||||||
n.UDP = uint16(a.Port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// compares the given address against the stored values.
|
|
||||||
func (n *Node) addrEqual(a *net.UDPAddr) bool {
|
|
||||||
ip := a.IP
|
|
||||||
if ipv4 := a.IP.To4(); ipv4 != nil {
|
|
||||||
ip = ipv4
|
|
||||||
}
|
|
||||||
return n.UDP == uint16(a.Port) && n.IP.Equal(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Incomplete returns true for nodes with no IP address.
|
// Incomplete returns true for nodes with no IP address.
|
||||||
func (n *Node) Incomplete() bool {
|
func (n *Node) Incomplete() bool {
|
||||||
return n.IP == nil
|
return n.IP == nil
|
||||||
|
@ -326,14 +309,6 @@ func (n NodeID) Pubkey() (*ecdsa.PublicKey, error) {
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (id NodeID) mustPubkey() ecdsa.PublicKey {
|
|
||||||
pk, err := id.Pubkey()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return *pk
|
|
||||||
}
|
|
||||||
|
|
||||||
// recoverNodeID computes the public key used to sign the
|
// recoverNodeID computes the public key used to sign the
|
||||||
// given hash from the signature.
|
// given hash from the signature.
|
||||||
func recoverNodeID(hash, sig []byte) (id NodeID, err error) {
|
func recoverNodeID(hash, sig []byte) (id NodeID, err error) {
|
||||||
|
|
|
@ -1,126 +0,0 @@
|
||||||
// Copyright 2016 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// Contains the NTP time drift detection via the SNTP protocol:
|
|
||||||
// https://tools.ietf.org/html/rfc4330
|
|
||||||
|
|
||||||
package discv5
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ntpPool = "pool.ntp.org" // ntpPool is the NTP server to query for the current time
|
|
||||||
ntpChecks = 3 // Number of measurements to do against the NTP server
|
|
||||||
)
|
|
||||||
|
|
||||||
// durationSlice attaches the methods of sort.Interface to []time.Duration,
|
|
||||||
// sorting in increasing order.
|
|
||||||
type durationSlice []time.Duration
|
|
||||||
|
|
||||||
func (s durationSlice) Len() int { return len(s) }
|
|
||||||
func (s durationSlice) Less(i, j int) bool { return s[i] < s[j] }
|
|
||||||
func (s durationSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
||||||
|
|
||||||
// checkClockDrift queries an NTP server for clock drifts and warns the user if
|
|
||||||
// one large enough is detected.
|
|
||||||
func checkClockDrift() {
|
|
||||||
drift, err := sntpDrift(ntpChecks)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if drift < -driftThreshold || drift > driftThreshold {
|
|
||||||
warning := fmt.Sprintf("System clock seems off by %v, which can prevent network connectivity", drift)
|
|
||||||
howtofix := fmt.Sprintf("Please enable network time synchronisation in system settings")
|
|
||||||
separator := strings.Repeat("-", len(warning))
|
|
||||||
|
|
||||||
log.Warn(separator)
|
|
||||||
log.Warn(warning)
|
|
||||||
log.Warn(howtofix)
|
|
||||||
log.Warn(separator)
|
|
||||||
} else {
|
|
||||||
log.Debug(fmt.Sprintf("Sanity NTP check reported %v drift, all ok", drift))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// sntpDrift does a naive time resolution against an NTP server and returns the
|
|
||||||
// measured drift. This method uses the simple version of NTP. It's not precise
|
|
||||||
// but should be fine for these purposes.
|
|
||||||
//
|
|
||||||
// Note, it executes two extra measurements compared to the number of requested
|
|
||||||
// ones to be able to discard the two extremes as outliers.
|
|
||||||
func sntpDrift(measurements int) (time.Duration, error) {
|
|
||||||
// Resolve the address of the NTP server
|
|
||||||
addr, err := net.ResolveUDPAddr("udp", ntpPool+":123")
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
// Construct the time request (empty package with only 2 fields set):
|
|
||||||
// Bits 3-5: Protocol version, 3
|
|
||||||
// Bits 6-8: Mode of operation, client, 3
|
|
||||||
request := make([]byte, 48)
|
|
||||||
request[0] = 3<<3 | 3
|
|
||||||
|
|
||||||
// Execute each of the measurements
|
|
||||||
drifts := []time.Duration{}
|
|
||||||
for i := 0; i < measurements+2; i++ {
|
|
||||||
// Dial the NTP server and send the time retrieval request
|
|
||||||
conn, err := net.DialUDP("udp", nil, addr)
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
sent := time.Now()
|
|
||||||
if _, err = conn.Write(request); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
// Retrieve the reply and calculate the elapsed time
|
|
||||||
conn.SetDeadline(time.Now().Add(5 * time.Second))
|
|
||||||
|
|
||||||
reply := make([]byte, 48)
|
|
||||||
if _, err = conn.Read(reply); err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
elapsed := time.Since(sent)
|
|
||||||
|
|
||||||
// Reconstruct the time from the reply data
|
|
||||||
sec := uint64(reply[43]) | uint64(reply[42])<<8 | uint64(reply[41])<<16 | uint64(reply[40])<<24
|
|
||||||
frac := uint64(reply[47]) | uint64(reply[46])<<8 | uint64(reply[45])<<16 | uint64(reply[44])<<24
|
|
||||||
|
|
||||||
nanosec := sec*1e9 + (frac*1e9)>>32
|
|
||||||
|
|
||||||
t := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC).Add(time.Duration(nanosec)).Local()
|
|
||||||
|
|
||||||
// Calculate the drift based on an assumed answer time of RRT/2
|
|
||||||
drifts = append(drifts, sent.Sub(t)+elapsed/2)
|
|
||||||
}
|
|
||||||
// Calculate average drif (drop two extremities to avoid outliers)
|
|
||||||
sort.Sort(durationSlice(drifts))
|
|
||||||
|
|
||||||
drift := time.Duration(0)
|
|
||||||
for i := 1; i < len(drifts)-1; i++ {
|
|
||||||
drift += drifts[i]
|
|
||||||
}
|
|
||||||
return drift / time.Duration(measurements), nil
|
|
||||||
}
|
|
|
@ -14,12 +14,8 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// Package discv5 implements the RLPx v5 Topic Discovery Protocol.
|
// Package discv5 is a prototype implementation of Discvery v5.
|
||||||
//
|
// Deprecated: do not use this package.
|
||||||
// The Topic Discovery protocol provides a way to find RLPx nodes that
|
|
||||||
// can be connected to. It uses a Kademlia-like protocol to maintain a
|
|
||||||
// distributed database of the IDs and endpoints of all listening
|
|
||||||
// nodes.
|
|
||||||
package discv5
|
package discv5
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -22,7 +22,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sort"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
@ -33,8 +32,6 @@ import (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ticketTimeBucketLen = time.Minute
|
ticketTimeBucketLen = time.Minute
|
||||||
timeWindow = 10 // * ticketTimeBucketLen
|
|
||||||
wantTicketsInWindow = 10
|
|
||||||
collectFrequency = time.Second * 30
|
collectFrequency = time.Second * 30
|
||||||
registerFrequency = time.Second * 60
|
registerFrequency = time.Second * 60
|
||||||
maxCollectDebt = 10
|
maxCollectDebt = 10
|
||||||
|
@ -139,7 +136,6 @@ type ticketStore struct {
|
||||||
|
|
||||||
lastBucketFetched timeBucket
|
lastBucketFetched timeBucket
|
||||||
nextTicketCached *ticketRef
|
nextTicketCached *ticketRef
|
||||||
nextTicketReg mclock.AbsTime
|
|
||||||
|
|
||||||
searchTopicMap map[Topic]searchTopic
|
searchTopicMap map[Topic]searchTopic
|
||||||
nextTopicQueryCleanup mclock.AbsTime
|
nextTopicQueryCleanup mclock.AbsTime
|
||||||
|
@ -268,57 +264,6 @@ func (s *ticketStore) nextSearchLookup(topic Topic) lookupInfo {
|
||||||
return target
|
return target
|
||||||
}
|
}
|
||||||
|
|
||||||
// ticketsInWindow returns the tickets of a given topic in the registration window.
|
|
||||||
func (s *ticketStore) ticketsInWindow(topic Topic) []ticketRef {
|
|
||||||
// Sanity check that the topic still exists before operating on it
|
|
||||||
if s.tickets[topic] == nil {
|
|
||||||
log.Warn("Listing non-existing discovery tickets", "topic", topic)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Gather all the tickers in the next time window
|
|
||||||
var tickets []ticketRef
|
|
||||||
|
|
||||||
buckets := s.tickets[topic].buckets
|
|
||||||
for idx := timeBucket(0); idx < timeWindow; idx++ {
|
|
||||||
tickets = append(tickets, buckets[s.lastBucketFetched+idx]...)
|
|
||||||
}
|
|
||||||
log.Trace("Retrieved discovery registration tickets", "topic", topic, "from", s.lastBucketFetched, "tickets", len(tickets))
|
|
||||||
return tickets
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ticketStore) removeExcessTickets(t Topic) {
|
|
||||||
tickets := s.ticketsInWindow(t)
|
|
||||||
if len(tickets) <= wantTicketsInWindow {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
sort.Sort(ticketRefByWaitTime(tickets))
|
|
||||||
for _, r := range tickets[wantTicketsInWindow:] {
|
|
||||||
s.removeTicketRef(r)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type ticketRefByWaitTime []ticketRef
|
|
||||||
|
|
||||||
// Len is the number of elements in the collection.
|
|
||||||
func (s ticketRefByWaitTime) Len() int {
|
|
||||||
return len(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ref ticketRef) waitTime() mclock.AbsTime {
|
|
||||||
return ref.t.regTime[ref.idx] - ref.t.issueTime
|
|
||||||
}
|
|
||||||
|
|
||||||
// Less reports whether the element with
|
|
||||||
// index i should sort before the element with index j.
|
|
||||||
func (s ticketRefByWaitTime) Less(i, j int) bool {
|
|
||||||
return s[i].waitTime() < s[j].waitTime()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap swaps the elements with indexes i and j.
|
|
||||||
func (s ticketRefByWaitTime) Swap(i, j int) {
|
|
||||||
s[i], s[j] = s[j], s[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ticketStore) addTicketRef(r ticketRef) {
|
func (s *ticketStore) addTicketRef(r ticketRef) {
|
||||||
topic := r.t.topics[r.idx]
|
topic := r.t.topics[r.idx]
|
||||||
tickets := s.tickets[topic]
|
tickets := s.tickets[topic]
|
||||||
|
@ -565,15 +510,6 @@ func (s *ticketStore) addTicket(localTime mclock.AbsTime, pingHash []byte, ticke
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ticketStore) getNodeTicket(node *Node) *ticket {
|
|
||||||
if s.nodes[node] == nil {
|
|
||||||
log.Trace("Retrieving node ticket", "node", node.ID, "serial", nil)
|
|
||||||
} else {
|
|
||||||
log.Trace("Retrieving node ticket", "node", node.ID, "serial", s.nodes[node].serial)
|
|
||||||
}
|
|
||||||
return s.nodes[node]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *ticketStore) canQueryTopic(node *Node, topic Topic) bool {
|
func (s *ticketStore) canQueryTopic(node *Node, topic Topic) bool {
|
||||||
qq := s.queriesSent[node]
|
qq := s.queriesSent[node]
|
||||||
if qq != nil {
|
if qq != nil {
|
||||||
|
@ -770,12 +706,6 @@ func globalRandRead(b []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *topicRadius) isInRadius(addrHash common.Hash) bool {
|
|
||||||
nodePrefix := binary.BigEndian.Uint64(addrHash[0:8])
|
|
||||||
dist := nodePrefix ^ r.topicHashPrefix
|
|
||||||
return dist < r.radius
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *topicRadius) chooseLookupBucket(a, b int) int {
|
func (r *topicRadius) chooseLookupBucket(a, b int) int {
|
||||||
if a < 0 {
|
if a < 0 {
|
||||||
a = 0
|
a = 0
|
||||||
|
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
@ -38,15 +37,12 @@ const Version = 4
|
||||||
var (
|
var (
|
||||||
errPacketTooSmall = errors.New("too small")
|
errPacketTooSmall = errors.New("too small")
|
||||||
errBadPrefix = errors.New("bad prefix")
|
errBadPrefix = errors.New("bad prefix")
|
||||||
errTimeout = errors.New("RPC timeout")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Timeouts
|
// Timeouts
|
||||||
const (
|
const (
|
||||||
respTimeout = 500 * time.Millisecond
|
respTimeout = 500 * time.Millisecond
|
||||||
expiration = 20 * time.Second
|
expiration = 20 * time.Second
|
||||||
|
|
||||||
driftThreshold = 10 * time.Second // Allowed clock drift before warning user
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RPC request structures
|
// RPC request structures
|
||||||
|
@ -187,10 +183,6 @@ func makeEndpoint(addr *net.UDPAddr, tcpPort uint16) rpcEndpoint {
|
||||||
return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
|
return rpcEndpoint{IP: ip, UDP: uint16(addr.Port), TCP: tcpPort}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e1 rpcEndpoint) equal(e2 rpcEndpoint) bool {
|
|
||||||
return e1.UDP == e2.UDP && e1.TCP == e2.TCP && e1.IP.Equal(e2.IP)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) {
|
func nodeFromRPC(sender *net.UDPAddr, rn rpcNode) (*Node, error) {
|
||||||
if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil {
|
if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -225,7 +217,6 @@ type udp struct {
|
||||||
conn conn
|
conn conn
|
||||||
priv *ecdsa.PrivateKey
|
priv *ecdsa.PrivateKey
|
||||||
ourEndpoint rpcEndpoint
|
ourEndpoint rpcEndpoint
|
||||||
nat nat.Interface
|
|
||||||
net *Network
|
net *Network
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,13 +265,6 @@ func (t *udp) sendPing(remote *Node, toaddr *net.UDPAddr, topics []Topic) (hash
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *udp) sendFindnode(remote *Node, target NodeID) {
|
|
||||||
t.sendPacket(remote.ID, remote.addr(), byte(findnodePacket), findnode{
|
|
||||||
Target: target,
|
|
||||||
Expiration: uint64(time.Now().Add(expiration).Unix()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *udp) sendNeighbours(remote *Node, results []*Node) {
|
func (t *udp) sendNeighbours(remote *Node, results []*Node) {
|
||||||
// Send neighbors in chunks with at most maxNeighbors per packet
|
// Send neighbors in chunks with at most maxNeighbors per packet
|
||||||
// to stay below the 1280 byte limit.
|
// to stay below the 1280 byte limit.
|
||||||
|
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
|
@ -104,7 +105,7 @@ type Config struct {
|
||||||
// BootstrapNodesV5 are used to establish connectivity
|
// BootstrapNodesV5 are used to establish connectivity
|
||||||
// with the rest of the network using the V5 discovery
|
// with the rest of the network using the V5 discovery
|
||||||
// protocol.
|
// protocol.
|
||||||
BootstrapNodesV5 []*enode.Node `toml:",omitempty"`
|
BootstrapNodesV5 []*discv5.Node `toml:",omitempty"`
|
||||||
|
|
||||||
// Static nodes are used as pre-configured connections which are always
|
// Static nodes are used as pre-configured connections which are always
|
||||||
// maintained and re-connected on disconnects.
|
// maintained and re-connected on disconnects.
|
||||||
|
@ -181,7 +182,7 @@ type Server struct {
|
||||||
nodedb *enode.DB
|
nodedb *enode.DB
|
||||||
localnode *enode.LocalNode
|
localnode *enode.LocalNode
|
||||||
ntab *discover.UDPv4
|
ntab *discover.UDPv4
|
||||||
DiscV5 *discover.UDPv5
|
DiscV5 *discv5.Network
|
||||||
discmix *enode.FairMix
|
discmix *enode.FairMix
|
||||||
dialsched *dialScheduler
|
dialsched *dialScheduler
|
||||||
|
|
||||||
|
@ -442,7 +443,7 @@ type sharedUDPConn struct {
|
||||||
unhandled chan discover.ReadPacket
|
unhandled chan discover.ReadPacket
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFromUDP implements discover.UDPConn
|
// ReadFromUDP implements discv5.conn
|
||||||
func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
|
func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err error) {
|
||||||
packet, ok := <-s.unhandled
|
packet, ok := <-s.unhandled
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -456,7 +457,7 @@ func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err err
|
||||||
return l, packet.Addr, nil
|
return l, packet.Addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close implements discover.UDPConn
|
// Close implements discv5.conn
|
||||||
func (s *sharedUDPConn) Close() error {
|
func (s *sharedUDPConn) Close() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -615,7 +616,7 @@ func (srv *Server) setupDiscovery() error {
|
||||||
Unhandled: unhandled,
|
Unhandled: unhandled,
|
||||||
Log: srv.log,
|
Log: srv.log,
|
||||||
}
|
}
|
||||||
ntab, err := discover.ListenV4(conn, srv.localnode, cfg)
|
ntab, err := discover.ListenUDP(conn, srv.localnode, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -625,21 +626,20 @@ func (srv *Server) setupDiscovery() error {
|
||||||
|
|
||||||
// Discovery V5
|
// Discovery V5
|
||||||
if srv.DiscoveryV5 {
|
if srv.DiscoveryV5 {
|
||||||
cfg := discover.Config{
|
var ntab *discv5.Network
|
||||||
PrivateKey: srv.PrivateKey,
|
|
||||||
NetRestrict: srv.NetRestrict,
|
|
||||||
Bootnodes: srv.BootstrapNodesV5,
|
|
||||||
Log: srv.log,
|
|
||||||
}
|
|
||||||
var err error
|
var err error
|
||||||
if sconn != nil {
|
if sconn != nil {
|
||||||
srv.DiscV5, err = discover.ListenV5(sconn, srv.localnode, cfg)
|
ntab, err = discv5.ListenUDP(srv.PrivateKey, sconn, "", srv.NetRestrict)
|
||||||
} else {
|
} else {
|
||||||
srv.DiscV5, err = discover.ListenV5(conn, srv.localnode, cfg)
|
ntab, err = discv5.ListenUDP(srv.PrivateKey, conn, "", srv.NetRestrict)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := ntab.SetFallbackNodes(srv.BootstrapNodesV5); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
srv.DiscV5 = ntab
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -671,6 +671,7 @@ func (srv *Server) maxInboundConns() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) maxDialedConns() (limit int) {
|
func (srv *Server) maxDialedConns() (limit int) {
|
||||||
|
log.Info("max dialled", "no-dial", srv.NoDial, "max-peers", srv.MaxPeers)
|
||||||
if srv.NoDial || srv.MaxPeers == 0 {
|
if srv.NoDial || srv.MaxPeers == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -780,6 +781,7 @@ running:
|
||||||
c.cont <- srv.postHandshakeChecks(peers, inboundCount, c)
|
c.cont <- srv.postHandshakeChecks(peers, inboundCount, c)
|
||||||
|
|
||||||
case c := <-srv.checkpointAddPeer:
|
case c := <-srv.checkpointAddPeer:
|
||||||
|
log.Info("checkpoing add peer")
|
||||||
// At this point the connection is past the protocol handshake.
|
// At this point the connection is past the protocol handshake.
|
||||||
// Its capabilities are known and the remote identity is verified.
|
// Its capabilities are known and the remote identity is verified.
|
||||||
err := srv.addPeerChecks(peers, inboundCount, c)
|
err := srv.addPeerChecks(peers, inboundCount, c)
|
||||||
|
@ -1043,6 +1045,7 @@ func (srv *Server) checkpoint(c *conn, stage chan<- *conn) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) launchPeer(c *conn) *Peer {
|
func (srv *Server) launchPeer(c *conn) *Peer {
|
||||||
|
log.Info("launching peer")
|
||||||
p := newPeer(srv.log, c, srv.Protocols)
|
p := newPeer(srv.log, c, srv.Protocols)
|
||||||
if srv.EnableMsgEvents {
|
if srv.EnableMsgEvents {
|
||||||
// If message events are enabled, pass the peerFeed
|
// If message events are enabled, pass the peerFeed
|
||||||
|
@ -1055,6 +1058,7 @@ func (srv *Server) launchPeer(c *conn) *Peer {
|
||||||
|
|
||||||
// runPeer runs in its own goroutine for each peer.
|
// runPeer runs in its own goroutine for each peer.
|
||||||
func (srv *Server) runPeer(p *Peer) {
|
func (srv *Server) runPeer(p *Peer) {
|
||||||
|
log.Info("Running peer", "peer", p)
|
||||||
if srv.newPeerHook != nil {
|
if srv.newPeerHook != nil {
|
||||||
srv.newPeerHook(p)
|
srv.newPeerHook(p)
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,24 +73,6 @@ var CalaverasBootnodes = []string{
|
||||||
"enode://9e1096aa59862a6f164994cb5cb16f5124d6c992cdbf4535ff7dea43ea1512afe5448dca9df1b7ab0726129603f1a3336b631e4d7a1a44c94daddd03241587f9@3.9.20.133:30303",
|
"enode://9e1096aa59862a6f164994cb5cb16f5124d6c992cdbf4535ff7dea43ea1512afe5448dca9df1b7ab0726129603f1a3336b631e4d7a1a44c94daddd03241587f9@3.9.20.133:30303",
|
||||||
}
|
}
|
||||||
|
|
||||||
var V5Bootnodes = []string{
|
|
||||||
// Teku team's bootnode
|
|
||||||
"enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2Gxb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNlY3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA",
|
|
||||||
"enr:-KG4QDyytgmE4f7AnvW-ZaUOIi9i79qX4JwjRAiXBZCU65wOfBu-3Nb5I7b_Rmg3KCOcZM_C3y5pg7EBU5XGrcLTduQEhGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQ2_DUbiXNlY3AyNTZrMaEDKnz_-ps3UUOfHWVYaskI5kWYO_vtYMGYCQRAR3gHDouDdGNwgiMog3VkcIIjKA",
|
|
||||||
// Prylab team's bootnodes
|
|
||||||
"enr:-Ku4QImhMc1z8yCiNJ1TyUxdcfNucje3BGwEHzodEZUan8PherEo4sF7pPHPSIB1NNuSg5fZy7qFsjmUKs2ea1Whi0EBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQOVphkDqal4QzPMksc5wnpuC3gvSC8AfbFOnZY_On34wIN1ZHCCIyg",
|
|
||||||
"enr:-Ku4QP2xDnEtUXIjzJ_DhlCRN9SN99RYQPJL92TMlSv7U5C1YnYLjwOQHgZIUXw6c-BvRg2Yc2QsZxxoS_pPRVe0yK8Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQMeFF5GrS7UZpAH2Ly84aLK-TyvH-dRo0JM1i8yygH50YN1ZHCCJxA",
|
|
||||||
"enr:-Ku4QPp9z1W4tAO8Ber_NQierYaOStqhDqQdOPY3bB3jDgkjcbk6YrEnVYIiCBbTxuar3CzS528d2iE7TdJsrL-dEKoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQMw5fqqkw2hHC4F5HZZDPsNmPdB1Gi8JPQK7pRc9XHh-oN1ZHCCKvg",
|
|
||||||
// Lighthouse team's bootnodes
|
|
||||||
"enr:-IS4QLkKqDMy_ExrpOEWa59NiClemOnor-krjp4qoeZwIw2QduPC-q7Kz4u1IOWf3DDbdxqQIgC4fejavBOuUPy-HE4BgmlkgnY0gmlwhCLzAHqJc2VjcDI1NmsxoQLQSJfEAHZApkm5edTCZ_4qps_1k_ub2CxHFxi-gr2JMIN1ZHCCIyg",
|
|
||||||
"enr:-IS4QDAyibHCzYZmIYZCjXwU9BqpotWmv2BsFlIq1V31BwDDMJPFEbox1ijT5c2Ou3kvieOKejxuaCqIcjxBjJ_3j_cBgmlkgnY0gmlwhAMaHiCJc2VjcDI1NmsxoQJIdpj_foZ02MXz4It8xKD7yUHTBx7lVFn3oeRP21KRV4N1ZHCCIyg",
|
|
||||||
// EF bootnodes
|
|
||||||
"enr:-Ku4QHqVeJ8PPICcWk1vSn_XcSkjOkNiTg6Fmii5j6vUQgvzMc9L1goFnLKgXqBJspJjIsB91LTOleFmyWWrFVATGngBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhAMRHkWJc2VjcDI1NmsxoQKLVXFOhp2uX6jeT0DvvDpPcU8FWMjQdR4wMuORMhpX24N1ZHCCIyg",
|
|
||||||
"enr:-Ku4QG-2_Md3sZIAUebGYT6g0SMskIml77l6yR-M_JXc-UdNHCmHQeOiMLbylPejyJsdAPsTHJyjJB2sYGDLe0dn8uYBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhBLY-NyJc2VjcDI1NmsxoQORcM6e19T1T9gi7jxEZjk_sjVLGFscUNqAY9obgZaxbIN1ZHCCIyg",
|
|
||||||
"enr:-Ku4QPn5eVhcoF1opaFEvg1b6JNFD2rqVkHQ8HApOKK61OIcIXD127bKWgAtbwI7pnxx6cDyk_nI88TrZKQaGMZj0q0Bh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDayLMaJc2VjcDI1NmsxoQK2sBOLGcUb4AwuYzFuAVCaNHA-dy24UuEKkeFNgCVCsIN1ZHCCIyg",
|
|
||||||
"enr:-Ku4QEWzdnVtXc2Q0ZVigfCGggOVB2Vc1ZCPEc6j21NIFLODSJbvNaef1g4PxhPwl_3kax86YPheFUSLXPRs98vvYsoBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpC1MD8qAAAAAP__________gmlkgnY0gmlwhDZBrP2Jc2VjcDI1NmsxoQM6jr8Rb1ktLEsVcKAPa08wCsKUmvoQ8khiOl_SLozf9IN1ZHCCIyg",
|
|
||||||
}
|
|
||||||
|
|
||||||
const dnsPrefix = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@"
|
const dnsPrefix = "enrtree://AKA3AM6LPBYEUDMVNU3BSVQJ5AD45Y7YPOHJLEF6W26QOE4VTUDPE@"
|
||||||
|
|
||||||
// KnownDNSNetwork returns the address of a public DNS-based node list for the given
|
// KnownDNSNetwork returns the address of a public DNS-based node list for the given
|
||||||
|
|
|
@ -1056,7 +1056,7 @@ func (w *Waku) Send(envelope *common.Envelope) error {
|
||||||
|
|
||||||
// Start implements node.Service, starting the background data propagation thread
|
// Start implements node.Service, starting the background data propagation thread
|
||||||
// of the Waku protocol.
|
// of the Waku protocol.
|
||||||
func (w *Waku) Start(*p2p.Server) error {
|
func (w *Waku) Start() error {
|
||||||
go w.update()
|
go w.update()
|
||||||
|
|
||||||
numCPU := runtime.NumCPU()
|
numCPU := runtime.NumCPU()
|
||||||
|
@ -1519,6 +1519,10 @@ func (w *Waku) GetEnvelope(hash gethcommon.Hash) *common.Envelope {
|
||||||
return w.envelopes[hash]
|
return w.envelopes[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *Waku) Version() uint {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
// isEnvelopeCached checks if envelope with specific hash has already been received and cached.
|
// isEnvelopeCached checks if envelope with specific hash has already been received and cached.
|
||||||
func (w *Waku) IsEnvelopeCached(hash gethcommon.Hash) bool {
|
func (w *Waku) IsEnvelopeCached(hash gethcommon.Hash) bool {
|
||||||
w.poolMu.Lock()
|
w.poolMu.Lock()
|
||||||
|
|
|
@ -548,7 +548,7 @@ func (w *Waku) Query(topics []types.TopicType, from uint64, to uint64, opts []st
|
||||||
|
|
||||||
// Start implements node.Service, starting the background data propagation thread
|
// Start implements node.Service, starting the background data propagation thread
|
||||||
// of the Waku protocol.
|
// of the Waku protocol.
|
||||||
func (w *Waku) Start(*p2p.Server) error {
|
func (w *Waku) Start() error {
|
||||||
numCPU := runtime.NumCPU()
|
numCPU := runtime.NumCPU()
|
||||||
for i := 0; i < numCPU; i++ {
|
for i := 0; i < numCPU; i++ {
|
||||||
go w.processQueue()
|
go w.processQueue()
|
||||||
|
|
Loading…
Reference in New Issue