12
vendor/github.com/status-im/status-go/node/README.md
generated
vendored
Normal file
12
vendor/github.com/status-im/status-go/node/README.md
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
### Structure
|
||||
|
||||
A Status node is a container of services.
|
||||
These services are passed to geth and registered with geth as APIs and Protocols.
|
||||
|
||||
Status node manages all the services and the geth node.
|
||||
|
||||
Status node is managed by `api/geth_backend.go`
|
||||
|
||||
So:
|
||||
|
||||
`GethBackend` manages `StatusNode`, `StatusNode` manages `GethNode`
|
||||
707
vendor/github.com/status-im/status-go/node/get_status_node.go
generated
vendored
Normal file
707
vendor/github.com/status-im/status-go/node/get_status_node.go
generated
vendored
Normal file
@@ -0,0 +1,707 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
ma "github.com/multiformats/go-multiaddr"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"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/common"
|
||||
"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/ipfs"
|
||||
"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"
|
||||
"github.com/status-im/status-go/server"
|
||||
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/chat"
|
||||
"github.com/status-im/status-go/services/communitytokens"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/gif"
|
||||
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/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/status"
|
||||
"github.com/status-im/status-go/services/stickers"
|
||||
"github.com/status-im/status-go/services/subscriptions"
|
||||
"github.com/status-im/status-go/services/updates"
|
||||
"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/services/web3provider"
|
||||
"github.com/status-im/status-go/timesource"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
"github.com/status-im/status-go/waku"
|
||||
"github.com/status-im/status-go/wakuv2"
|
||||
)
|
||||
|
||||
// errors
|
||||
var (
|
||||
ErrNodeRunning = errors.New("node is already running")
|
||||
ErrNoGethNode = errors.New("geth node is not available")
|
||||
ErrNoRunningNode = errors.New("there is no running node")
|
||||
ErrAccountKeyStoreMissing = errors.New("account key store is not set")
|
||||
ErrServiceUnknown = errors.New("service unknown")
|
||||
ErrDiscoveryRunning = errors.New("discovery is already running")
|
||||
ErrRPCMethodUnavailable = `{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"the method called does not exist/is not available"}}`
|
||||
)
|
||||
|
||||
// StatusNode abstracts contained geth node and provides helper methods to
|
||||
// interact with it.
|
||||
type StatusNode struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
appDB *sql.DB
|
||||
multiaccountsDB *multiaccounts.Database
|
||||
walletDB *sql.DB
|
||||
|
||||
config *params.NodeConfig // Status node configuration
|
||||
gethNode *node.Node // reference to Geth P2P stack/node
|
||||
rpcClient *rpc.Client // reference to an RPC client
|
||||
|
||||
downloader *ipfs.Downloader
|
||||
httpServer *server.MediaServer
|
||||
|
||||
discovery discovery.Discovery
|
||||
register *peers.Register
|
||||
peerPool *peers.PeerPool
|
||||
db *leveldb.DB // used as a cache for PeerPool
|
||||
|
||||
log log.Logger
|
||||
|
||||
gethAccountManager *account.GethManager
|
||||
accountsManager *accounts.Manager
|
||||
transactor *transactions.Transactor
|
||||
|
||||
// services
|
||||
services []common.StatusService
|
||||
publicMethods map[string]bool
|
||||
// we explicitly list every service, we could use interfaces
|
||||
// and store them in a nicer way and user reflection, but for now stupid is good
|
||||
rpcFiltersSrvc *rpcfilters.Service
|
||||
subscriptionsSrvc *subscriptions.Service
|
||||
rpcStatsSrvc *rpcstats.Service
|
||||
statusPublicSrvc *status.Service
|
||||
accountsSrvc *accountssvc.Service
|
||||
browsersSrvc *browsers.Service
|
||||
permissionsSrvc *permissions.Service
|
||||
mailserversSrvc *mailservers.Service
|
||||
providerSrvc *web3provider.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
|
||||
ensSrvc *ens.Service
|
||||
communityTokensSrvc *communitytokens.Service
|
||||
gifSrvc *gif.Service
|
||||
stickersSrvc *stickers.Service
|
||||
chatSrvc *chat.Service
|
||||
updatesSrvc *updates.Service
|
||||
pendingTracker *transactions.PendingTxTracker
|
||||
|
||||
walletFeed event.Feed
|
||||
}
|
||||
|
||||
// New makes new instance of StatusNode.
|
||||
func New(transactor *transactions.Transactor) *StatusNode {
|
||||
return &StatusNode{
|
||||
gethAccountManager: account.NewGethManager(),
|
||||
transactor: transactor,
|
||||
log: log.New("package", "status-go/node.StatusNode"),
|
||||
publicMethods: make(map[string]bool),
|
||||
}
|
||||
}
|
||||
|
||||
// Config exposes reference to running node's configuration
|
||||
func (n *StatusNode) Config() *params.NodeConfig {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
return n.config
|
||||
}
|
||||
|
||||
// GethNode returns underlying geth node.
|
||||
func (n *StatusNode) GethNode() *node.Node {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
return n.gethNode
|
||||
}
|
||||
|
||||
func (n *StatusNode) HTTPServer() *server.MediaServer {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
return n.httpServer
|
||||
}
|
||||
|
||||
// Server retrieves the currently running P2P network layer.
|
||||
func (n *StatusNode) Server() *p2p.Server {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if n.gethNode == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return n.gethNode.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) error {
|
||||
return n.StartWithOptions(config, StartOptions{
|
||||
StartDiscovery: true,
|
||||
AccountsManager: accs,
|
||||
})
|
||||
}
|
||||
|
||||
// StartOptions allows to control some parameters of Start() method.
|
||||
type StartOptions struct {
|
||||
StartDiscovery bool
|
||||
AccountsManager *accounts.Manager
|
||||
}
|
||||
|
||||
// StartMediaServerWithoutDB starts media server without starting the node
|
||||
// The server can only handle requests that don't require appdb or IPFS downloader
|
||||
func (n *StatusNode) StartMediaServerWithoutDB() error {
|
||||
if n.isRunning() {
|
||||
n.log.Debug("node is already running, no need to StartMediaServerWithoutDB")
|
||||
return nil
|
||||
}
|
||||
|
||||
if n.httpServer != nil {
|
||||
if err := n.httpServer.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
httpServer, err := server.NewMediaServer(nil, nil, n.multiaccountsDB, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.httpServer = httpServer
|
||||
|
||||
if err := n.httpServer.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartWithOptions starts current StatusNode, failing if it's already started.
|
||||
// It takes some options that allows to further configure starting process.
|
||||
func (n *StatusNode) StartWithOptions(config *params.NodeConfig, options StartOptions) error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if n.isRunning() {
|
||||
n.log.Debug("node is already running")
|
||||
return ErrNodeRunning
|
||||
}
|
||||
|
||||
n.accountsManager = options.AccountsManager
|
||||
|
||||
n.log.Debug("starting with options", "ClusterConfig", config.ClusterConfig)
|
||||
|
||||
db, err := db.Create(config.DataDir, params.StatusDatabase)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create database at %s: %v", config.DataDir, err)
|
||||
}
|
||||
|
||||
n.db = db
|
||||
|
||||
err = n.startWithDB(config, options.AccountsManager, db)
|
||||
|
||||
// continue only if there was no error when starting node with a db
|
||||
if err == nil && options.StartDiscovery && n.discoveryEnabled() {
|
||||
err = n.startDiscovery()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if dberr := db.Close(); dberr != nil {
|
||||
n.log.Error("error while closing leveldb after node crash", "error", dberr)
|
||||
}
|
||||
n.db = nil
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if err := n.setupRPCClient(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.downloader = ipfs.NewDownloader(config.RootDataDir)
|
||||
|
||||
if n.httpServer != nil {
|
||||
if err := n.httpServer.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
httpServer, err := server.NewMediaServer(n.appDB, n.downloader, n.multiaccountsDB, n.walletDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.httpServer = httpServer
|
||||
|
||||
if err := n.httpServer.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := n.initServices(config, n.httpServer); err != nil {
|
||||
return err
|
||||
}
|
||||
return n.startGethNode()
|
||||
}
|
||||
|
||||
func (n *StatusNode) createNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) (err error) {
|
||||
n.gethNode, err = MakeNode(config, accs, db)
|
||||
return err
|
||||
}
|
||||
|
||||
// startGethNode starts current StatusNode, will fail if it's already started.
|
||||
func (n *StatusNode) startGethNode() error {
|
||||
return n.gethNode.Start()
|
||||
}
|
||||
|
||||
func (n *StatusNode) setupRPCClient() (err error) {
|
||||
// setup RPC client
|
||||
gethNodeClient, err := n.gethNode.Attach()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n.rpcClient, err = rpc.NewClient(gethNodeClient, n.config.NetworkID, n.config.UpstreamConfig, n.config.Networks, n.appDB)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (n *StatusNode) discoveryEnabled() bool {
|
||||
return n.config != nil && (!n.config.NoDiscovery || n.config.Rendezvous) && n.config.ClusterConfig.Enabled
|
||||
}
|
||||
|
||||
func (n *StatusNode) discoverNode() (*enode.Node, error) {
|
||||
if !n.isRunning() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
server := n.gethNode.Server()
|
||||
discNode := server.Self()
|
||||
|
||||
if n.config.AdvertiseAddr == "" {
|
||||
return discNode, nil
|
||||
}
|
||||
|
||||
n.log.Info("Using AdvertiseAddr for rendezvous", "addr", n.config.AdvertiseAddr)
|
||||
|
||||
r := discNode.Record()
|
||||
r.Set(enr.IP(net.ParseIP(n.config.AdvertiseAddr)))
|
||||
if err := enode.SignV4(r, server.PrivateKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return enode.New(enode.ValidSchemes[r.IdentityScheme()], r)
|
||||
}
|
||||
|
||||
func (n *StatusNode) startRendezvous() (discovery.Discovery, error) {
|
||||
if !n.config.Rendezvous {
|
||||
return nil, errors.New("rendezvous is not enabled")
|
||||
}
|
||||
if len(n.config.ClusterConfig.RendezvousNodes) == 0 {
|
||||
return nil, errors.New("rendezvous node must be provided if rendezvous discovery is enabled")
|
||||
}
|
||||
maddrs := make([]ma.Multiaddr, len(n.config.ClusterConfig.RendezvousNodes))
|
||||
for i, addr := range n.config.ClusterConfig.RendezvousNodes {
|
||||
var err error
|
||||
maddrs[i], err = ma.NewMultiaddr(addr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse rendezvous node %s: %v", n.config.ClusterConfig.RendezvousNodes[0], err)
|
||||
}
|
||||
}
|
||||
node, err := n.discoverNode()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get a discover node: %v", err)
|
||||
}
|
||||
|
||||
return discovery.NewRendezvous(maddrs, n.gethNode.Server().PrivateKey, node)
|
||||
}
|
||||
|
||||
// StartDiscovery starts the peers discovery protocols depending on the node config.
|
||||
func (n *StatusNode) StartDiscovery() error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if n.discoveryEnabled() {
|
||||
return n.startDiscovery()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) startDiscovery() error {
|
||||
if n.isDiscoveryRunning() {
|
||||
return ErrDiscoveryRunning
|
||||
}
|
||||
|
||||
discoveries := []discovery.Discovery{}
|
||||
if !n.config.NoDiscovery {
|
||||
discoveries = append(discoveries, discovery.NewDiscV5(
|
||||
n.gethNode.Server().PrivateKey,
|
||||
n.config.ListenAddr,
|
||||
parseNodesV5(n.config.ClusterConfig.BootNodes)))
|
||||
}
|
||||
if n.config.Rendezvous {
|
||||
d, err := n.startRendezvous()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
discoveries = append(discoveries, d)
|
||||
}
|
||||
if len(discoveries) == 0 {
|
||||
return errors.New("wasn't able to register any discovery")
|
||||
} else if len(discoveries) > 1 {
|
||||
n.discovery = discovery.NewMultiplexer(discoveries)
|
||||
} else {
|
||||
n.discovery = discoveries[0]
|
||||
}
|
||||
log.Debug(
|
||||
"using discovery",
|
||||
"instance", reflect.TypeOf(n.discovery),
|
||||
"registerTopics", n.config.RegisterTopics,
|
||||
"requireTopics", n.config.RequireTopics,
|
||||
)
|
||||
n.register = peers.NewRegister(n.discovery, n.config.RegisterTopics...)
|
||||
options := peers.NewDefaultOptions()
|
||||
// TODO(dshulyak) consider adding a flag to define this behaviour
|
||||
options.AllowStop = len(n.config.RegisterTopics) == 0
|
||||
options.TrustedMailServers = parseNodesToNodeID(n.config.ClusterConfig.TrustedMailServers)
|
||||
|
||||
n.peerPool = peers.NewPeerPool(
|
||||
n.discovery,
|
||||
n.config.RequireTopics,
|
||||
peers.NewCache(n.db),
|
||||
options,
|
||||
)
|
||||
if err := n.discovery.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := n.register.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
return n.peerPool.Start(n.gethNode.Server())
|
||||
}
|
||||
|
||||
// Stop will stop current StatusNode. A stopped node cannot be resumed.
|
||||
func (n *StatusNode) Stop() error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
return n.stop()
|
||||
}
|
||||
|
||||
// stop will stop current StatusNode. A stopped node cannot be resumed.
|
||||
func (n *StatusNode) stop() error {
|
||||
if n.isDiscoveryRunning() {
|
||||
if err := n.stopDiscovery(); err != nil {
|
||||
n.log.Error("Error stopping the discovery components", "error", err)
|
||||
}
|
||||
n.register = nil
|
||||
n.peerPool = nil
|
||||
n.discovery = nil
|
||||
}
|
||||
|
||||
if err := n.gethNode.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.rpcClient = nil
|
||||
// We need to clear `gethNode` because config is passed to `Start()`
|
||||
// and may be completely different. Similarly with `config`.
|
||||
n.gethNode = nil
|
||||
n.config = nil
|
||||
|
||||
err := n.httpServer.Stop()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
n.httpServer = nil
|
||||
|
||||
n.downloader.Stop()
|
||||
n.downloader = nil
|
||||
|
||||
if n.db != nil {
|
||||
err := n.db.Close()
|
||||
|
||||
n.db = nil
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
n.rpcFiltersSrvc = nil
|
||||
n.subscriptionsSrvc = nil
|
||||
n.rpcStatsSrvc = nil
|
||||
n.accountsSrvc = nil
|
||||
n.browsersSrvc = nil
|
||||
n.permissionsSrvc = nil
|
||||
n.mailserversSrvc = nil
|
||||
n.providerSrvc = nil
|
||||
n.appMetricsSrvc = nil
|
||||
n.walletSrvc = nil
|
||||
n.peerSrvc = nil
|
||||
n.localNotificationsSrvc = nil
|
||||
n.personalSrvc = nil
|
||||
n.timeSourceSrvc = nil
|
||||
n.wakuSrvc = nil
|
||||
n.wakuExtSrvc = nil
|
||||
n.wakuV2Srvc = nil
|
||||
n.wakuV2ExtSrvc = nil
|
||||
n.ensSrvc = nil
|
||||
n.communityTokensSrvc = nil
|
||||
n.stickersSrvc = nil
|
||||
n.publicMethods = make(map[string]bool)
|
||||
n.pendingTracker = nil
|
||||
n.log.Debug("status node stopped")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) isDiscoveryRunning() bool {
|
||||
return n.register != nil || n.peerPool != nil || n.discovery != nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) stopDiscovery() error {
|
||||
n.register.Stop()
|
||||
n.peerPool.Stop()
|
||||
return n.discovery.Stop()
|
||||
}
|
||||
|
||||
// ResetChainData removes chain data if node is not running.
|
||||
func (n *StatusNode) ResetChainData(config *params.NodeConfig) error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if n.isRunning() {
|
||||
return ErrNodeRunning
|
||||
}
|
||||
|
||||
chainDataDir := filepath.Join(config.DataDir, config.Name, "lightchaindata")
|
||||
if _, err := os.Stat(chainDataDir); os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
err := os.RemoveAll(chainDataDir)
|
||||
if err == nil {
|
||||
n.log.Info("Chain data has been removed", "dir", chainDataDir)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// IsRunning confirm that node is running.
|
||||
func (n *StatusNode) IsRunning() bool {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
return n.isRunning()
|
||||
}
|
||||
|
||||
func (n *StatusNode) isRunning() bool {
|
||||
return n.gethNode != nil && n.gethNode.Server() != nil
|
||||
}
|
||||
|
||||
// populateStaticPeers connects current node with our publicly available LES/SHH/Swarm cluster
|
||||
func (n *StatusNode) populateStaticPeers() error {
|
||||
if !n.config.ClusterConfig.Enabled {
|
||||
n.log.Info("Static peers are disabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, enode := range n.config.ClusterConfig.StaticNodes {
|
||||
if err := n.addPeer(enode); err != nil {
|
||||
n.log.Error("Static peer addition failed", "error", err)
|
||||
return err
|
||||
}
|
||||
n.log.Info("Static peer added", "enode", enode)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) removeStaticPeers() error {
|
||||
if !n.config.ClusterConfig.Enabled {
|
||||
n.log.Info("Static peers are disabled")
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, enode := range n.config.ClusterConfig.StaticNodes {
|
||||
if err := n.removePeer(enode); err != nil {
|
||||
n.log.Error("Static peer deletion failed", "error", err)
|
||||
return err
|
||||
}
|
||||
n.log.Info("Static peer deleted", "enode", enode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReconnectStaticPeers removes and adds static peers to a server.
|
||||
func (n *StatusNode) ReconnectStaticPeers() error {
|
||||
n.mu.Lock()
|
||||
defer n.mu.Unlock()
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
if err := n.removeStaticPeers(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return n.populateStaticPeers()
|
||||
}
|
||||
|
||||
// AddPeer adds new static peer node
|
||||
func (n *StatusNode) AddPeer(url string) error {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
return n.addPeer(url)
|
||||
}
|
||||
|
||||
// addPeer adds new static peer node
|
||||
func (n *StatusNode) addPeer(url string) error {
|
||||
parsedNode, err := enode.ParseV4(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
n.gethNode.Server().AddPeer(parsedNode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *StatusNode) removePeer(url string) error {
|
||||
parsedNode, err := enode.ParseV4(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !n.isRunning() {
|
||||
return ErrNoRunningNode
|
||||
}
|
||||
|
||||
n.gethNode.Server().RemovePeer(parsedNode)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PeerCount returns the number of connected peers.
|
||||
func (n *StatusNode) PeerCount() int {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if !n.isRunning() {
|
||||
return 0
|
||||
}
|
||||
|
||||
return n.gethNode.Server().PeerCount()
|
||||
}
|
||||
|
||||
func (n *StatusNode) ConnectionChanged(state connection.State) {
|
||||
if n.wakuExtSrvc != nil {
|
||||
n.wakuExtSrvc.ConnectionChanged(state)
|
||||
}
|
||||
|
||||
if n.wakuV2ExtSrvc != nil {
|
||||
n.wakuV2ExtSrvc.ConnectionChanged(state)
|
||||
}
|
||||
}
|
||||
|
||||
// AccountManager exposes reference to node's accounts manager
|
||||
func (n *StatusNode) AccountManager() (*accounts.Manager, error) {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
|
||||
if n.gethNode == nil {
|
||||
return nil, ErrNoGethNode
|
||||
}
|
||||
|
||||
return n.gethNode.AccountManager(), nil
|
||||
}
|
||||
|
||||
// RPCClient exposes reference to RPC client connected to the running node.
|
||||
func (n *StatusNode) RPCClient() *rpc.Client {
|
||||
n.mu.RLock()
|
||||
defer n.mu.RUnlock()
|
||||
return n.rpcClient
|
||||
}
|
||||
|
||||
// Discover sets up the discovery for a specific topic.
|
||||
func (n *StatusNode) Discover(topic string, max, min int) (err error) {
|
||||
if n.peerPool == nil {
|
||||
return errors.New("peerPool not running")
|
||||
}
|
||||
return n.peerPool.UpdateTopic(topic, params.Limits{
|
||||
Max: max,
|
||||
Min: min,
|
||||
})
|
||||
}
|
||||
|
||||
func (n *StatusNode) SetAppDB(db *sql.DB) {
|
||||
n.appDB = db
|
||||
}
|
||||
|
||||
func (n *StatusNode) SetMultiaccountsDB(db *multiaccounts.Database) {
|
||||
n.multiaccountsDB = db
|
||||
}
|
||||
|
||||
func (n *StatusNode) SetWalletDB(db *sql.DB) {
|
||||
n.walletDB = db
|
||||
}
|
||||
169
vendor/github.com/status-im/status-go/node/geth_node.go
generated
vendored
Normal file
169
vendor/github.com/status-im/status-go/node/geth_node.go
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||
|
||||
"github.com/status-im/status-go/eth-node/crypto"
|
||||
"github.com/status-im/status-go/params"
|
||||
)
|
||||
|
||||
// Errors related to node and services creation.
|
||||
var (
|
||||
ErrNodeMakeFailureFormat = "error creating p2p node: %s"
|
||||
ErrWakuServiceRegistrationFailure = errors.New("failed to register the Waku service")
|
||||
ErrWakuV2ServiceRegistrationFailure = errors.New("failed to register the WakuV2 service")
|
||||
ErrLightEthRegistrationFailure = errors.New("failed to register the LES service")
|
||||
ErrLightEthRegistrationFailureUpstreamEnabled = errors.New("failed to register the LES service, upstream is also configured")
|
||||
ErrPersonalServiceRegistrationFailure = errors.New("failed to register the personal api service")
|
||||
ErrStatusServiceRegistrationFailure = errors.New("failed to register the Status service")
|
||||
ErrPeerServiceRegistrationFailure = errors.New("failed to register the Peer service")
|
||||
)
|
||||
|
||||
// All general log messages in this package should be routed through this logger.
|
||||
var logger = log.New("package", "status-go/node")
|
||||
|
||||
// MakeNode creates a geth node entity
|
||||
func MakeNode(config *params.NodeConfig, accs *accounts.Manager, db *leveldb.DB) (*node.Node, error) {
|
||||
// If DataDir is empty, it means we want to create an ephemeral node
|
||||
// keeping data only in memory.
|
||||
if config.DataDir != "" {
|
||||
// make sure data directory exists
|
||||
if err := os.MkdirAll(filepath.Clean(config.DataDir), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("make node: make data directory: %v", err)
|
||||
}
|
||||
|
||||
// make sure keys directory exists
|
||||
if err := os.MkdirAll(filepath.Clean(config.KeyStoreDir), os.ModePerm); err != nil {
|
||||
return nil, fmt.Errorf("make node: make keys directory: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
stackConfig, err := newGethNodeConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stack, err := node.New(stackConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(ErrNodeMakeFailureFormat, err.Error())
|
||||
}
|
||||
|
||||
return stack, nil
|
||||
}
|
||||
|
||||
// newGethNodeConfig returns default stack configuration for mobile client node
|
||||
func newGethNodeConfig(config *params.NodeConfig) (*node.Config, error) {
|
||||
// NOTE: I haven't changed anything related to this parameters, but
|
||||
// it seems they were previously ignored if set to 0, but now they seem
|
||||
// to be used, so they need to be set to something
|
||||
maxPeers := 100
|
||||
maxPendingPeers := 100
|
||||
|
||||
if config.MaxPeers != 0 {
|
||||
maxPeers = config.MaxPeers
|
||||
}
|
||||
|
||||
if config.MaxPendingPeers != 0 {
|
||||
maxPendingPeers = config.MaxPendingPeers
|
||||
}
|
||||
|
||||
nc := &node.Config{
|
||||
DataDir: config.DataDir,
|
||||
KeyStoreDir: config.KeyStoreDir,
|
||||
UseLightweightKDF: true,
|
||||
NoUSB: true,
|
||||
Name: config.Name,
|
||||
Version: config.Version,
|
||||
P2P: p2p.Config{
|
||||
NoDiscovery: true, // we always use only v5 server
|
||||
ListenAddr: config.ListenAddr,
|
||||
NAT: nat.Any(),
|
||||
MaxPeers: maxPeers,
|
||||
MaxPendingPeers: maxPendingPeers,
|
||||
},
|
||||
HTTPModules: config.FormatAPIModules(),
|
||||
}
|
||||
|
||||
if config.IPCEnabled {
|
||||
// use well-known defaults
|
||||
if config.IPCFile == "" {
|
||||
config.IPCFile = "geth.ipc"
|
||||
}
|
||||
|
||||
nc.IPCPath = config.IPCFile
|
||||
}
|
||||
|
||||
if config.HTTPEnabled {
|
||||
nc.HTTPHost = config.HTTPHost
|
||||
nc.HTTPPort = config.HTTPPort
|
||||
nc.HTTPVirtualHosts = config.HTTPVirtualHosts
|
||||
nc.HTTPCors = config.HTTPCors
|
||||
}
|
||||
|
||||
if config.ClusterConfig.Enabled {
|
||||
nc.P2P.BootstrapNodesV5 = parseNodesV5(config.ClusterConfig.BootNodes)
|
||||
nc.P2P.StaticNodes = parseNodes(config.ClusterConfig.StaticNodes)
|
||||
}
|
||||
|
||||
if config.NodeKey != "" {
|
||||
sk, err := crypto.HexToECDSA(config.NodeKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// override node's private key
|
||||
nc.P2P.PrivateKey = sk
|
||||
}
|
||||
|
||||
return nc, nil
|
||||
}
|
||||
|
||||
// parseNodes creates list of enode.Node out of enode strings.
|
||||
func parseNodes(enodes []string) []*enode.Node {
|
||||
var nodes []*enode.Node
|
||||
for _, item := range enodes {
|
||||
parsedPeer, err := enode.ParseV4(item)
|
||||
if err == nil {
|
||||
nodes = append(nodes, parsedPeer)
|
||||
} else {
|
||||
logger.Error("Failed to parse enode", "enode", item, "err", err)
|
||||
}
|
||||
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
// parseNodesV5 creates list of discv5.Node out of enode strings.
|
||||
func parseNodesV5(enodes []string) []*discv5.Node {
|
||||
var nodes []*discv5.Node
|
||||
for _, enode := range enodes {
|
||||
parsedPeer, err := discv5.ParseNode(enode)
|
||||
|
||||
if err == nil {
|
||||
nodes = append(nodes, parsedPeer)
|
||||
} else {
|
||||
logger.Error("Failed to parse enode", "enode", enode, "err", err)
|
||||
}
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
func parseNodesToNodeID(enodes []string) []enode.ID {
|
||||
nodeIDs := make([]enode.ID, 0, len(enodes))
|
||||
for _, node := range parseNodes(enodes) {
|
||||
nodeIDs = append(nodeIDs, node.ID())
|
||||
}
|
||||
return nodeIDs
|
||||
}
|
||||
30
vendor/github.com/status-im/status-go/node/rpc.go
generated
vendored
Normal file
30
vendor/github.com/status-im/status-go/node/rpc.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// firstCharToLower converts to first character of name to lowercase.
|
||||
func firstCharToLower(name string) string {
|
||||
ret := []rune(name)
|
||||
if len(ret) > 0 {
|
||||
ret[0] = unicode.ToLower(ret[0])
|
||||
}
|
||||
return string(ret)
|
||||
}
|
||||
|
||||
// addSuitableCallbacks iterates over the methods of the given type and adds them to
|
||||
// the methods list
|
||||
// This is taken from go-ethereum services
|
||||
func addSuitableCallbacks(receiver reflect.Value, namespace string, methods map[string]bool) {
|
||||
typ := receiver.Type()
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
if method.PkgPath != "" {
|
||||
continue // method not exported
|
||||
}
|
||||
name := firstCharToLower(method.Name)
|
||||
methods[namespace+"_"+name] = true
|
||||
}
|
||||
}
|
||||
711
vendor/github.com/status-im/status-go/node/status_node_services.go
generated
vendored
Normal file
711
vendor/github.com/status-im/status-go/node/status_node_services.go
generated
vendored
Normal file
@@ -0,0 +1,711 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/status-im/status-go/protocol/common/shard"
|
||||
"github.com/status-im/status-go/server"
|
||||
"github.com/status-im/status-go/signal"
|
||||
"github.com/status-im/status-go/transactions"
|
||||
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
gethrpc "github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"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/multiaccounts/settings"
|
||||
"github.com/status-im/status-go/params"
|
||||
"github.com/status-im/status-go/rpc"
|
||||
accountssvc "github.com/status-im/status-go/services/accounts"
|
||||
"github.com/status-im/status-go/services/accounts/settingsevent"
|
||||
appmetricsservice "github.com/status-im/status-go/services/appmetrics"
|
||||
"github.com/status-im/status-go/services/browsers"
|
||||
"github.com/status-im/status-go/services/chat"
|
||||
"github.com/status-im/status-go/services/communitytokens"
|
||||
"github.com/status-im/status-go/services/ens"
|
||||
"github.com/status-im/status-go/services/ext"
|
||||
"github.com/status-im/status-go/services/gif"
|
||||
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/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/status"
|
||||
"github.com/status-im/status-go/services/stickers"
|
||||
"github.com/status-im/status-go/services/subscriptions"
|
||||
"github.com/status-im/status-go/services/updates"
|
||||
"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/services/wallet/thirdparty"
|
||||
"github.com/status-im/status-go/services/wallet/transfer"
|
||||
"github.com/status-im/status-go/services/web3provider"
|
||||
"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")
|
||||
// ErrRPCClientUnavailable is returned if an RPC client can't be retrieved.
|
||||
// This is a normal situation when a node is stopped.
|
||||
ErrRPCClientUnavailable = errors.New("JSON-RPC client is unavailable")
|
||||
)
|
||||
|
||||
func (b *StatusNode) initServices(config *params.NodeConfig, mediaServer *server.MediaServer) error {
|
||||
accountsFeed := &event.Feed{}
|
||||
settingsFeed := &event.Feed{}
|
||||
accDB, err := accounts.NewDB(b.appDB)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
setSettingsNotifier(accDB, settingsFeed)
|
||||
|
||||
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 = append(services, b.statusPublicService())
|
||||
services = append(services, b.pendingTrackerService(&b.walletFeed))
|
||||
services = append(services, b.ensService(b.timeSourceNow()))
|
||||
services = append(services, b.CommunityTokensService())
|
||||
services = append(services, b.stickersService(accDB))
|
||||
services = append(services, b.updatesService())
|
||||
services = appendIf(b.appDB != nil && b.multiaccountsDB != nil, services, b.accountsService(accountsFeed, accDB, mediaServer))
|
||||
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.Web3ProviderConfig.Enabled, services, b.providerService(accDB))
|
||||
services = append(services, b.gifService(accDB))
|
||||
services = append(services, b.ChatService(accDB))
|
||||
|
||||
// Wallet Service is used by wakuExtSrvc/wakuV2ExtSrvc
|
||||
// Keep this initialization before the other two
|
||||
if config.WalletConfig.Enabled {
|
||||
walletService := b.walletService(accDB, b.appDB, accountsFeed, settingsFeed, &b.walletFeed)
|
||||
services = append(services, walletService)
|
||||
}
|
||||
|
||||
// CollectiblesManager needs the WakuExt service to get metadata for
|
||||
// Community collectibles.
|
||||
// Messenger needs the CollectiblesManager to get the list of collectibles owned
|
||||
// by a certain account and check community entry permissions.
|
||||
// We handle circular dependency between the two by delaying ininitalization of the CommunityCollectibleInfoProvider
|
||||
// in the CollectiblesManager.
|
||||
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)
|
||||
|
||||
b.SetWalletCommunityInfoProvider(wakuext)
|
||||
}
|
||||
|
||||
if config.WakuV2Config.Enabled {
|
||||
telemetryServerURL := ""
|
||||
if accDB.DB() != nil {
|
||||
telemetryServerURL, err = accDB.GetTelemetryServerURL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
waku2Service, err := b.wakuV2Service(config, telemetryServerURL)
|
||||
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.SetWalletCommunityInfoProvider(wakuext)
|
||||
}
|
||||
|
||||
// We ignore for now local notifications flag as users who are upgrading have no mean to enable it
|
||||
lns, err := b.localNotificationsService(config.NetworkID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
services = append(services, lns)
|
||||
|
||||
b.peerSrvc.SetDiscoverer(b)
|
||||
|
||||
for i := range services {
|
||||
b.RegisterLifecycle(services[i])
|
||||
}
|
||||
|
||||
b.services = services
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *StatusNode) RegisterLifecycle(s common.StatusService) {
|
||||
b.addPublicMethods(s.APIs())
|
||||
b.gethNode.RegisterAPIs(s.APIs())
|
||||
b.gethNode.RegisterProtocols(s.Protocols())
|
||||
b.gethNode.RegisterLifecycle(s)
|
||||
}
|
||||
|
||||
// Add through reflection a list of public methods so we can check when the
|
||||
// user makes a call if they are allowed
|
||||
func (b *StatusNode) addPublicMethods(apis []gethrpc.API) {
|
||||
for _, api := range apis {
|
||||
if api.Public {
|
||||
addSuitableCallbacks(reflect.ValueOf(api.Service), api.Namespace, b.publicMethods)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *StatusNode) nodeBridge() types.Node {
|
||||
return gethbridge.NewNodeBridge(b.gethNode, b.wakuSrvc, b.wakuV2Srvc)
|
||||
}
|
||||
|
||||
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, b.nodeBridge(), b.rpcClient, 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, b.nodeBridge(), b.rpcClient, ext.EnvelopeSignalHandler{}, b.db)
|
||||
}
|
||||
|
||||
b.wakuV2ExtSrvc.SetP2PServer(b.gethNode.Server())
|
||||
return b.wakuV2ExtSrvc, nil
|
||||
}
|
||||
|
||||
func (b *StatusNode) statusPublicService() *status.Service {
|
||||
if b.statusPublicSrvc == nil {
|
||||
b.statusPublicSrvc = status.New()
|
||||
}
|
||||
return b.statusPublicSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) StatusPublicService() *status.Service {
|
||||
return b.statusPublicSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) AccountService() *accountssvc.Service {
|
||||
return b.accountsSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) BrowserService() *browsers.Service {
|
||||
return b.browsersSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) EnsService() *ens.Service {
|
||||
return b.ensSrvc
|
||||
}
|
||||
|
||||
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(nodeConfig *params.NodeConfig, telemetryServerURL string) (*wakuv2.Waku, error) {
|
||||
if b.wakuV2Srvc == nil {
|
||||
cfg := &wakuv2.Config{
|
||||
MaxMessageSize: wakucommon.DefaultMaxMessageSize,
|
||||
Host: nodeConfig.WakuV2Config.Host,
|
||||
Port: nodeConfig.WakuV2Config.Port,
|
||||
LightClient: nodeConfig.WakuV2Config.LightClient,
|
||||
KeepAliveInterval: nodeConfig.WakuV2Config.KeepAliveInterval,
|
||||
Rendezvous: nodeConfig.Rendezvous,
|
||||
WakuNodes: nodeConfig.ClusterConfig.WakuNodes,
|
||||
PeerExchange: nodeConfig.WakuV2Config.PeerExchange,
|
||||
EnableStore: nodeConfig.WakuV2Config.EnableStore,
|
||||
StoreCapacity: nodeConfig.WakuV2Config.StoreCapacity,
|
||||
StoreSeconds: nodeConfig.WakuV2Config.StoreSeconds,
|
||||
DiscoveryLimit: nodeConfig.WakuV2Config.DiscoveryLimit,
|
||||
DiscV5BootstrapNodes: nodeConfig.ClusterConfig.DiscV5BootstrapNodes,
|
||||
Nameserver: nodeConfig.WakuV2Config.Nameserver,
|
||||
EnableDiscV5: nodeConfig.WakuV2Config.EnableDiscV5,
|
||||
UDPPort: nodeConfig.WakuV2Config.UDPPort,
|
||||
AutoUpdate: nodeConfig.WakuV2Config.AutoUpdate,
|
||||
DefaultShardPubsubTopic: shard.DefaultShardPubsubTopic(),
|
||||
UseShardAsDefaultTopic: nodeConfig.WakuV2Config.UseShardAsDefaultTopic,
|
||||
TelemetryServerURL: telemetryServerURL,
|
||||
ClusterID: nodeConfig.ClusterConfig.ClusterID,
|
||||
}
|
||||
|
||||
if nodeConfig.WakuV2Config.MaxMessageSize > 0 {
|
||||
cfg.MaxMessageSize = nodeConfig.WakuV2Config.MaxMessageSize
|
||||
}
|
||||
|
||||
w, err := wakuv2.New(nodeConfig.NodeKey, nodeConfig.ClusterConfig.Fleet, cfg, logutils.ZapLogger(), b.appDB, b.timeSource(), signal.SendHistoricMessagesRequestFailed, signal.SendPeerStats)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.wakuV2Srvc = w
|
||||
}
|
||||
|
||||
return b.wakuV2Srvc, nil
|
||||
}
|
||||
|
||||
func setSettingsNotifier(db *accounts.Database, feed *event.Feed) {
|
||||
db.SetSettingsNotifier(func(setting settings.SettingField, val interface{}) {
|
||||
feed.Send(settingsevent.Event{
|
||||
Type: settingsevent.EventTypeChanged,
|
||||
Setting: setting,
|
||||
Value: val,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
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.RPCClient() })
|
||||
}
|
||||
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, accDB *accounts.Database, mediaServer *server.MediaServer) *accountssvc.Service {
|
||||
if b.accountsSrvc == nil {
|
||||
b.accountsSrvc = accountssvc.NewService(
|
||||
accDB,
|
||||
b.multiaccountsDB,
|
||||
b.gethAccountManager,
|
||||
b.config,
|
||||
accountsFeed,
|
||||
mediaServer,
|
||||
)
|
||||
}
|
||||
|
||||
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) ensService(timesource func() time.Time) *ens.Service {
|
||||
if b.ensSrvc == nil {
|
||||
b.ensSrvc = ens.NewService(b.rpcClient, b.gethAccountManager, b.pendingTracker, b.config, b.appDB, timesource)
|
||||
}
|
||||
return b.ensSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) pendingTrackerService(walletFeed *event.Feed) *transactions.PendingTxTracker {
|
||||
if b.pendingTracker == nil {
|
||||
b.pendingTracker = transactions.NewPendingTxTracker(b.walletDB, b.rpcClient, b.rpcFiltersSrvc, walletFeed, transactions.PendingCheckInterval)
|
||||
}
|
||||
return b.pendingTracker
|
||||
}
|
||||
|
||||
func (b *StatusNode) CommunityTokensService() *communitytokens.Service {
|
||||
if b.communityTokensSrvc == nil {
|
||||
b.communityTokensSrvc = communitytokens.NewService(b.rpcClient, b.gethAccountManager, b.pendingTracker, b.config, b.appDB)
|
||||
}
|
||||
return b.communityTokensSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) stickersService(accountDB *accounts.Database) *stickers.Service {
|
||||
if b.stickersSrvc == nil {
|
||||
b.stickersSrvc = stickers.NewService(accountDB, b.rpcClient, b.gethAccountManager, b.config, b.downloader, b.httpServer, b.pendingTracker)
|
||||
}
|
||||
return b.stickersSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) updatesService() *updates.Service {
|
||||
if b.updatesSrvc == nil {
|
||||
b.updatesSrvc = updates.NewService(b.ensService(b.timeSourceNow()))
|
||||
}
|
||||
|
||||
return b.updatesSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) gifService(accountsDB *accounts.Database) *gif.Service {
|
||||
if b.gifSrvc == nil {
|
||||
b.gifSrvc = gif.NewService(accountsDB)
|
||||
}
|
||||
return b.gifSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) ChatService(accountsDB *accounts.Database) *chat.Service {
|
||||
if b.chatSrvc == nil {
|
||||
b.chatSrvc = chat.NewService(accountsDB)
|
||||
}
|
||||
return b.chatSrvc
|
||||
}
|
||||
|
||||
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) providerService(accountsDB *accounts.Database) *web3provider.Service {
|
||||
web3S := web3provider.NewService(b.appDB, accountsDB, b.rpcClient, b.config, b.gethAccountManager, b.rpcFiltersSrvc, b.transactor)
|
||||
if b.providerSrvc == nil {
|
||||
b.providerSrvc = web3S
|
||||
}
|
||||
return b.providerSrvc
|
||||
}
|
||||
|
||||
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() *wallet.Service {
|
||||
return b.walletSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) SetWalletCommunityInfoProvider(provider thirdparty.CommunityInfoProvider) {
|
||||
if b.walletSrvc != nil {
|
||||
b.walletSrvc.SetWalletCommunityInfoProvider(provider)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *StatusNode) walletService(accountsDB *accounts.Database, appDB *sql.DB, accountsFeed *event.Feed, settingsFeed *event.Feed, walletFeed *event.Feed) *wallet.Service {
|
||||
if b.walletSrvc == nil {
|
||||
b.walletSrvc = wallet.NewService(
|
||||
b.walletDB, accountsDB, appDB, b.rpcClient, accountsFeed, settingsFeed, b.gethAccountManager, b.transactor, b.config,
|
||||
b.ensService(b.timeSourceNow()),
|
||||
b.stickersService(accountsDB),
|
||||
b.pendingTracker,
|
||||
walletFeed,
|
||||
b.httpServer,
|
||||
)
|
||||
}
|
||||
return b.walletSrvc
|
||||
}
|
||||
|
||||
func (b *StatusNode) localNotificationsService(network uint64) (*localnotifications.Service, error) {
|
||||
var err error
|
||||
if b.localNotificationsSrvc == nil {
|
||||
b.localNotificationsSrvc, err = localnotifications.NewService(b.appDB, transfer.NewDB(b.walletDB), network)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return b.localNotificationsSrvc, nil
|
||||
}
|
||||
|
||||
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) PendingTracker() *transactions.PendingTxTracker {
|
||||
return b.pendingTracker
|
||||
}
|
||||
|
||||
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.walletFeed)
|
||||
|
||||
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) timeSourceNow() func() time.Time {
|
||||
return b.timeSource().Now
|
||||
}
|
||||
|
||||
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() != nil && b.Config().WalletConfig.Enabled {
|
||||
if b.walletSrvc != nil {
|
||||
if b.walletSrvc.IsStarted() {
|
||||
err := b.walletSrvc.Stop()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if b.ensSrvc != nil {
|
||||
err := b.ensSrvc.Stop()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type RPCCall struct {
|
||||
Method string `json:"method"`
|
||||
}
|
||||
|
||||
func (b *StatusNode) CallPrivateRPC(inputJSON string) (string, error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.rpcClient == nil {
|
||||
return "", ErrRPCClientUnavailable
|
||||
}
|
||||
|
||||
return b.rpcClient.CallRaw(inputJSON), nil
|
||||
}
|
||||
|
||||
// CallRPC calls public methods on the node, we register public methods
|
||||
// in a map and check if they can be called in this function
|
||||
func (b *StatusNode) CallRPC(inputJSON string) (string, error) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
if b.rpcClient == nil {
|
||||
return "", ErrRPCClientUnavailable
|
||||
}
|
||||
|
||||
rpcCall := &RPCCall{}
|
||||
err := json.Unmarshal([]byte(inputJSON), rpcCall)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if rpcCall.Method == "" || !b.publicMethods[rpcCall.Method] {
|
||||
return ErrRPCMethodUnavailable, nil
|
||||
}
|
||||
|
||||
return b.rpcClient.CallRaw(inputJSON), nil
|
||||
}
|
||||
Reference in New Issue
Block a user