cmd, mobile, node, p2p: surface the discovery V5 bootnodes
This commit is contained in:
parent
de4b39a1a3
commit
b61f48e5aa
@ -19,6 +19,7 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -44,6 +45,14 @@ var TestnetBootnodes = []*discover.Node{
|
|||||||
// ETH/DEV Cpp Bootnodes
|
// ETH/DEV Cpp Bootnodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DiscoveryV5Bootnodes are the enode URLs of the P2P bootstrap nodes for the
|
||||||
|
// experimental RLPx v5 topic-discovery network.
|
||||||
|
var DiscoveryV5Bootnodes = []*discv5.Node{
|
||||||
|
discv5.MustParseNode("enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30305"),
|
||||||
|
discv5.MustParseNode("enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308"),
|
||||||
|
discv5.MustParseNode("enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309"),
|
||||||
|
}
|
||||||
|
|
||||||
// MainnetChainConfig is the chain parameters to run a node on the main network.
|
// MainnetChainConfig is the chain parameters to run a node on the main network.
|
||||||
var MainnetChainConfig = &core.ChainConfig{
|
var MainnetChainConfig = &core.ChainConfig{
|
||||||
HomesteadBlock: params.MainNetHomesteadBlock,
|
HomesteadBlock: params.MainNetHomesteadBlock,
|
||||||
|
@ -46,6 +46,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
@ -505,13 +506,36 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
|||||||
return bootnodes
|
return bootnodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line
|
||||||
|
// flags, reverting to pre-configured ones if none have been specified.
|
||||||
|
func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
|
||||||
|
// Return pre-configured nodes if none were manually requested
|
||||||
|
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||||
|
return DiscoveryV5Bootnodes
|
||||||
|
}
|
||||||
|
// Otherwise parse and use the CLI bootstrap nodes
|
||||||
|
bootnodes := []*discv5.Node{}
|
||||||
|
|
||||||
|
for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") {
|
||||||
|
node, err := discv5.ParseNode(url)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bootnodes = append(bootnodes, node)
|
||||||
|
}
|
||||||
|
return bootnodes
|
||||||
|
}
|
||||||
|
|
||||||
// MakeListenAddress creates a TCP listening address string from set command
|
// MakeListenAddress creates a TCP listening address string from set command
|
||||||
// line flags.
|
// line flags.
|
||||||
func MakeListenAddress(ctx *cli.Context) string {
|
func MakeListenAddress(ctx *cli.Context) string {
|
||||||
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
|
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeListenAddressV5(ctx *cli.Context) string {
|
// MakeDiscoveryV5Address creates a UDP listening address string from set command
|
||||||
|
// line flags for the V5 discovery protocol.
|
||||||
|
func MakeDiscoveryV5Address(ctx *cli.Context) string {
|
||||||
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1)
|
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,9 +671,10 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
|
|||||||
UserIdent: makeNodeUserIdent(ctx),
|
UserIdent: makeNodeUserIdent(ctx),
|
||||||
NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name),
|
NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name),
|
||||||
DiscoveryV5: ctx.GlobalBool(DiscoveryV5Flag.Name) || ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0,
|
DiscoveryV5: ctx.GlobalBool(DiscoveryV5Flag.Name) || ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0,
|
||||||
|
DiscoveryV5Addr: MakeDiscoveryV5Address(ctx),
|
||||||
BootstrapNodes: MakeBootstrapNodes(ctx),
|
BootstrapNodes: MakeBootstrapNodes(ctx),
|
||||||
|
BootstrapNodesV5: MakeBootstrapNodesV5(ctx),
|
||||||
ListenAddr: MakeListenAddress(ctx),
|
ListenAddr: MakeListenAddress(ctx),
|
||||||
ListenAddrV5: MakeListenAddressV5(ctx),
|
|
||||||
NAT: MakeNAT(ctx),
|
NAT: MakeNAT(ctx),
|
||||||
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
||||||
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
||||||
|
@ -23,28 +23,14 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MainnetBootnodes returns the enode URLs of the P2P bootstrap nodes running
|
// FoundationBootnodes returns the enode URLs of the P2P bootstrap nodes operated
|
||||||
// on the main network.
|
// by the foundation running the V5 discovery protocol.
|
||||||
//
|
func FoundationBootnodes() *Enodes {
|
||||||
// Note, this needs to be a method to prevent gomobile generating a setter for it.
|
nodes := &Enodes{nodes: make([]*discv5.Node, len(utils.DiscoveryV5Bootnodes))}
|
||||||
func MainnetBootnodes() *Enodes {
|
for i, node := range utils.DiscoveryV5Bootnodes {
|
||||||
nodes := &Enodes{nodes: make([]*discover.Node, len(utils.MainnetBootnodes))}
|
|
||||||
for i, node := range utils.MainnetBootnodes {
|
|
||||||
nodes.nodes[i] = node
|
|
||||||
}
|
|
||||||
return nodes
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestnetBootnodes returns the enode URLs of the P2P bootstrap nodes running
|
|
||||||
// on the test network.
|
|
||||||
//
|
|
||||||
// Note, this needs to be a method to prevent gomobile generating a setter for it.
|
|
||||||
func TestnetBootnodes() *Enodes {
|
|
||||||
nodes := &Enodes{nodes: make([]*discover.Node, len(utils.TestnetBootnodes))}
|
|
||||||
for i, node := range utils.TestnetBootnodes {
|
|
||||||
nodes.nodes[i] = node
|
nodes.nodes[i] = node
|
||||||
}
|
}
|
||||||
return nodes
|
return nodes
|
||||||
@ -52,7 +38,7 @@ func TestnetBootnodes() *Enodes {
|
|||||||
|
|
||||||
// Enode represents a host on the network.
|
// Enode represents a host on the network.
|
||||||
type Enode struct {
|
type Enode struct {
|
||||||
node *discover.Node
|
node *discv5.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnode parses a node designator.
|
// NewEnode parses a node designator.
|
||||||
@ -79,7 +65,7 @@ type Enode struct {
|
|||||||
//
|
//
|
||||||
// enode://<hex node id>@10.3.58.6:30303?discport=30301
|
// enode://<hex node id>@10.3.58.6:30303?discport=30301
|
||||||
func NewEnode(rawurl string) (*Enode, error) {
|
func NewEnode(rawurl string) (*Enode, error) {
|
||||||
node, err := discover.ParseNode(rawurl)
|
node, err := discv5.ParseNode(rawurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -87,12 +73,12 @@ func NewEnode(rawurl string) (*Enode, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Enodes represents a slice of accounts.
|
// Enodes represents a slice of accounts.
|
||||||
type Enodes struct{ nodes []*discover.Node }
|
type Enodes struct{ nodes []*discv5.Node }
|
||||||
|
|
||||||
// NewEnodes creates a slice of uninitialized enodes.
|
// NewEnodes creates a slice of uninitialized enodes.
|
||||||
func NewEnodes(size int) *Enodes {
|
func NewEnodes(size int) *Enodes {
|
||||||
return &Enodes{
|
return &Enodes{
|
||||||
nodes: make([]*discover.Node, size),
|
nodes: make([]*discv5.Node, size),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,11 +78,11 @@ type NodeConfig struct {
|
|||||||
// defaultNodeConfig contains the default node configuration values to use if all
|
// defaultNodeConfig contains the default node configuration values to use if all
|
||||||
// or some fields are missing from the user's specified list.
|
// or some fields are missing from the user's specified list.
|
||||||
var defaultNodeConfig = &NodeConfig{
|
var defaultNodeConfig = &NodeConfig{
|
||||||
BootstrapNodes: MainnetBootnodes(),
|
BootstrapNodes: FoundationBootnodes(),
|
||||||
MaxPeers: 25,
|
MaxPeers: 25,
|
||||||
EthereumEnabled: true,
|
EthereumEnabled: true,
|
||||||
EthereumNetworkID: 1,
|
EthereumNetworkID: 1,
|
||||||
EthereumChainConfig: MainnetChainConfig,
|
EthereumChainConfig: MainnetChainConfig(),
|
||||||
EthereumDatabaseCache: 16,
|
EthereumDatabaseCache: 16,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,17 +106,21 @@ func NewNode(datadir string, config *NodeConfig) (*Node, error) {
|
|||||||
if config.MaxPeers == 0 {
|
if config.MaxPeers == 0 {
|
||||||
config.MaxPeers = defaultNodeConfig.MaxPeers
|
config.MaxPeers = defaultNodeConfig.MaxPeers
|
||||||
}
|
}
|
||||||
|
if config.BootstrapNodes == nil || config.BootstrapNodes.Size() == 0 {
|
||||||
|
config.BootstrapNodes = defaultNodeConfig.BootstrapNodes
|
||||||
|
}
|
||||||
// Create the empty networking stack
|
// Create the empty networking stack
|
||||||
nodeConf := &node.Config{
|
nodeConf := &node.Config{
|
||||||
Name: clientIdentifier,
|
Name: clientIdentifier,
|
||||||
DataDir: datadir,
|
DataDir: datadir,
|
||||||
KeyStoreDir: filepath.Join(datadir, "keystore"), // Mobile should never use internal keystores!
|
KeyStoreDir: filepath.Join(datadir, "keystore"), // Mobile should never use internal keystores!
|
||||||
NoDiscovery: true,
|
NoDiscovery: true,
|
||||||
DiscoveryV5: true,
|
DiscoveryV5: true,
|
||||||
BootstrapNodes: config.BootstrapNodes.nodes,
|
DiscoveryV5Addr: ":0",
|
||||||
ListenAddr: ":0",
|
BootstrapNodesV5: config.BootstrapNodes.nodes,
|
||||||
NAT: nat.Any(),
|
ListenAddr: ":0",
|
||||||
MaxPeers: config.MaxPeers,
|
NAT: nat.Any(),
|
||||||
|
MaxPeers: config.MaxPeers,
|
||||||
}
|
}
|
||||||
stack, err := node.New(nodeConf)
|
stack, err := node.New(nodeConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -95,16 +96,23 @@ type Config struct {
|
|||||||
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
||||||
NoDiscovery bool
|
NoDiscovery bool
|
||||||
|
|
||||||
|
// DiscoveryV5 specifies whether the the new topic-discovery based V5 discovery
|
||||||
|
// protocol should be started or not.
|
||||||
DiscoveryV5 bool
|
DiscoveryV5 bool
|
||||||
|
|
||||||
// Bootstrap nodes used to establish connectivity with the rest of the network.
|
// Listener address for the V5 discovery protocol UDP traffic.
|
||||||
|
DiscoveryV5Addr string
|
||||||
|
|
||||||
|
// BootstrapNodes used to establish connectivity with the rest of the network.
|
||||||
BootstrapNodes []*discover.Node
|
BootstrapNodes []*discover.Node
|
||||||
|
|
||||||
|
// BootstrapNodesV5 used to establish connectivity with the rest of the network
|
||||||
|
// using the V5 discovery protocol.
|
||||||
|
BootstrapNodesV5 []*discv5.Node
|
||||||
|
|
||||||
// Network interface address on which the node should listen for inbound peers.
|
// Network interface address on which the node should listen for inbound peers.
|
||||||
ListenAddr string
|
ListenAddr string
|
||||||
|
|
||||||
ListenAddrV5 string
|
|
||||||
|
|
||||||
// If set to a non-nil value, the given NAT port mapper is used to make the
|
// If set to a non-nil value, the given NAT port mapper is used to make the
|
||||||
// listening port available to the Internet.
|
// listening port available to the Internet.
|
||||||
NAT nat.Interface
|
NAT nat.Interface
|
||||||
|
31
node/node.go
31
node/node.go
@ -154,21 +154,22 @@ func (n *Node) Start() error {
|
|||||||
// Initialize the p2p server. This creates the node key and
|
// Initialize the p2p server. This creates the node key and
|
||||||
// discovery databases.
|
// discovery databases.
|
||||||
n.serverConfig = p2p.Config{
|
n.serverConfig = p2p.Config{
|
||||||
PrivateKey: n.config.NodeKey(),
|
PrivateKey: n.config.NodeKey(),
|
||||||
Name: n.config.NodeName(),
|
Name: n.config.NodeName(),
|
||||||
Discovery: !n.config.NoDiscovery,
|
Discovery: !n.config.NoDiscovery,
|
||||||
DiscoveryV5: n.config.DiscoveryV5,
|
DiscoveryV5: n.config.DiscoveryV5,
|
||||||
BootstrapNodes: n.config.BootstrapNodes,
|
DiscoveryV5Addr: n.config.DiscoveryV5Addr,
|
||||||
StaticNodes: n.config.StaticNodes(),
|
BootstrapNodes: n.config.BootstrapNodes,
|
||||||
TrustedNodes: n.config.TrusterNodes(),
|
BootstrapNodesV5: n.config.BootstrapNodesV5,
|
||||||
NodeDatabase: n.config.NodeDB(),
|
StaticNodes: n.config.StaticNodes(),
|
||||||
ListenAddr: n.config.ListenAddr,
|
TrustedNodes: n.config.TrusterNodes(),
|
||||||
ListenAddrV5: n.config.ListenAddrV5,
|
NodeDatabase: n.config.NodeDB(),
|
||||||
NAT: n.config.NAT,
|
ListenAddr: n.config.ListenAddr,
|
||||||
Dialer: n.config.Dialer,
|
NAT: n.config.NAT,
|
||||||
NoDial: n.config.NoDial,
|
Dialer: n.config.Dialer,
|
||||||
MaxPeers: n.config.MaxPeers,
|
NoDial: n.config.NoDial,
|
||||||
MaxPendingPeers: n.config.MaxPendingPeers,
|
MaxPeers: n.config.MaxPeers,
|
||||||
|
MaxPendingPeers: n.config.MaxPendingPeers,
|
||||||
}
|
}
|
||||||
running := &p2p.Server{Config: n.serverConfig}
|
running := &p2p.Server{Config: n.serverConfig}
|
||||||
glog.V(logger.Info).Infoln("instance:", n.serverConfig.Name)
|
glog.V(logger.Info).Infoln("instance:", n.serverConfig.Name)
|
||||||
|
@ -60,14 +60,6 @@ func debugLog(s string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BootNodes are the enode URLs of the P2P bootstrap nodes for the experimental RLPx v5 "Topic Discovery" network
|
|
||||||
// warning: local bootnodes for testing!!!
|
|
||||||
var BootNodes = []*Node{
|
|
||||||
MustParseNode("enode://0cc5f5ffb5d9098c8b8c62325f3797f56509bff942704687b6530992ac706e2cb946b90a34f1f19548cd3c7baccbcaea354531e5983c7d1bc0dee16ce4b6440b@40.118.3.223:30305"),
|
|
||||||
MustParseNode("enode://1c7a64d76c0334b0418c004af2f67c50e36a3be60b5e4790bdac0439d21603469a85fad36f2473c9a80eb043ae60936df905fa28f1ff614c3e5dc34f15dcd2dc@40.118.3.223:30308"),
|
|
||||||
MustParseNode("enode://85c85d7143ae8bb96924f2b54f1b3e70d8c4d367af305325d30a61385a432f247d2c75c45c6b4a60335060d072d7f5b35dd1d4c45f76941f62a4f83b6e75daaf@40.118.3.223:30309"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Network manages the table and all protocol interaction.
|
// Network manages the table and all protocol interaction.
|
||||||
type Network struct {
|
type Network struct {
|
||||||
db *nodeDB // database of known nodes
|
db *nodeDB // database of known nodes
|
||||||
|
@ -73,16 +73,26 @@ type Config struct {
|
|||||||
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
// or not. Disabling is usually useful for protocol debugging (manual topology).
|
||||||
Discovery bool
|
Discovery bool
|
||||||
|
|
||||||
|
// DiscoveryV5 specifies whether the the new topic-discovery based V5 discovery
|
||||||
|
// protocol should be started or not.
|
||||||
DiscoveryV5 bool
|
DiscoveryV5 bool
|
||||||
|
|
||||||
|
// Listener address for the V5 discovery protocol UDP traffic.
|
||||||
|
DiscoveryV5Addr string
|
||||||
|
|
||||||
// Name sets the node name of this server.
|
// Name sets the node name of this server.
|
||||||
// Use common.MakeName to create a name that follows existing conventions.
|
// Use common.MakeName to create a name that follows existing conventions.
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
// Bootstrap nodes are used to establish connectivity
|
// BootstrapNodes are used to establish connectivity
|
||||||
// with the rest of the network.
|
// with the rest of the network.
|
||||||
BootstrapNodes []*discover.Node
|
BootstrapNodes []*discover.Node
|
||||||
|
|
||||||
|
// BootstrapNodesV5 are used to establish connectivity
|
||||||
|
// with the rest of the network using the V5 discovery
|
||||||
|
// protocol.
|
||||||
|
BootstrapNodesV5 []*discv5.Node
|
||||||
|
|
||||||
// Static nodes are used as pre-configured connections which are always
|
// Static nodes are used as pre-configured connections which are always
|
||||||
// maintained and re-connected on disconnects.
|
// maintained and re-connected on disconnects.
|
||||||
StaticNodes []*discover.Node
|
StaticNodes []*discover.Node
|
||||||
@ -108,8 +118,6 @@ type Config struct {
|
|||||||
// the server is started.
|
// the server is started.
|
||||||
ListenAddr string
|
ListenAddr string
|
||||||
|
|
||||||
ListenAddrV5 string
|
|
||||||
|
|
||||||
// If set to a non-nil value, the given NAT port mapper
|
// If set to a non-nil value, the given NAT port mapper
|
||||||
// is used to make the listening port available to the
|
// is used to make the listening port available to the
|
||||||
// Internet.
|
// Internet.
|
||||||
@ -359,11 +367,11 @@ func (srv *Server) Start() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if srv.DiscoveryV5 {
|
if srv.DiscoveryV5 {
|
||||||
ntab, err := discv5.ListenUDP(srv.PrivateKey, srv.ListenAddrV5, srv.NAT, "") //srv.NodeDatabase)
|
ntab, err := discv5.ListenUDP(srv.PrivateKey, srv.DiscoveryV5Addr, srv.NAT, "") //srv.NodeDatabase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := ntab.SetFallbackNodes(discv5.BootNodes); err != nil {
|
if err := ntab.SetFallbackNodes(srv.BootstrapNodesV5); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
srv.DiscV5 = ntab
|
srv.DiscV5 = ntab
|
||||||
|
Loading…
Reference in New Issue
Block a user