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"
|
||||
"sync"
|
||||
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/google/uuid"
|
||||
|
||||
gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
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
|
||||
func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) {
|
||||
func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
address := crypto.PubkeyToAddress(privKey.PublicKey)
|
||||
id := uuid.NewRandom()
|
||||
id, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := &types.Key{
|
||||
ID: id,
|
||||
Address: address,
|
||||
|
@ -222,6 +226,7 @@ func (m *Manager) SetChatAccount(privKey *ecdsa.PrivateKey) {
|
|||
Address: address,
|
||||
AccountKey: key,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// MainAccountAddress returns currently selected watch addresses.
|
||||
|
|
|
@ -35,7 +35,6 @@ type StatusBackend interface {
|
|||
|
||||
CallPrivateRPC(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)
|
||||
HashTypedData(typed typeddata.TypedData) (types.Hash, error)
|
||||
HashTypedDataV4(typed signercore.TypedData) (types.Hash, error)
|
||||
|
|
|
@ -11,18 +11,13 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
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"
|
||||
gethnode "github.com/ethereum/go-ethereum/node"
|
||||
signercore "github.com/ethereum/go-ethereum/signer/core"
|
||||
|
||||
"github.com/status-im/status-go/account"
|
||||
"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/eth-node/crypto"
|
||||
"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/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"
|
||||
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/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/wakuext"
|
||||
"github.com/status-im/status-go/services/wallet"
|
||||
"github.com/status-im/status-go/signal"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
)
|
||||
|
@ -58,8 +42,6 @@ var (
|
|||
ErrWhisperClearIdentitiesFailure = errors.New("failed to clear whisper identities")
|
||||
// ErrWhisperIdentityInjectionFailure injecting whisper identities has failed.
|
||||
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 = errors.New("failed to inject identity into waku")
|
||||
// ErrUnsupportedRPCMethod is for methods not supported by the RPC interface
|
||||
|
@ -81,7 +63,6 @@ type GethStatusBackend struct {
|
|||
appDB *sql.DB
|
||||
statusNode *node.StatusNode
|
||||
personalAPI *personal.PublicAPI
|
||||
rpcFilters *rpcfilters.Service
|
||||
multiaccountsDB *multiaccounts.Database
|
||||
account *multiaccounts.Account
|
||||
accountManager *account.GethManager
|
||||
|
@ -91,6 +72,7 @@ type GethStatusBackend struct {
|
|||
selectedAccountKeyID string
|
||||
log log.Logger
|
||||
allowAllRPC bool // used only for tests, disables api method restrictions
|
||||
|
||||
}
|
||||
|
||||
// NewGethStatusBackend create a new GethStatusBackend instance
|
||||
|
@ -101,14 +83,12 @@ func NewGethStatusBackend() *GethStatusBackend {
|
|||
accountManager := account.NewGethManager()
|
||||
transactor := transactions.NewTransactor()
|
||||
personalAPI := personal.NewAPI()
|
||||
rpcFilters := rpcfilters.New(statusNode)
|
||||
|
||||
return &GethStatusBackend{
|
||||
statusNode: statusNode,
|
||||
accountManager: accountManager,
|
||||
transactor: transactor,
|
||||
personalAPI: personalAPI,
|
||||
rpcFilters: rpcFilters,
|
||||
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 {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
log.Info("STARTING NODE")
|
||||
if err := b.startNode(config); err != nil {
|
||||
signal.SendNodeCrashed(err)
|
||||
return err
|
||||
}
|
||||
log.Info("STARTED NODE")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -167,6 +149,7 @@ func (b *GethStatusBackend) OpenAccounts() error {
|
|||
return err
|
||||
}
|
||||
b.multiaccountsDB = db
|
||||
b.statusNode.SetMultiaccountsDB(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -251,6 +234,7 @@ func (b *GethStatusBackend) ensureAppDBOpened(account multiaccounts.Account, pas
|
|||
b.log.Error("failed to initialize db", "err", err)
|
||||
return err
|
||||
}
|
||||
b.statusNode.SetAppDB(b.appDB)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -503,14 +487,17 @@ func (b *GethStatusBackend) StartNodeWithAccountAndConfig(
|
|||
nodecfg *params.NodeConfig,
|
||||
subaccs []accounts.Account,
|
||||
) error {
|
||||
log.Info("STARTING 1 NODE")
|
||||
err := b.SaveAccount(account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("STARTING 2 NODE")
|
||||
err = b.ensureAppDBOpened(account, password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("STARTING 3 NODE")
|
||||
err = b.saveAccountsAndSettings(settings, nodecfg, subaccs)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -565,66 +552,6 @@ func (b *GethStatusBackend) GetNodeConfig() (*params.NodeConfig, error) {
|
|||
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) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
|
@ -644,26 +571,12 @@ func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
|
|||
if err := config.Validate(); err != nil {
|
||||
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()
|
||||
if manager == nil {
|
||||
return errors.New("ethereum accounts.Manager is nil")
|
||||
}
|
||||
if err = b.statusNode.StartWithOptions(config, node.StartOptions{
|
||||
Services: services,
|
||||
// The peers discovery protocols are started manually after
|
||||
// `node.ready` signal is sent.
|
||||
// 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 {
|
||||
return
|
||||
}
|
||||
if config.WalletConfig.Enabled {
|
||||
walletService, err := b.statusNode.WalletService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
walletService.SetClient(b.statusNode.RPCClient().Ethclient())
|
||||
}
|
||||
|
||||
signal.SendNodeStarted()
|
||||
|
||||
b.transactor.SetNetworkID(config.NetworkID)
|
||||
|
@ -691,14 +598,6 @@ func (b *GethStatusBackend) startNode(config *params.NodeConfig) (err error) {
|
|||
}
|
||||
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.
|
||||
// If there is no account selected, an error is returned.
|
||||
if _, err := b.accountManager.SelectedChatAccount(); err == nil {
|
||||
|
@ -796,7 +695,7 @@ func (b *GethStatusBackend) SendTransaction(sendArgs transactions.SendTxArgs, pa
|
|||
return
|
||||
}
|
||||
|
||||
go b.rpcFilters.TriggerTransactionSentToUpstreamEvent(hash)
|
||||
go b.statusNode.RPCFiltersService().TriggerTransactionSentToUpstreamEvent(hash)
|
||||
|
||||
return
|
||||
}
|
||||
|
@ -807,7 +706,7 @@ func (b *GethStatusBackend) SendTransactionWithSignature(sendArgs transactions.S
|
|||
return
|
||||
}
|
||||
|
||||
go b.rpcFilters.TriggerTransactionSentToUpstreamEvent(hash)
|
||||
go b.statusNode.RPCFiltersService().TriggerTransactionSentToUpstreamEvent(hash)
|
||||
|
||||
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.connectionState = state
|
||||
err := b.statusNode.ConnectionChanged(state)
|
||||
if err != nil {
|
||||
b.log.Error("failed to notify of connection changed", "err", err)
|
||||
}
|
||||
b.statusNode.ConnectionChanged(state)
|
||||
|
||||
// logic of handling state changes here
|
||||
// restart node? force peers reconnect? etc
|
||||
|
@ -990,54 +886,18 @@ func (b *GethStatusBackend) AppStateChange(state string) {
|
|||
}
|
||||
|
||||
func (b *GethStatusBackend) StopLocalNotifications() error {
|
||||
localPN, err := b.statusNode.LocalNotificationsService()
|
||||
if err != nil {
|
||||
b.log.Error("Retrieving of LocalNotifications service failed on StopLocalNotifications", "error", err)
|
||||
if b.statusNode == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if localPN.IsStarted() {
|
||||
err = localPN.Stop()
|
||||
if err != nil {
|
||||
b.log.Error("LocalNotifications service stop failed on StopLocalNotifications", "error", err)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return b.statusNode.StopLocalNotifications()
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) StartLocalNotifications() error {
|
||||
localPN, err := b.statusNode.LocalNotificationsService()
|
||||
|
||||
if err != nil {
|
||||
b.log.Error("Retrieving of local notifications service failed on StartLocalNotifications", "error", err)
|
||||
if b.statusNode == 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.
|
||||
|
@ -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.
|
||||
func (b *GethStatusBackend) cleanupServices() error {
|
||||
wakuService, err := b.statusNode.WakuService()
|
||||
switch err {
|
||||
case node.ErrServiceUnknown: // Waku was never registered
|
||||
case nil:
|
||||
if err := wakuService.DeleteKeyPairs(); err != nil {
|
||||
return fmt.Errorf("%s: %v", ErrWakuClearIdentitiesFailure, err)
|
||||
}
|
||||
b.selectedAccountKeyID = ""
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
if b.statusNode == nil {
|
||||
return nil
|
||||
}
|
||||
return b.statusNode.Cleanup()
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) closeAppDB() error {
|
||||
|
@ -1135,9 +972,6 @@ func (b *GethStatusBackend) GetActiveAccount() (*multiaccounts.Account, error) {
|
|||
|
||||
return b.account, nil
|
||||
}
|
||||
func (b *GethStatusBackend) WakuExtService() (*wakuext.Service, error) {
|
||||
return b.statusNode.WakuExtService()
|
||||
}
|
||||
|
||||
func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
||||
chatAccount, err := b.accountManager.SelectedChatAccount()
|
||||
|
@ -1152,11 +986,9 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
|||
return err
|
||||
}
|
||||
|
||||
wakuService, err := b.statusNode.WakuService()
|
||||
wakuService := b.statusNode.WakuService()
|
||||
|
||||
switch err {
|
||||
case node.ErrServiceUnknown: // Waku was never registered
|
||||
case nil:
|
||||
if wakuService != nil {
|
||||
if err := wakuService.DeleteKeyPairs(); err != nil { // err is not possible; method return value is incorrect
|
||||
return err
|
||||
}
|
||||
|
@ -1164,29 +996,21 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
|||
if err != nil {
|
||||
return ErrWakuIdentityInjectionFailure
|
||||
}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
if wakuService != nil {
|
||||
st, err := b.statusNode.WakuExtService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st := b.statusNode.WakuExtService()
|
||||
|
||||
if st != nil {
|
||||
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()
|
||||
}
|
||||
|
||||
switch err {
|
||||
case node.ErrServiceUnknown: // WakuV2 was never registered
|
||||
case nil:
|
||||
wakuV2Service := b.statusNode.WakuV2Service()
|
||||
|
||||
if wakuV2Service != nil {
|
||||
if err := wakuV2Service.DeleteKeyPairs(); err != nil { // err is not possible; method return value is incorrect
|
||||
return err
|
||||
}
|
||||
|
@ -1194,15 +1018,7 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
|||
if err != nil {
|
||||
return ErrWakuIdentityInjectionFailure
|
||||
}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
if wakuV2Service != nil {
|
||||
st, err := b.statusNode.WakuV2ExtService()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
st := b.statusNode.WakuV2ExtService()
|
||||
|
||||
if err := st.InitProtocol(identity, b.appDB, b.multiaccountsDB, acc, logutils.ZapLogger()); err != nil {
|
||||
return err
|
||||
|
@ -1212,13 +1028,6 @@ func (b *GethStatusBackend) injectAccountsIntoServices() error {
|
|||
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
|
||||
func (b *GethStatusBackend) ExtractGroupMembershipSignatures(signaturePairs [][2]string) ([]string, error) {
|
||||
return crypto.ExtractSignatures(signaturePairs)
|
||||
|
|
|
@ -140,13 +140,13 @@ func main() {
|
|||
backend := api.NewGethStatusBackend()
|
||||
err = ImportAccount(*seedPhrase, backend)
|
||||
if err != nil {
|
||||
logger.Error("failed", "err", err)
|
||||
logger.Error("failed import account", "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
wakuextservice, err := backend.WakuExtService()
|
||||
if err != nil {
|
||||
logger.Error("failed", "err", err)
|
||||
wakuextservice := backend.StatusNode().WakuExtService()
|
||||
if wakuextservice == nil {
|
||||
logger.Error("wakuext not available")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -165,14 +165,14 @@ func main() {
|
|||
for i := 0; i < *nAddedContacts; i++ {
|
||||
key, err := crypto.GenerateKey()
|
||||
if err != nil {
|
||||
logger.Error("failed", err)
|
||||
logger.Error("failed generate key", err)
|
||||
return
|
||||
}
|
||||
|
||||
keyString := common.PubkeyToHex(&key.PublicKey)
|
||||
_, err = wakuext.AddContact(context.Background(), keyString)
|
||||
if err != nil {
|
||||
logger.Error("failed", "err", err)
|
||||
logger.Error("failed Add contact", "err", err)
|
||||
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")
|
||||
err := backend.OpenAccounts()
|
||||
if err != nil {
|
||||
logger.Error("failed open accounts", err)
|
||||
return err
|
||||
}
|
||||
generator := manager.AccountsGenerator()
|
||||
generatedAccountInfo, err := generator.ImportMnemonic(seedPhrase, "")
|
||||
if err != nil {
|
||||
logger.Error("import mnemonic", err)
|
||||
return err
|
||||
}
|
||||
|
||||
derivedAddresses, err := generator.DeriveAddresses(generatedAccountInfo.ID, paths)
|
||||
if err != nil {
|
||||
logger.Error("deriver addressess", err)
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = generator.StoreDerivedAccounts(generatedAccountInfo.ID, "", paths)
|
||||
if err != nil {
|
||||
logger.Error("store addressess", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -450,11 +459,13 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
|||
}
|
||||
settings, err := defaultSettings(generatedAccountInfo, derivedAddresses, &seedPhrase)
|
||||
if err != nil {
|
||||
logger.Error("default settings", err)
|
||||
return err
|
||||
}
|
||||
|
||||
nodeConfig, err := defaultNodeConfig(settings.InstallationID)
|
||||
if err != nil {
|
||||
logger.Error("node config", err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -477,8 +488,15 @@ func ImportAccount(seedPhrase string, backend *api.GethStatusBackend) error {
|
|||
Path: pathDefaultChat,
|
||||
}
|
||||
|
||||
fmt.Println(nodeConfig)
|
||||
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")
|
||||
|
@ -486,7 +504,7 @@ var letterRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
|
|||
func buildMessage(chat *protocol.Chat, count int) *common.Message {
|
||||
key, err := crypto.GenerateKey()
|
||||
if err != nil {
|
||||
logger.Error("failed", err)
|
||||
logger.Error("failed build message", err)
|
||||
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 (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/status-im/status-go/node"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
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")
|
||||
|
||||
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.
|
||||
|
@ -182,20 +180,6 @@ func main() {
|
|||
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.NodeKey == "" {
|
||||
logger.Error("node key needs to be set if running a push notification server")
|
||||
|
@ -227,7 +211,7 @@ func main() {
|
|||
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 {
|
||||
logger.Error("failed to create messenger", "error", err)
|
||||
return
|
||||
|
|
|
@ -3,8 +3,6 @@ package main
|
|||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/status-im/status-go/node"
|
||||
)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
stack *node.Node
|
||||
waku1 *waku.Waku
|
||||
waku2 *wakuv2.Waku
|
||||
}
|
||||
|
||||
func NewNodeBridge(stack *node.Node) types.Node {
|
||||
return &gethNodeWrapper{stack: stack}
|
||||
func NewNodeBridge(stack *node.Node, waku1 *waku.Waku, waku2 *wakuv2.Waku) types.Node {
|
||||
return &gethNodeWrapper{stack: stack, waku1: waku1, waku2: waku2}
|
||||
}
|
||||
|
||||
func (w *gethNodeWrapper) Poll() {
|
||||
|
@ -32,50 +34,28 @@ func (w *gethNodeWrapper) NewENSVerifier(logger *zap.Logger) enstypes.ENSVerifie
|
|||
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) {
|
||||
var nativeWaku *waku.Waku
|
||||
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 {
|
||||
if w.waku1 == nil {
|
||||
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) {
|
||||
var nativeWaku *wakuv2.Waku
|
||||
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 {
|
||||
if w.waku2 == nil {
|
||||
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 {
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
|
||||
|
@ -107,8 +107,13 @@ func DecryptKey(keyjson []byte, auth string) (*types.Key, error) {
|
|||
}
|
||||
key := crypto.ToECDSAUnsafe(keyBytes)
|
||||
|
||||
id, err := uuid.FromBytes(keyId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &types.Key{
|
||||
ID: uuid.UUID(keyId),
|
||||
ID: id,
|
||||
Address: crypto.PubkeyToAddress(key.PublicKey),
|
||||
PrivateKey: key,
|
||||
ExtendedKey: extKey,
|
||||
|
@ -156,7 +161,11 @@ func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byt
|
|||
if keyProtected.Version != 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)
|
||||
if err != nil {
|
||||
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) {
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
@ -329,8 +343,7 @@ func pkcs7Unpad(in []byte) []byte {
|
|||
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
|
||||
if e := json.Unmarshal(rawKeyFile, &keyJSON); e != nil {
|
||||
return cj, fmt.Errorf("failed to read key file: %s", e)
|
||||
|
|
|
@ -3,7 +3,7 @@ package types
|
|||
import (
|
||||
"crypto/ecdsa"
|
||||
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/status-im/status-go/extkeys"
|
||||
)
|
||||
|
|
|
@ -516,27 +516,6 @@ func makeJSONResponse(err error) string {
|
|||
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.
|
||||
func AddPeer(enode string) string {
|
||||
err := statusBackend.StatusNode().AddPeer(enode)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package node
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
|
@ -16,27 +16,36 @@ import (
|
|||
"github.com/syndtr/goleveldb/leveldb"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/les"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"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/db"
|
||||
"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/peers"
|
||||
"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/nodebridge"
|
||||
"github.com/status-im/status-go/services/peer"
|
||||
"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/wakuv2ext"
|
||||
"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/wakuv2"
|
||||
)
|
||||
|
@ -59,6 +68,9 @@ var (
|
|||
type StatusNode struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
appDB *sql.DB
|
||||
multiaccountsDB *multiaccounts.Database
|
||||
|
||||
config *params.NodeConfig // Status node configuration
|
||||
gethNode *node.Node // reference to Geth P2P stack/node
|
||||
rpcClient *rpc.Client // reference to public RPC client
|
||||
|
@ -70,11 +82,36 @@ type StatusNode struct {
|
|||
db *leveldb.DB // used as a cache for PeerPool
|
||||
|
||||
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.
|
||||
func New() *StatusNode {
|
||||
return &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.
|
||||
// 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{
|
||||
Services: services,
|
||||
StartDiscovery: true,
|
||||
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.
|
||||
type StartOptions struct {
|
||||
Services []node.ServiceConstructor
|
||||
StartDiscovery bool
|
||||
AccountsManager *accounts.Manager
|
||||
}
|
||||
|
@ -135,6 +171,8 @@ func (n *StatusNode) StartWithOptions(config *params.NodeConfig, options StartOp
|
|||
return ErrNodeRunning
|
||||
}
|
||||
|
||||
n.accountsManager = options.AccountsManager
|
||||
|
||||
n.log.Debug("starting with options", "ClusterConfig", config.ClusterConfig)
|
||||
|
||||
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.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
|
||||
if err == nil && options.StartDiscovery && n.discoveryEnabled() {
|
||||
err = n.startDiscovery()
|
||||
|
@ -162,21 +202,22 @@ func (n *StatusNode) StartWithOptions(config *params.NodeConfig, options StartOp
|
|||
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 {
|
||||
return err
|
||||
}
|
||||
n.config = config
|
||||
n.log.Info("starting geth node")
|
||||
|
||||
if err := n.startGethNode(services); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.log.Info("setting up rpc client")
|
||||
if err := n.setupRPCClient(); err != nil {
|
||||
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) {
|
||||
|
@ -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.
|
||||
func (n *StatusNode) startGethNode(services []node.ServiceConstructor) error {
|
||||
for _, service := range services {
|
||||
if err := n.gethNode.Register(service); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StatusNode) startGethNode() error {
|
||||
return n.gethNode.Start()
|
||||
}
|
||||
|
||||
func (n *StatusNode) setupRPCClient() (err error) {
|
||||
// setup public RPC client
|
||||
gethNodeClient, err := n.gethNode.AttachPublic()
|
||||
gethNodeClient, err := n.gethNode.Attach()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -315,8 +350,6 @@ func (n *StatusNode) startDiscovery() error {
|
|||
options.AllowStop = len(n.config.RegisterTopics) == 0
|
||||
options.TrustedMailServers = parseNodesToNodeID(n.config.ClusterConfig.TrustedMailServers)
|
||||
|
||||
options.MailServerRegistryAddress = n.config.MailServerRegistryAddress
|
||||
|
||||
n.peerPool = peers.NewPeerPool(
|
||||
n.discovery,
|
||||
n.config.RequireTopics,
|
||||
|
@ -355,7 +388,7 @@ func (n *StatusNode) stop() error {
|
|||
n.discovery = nil
|
||||
}
|
||||
|
||||
if err := n.gethNode.Stop(); err != nil {
|
||||
if err := n.gethNode.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -520,163 +553,12 @@ func (n *StatusNode) PeerCount() int {
|
|||
return n.gethNode.Server().PeerCount()
|
||||
}
|
||||
|
||||
// gethService is a wrapper for gethNode.Service which retrieves a currently
|
||||
// running service registered of a specific type.
|
||||
func (n *StatusNode) gethService(serviceInstance interface{}) error {
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
if err := n.gethNode.Service(serviceInstance); err != nil {
|
||||
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
|
||||
}
|
||||
|
||||
func (n *StatusNode) ConnectionChanged(state connection.State) {
|
||||
if n.wakuExtSrvc == nil {
|
||||
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
|
||||
n.wakuExtSrvc.ConnectionChanged(state)
|
||||
}
|
||||
|
||||
// AccountManager exposes reference to node's accounts manager
|
||||
|
@ -735,67 +617,6 @@ func (n *StatusNode) ChaosModeCheckRPCClientsUpstreamURL(on bool) error {
|
|||
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.
|
||||
func (n *StatusNode) Discover(topic string, max, min int) (err error) {
|
||||
if n.peerPool == nil {
|
||||
|
@ -806,3 +627,11 @@ func (n *StatusNode) Discover(topic string, max, min int) (err error) {
|
|||
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"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
logging "github.com/ipfs/go-log"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"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/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
|
@ -24,22 +18,9 @@ import (
|
|||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"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/logutils"
|
||||
"github.com/status-im/status-go/mailserver"
|
||||
"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/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.
|
||||
|
@ -83,77 +64,9 @@ func MakeNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB)
|
|||
return nil, fmt.Errorf(ErrNodeMakeFailureFormat, err.Error())
|
||||
}
|
||||
|
||||
err = activateServices(stack, config, accs, db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
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
|
||||
func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
|
||||
nc := &node.Config{
|
||||
|
@ -167,8 +80,9 @@ func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
|
|||
NoDiscovery: true, // we always use only v5 server
|
||||
ListenAddr: config.ListenAddr,
|
||||
NAT: nat.Any(),
|
||||
MaxPeers: config.MaxPeers,
|
||||
MaxPendingPeers: config.MaxPendingPeers,
|
||||
// FIX ME: don't hardcode
|
||||
MaxPeers: 200,
|
||||
MaxPendingPeers: 200,
|
||||
},
|
||||
HTTPModules: config.FormatAPIModules(),
|
||||
}
|
||||
|
@ -214,7 +128,7 @@ func calculateGenesis(networkID uint64) (*core.Genesis, error) {
|
|||
case params.MainNetworkID:
|
||||
genesis = core.DefaultGenesisBlock()
|
||||
case params.RopstenNetworkID:
|
||||
genesis = core.DefaultTestnetGenesisBlock()
|
||||
genesis = core.DefaultRopstenGenesisBlock()
|
||||
case params.RinkebyNetworkID:
|
||||
genesis = core.DefaultRinkebyGenesisBlock()
|
||||
case params.GoerliNetworkID:
|
||||
|
@ -246,191 +160,6 @@ func defaultStatusChainGenesisBlock() (*core.Genesis, error) {
|
|||
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.
|
||||
func parseNodes(enodes []string) []*enode.Node {
|
||||
var nodes []*enode.Node
|
||||
|
@ -469,6 +198,7 @@ func parseNodesToNodeID(enodes []string) []enode.ID {
|
|||
return nodeIDs
|
||||
}
|
||||
|
||||
/*
|
||||
// timeSource get timeSource to be used by whisper
|
||||
func timeSource(ctx *node.ServiceContext) (func() time.Time, error) {
|
||||
var timeSource *timesource.NTPTimeSource
|
||||
|
@ -476,33 +206,4 @@ func timeSource(ctx *node.ServiceContext) (func() time.Time, error) {
|
|||
return nil, err
|
||||
}
|
||||
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/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/types"
|
||||
"github.com/status-im/status-go/protocol/pushnotificationserver"
|
||||
"github.com/status-im/status-go/static"
|
||||
wakucommon "github.com/status-im/status-go/waku/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
|
||||
// ----------
|
||||
|
@ -412,6 +434,9 @@ type NodeConfig struct {
|
|||
// ClusterConfig extra configuration for supporting cluster peers.
|
||||
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 WakuConfig `json:"WakuConfig" validate:"structonly"`
|
||||
|
||||
|
@ -705,6 +730,9 @@ func (c *NodeConfig) updatePeerLimits() {
|
|||
if c.NoDiscovery && !c.Rendezvous {
|
||||
return
|
||||
}
|
||||
if c.LightEthConfig.Enabled {
|
||||
c.RequireTopics[discv5.Topic(LesTopic(int(c.NetworkID)))] = LesDiscoveryLimits
|
||||
}
|
||||
}
|
||||
|
||||
// NewNodeConfig creates new node configuration object with bare-minimum defaults.
|
||||
|
@ -739,6 +767,9 @@ func NewNodeConfig(dataDir string, networkID uint64) (*NodeConfig, error) {
|
|||
UpstreamConfig: UpstreamRPCConfig{
|
||||
URL: getUpstreamURL(networkID),
|
||||
},
|
||||
LightEthConfig: LightEthConfig{
|
||||
DatabaseCache: 16,
|
||||
},
|
||||
WakuConfig: WakuConfig{
|
||||
DataDir: wakuDir,
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
@ -889,6 +924,9 @@ func (c *NodeConfig) validateChildStructs(validate *validator.Validate) error {
|
|||
if err := c.ClusterConfig.Validate(validate); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.LightEthConfig.Validate(validate); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.SwarmConfig.Validate(validate); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -928,6 +966,19 @@ func (c *ClusterConfig) Validate(validate *validator.Validate) error {
|
|||
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
|
||||
func (c *SwarmConfig) Validate(validate *validator.Validate) error {
|
||||
if !c.Enabled {
|
||||
|
@ -995,3 +1046,18 @@ func (c *NodeConfig) FormatAPIModules() []string {
|
|||
func (c *NodeConfig) AddAPIModule(m string) {
|
||||
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{
|
||||
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()
|
||||
s.Require().NoError(err)
|
||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||
|
@ -177,7 +177,7 @@ func TestPeerPoolMaxPeersOverflow(t *testing.T) {
|
|||
defer func() { assert.NoError(t, discovery.Stop()) }()
|
||||
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)
|
||||
require.NoError(t, pool.Start(peer, nil))
|
||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||
|
@ -230,7 +230,7 @@ func TestPeerPoolDiscV5Timeout(t *testing.T) {
|
|||
require.True(t, discovery.Running())
|
||||
|
||||
// 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)
|
||||
require.NoError(t, pool.Start(server, nil))
|
||||
require.Equal(t, signal.EventDiscoveryStarted, <-signals)
|
||||
|
@ -277,7 +277,7 @@ func TestPeerPoolNotAllowedStopping(t *testing.T) {
|
|||
require.True(t, discovery.Running())
|
||||
|
||||
// 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)
|
||||
require.NoError(t, pool.Start(server, nil))
|
||||
|
||||
|
@ -294,7 +294,7 @@ func (s *PeerPoolSimulationSuite) TestUpdateTopicLimits() {
|
|||
config := map[discv5.Topic]params.Limits{
|
||||
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()
|
||||
s.Require().NoError(err)
|
||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||
|
@ -373,7 +373,6 @@ func (s *PeerPoolSimulationSuite) TestMailServerPeersDiscovery() {
|
|||
true,
|
||||
100 * time.Millisecond,
|
||||
[]enode.ID{s.peers[0].Self().ID()},
|
||||
"",
|
||||
}
|
||||
peerPool := NewPeerPool(s.discovery[1], config, cache, peerPoolOpts)
|
||||
s.Require().NoError(peerPool.Start(s.peers[1], nil))
|
||||
|
|
|
@ -206,8 +206,7 @@ func NewMessenger(
|
|||
// Initialize transport layer.
|
||||
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 {
|
||||
transp, err = transport.NewTransport(
|
||||
waku,
|
||||
|
|
|
@ -24,7 +24,7 @@ type Service struct {
|
|||
}
|
||||
|
||||
// Start a service.
|
||||
func (s *Service) Start(*p2p.Server) error {
|
||||
func (s *Service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ type Service struct {
|
|||
db *appmetrics.Database
|
||||
}
|
||||
|
||||
func (s *Service) Start(*p2p.Server) error {
|
||||
func (s *Service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ type Service struct {
|
|||
}
|
||||
|
||||
// Start a service.
|
||||
func (s *Service) Start(*p2p.Server) error {
|
||||
func (s *Service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ type Service struct {
|
|||
}
|
||||
|
||||
// Make sure that Service implements node.Service interface.
|
||||
var _ node.Service = (*Service)(nil)
|
||||
var _ node.Lifecycle = (*Service)(nil)
|
||||
|
||||
func New(
|
||||
config params.ShhextConfig,
|
||||
|
@ -209,7 +209,7 @@ func (c *verifyTransactionClient) TransactionByHash(ctx context.Context, hash ty
|
|||
return coretypes.Message{}, coretypes.TransactionStatusPending, err
|
||||
}
|
||||
|
||||
message, err := transaction.AsMessage(signer)
|
||||
message, err := transaction.AsMessage(signer, nil)
|
||||
if err != nil {
|
||||
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")
|
||||
}
|
||||
|
||||
func (s *Service) SetP2PServer(server *p2p.Server) {
|
||||
s.server = server
|
||||
}
|
||||
|
||||
// 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 {
|
||||
s.server = server
|
||||
func (s *Service) Start() error {
|
||||
// TODO: set server before start
|
||||
// s.server = server
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ func pushMessage(notification *Notification) {
|
|||
}
|
||||
|
||||
// Start Worker which processes all incoming messages
|
||||
func (s *Service) Start(_ *p2p.Server) error {
|
||||
func (s *Service) Start() error {
|
||||
s.started = true
|
||||
|
||||
s.transmitter.quit = make(chan struct{})
|
||||
|
|
|
@ -13,7 +13,7 @@ type Service struct {
|
|||
db *Database
|
||||
}
|
||||
|
||||
func (s *Service) Start(*p2p.Server) error {
|
||||
func (s *Service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ type Service struct {
|
|||
}
|
||||
|
||||
// Start a service.
|
||||
func (s *Service) Start(*p2p.Server) error {
|
||||
func (s *Service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
)
|
||||
|
||||
// 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.
|
||||
type Service struct {
|
||||
|
@ -40,7 +40,7 @@ func (s *Service) APIs() []rpc.API {
|
|||
|
||||
// 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 {
|
||||
func (s *Service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ func (s *Service) Protocols() []p2p.Protocol {
|
|||
|
||||
// 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 {
|
||||
func (s *Service) Start() error {
|
||||
resetStats()
|
||||
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
|
||||
}
|
||||
|
||||
func New(config params.ShhextConfig, n types.Node, ctx interface{}, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
||||
w, err := n.GetWaku(ctx)
|
||||
func New(config params.ShhextConfig, n types.Node, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
||||
w, err := n.GetWaku(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -15,8 +15,8 @@ type Service struct {
|
|||
w types.Waku
|
||||
}
|
||||
|
||||
func New(config params.ShhextConfig, n types.Node, ctx interface{}, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
||||
w, err := n.GetWakuV2(ctx)
|
||||
func New(config params.ShhextConfig, n types.Node, handler ext.EnvelopeEventsHandler, ldb *leveldb.DB) *Service {
|
||||
w, err := n.GetWakuV2(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ type Service struct {
|
|||
}
|
||||
|
||||
// Start signals transmitter.
|
||||
func (s *Service) Start(*p2p.Server) error {
|
||||
func (s *Service) Start() error {
|
||||
s.group = NewGroup(context.Background())
|
||||
return s.signals.Start()
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ func (s *NTPTimeSource) StartService() error {
|
|||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
|
|
@ -43,9 +43,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"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/rlp"
|
||||
"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 {
|
||||
return nil
|
||||
}
|
||||
reqsEnc, _ := rlp.EncodeToBytes(&reqs)
|
||||
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
|
||||
// service, as advertised in the ENR record
|
||||
func (s *LightEthereum) vfxVersion(n *enode.Node) uint {
|
||||
if n.Seq() == 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
|
||||
|
|
|
@ -54,11 +54,6 @@ func (eth *LightEthereum) setupDiscovery() (enode.Iterator, error) {
|
|||
it.AddSource(dns)
|
||||
}
|
||||
|
||||
// Enable DHT.
|
||||
if eth.udpEnabled {
|
||||
it.AddSource(eth.p2pServer.DiscV5.RandomNodes())
|
||||
}
|
||||
|
||||
forkFilter := forkid.NewFilter(eth.blockchain)
|
||||
iterator := enode.Filter(it, func(n *enode.Node) bool { return nodeIsServer(forkFilter, n) })
|
||||
return iterator, nil
|
||||
|
|
|
@ -201,9 +201,10 @@ func (s *LesServer) Start() error {
|
|||
s.handler.start()
|
||||
s.wg.Add(1)
|
||||
go s.capacityManagement()
|
||||
/*
|
||||
if s.p2pSrv.DiscV5 != nil {
|
||||
s.p2pSrv.DiscV5.RegisterTalkHandler("vfx", s.vfluxServer.ServeEncoded)
|
||||
}
|
||||
}*/
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -206,6 +206,7 @@ func (d *dialScheduler) removeStatic(n *enode.Node) {
|
|||
|
||||
// peerAdded updates the peer set.
|
||||
func (d *dialScheduler) peerAdded(c *conn) {
|
||||
log.Info("PEER added")
|
||||
select {
|
||||
case d.addPeerCh <- c:
|
||||
case <-d.ctx.Done():
|
||||
|
@ -214,6 +215,7 @@ func (d *dialScheduler) peerAdded(c *conn) {
|
|||
|
||||
// peerRemoved updates the peer set.
|
||||
func (d *dialScheduler) peerRemoved(c *conn) {
|
||||
log.Info("PEER removed")
|
||||
select {
|
||||
case d.remPeerCh <- c:
|
||||
case <-d.ctx.Done():
|
||||
|
@ -243,7 +245,7 @@ loop:
|
|||
select {
|
||||
case node := <-nodesCh:
|
||||
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 {
|
||||
d.startDial(newDialTask(node, dynDialedConn))
|
||||
}
|
||||
|
@ -277,14 +279,22 @@ loop:
|
|||
case node := <-d.addStaticCh:
|
||||
id := node.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 {
|
||||
d.log.Info("existing, continue")
|
||||
continue loop
|
||||
}
|
||||
task := newDialTask(node, staticDialedConn)
|
||||
d.log.Info("new dial 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)
|
||||
} else {
|
||||
d.log.Info("error", "err", err)
|
||||
}
|
||||
|
||||
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
|
||||
// when peers are connected while their task is still running.
|
||||
func (d *dialScheduler) freeDialSlots() int {
|
||||
log.Info("checkign slots", "max dials", d.maxDialPeers, "dial peers", d.dialPeers)
|
||||
slots := (d.maxDialPeers - d.dialPeers) * 2
|
||||
if slots > d.maxActiveDials {
|
||||
slots = d.maxActiveDials
|
||||
|
@ -412,7 +423,9 @@ func (d *dialScheduler) checkDial(n *enode.Node) error {
|
|||
|
||||
// startStaticDials starts n static dial tasks.
|
||||
func (d *dialScheduler) startStaticDials(n int) (started int) {
|
||||
log.Info("starting", "n", n)
|
||||
for started = 0; started < n && len(d.staticPool) > 0; started++ {
|
||||
log.Info("starting static")
|
||||
idx := d.rand.Intn(len(d.staticPool))
|
||||
task := d.staticPool[idx]
|
||||
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.
|
|
@ -62,7 +62,6 @@ var (
|
|||
nodeDBDiscoverPing = nodeDBDiscoverRoot + ":lastping"
|
||||
nodeDBDiscoverPong = nodeDBDiscoverRoot + ":lastpong"
|
||||
nodeDBDiscoverFindFails = nodeDBDiscoverRoot + ":findfail"
|
||||
nodeDBDiscoverLocalEndpoint = nodeDBDiscoverRoot + ":localendpoint"
|
||||
nodeDBTopicRegTickets = ":tickets"
|
||||
)
|
||||
|
||||
|
@ -311,20 +310,6 @@ func (db *nodeDB) updateFindFails(id NodeID, fails int) error {
|
|||
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
|
||||
// for bootstrapping.
|
||||
func (db *nodeDB) querySeeds(n int, maxAge time.Duration) []*Node {
|
||||
|
|
|
@ -77,14 +77,6 @@ type Network struct {
|
|||
nursery []*Node
|
||||
nodes map[NodeID]*Node // tracks active nodes with state != known
|
||||
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.
|
||||
|
@ -107,7 +99,6 @@ type findnodeQuery struct {
|
|||
remote *Node
|
||||
target common.Hash
|
||||
reply chan<- []*Node
|
||||
nresults int // counter for received nodes
|
||||
}
|
||||
|
||||
type topicRegisterReq struct {
|
||||
|
@ -366,6 +357,8 @@ func (net *Network) loop() {
|
|||
bucketRefreshTimer = time.NewTimer(bucketRefreshInterval)
|
||||
refreshDone chan struct{} // closed when the 'refresh' lookup has ended
|
||||
)
|
||||
defer refreshTimer.Stop()
|
||||
defer bucketRefreshTimer.Stop()
|
||||
|
||||
// Tracking the next ticket to register.
|
||||
var (
|
||||
|
@ -402,11 +395,13 @@ func (net *Network) loop() {
|
|||
searchInfo = make(map[Topic]topicSearchInfo)
|
||||
activeSearchCount int
|
||||
)
|
||||
defer topicRegisterLookupTick.Stop()
|
||||
topicSearchLookupDone := make(chan topicSearchResult, 100)
|
||||
topicSearch := make(chan Topic, 100)
|
||||
<-topicRegisterLookupTick.C
|
||||
|
||||
statsDump := time.NewTicker(10 * time.Second)
|
||||
defer statsDump.Stop()
|
||||
|
||||
loop:
|
||||
for {
|
||||
|
@ -646,14 +641,14 @@ loop:
|
|||
}
|
||||
log.Trace("loop stopped")
|
||||
|
||||
log.Debug(fmt.Sprintf("shutting down"))
|
||||
log.Debug("shutting down")
|
||||
if net.conn != nil {
|
||||
net.conn.Close()
|
||||
}
|
||||
if refreshDone != nil {
|
||||
// TODO: wait for pending refresh.
|
||||
//<-refreshResults
|
||||
}
|
||||
// if refreshDone != nil {
|
||||
// <-refreshResults
|
||||
// }
|
||||
// Cancel all pending timeouts.
|
||||
for _, timer := range net.timeoutTimers {
|
||||
timer.Stop()
|
||||
|
@ -1042,6 +1037,9 @@ func (net *Network) handle(n *Node, ev nodeEvent, pkt *ingressPacket) error {
|
|||
net.db.ensureExpirer()
|
||||
}
|
||||
}
|
||||
if ev == pongTimeout {
|
||||
n.pingEcho = nil // clean up if pongtimeout
|
||||
}
|
||||
if n.state == nil {
|
||||
n.state = unknown //???
|
||||
}
|
||||
|
|
|
@ -66,23 +66,6 @@ func (n *Node) addr() *net.UDPAddr {
|
|||
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.
|
||||
func (n *Node) Incomplete() bool {
|
||||
return n.IP == nil
|
||||
|
@ -326,14 +309,6 @@ func (n NodeID) Pubkey() (*ecdsa.PublicKey, error) {
|
|||
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
|
||||
// given hash from the signature.
|
||||
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
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Package discv5 implements the RLPx v5 Topic Discovery Protocol.
|
||||
//
|
||||
// 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 is a prototype implementation of Discvery v5.
|
||||
// Deprecated: do not use this package.
|
||||
package discv5
|
||||
|
||||
import (
|
||||
|
|
|
@ -22,7 +22,6 @@ import (
|
|||
"fmt"
|
||||
"math"
|
||||
"math/rand"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
@ -33,8 +32,6 @@ import (
|
|||
|
||||
const (
|
||||
ticketTimeBucketLen = time.Minute
|
||||
timeWindow = 10 // * ticketTimeBucketLen
|
||||
wantTicketsInWindow = 10
|
||||
collectFrequency = time.Second * 30
|
||||
registerFrequency = time.Second * 60
|
||||
maxCollectDebt = 10
|
||||
|
@ -139,7 +136,6 @@ type ticketStore struct {
|
|||
|
||||
lastBucketFetched timeBucket
|
||||
nextTicketCached *ticketRef
|
||||
nextTicketReg mclock.AbsTime
|
||||
|
||||
searchTopicMap map[Topic]searchTopic
|
||||
nextTopicQueryCleanup mclock.AbsTime
|
||||
|
@ -268,57 +264,6 @@ func (s *ticketStore) nextSearchLookup(topic Topic) lookupInfo {
|
|||
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) {
|
||||
topic := r.t.topics[r.idx]
|
||||
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 {
|
||||
qq := s.queriesSent[node]
|
||||
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 {
|
||||
if a < 0 {
|
||||
a = 0
|
||||
|
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"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/rlp"
|
||||
)
|
||||
|
@ -38,15 +37,12 @@ const Version = 4
|
|||
var (
|
||||
errPacketTooSmall = errors.New("too small")
|
||||
errBadPrefix = errors.New("bad prefix")
|
||||
errTimeout = errors.New("RPC timeout")
|
||||
)
|
||||
|
||||
// Timeouts
|
||||
const (
|
||||
respTimeout = 500 * time.Millisecond
|
||||
expiration = 20 * time.Second
|
||||
|
||||
driftThreshold = 10 * time.Second // Allowed clock drift before warning user
|
||||
)
|
||||
|
||||
// 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}
|
||||
}
|
||||
|
||||
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) {
|
||||
if err := netutil.CheckRelayIP(sender.IP, rn.IP); err != nil {
|
||||
return nil, err
|
||||
|
@ -225,7 +217,6 @@ type udp struct {
|
|||
conn conn
|
||||
priv *ecdsa.PrivateKey
|
||||
ourEndpoint rpcEndpoint
|
||||
nat nat.Interface
|
||||
net *Network
|
||||
}
|
||||
|
||||
|
@ -274,13 +265,6 @@ func (t *udp) sendPing(remote *Node, toaddr *net.UDPAddr, topics []Topic) (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) {
|
||||
// Send neighbors in chunks with at most maxNeighbors per packet
|
||||
// to stay below the 1280 byte limit.
|
||||
|
|
|
@ -35,6 +35,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"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/enr"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
|
@ -104,7 +105,7 @@ type Config struct {
|
|||
// BootstrapNodesV5 are used to establish connectivity
|
||||
// with the rest of the network using the V5 discovery
|
||||
// protocol.
|
||||
BootstrapNodesV5 []*enode.Node `toml:",omitempty"`
|
||||
BootstrapNodesV5 []*discv5.Node `toml:",omitempty"`
|
||||
|
||||
// Static nodes are used as pre-configured connections which are always
|
||||
// maintained and re-connected on disconnects.
|
||||
|
@ -181,7 +182,7 @@ type Server struct {
|
|||
nodedb *enode.DB
|
||||
localnode *enode.LocalNode
|
||||
ntab *discover.UDPv4
|
||||
DiscV5 *discover.UDPv5
|
||||
DiscV5 *discv5.Network
|
||||
discmix *enode.FairMix
|
||||
dialsched *dialScheduler
|
||||
|
||||
|
@ -442,7 +443,7 @@ type sharedUDPConn struct {
|
|||
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) {
|
||||
packet, ok := <-s.unhandled
|
||||
if !ok {
|
||||
|
@ -456,7 +457,7 @@ func (s *sharedUDPConn) ReadFromUDP(b []byte) (n int, addr *net.UDPAddr, err err
|
|||
return l, packet.Addr, nil
|
||||
}
|
||||
|
||||
// Close implements discover.UDPConn
|
||||
// Close implements discv5.conn
|
||||
func (s *sharedUDPConn) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
@ -615,7 +616,7 @@ func (srv *Server) setupDiscovery() error {
|
|||
Unhandled: unhandled,
|
||||
Log: srv.log,
|
||||
}
|
||||
ntab, err := discover.ListenV4(conn, srv.localnode, cfg)
|
||||
ntab, err := discover.ListenUDP(conn, srv.localnode, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -625,21 +626,20 @@ func (srv *Server) setupDiscovery() error {
|
|||
|
||||
// Discovery V5
|
||||
if srv.DiscoveryV5 {
|
||||
cfg := discover.Config{
|
||||
PrivateKey: srv.PrivateKey,
|
||||
NetRestrict: srv.NetRestrict,
|
||||
Bootnodes: srv.BootstrapNodesV5,
|
||||
Log: srv.log,
|
||||
}
|
||||
var ntab *discv5.Network
|
||||
var err error
|
||||
if sconn != nil {
|
||||
srv.DiscV5, err = discover.ListenV5(sconn, srv.localnode, cfg)
|
||||
ntab, err = discv5.ListenUDP(srv.PrivateKey, sconn, "", srv.NetRestrict)
|
||||
} else {
|
||||
srv.DiscV5, err = discover.ListenV5(conn, srv.localnode, cfg)
|
||||
ntab, err = discv5.ListenUDP(srv.PrivateKey, conn, "", srv.NetRestrict)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ntab.SetFallbackNodes(srv.BootstrapNodesV5); err != nil {
|
||||
return err
|
||||
}
|
||||
srv.DiscV5 = ntab
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -671,6 +671,7 @@ func (srv *Server) maxInboundConns() 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 {
|
||||
return 0
|
||||
}
|
||||
|
@ -780,6 +781,7 @@ running:
|
|||
c.cont <- srv.postHandshakeChecks(peers, inboundCount, c)
|
||||
|
||||
case c := <-srv.checkpointAddPeer:
|
||||
log.Info("checkpoing add peer")
|
||||
// At this point the connection is past the protocol handshake.
|
||||
// Its capabilities are known and the remote identity is verified.
|
||||
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 {
|
||||
log.Info("launching peer")
|
||||
p := newPeer(srv.log, c, srv.Protocols)
|
||||
if srv.EnableMsgEvents {
|
||||
// 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.
|
||||
func (srv *Server) runPeer(p *Peer) {
|
||||
log.Info("Running peer", "peer", p)
|
||||
if srv.newPeerHook != nil {
|
||||
srv.newPeerHook(p)
|
||||
}
|
||||
|
|
|
@ -73,24 +73,6 @@ var CalaverasBootnodes = []string{
|
|||
"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@"
|
||||
|
||||
// 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
|
||||
// of the Waku protocol.
|
||||
func (w *Waku) Start(*p2p.Server) error {
|
||||
func (w *Waku) Start() error {
|
||||
go w.update()
|
||||
|
||||
numCPU := runtime.NumCPU()
|
||||
|
@ -1519,6 +1519,10 @@ func (w *Waku) GetEnvelope(hash gethcommon.Hash) *common.Envelope {
|
|||
return w.envelopes[hash]
|
||||
}
|
||||
|
||||
func (w *Waku) Version() uint {
|
||||
return 1
|
||||
}
|
||||
|
||||
// isEnvelopeCached checks if envelope with specific hash has already been received and cached.
|
||||
func (w *Waku) IsEnvelopeCached(hash gethcommon.Hash) bool {
|
||||
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
|
||||
// of the Waku protocol.
|
||||
func (w *Waku) Start(*p2p.Server) error {
|
||||
func (w *Waku) Start() error {
|
||||
numCPU := runtime.NumCPU()
|
||||
for i := 0; i < numCPU; i++ {
|
||||
go w.processQueue()
|
||||
|
|
Loading…
Reference in New Issue