forked from TrueCloudLab/neoneo-go
network: allow multiple bind addresses for server
And replace Transporter.Address() with Transporter.HostPort() along the way.
This commit is contained in:
parent
9087854b1e
commit
9cf6cc61f4
32 changed files with 538 additions and 161 deletions
21
ROADMAP.md
21
ROADMAP.md
|
@ -103,15 +103,20 @@ change, just replace one line.
|
||||||
|
|
||||||
Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release).
|
Removal of SecondsPerBlock is scheduled for May-June 2023 (~0.103.0 release).
|
||||||
|
|
||||||
## Services address and port configuration
|
## Services/node address and port configuration
|
||||||
|
|
||||||
Version 0.100.0 of NeoGo introduces a multiple binding addresses capability to
|
Version 0.100.0 of NeoGo introduces a multiple binding addresses capability to
|
||||||
the node's services (RPC server, TLS RPC configuration, Prometheus, Pprof)
|
the node's services (RPC server, TLS RPC configuration, Prometheus, Pprof) and
|
||||||
that allows to specify several listen addresses/ports using an array of
|
the node itself. It allows to specify several listen addresses/ports using an
|
||||||
"address:port" pairs in the service `Addresses` config section. Deprecated
|
array of "address:port" pairs in the service's `Addresses` config section and
|
||||||
`Address` and `Port` sections of `RPC`, `Prometheus`, `Pprof` subsections of the
|
array of "address:port:announcedPort" tuples in the `ApplicationConfiguration`'s
|
||||||
`ApplicationConfiguration` as far as the one of RPC server's `TLSConfig` are
|
`Addresses` node config section. Deprecated `Address` and `Port` sections of
|
||||||
still available, but will be removed, so please convert your node configuration
|
`RPC`, `Prometheus`, `Pprof` subsections of the `ApplicationConfiguration`
|
||||||
file to use new `Addresses` section for node services.
|
as far as the one of RPC server's `TLSConfig` are still available, but will be
|
||||||
|
removed, so please convert your node configuration file to use new `Addresses`
|
||||||
|
section for the node services. Deprecated `Address`, `NodePort` and `AnnouncedPort`
|
||||||
|
sections of `ApplicationConfiguration` will also be removed eventually, so please
|
||||||
|
update your node configuration file to use `Addresses` section for the P2P
|
||||||
|
addresses configuration.
|
||||||
|
|
||||||
Removal of these config sections is scheduled for May-June 2023 (~0.103.0 release).
|
Removal of these config sections is scheduled for May-June 2023 (~0.103.0 release).
|
|
@ -446,7 +446,10 @@ func startServer(ctx *cli.Context) error {
|
||||||
grace, cancel := context.WithCancel(newGraceContext())
|
grace, cancel := context.WithCancel(newGraceContext())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig, err := network.NewServerConfig(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return cli.NewExitError(err, 1)
|
||||||
|
}
|
||||||
|
|
||||||
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
chain, prometheus, pprof, err := initBCWithMetrics(cfg, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -635,15 +638,15 @@ Main:
|
||||||
// In case global Address (of the node) provided and RPC/Prometheus/Pprof don't have configured addresses they will
|
// In case global Address (of the node) provided and RPC/Prometheus/Pprof don't have configured addresses they will
|
||||||
// use global one. So Node and RPC and Prometheus and Pprof will run on one address.
|
// use global one. So Node and RPC and Prometheus and Pprof will run on one address.
|
||||||
func configureAddresses(cfg *config.ApplicationConfiguration) {
|
func configureAddresses(cfg *config.ApplicationConfiguration) {
|
||||||
if cfg.Address != "" {
|
if cfg.Address != nil && *cfg.Address != "" { //nolint:staticcheck // SA1019: cfg.Address is deprecated
|
||||||
if cfg.RPC.Address == nil || *cfg.RPC.Address == "" {
|
if cfg.RPC.Address == nil || *cfg.RPC.Address == "" { //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||||
cfg.RPC.Address = &cfg.Address
|
cfg.RPC.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||||
}
|
}
|
||||||
if cfg.Prometheus.Address == nil || *cfg.Prometheus.Address == "" {
|
if cfg.Prometheus.Address == nil || *cfg.Prometheus.Address == "" { //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||||
cfg.Prometheus.Address = &cfg.Address
|
cfg.Prometheus.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Prometheus.Address is deprecated
|
||||||
}
|
}
|
||||||
if cfg.Pprof.Address == nil || *cfg.Pprof.Address == "" {
|
if cfg.Pprof.Address == nil || *cfg.Pprof.Address == "" { //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||||
cfg.Pprof.Address = &cfg.Address
|
cfg.Pprof.Address = cfg.Address //nolint:staticcheck // SA1019: cfg.Pprof.Address is deprecated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,13 +312,15 @@ func TestRestoreDB(t *testing.T) {
|
||||||
require.NoError(t, restoreDB(ctx))
|
require.NoError(t, restoreDB(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestConfigureAddresses checks deprecated code compatibility, it should be removed
|
||||||
|
// along with deprecated `Address` field removal.
|
||||||
func TestConfigureAddresses(t *testing.T) {
|
func TestConfigureAddresses(t *testing.T) {
|
||||||
defaultAddress := "http://localhost:10333"
|
defaultAddress := "http://localhost:10333"
|
||||||
customAddress := "http://localhost:10334"
|
customAddress := "http://localhost:10334"
|
||||||
|
|
||||||
t.Run("default addresses", func(t *testing.T) {
|
t.Run("default addresses", func(t *testing.T) {
|
||||||
cfg := &config.ApplicationConfiguration{
|
cfg := &config.ApplicationConfiguration{
|
||||||
Address: defaultAddress,
|
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||||
}
|
}
|
||||||
configureAddresses(cfg)
|
configureAddresses(cfg)
|
||||||
require.Equal(t, defaultAddress, *cfg.RPC.Address) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
require.Equal(t, defaultAddress, *cfg.RPC.Address) //nolint:staticcheck // SA1019: cfg.RPC.Address is deprecated
|
||||||
|
@ -328,10 +330,10 @@ func TestConfigureAddresses(t *testing.T) {
|
||||||
|
|
||||||
t.Run("custom RPC address", func(t *testing.T) {
|
t.Run("custom RPC address", func(t *testing.T) {
|
||||||
cfg := &config.ApplicationConfiguration{
|
cfg := &config.ApplicationConfiguration{
|
||||||
Address: defaultAddress,
|
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||||
RPC: config.RPC{
|
RPC: config.RPC{
|
||||||
BasicService: config.BasicService{
|
BasicService: config.BasicService{
|
||||||
Address: &customAddress,
|
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -343,9 +345,9 @@ func TestConfigureAddresses(t *testing.T) {
|
||||||
|
|
||||||
t.Run("custom Pprof address", func(t *testing.T) {
|
t.Run("custom Pprof address", func(t *testing.T) {
|
||||||
cfg := &config.ApplicationConfiguration{
|
cfg := &config.ApplicationConfiguration{
|
||||||
Address: defaultAddress,
|
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||||
Pprof: config.BasicService{
|
Pprof: config.BasicService{
|
||||||
Address: &customAddress,
|
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
configureAddresses(cfg)
|
configureAddresses(cfg)
|
||||||
|
@ -356,9 +358,9 @@ func TestConfigureAddresses(t *testing.T) {
|
||||||
|
|
||||||
t.Run("custom Prometheus address", func(t *testing.T) {
|
t.Run("custom Prometheus address", func(t *testing.T) {
|
||||||
cfg := &config.ApplicationConfiguration{
|
cfg := &config.ApplicationConfiguration{
|
||||||
Address: defaultAddress,
|
Address: &defaultAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||||
Prometheus: config.BasicService{
|
Prometheus: config.BasicService{
|
||||||
Address: &customAddress,
|
Address: &customAddress, //nolint:staticcheck // SA1019: Address is deprecated
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
configureAddresses(cfg)
|
configureAddresses(cfg)
|
||||||
|
|
|
@ -47,9 +47,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "./chains/mainnet.neofs"
|
DataDirectoryPath: "./chains/mainnet.neofs"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/mainnet.bolt"
|
# FilePath: "./chains/mainnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":40333" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 40333
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -59,9 +59,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "./chains/mainnet"
|
DataDirectoryPath: "./chains/mainnet"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/mainnet.bolt"
|
# FilePath: "./chains/mainnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":10333" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 10333
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -39,8 +39,8 @@ ApplicationConfiguration:
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
# Uncomment in order to set up custom address for node.
|
||||||
# Address: localhost
|
Addresses:
|
||||||
NodePort: 20336
|
- ":20336" # in form of "[host]:[port][:announcedPort]"
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -38,9 +38,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "/chains/one"
|
DataDirectoryPath: "/chains/one"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":20333" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 20333
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -32,9 +32,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "/chains/single"
|
DataDirectoryPath: "/chains/single"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":20333" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 20333
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -38,9 +38,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "/chains/three"
|
DataDirectoryPath: "/chains/three"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":20335" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 20335
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -38,9 +38,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "/chains/two"
|
DataDirectoryPath: "/chains/two"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":20334" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 20334
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -38,9 +38,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "./chains/privnet"
|
DataDirectoryPath: "./chains/privnet"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/privnet.bolt"
|
# FilePath: "./chains/privnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":20332" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 20332
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -47,9 +47,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "./chains/testnet.neofs"
|
DataDirectoryPath: "./chains/testnet.neofs"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/testnet.bolt"
|
# FilePath: "./chains/testnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":50333" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 50333
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -62,9 +62,8 @@ ApplicationConfiguration:
|
||||||
DataDirectoryPath: "./chains/testnet"
|
DataDirectoryPath: "./chains/testnet"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/testnet.bolt"
|
# FilePath: "./chains/testnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":20333" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 20333
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -33,9 +33,8 @@ ApplicationConfiguration:
|
||||||
# DataDirectoryPath: "./chains/unit_testnet"
|
# DataDirectoryPath: "./chains/unit_testnet"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/unit_testnet.bolt"
|
# FilePath: "./chains/unit_testnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":0" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 0
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -42,9 +42,8 @@ ApplicationConfiguration:
|
||||||
# DataDirectoryPath: "./chains/unit_testnet"
|
# DataDirectoryPath: "./chains/unit_testnet"
|
||||||
# BoltDBOptions:
|
# BoltDBOptions:
|
||||||
# FilePath: "./chains/unit_testnet.bolt"
|
# FilePath: "./chains/unit_testnet.bolt"
|
||||||
# Uncomment in order to set up custom address for node.
|
Addresses:
|
||||||
# Address: localhost
|
- ":20333" # in form of "[host]:[port][:announcedPort]"
|
||||||
NodePort: 20333
|
|
||||||
Relay: true
|
Relay: true
|
||||||
DialTimeout: 3
|
DialTimeout: 3
|
||||||
ProtoTickInterval: 2
|
ProtoTickInterval: 2
|
||||||
|
|
|
@ -16,8 +16,9 @@ node-related settings described in the table below.
|
||||||
|
|
||||||
| Section | Type | Default value | Description |
|
| Section | Type | Default value | Description |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Address | `string` | `0.0.0.0` | Node address that P2P protocol handler binds to. |
|
| Address | `string` | `0.0.0.0` | Node address that P2P protocol handler binds to. Warning: this field is deprecated, please, use `Addresses` instead. |
|
||||||
| AnnouncedPort | `uint16` | Same as `NodePort` | Node port which should be used to announce node's port on P2P layer, it can differ from the `NodePort` the node is bound to (for example, if your node is behind NAT). |
|
| AnnouncedPort | `uint16` | Same as `NodePort` | Node port which should be used to announce node's port on P2P layer, it can differ from the `NodePort` the node is bound to (for example, if your node is behind NAT). Warning: this field is deprecated, please, use `Addresses` instead. |
|
||||||
|
| Addresses | `[]string` | `["0.0.0.0:0"]`, which is any free port on all available addresses | List of the node addresses that P2P protocol handler binds to. Each address has the form of `[address]:[nodePort][:announcedPort]` where `address` is the address itself, `nodePort` is the actual P2P port node listens at; `announcedPort` is the node port which should be used to announce node's port on P2P layer, it can differ from the `nodePort` the node is bound to if specified (for example, if your node is behind NAT).|
|
||||||
| AttemptConnPeers | `int` | `20` | Number of connection to try to establish when the connection count drops below the `MinPeers` value.|
|
| AttemptConnPeers | `int` | `20` | Number of connection to try to establish when the connection count drops below the `MinPeers` value.|
|
||||||
| BroadcastFactor | `int` | `0` | Multiplier that is used to determine the number of optimal gossip fan-out peer number for broadcasted messages (0-100). By default it's zero, node uses the most optimized value depending on the estimated network size (`2.5×log(size)`), so the node may have 20 peers and calculate that it needs to broadcast messages to just 10 of them. With BroadcastFactor set to 100 it will always send messages to all peers, any value in-between 0 and 100 is used for weighted calculation, for example if it's 30 then 13 neighbors will be used in the previous case. |
|
| BroadcastFactor | `int` | `0` | Multiplier that is used to determine the number of optimal gossip fan-out peer number for broadcasted messages (0-100). By default it's zero, node uses the most optimized value depending on the estimated network size (`2.5×log(size)`), so the node may have 20 peers and calculate that it needs to broadcast messages to just 10 of them. With BroadcastFactor set to 100 it will always send messages to all peers, any value in-between 0 and 100 is used for weighted calculation, for example if it's 30 then 13 neighbors will be used in the previous case. |
|
||||||
| DBConfiguration | [DB Configuration](#DB-Configuration) | | Describes configuration for database. See the [DB Configuration](#DB-Configuration) section for details. |
|
| DBConfiguration | [DB Configuration](#DB-Configuration) | | Describes configuration for database. See the [DB Configuration](#DB-Configuration) section for details. |
|
||||||
|
@ -27,7 +28,7 @@ node-related settings described in the table below.
|
||||||
| LogPath | `string` | "", so only console logging | File path where to store node logs. |
|
| LogPath | `string` | "", so only console logging | File path where to store node logs. |
|
||||||
| MaxPeers | `int` | `100` | Maximum numbers of peers that can be connected to the server. |
|
| MaxPeers | `int` | `100` | Maximum numbers of peers that can be connected to the server. |
|
||||||
| MinPeers | `int` | `5` | Minimum number of peers for normal operation; when the node has less than this number of peers it tries to connect with some new ones. |
|
| MinPeers | `int` | `5` | Minimum number of peers for normal operation; when the node has less than this number of peers it tries to connect with some new ones. |
|
||||||
| NodePort | `uint16` | `0`, which is any free port | The actual node port it is bound to. |
|
| NodePort | `uint16` | `0`, which is any free port | The actual node port it is bound to. Warning: this field is deprecated, please, use `Addresses` instead. |
|
||||||
| Oracle | [Oracle Configuration](#Oracle-Configuration) | | Oracle module configuration. See the [Oracle Configuration](#Oracle-Configuration) section for details. |
|
| Oracle | [Oracle Configuration](#Oracle-Configuration) | | Oracle module configuration. See the [Oracle Configuration](#Oracle-Configuration) section for details. |
|
||||||
| P2PNotary | [P2P Notary Configuration](#P2P-Notary-Configuration) | | P2P Notary module configuration. See the [P2P Notary Configuration](#P2P-Notary-Configuration) section for details. |
|
| P2PNotary | [P2P Notary Configuration](#P2P-Notary-Configuration) | | P2P Notary module configuration. See the [P2P Notary Configuration](#P2P-Notary-Configuration) section for details. |
|
||||||
| PingInterval | `int64` | `30` | Interval in seconds used in pinging mechanism for syncing blocks. |
|
| PingInterval | `int64` | `30` | Interval in seconds used in pinging mechanism for syncing blocks. |
|
||||||
|
|
|
@ -146,7 +146,8 @@ func NewTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
|
||||||
go chain.Run()
|
go chain.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig, err := network.NewServerConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.3-test")
|
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.3-test")
|
||||||
netSrv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), zap.NewNop())
|
netSrv, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), zap.NewNop())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -1,34 +1,45 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ApplicationConfiguration config specific to the node.
|
// ApplicationConfiguration config specific to the node.
|
||||||
type ApplicationConfiguration struct {
|
type ApplicationConfiguration struct {
|
||||||
Address string `yaml:"Address"`
|
// Deprecated: please, use Addresses instead, this field will be removed in future versions.
|
||||||
AnnouncedNodePort uint16 `yaml:"AnnouncedPort"`
|
Address *string `yaml:"Address,omitempty"`
|
||||||
AttemptConnPeers int `yaml:"AttemptConnPeers"`
|
// Addresses stores the node address list in the form of "[host]:[port][:announcedPort]".
|
||||||
|
Addresses []string `yaml:"Addresses"`
|
||||||
|
// Deprecated: please, use Addresses instead, this field will be removed in future versions.
|
||||||
|
AnnouncedNodePort *uint16 `yaml:"AnnouncedPort,omitempty"`
|
||||||
|
AttemptConnPeers int `yaml:"AttemptConnPeers"`
|
||||||
// BroadcastFactor is the factor (0-100) controlling gossip fan-out number optimization.
|
// BroadcastFactor is the factor (0-100) controlling gossip fan-out number optimization.
|
||||||
BroadcastFactor int `yaml:"BroadcastFactor"`
|
BroadcastFactor int `yaml:"BroadcastFactor"`
|
||||||
DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"`
|
DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"`
|
||||||
DialTimeout int64 `yaml:"DialTimeout"`
|
DialTimeout int64 `yaml:"DialTimeout"`
|
||||||
LogLevel string `yaml:"LogLevel"`
|
LogLevel string `yaml:"LogLevel"`
|
||||||
LogPath string `yaml:"LogPath"`
|
LogPath string `yaml:"LogPath"`
|
||||||
MaxPeers int `yaml:"MaxPeers"`
|
MaxPeers int `yaml:"MaxPeers"`
|
||||||
MinPeers int `yaml:"MinPeers"`
|
MinPeers int `yaml:"MinPeers"`
|
||||||
NodePort uint16 `yaml:"NodePort"`
|
// Deprecated: please, use Addresses instead, this field will be removed in future versions.
|
||||||
PingInterval int64 `yaml:"PingInterval"`
|
NodePort *uint16 `yaml:"NodePort,omitempty"`
|
||||||
PingTimeout int64 `yaml:"PingTimeout"`
|
PingInterval int64 `yaml:"PingInterval"`
|
||||||
Pprof BasicService `yaml:"Pprof"`
|
PingTimeout int64 `yaml:"PingTimeout"`
|
||||||
Prometheus BasicService `yaml:"Prometheus"`
|
Pprof BasicService `yaml:"Pprof"`
|
||||||
ProtoTickInterval int64 `yaml:"ProtoTickInterval"`
|
Prometheus BasicService `yaml:"Prometheus"`
|
||||||
Relay bool `yaml:"Relay"`
|
ProtoTickInterval int64 `yaml:"ProtoTickInterval"`
|
||||||
RPC RPC `yaml:"RPC"`
|
Relay bool `yaml:"Relay"`
|
||||||
UnlockWallet Wallet `yaml:"UnlockWallet"`
|
RPC RPC `yaml:"RPC"`
|
||||||
Oracle OracleConfiguration `yaml:"Oracle"`
|
UnlockWallet Wallet `yaml:"UnlockWallet"`
|
||||||
P2PNotary P2PNotary `yaml:"P2PNotary"`
|
Oracle OracleConfiguration `yaml:"Oracle"`
|
||||||
StateRoot StateRoot `yaml:"StateRoot"`
|
P2PNotary P2PNotary `yaml:"P2PNotary"`
|
||||||
|
StateRoot StateRoot `yaml:"StateRoot"`
|
||||||
// ExtensiblePoolSize is the maximum amount of the extensible payloads from a single sender.
|
// ExtensiblePoolSize is the maximum amount of the extensible payloads from a single sender.
|
||||||
ExtensiblePoolSize int `yaml:"ExtensiblePoolSize"`
|
ExtensiblePoolSize int `yaml:"ExtensiblePoolSize"`
|
||||||
}
|
}
|
||||||
|
@ -37,6 +48,20 @@ type ApplicationConfiguration struct {
|
||||||
// (Oracle, P2PNotary, Pprof, Prometheus, RPC, StateRoot and UnlockWallet sections)
|
// (Oracle, P2PNotary, Pprof, Prometheus, RPC, StateRoot and UnlockWallet sections)
|
||||||
// and LogLevel field.
|
// and LogLevel field.
|
||||||
func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration) bool {
|
func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration) bool {
|
||||||
|
if len(a.Addresses) != len(o.Addresses) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
aCp := make([]string, len(a.Addresses))
|
||||||
|
oCp := make([]string, len(o.Addresses))
|
||||||
|
copy(aCp, a.Addresses)
|
||||||
|
copy(oCp, o.Addresses)
|
||||||
|
sort.Strings(aCp)
|
||||||
|
sort.Strings(oCp)
|
||||||
|
for i := range aCp {
|
||||||
|
if aCp[i] != oCp[i] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
if a.Address != o.Address ||
|
if a.Address != o.Address ||
|
||||||
a.AnnouncedNodePort != o.AnnouncedNodePort ||
|
a.AnnouncedNodePort != o.AnnouncedNodePort ||
|
||||||
a.AttemptConnPeers != o.AttemptConnPeers ||
|
a.AttemptConnPeers != o.AttemptConnPeers ||
|
||||||
|
@ -56,3 +81,101 @@ func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AnnounceableAddress is a pair of node address in the form of "[host]:[port]"
|
||||||
|
// with optional corresponding announced port to be used in version exchange.
|
||||||
|
type AnnounceableAddress struct {
|
||||||
|
Address string
|
||||||
|
AnnouncedPort uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAddresses parses returns the list of AnnounceableAddress containing information
|
||||||
|
// gathered from both deprecated Address / NodePort / AnnouncedNodePort and newly
|
||||||
|
// created Addresses fields.
|
||||||
|
func (a *ApplicationConfiguration) GetAddresses() ([]AnnounceableAddress, error) {
|
||||||
|
addrs := make([]AnnounceableAddress, 0, len(a.Addresses)+1)
|
||||||
|
if a.Address != nil || a.NodePort != nil || a.AnnouncedNodePort != nil {
|
||||||
|
var (
|
||||||
|
host string
|
||||||
|
nodePort uint16
|
||||||
|
)
|
||||||
|
if a.Address != nil {
|
||||||
|
host = *a.Address
|
||||||
|
}
|
||||||
|
if a.NodePort != nil {
|
||||||
|
nodePort = *a.NodePort
|
||||||
|
}
|
||||||
|
addr := AnnounceableAddress{Address: net.JoinHostPort(host, strconv.Itoa(int(nodePort)))}
|
||||||
|
if a.AnnouncedNodePort != nil {
|
||||||
|
addr.AnnouncedPort = *a.AnnouncedNodePort
|
||||||
|
}
|
||||||
|
addrs = append(addrs, addr)
|
||||||
|
}
|
||||||
|
for i, addrStr := range a.Addresses {
|
||||||
|
if len(addrStr) == 0 {
|
||||||
|
return nil, fmt.Errorf("address #%d is empty", i)
|
||||||
|
}
|
||||||
|
lastCln := strings.LastIndex(addrStr, ":")
|
||||||
|
if lastCln == -1 {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr, // Plain IPv4 address without port.
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lastPort, err := strconv.ParseUint(addrStr[lastCln+1:], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr, // Still may be a valid IPv4 of the form "X.Y.Z.Q:" or plain IPv6 "A:B::", keep it.
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
penultimateCln := strings.LastIndex(addrStr[:lastCln], ":")
|
||||||
|
if penultimateCln == -1 {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr, // IPv4 address with port "X.Y.Z.Q:123"
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isV6 := strings.Count(addrStr, ":") > 2
|
||||||
|
hasBracket := strings.Contains(addrStr, "]")
|
||||||
|
if penultimateCln == lastCln-1 {
|
||||||
|
if isV6 && !hasBracket {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr, // Plain IPv6 of the form "A:B::123"
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr[:lastCln], // IPv4 with empty port and non-empty announced port "X.Y.Z.Q::123" or IPv6 with non-empty announced port "[A:B::]::123".
|
||||||
|
AnnouncedPort: uint16(lastPort),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
_, err = strconv.ParseUint(addrStr[penultimateCln+1:lastCln], 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
if isV6 {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr, // Still may be a valid plain IPv6 of the form "A::B:123" or IPv6 with single port [A:B::]:123, keep it.
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("failed to parse port from %s: %w", addrStr, err) // Some garbage.
|
||||||
|
}
|
||||||
|
if isV6 && !hasBracket {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr, // Plain IPv6 of the form "A::1:1"
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: addrStr[:lastCln], // IPv4 with both ports or IPv6 with both ports specified.
|
||||||
|
AnnouncedPort: uint16(lastPort),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(addrs) == 0 {
|
||||||
|
addrs = append(addrs, AnnounceableAddress{
|
||||||
|
Address: ":0",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return addrs, nil
|
||||||
|
}
|
||||||
|
|
|
@ -20,3 +20,168 @@ func TestApplicationConfigurationEquals(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.False(t, cfg1.ApplicationConfiguration.EqualsButServices(&cfg2.ApplicationConfiguration))
|
require.False(t, cfg1.ApplicationConfiguration.EqualsButServices(&cfg2.ApplicationConfiguration))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetAddresses(t *testing.T) {
|
||||||
|
type testcase struct {
|
||||||
|
cfg *ApplicationConfiguration
|
||||||
|
expected []AnnounceableAddress
|
||||||
|
shouldFail bool
|
||||||
|
}
|
||||||
|
addr1 := "1.2.3.4"
|
||||||
|
addr2 := "5.6.7.8"
|
||||||
|
addr3 := "4.3.2.1"
|
||||||
|
v6Plain0 := "3731:54:65fe:2::a7"
|
||||||
|
v6Plain1 := "3731:54:65fe:2::1"
|
||||||
|
v6Plain2 := "3731:54:65fe::a:1"
|
||||||
|
v6Plain3 := "3731:54:65fe::1:1"
|
||||||
|
v6Plain4 := "3731:54:65fe:2::"
|
||||||
|
port1 := uint16(1)
|
||||||
|
port2 := uint16(2)
|
||||||
|
port3 := uint16(3)
|
||||||
|
cases := []testcase{
|
||||||
|
// Compatibility with the old behaviour.
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{},
|
||||||
|
expected: []AnnounceableAddress{{Address: ":0"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{Address: &addr1},
|
||||||
|
expected: []AnnounceableAddress{{Address: addr1 + ":0"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{NodePort: &port1},
|
||||||
|
expected: []AnnounceableAddress{{Address: ":1"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{AnnouncedNodePort: &port1},
|
||||||
|
expected: []AnnounceableAddress{{Address: ":0", AnnouncedPort: port1}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{Address: &addr1, NodePort: &port1},
|
||||||
|
expected: []AnnounceableAddress{{Address: addr1 + ":1"}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{Address: &addr1, AnnouncedNodePort: &port1},
|
||||||
|
expected: []AnnounceableAddress{{Address: addr1 + ":0", AnnouncedPort: port1}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{NodePort: &port1, AnnouncedNodePort: &port2},
|
||||||
|
expected: []AnnounceableAddress{{Address: ":1", AnnouncedPort: port2}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{NodePort: &port1, AnnouncedNodePort: &port2},
|
||||||
|
expected: []AnnounceableAddress{{Address: ":1", AnnouncedPort: port2}},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{Address: &addr1, NodePort: &port1, AnnouncedNodePort: &port2},
|
||||||
|
expected: []AnnounceableAddress{{Address: addr1 + ":1", AnnouncedPort: port2}},
|
||||||
|
},
|
||||||
|
// Compatibility with new multi-addresses.
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Address: &addr1, NodePort: &port1, AnnouncedNodePort: &port2,
|
||||||
|
Addresses: []string{addr1, addr2 + ":3", addr3 + ":1:3"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: addr1 + ":1", AnnouncedPort: port2},
|
||||||
|
{Address: addr1},
|
||||||
|
{Address: addr2 + ":3"},
|
||||||
|
{Address: addr3 + ":1", AnnouncedPort: port3},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// Multi-addresses checks.
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{addr1},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: addr1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{":1"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: ":1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{"::1"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: ":", AnnouncedPort: port1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{addr1 + ":1"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: addr1 + ":1"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{addr1 + "::1"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: addr1 + ":", AnnouncedPort: port1},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{addr1 + ":1:2"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: addr1 + ":1", AnnouncedPort: port2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{addr1 + ":1", addr2 + "::2"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: addr1 + ":1"},
|
||||||
|
{Address: addr2 + ":", AnnouncedPort: port2},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{v6Plain0, v6Plain1, v6Plain2, v6Plain3, v6Plain4},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: v6Plain0},
|
||||||
|
{Address: v6Plain1},
|
||||||
|
{Address: v6Plain2},
|
||||||
|
{Address: v6Plain3},
|
||||||
|
{Address: v6Plain4},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{"[3731:54:65fe:2::]:123", "[3731:54:65fe:2::]:123:124"},
|
||||||
|
},
|
||||||
|
expected: []AnnounceableAddress{
|
||||||
|
{Address: "[3731:54:65fe:2::]:123"},
|
||||||
|
{Address: "[3731:54:65fe:2::]:123", AnnouncedPort: 124},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
cfg: &ApplicationConfiguration{
|
||||||
|
Addresses: []string{"127.0.0.1:QWER:123"},
|
||||||
|
},
|
||||||
|
shouldFail: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for i, c := range cases {
|
||||||
|
actual, err := c.cfg.GetAddresses()
|
||||||
|
if c.shouldFail {
|
||||||
|
require.Error(t, err, i)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, c.expected, actual, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -20,7 +20,8 @@ type fakeTransp struct {
|
||||||
started atomic2.Bool
|
started atomic2.Bool
|
||||||
closed atomic2.Bool
|
closed atomic2.Bool
|
||||||
dialCh chan string
|
dialCh chan string
|
||||||
addr string
|
host string
|
||||||
|
port string
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeAPeer struct {
|
type fakeAPeer struct {
|
||||||
|
@ -45,8 +46,14 @@ func (f *fakeAPeer) Version() *payload.Version {
|
||||||
return f.version
|
return f.version
|
||||||
}
|
}
|
||||||
|
|
||||||
func newFakeTransp(s *Server) Transporter {
|
func newFakeTransp(s *Server, addr string) Transporter {
|
||||||
return &fakeTransp{}
|
tr := &fakeTransp{}
|
||||||
|
h, p, err := net.SplitHostPort(addr)
|
||||||
|
if err == nil {
|
||||||
|
tr.host = h
|
||||||
|
tr.port = p
|
||||||
|
}
|
||||||
|
return tr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ft *fakeTransp) Dial(addr string, timeout time.Duration) (AddressablePeer, error) {
|
func (ft *fakeTransp) Dial(addr string, timeout time.Duration) (AddressablePeer, error) {
|
||||||
|
@ -62,14 +69,15 @@ func (ft *fakeTransp) Accept() {
|
||||||
if ft.started.Load() {
|
if ft.started.Load() {
|
||||||
panic("started twice")
|
panic("started twice")
|
||||||
}
|
}
|
||||||
ft.addr = net.JoinHostPort("0.0.0.0", "42")
|
ft.host = "0.0.0.0"
|
||||||
|
ft.port = "42"
|
||||||
ft.started.Store(true)
|
ft.started.Store(true)
|
||||||
}
|
}
|
||||||
func (ft *fakeTransp) Proto() string {
|
func (ft *fakeTransp) Proto() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
func (ft *fakeTransp) Address() string {
|
func (ft *fakeTransp) HostPort() (string, string) {
|
||||||
return ft.addr
|
return ft.host, ft.port
|
||||||
}
|
}
|
||||||
func (ft *fakeTransp) Close() {
|
func (ft *fakeTransp) Close() {
|
||||||
if ft.closed.Load() {
|
if ft.closed.Load() {
|
||||||
|
|
|
@ -158,7 +158,7 @@ func (p *localPeer) HandleVersion(v *payload.Version) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
func (p *localPeer) SendVersion() error {
|
func (p *localPeer) SendVersion() error {
|
||||||
m, err := p.server.getVersionMsg()
|
m, err := p.server.getVersionMsg(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -208,6 +208,10 @@ func newTestServer(t *testing.T, serverConfig ServerConfig) *Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTestServerWithCustomCfg(t *testing.T, serverConfig ServerConfig, protocolCfg func(*config.ProtocolConfiguration)) *Server {
|
func newTestServerWithCustomCfg(t *testing.T, serverConfig ServerConfig, protocolCfg func(*config.ProtocolConfiguration)) *Server {
|
||||||
|
if len(serverConfig.Addresses) == 0 {
|
||||||
|
// Normally it will be done by ApplicationConfiguration.GetAddresses().
|
||||||
|
serverConfig.Addresses = []config.AnnounceableAddress{{Address: ":0"}}
|
||||||
|
}
|
||||||
s, err := newServerFromConstructors(serverConfig, fakechain.NewFakeChainWithCustomCfg(protocolCfg), new(fakechain.FakeStateSync), zaptest.NewLogger(t),
|
s, err := newServerFromConstructors(serverConfig, fakechain.NewFakeChainWithCustomCfg(protocolCfg), new(fakechain.FakeStateSync), zaptest.NewLogger(t),
|
||||||
newFakeTransp, newTestDiscovery)
|
newFakeTransp, newTestDiscovery)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
|
@ -97,7 +97,7 @@ type (
|
||||||
// A copy of the Ledger's config.
|
// A copy of the Ledger's config.
|
||||||
config config.ProtocolConfiguration
|
config config.ProtocolConfiguration
|
||||||
|
|
||||||
transport Transporter
|
transports []Transporter
|
||||||
discovery Discoverer
|
discovery Discoverer
|
||||||
chain Ledger
|
chain Ledger
|
||||||
bQueue *blockQueue
|
bQueue *blockQueue
|
||||||
|
@ -154,13 +154,13 @@ func randomID() uint32 {
|
||||||
|
|
||||||
// NewServer returns a new Server, initialized with the given configuration.
|
// NewServer returns a new Server, initialized with the given configuration.
|
||||||
func NewServer(config ServerConfig, chain Ledger, stSync StateSync, log *zap.Logger) (*Server, error) {
|
func NewServer(config ServerConfig, chain Ledger, stSync StateSync, log *zap.Logger) (*Server, error) {
|
||||||
return newServerFromConstructors(config, chain, stSync, log, func(s *Server) Transporter {
|
return newServerFromConstructors(config, chain, stSync, log, func(s *Server, addr string) Transporter {
|
||||||
return NewTCPTransport(s, net.JoinHostPort(s.ServerConfig.Address, strconv.Itoa(int(s.ServerConfig.Port))), s.log)
|
return NewTCPTransport(s, addr, s.log)
|
||||||
}, newDefaultDiscovery)
|
}, newDefaultDiscovery)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSync, log *zap.Logger,
|
func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSync, log *zap.Logger,
|
||||||
newTransport func(*Server) Transporter,
|
newTransport func(*Server, string) Transporter,
|
||||||
newDiscovery func([]string, time.Duration, Transporter) Discoverer,
|
newDiscovery func([]string, time.Duration, Transporter) Discoverer,
|
||||||
) (*Server, error) {
|
) (*Server, error) {
|
||||||
if log == nil {
|
if log == nil {
|
||||||
|
@ -238,11 +238,20 @@ func newServerFromConstructors(config ServerConfig, chain Ledger, stSync StateSy
|
||||||
s.BroadcastFactor = defaultBroadcastFactor
|
s.BroadcastFactor = defaultBroadcastFactor
|
||||||
}
|
}
|
||||||
|
|
||||||
s.transport = newTransport(s)
|
if len(s.ServerConfig.Addresses) == 0 {
|
||||||
|
return nil, errors.New("no bind addresses configured")
|
||||||
|
}
|
||||||
|
transports := make([]Transporter, len(s.ServerConfig.Addresses))
|
||||||
|
for i, addr := range s.ServerConfig.Addresses {
|
||||||
|
transports[i] = newTransport(s, addr.Address)
|
||||||
|
}
|
||||||
|
s.transports = transports
|
||||||
s.discovery = newDiscovery(
|
s.discovery = newDiscovery(
|
||||||
s.Seeds,
|
s.Seeds,
|
||||||
s.DialTimeout,
|
s.DialTimeout,
|
||||||
s.transport,
|
// Here we need to pick up a single transporter, it will be used to
|
||||||
|
// dial, and it doesn't matter which one.
|
||||||
|
s.transports[0],
|
||||||
)
|
)
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
|
@ -271,7 +280,9 @@ func (s *Server) Start(errChan chan error) {
|
||||||
go s.relayBlocksLoop()
|
go s.relayBlocksLoop()
|
||||||
go s.bQueue.run()
|
go s.bQueue.run()
|
||||||
go s.bSyncQueue.run()
|
go s.bSyncQueue.run()
|
||||||
go s.transport.Accept()
|
for _, tr := range s.transports {
|
||||||
|
go tr.Accept()
|
||||||
|
}
|
||||||
setServerAndNodeVersions(s.UserAgent, strconv.FormatUint(uint64(s.id), 10))
|
setServerAndNodeVersions(s.UserAgent, strconv.FormatUint(uint64(s.id), 10))
|
||||||
s.run()
|
s.run()
|
||||||
}
|
}
|
||||||
|
@ -280,7 +291,9 @@ func (s *Server) Start(errChan chan error) {
|
||||||
// once stopped the same intance of the Server can't be started again by calling Start.
|
// once stopped the same intance of the Server can't be started again by calling Start.
|
||||||
func (s *Server) Shutdown() {
|
func (s *Server) Shutdown() {
|
||||||
s.log.Info("shutting down server", zap.Int("peers", s.PeerCount()))
|
s.log.Info("shutting down server", zap.Int("peers", s.PeerCount()))
|
||||||
s.transport.Close()
|
for _, tr := range s.transports {
|
||||||
|
tr.Close()
|
||||||
|
}
|
||||||
for _, p := range s.getPeers(nil) {
|
for _, p := range s.getPeers(nil) {
|
||||||
p.Disconnect(errServerShutdown)
|
p.Disconnect(errServerShutdown)
|
||||||
}
|
}
|
||||||
|
@ -600,11 +613,12 @@ func (s *Server) HandshakedPeersCount() int {
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
// getVersionMsg returns the current version message.
|
// getVersionMsg returns the current version message generated for the specified
|
||||||
func (s *Server) getVersionMsg() (*Message, error) {
|
// connection.
|
||||||
port, err := s.Port()
|
func (s *Server) getVersionMsg(localAddr net.Addr) (*Message, error) {
|
||||||
|
port, err := s.Port(localAddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to fetch server port: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
capabilities := []capability.Capability{
|
capabilities := []capability.Capability{
|
||||||
|
@ -1654,26 +1668,42 @@ func (s *Server) broadcastTxLoop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Port returns a server port that should be used in P2P version exchange. In
|
// Port returns a server port that should be used in P2P version exchange with the
|
||||||
// case `AnnouncedPort` is set in the server.Config, the announced node port
|
// peer connected on the given localAddr. In case if announced node port is set
|
||||||
// will be returned (e.g. consider the node running behind NAT). If `AnnouncedPort`
|
// in the server.Config for the given bind address, the announced node port will
|
||||||
// isn't set, the port returned may still differs from that of server.Config.
|
// be returned (e.g. consider the node running behind NAT). If `AnnouncedPort`
|
||||||
func (s *Server) Port() (uint16, error) {
|
// isn't set, the port returned may still differ from that of server.Config. If
|
||||||
if s.AnnouncedPort != 0 {
|
// no localAddr is given, then the first available port will be returned.
|
||||||
return s.ServerConfig.AnnouncedPort, nil
|
func (s *Server) Port(localAddr net.Addr) (uint16, error) {
|
||||||
|
var connIP string
|
||||||
|
if localAddr != nil {
|
||||||
|
connIP, _, _ = net.SplitHostPort(localAddr.String()) // Ignore error and provide info if possible.
|
||||||
}
|
}
|
||||||
var port uint16
|
var defaultPort *uint16
|
||||||
_, portStr, err := net.SplitHostPort(s.transport.Address())
|
for i, tr := range s.transports {
|
||||||
if err != nil {
|
listenIP, listenPort := tr.HostPort()
|
||||||
port = s.ServerConfig.Port
|
if listenIP == "::" || listenIP == "" || localAddr == nil || connIP == "" || connIP == listenIP {
|
||||||
} else {
|
var res uint16
|
||||||
p, err := strconv.ParseUint(portStr, 10, 16)
|
if s.ServerConfig.Addresses[i].AnnouncedPort != 0 {
|
||||||
if err != nil {
|
res = s.ServerConfig.Addresses[i].AnnouncedPort
|
||||||
return 0, err
|
} else {
|
||||||
|
p, err := strconv.ParseUint(listenPort, 10, 16)
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to parse bind port from '%s': %w", listenPort, err)
|
||||||
|
}
|
||||||
|
res = uint16(p)
|
||||||
|
}
|
||||||
|
if localAddr == nil || // no local address is specified => take the first port available
|
||||||
|
(listenIP != "::" && listenIP != "") { // direct match is always preferable
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
defaultPort = &res
|
||||||
}
|
}
|
||||||
port = uint16(p)
|
|
||||||
}
|
}
|
||||||
return port, nil
|
if defaultPort != nil {
|
||||||
|
return *defaultPort, nil
|
||||||
|
}
|
||||||
|
return 0, fmt.Errorf("bind address for connection '%s' is not registered", localAddr.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimalNumOfThreads returns the optimal number of processing threads to create
|
// optimalNumOfThreads returns the optimal number of processing threads to create
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config"
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
|
@ -28,14 +29,8 @@ type (
|
||||||
// The user agent of the server.
|
// The user agent of the server.
|
||||||
UserAgent string
|
UserAgent string
|
||||||
|
|
||||||
// Address. Example: "localhost".
|
// Addresses stores the list of bind addresses for the node.
|
||||||
Address string
|
Addresses []config.AnnounceableAddress
|
||||||
|
|
||||||
// AnnouncedPort is an announced node port for P2P version exchange.
|
|
||||||
AnnouncedPort uint16
|
|
||||||
|
|
||||||
// Port is the actual node port it is bound to. Example: 20332.
|
|
||||||
Port uint16
|
|
||||||
|
|
||||||
// The network mode the server will operate on.
|
// The network mode the server will operate on.
|
||||||
// ModePrivNet docker private network.
|
// ModePrivNet docker private network.
|
||||||
|
@ -86,7 +81,7 @@ type (
|
||||||
|
|
||||||
// NewServerConfig creates a new ServerConfig struct
|
// NewServerConfig creates a new ServerConfig struct
|
||||||
// using the main applications config.
|
// using the main applications config.
|
||||||
func NewServerConfig(cfg config.Config) ServerConfig {
|
func NewServerConfig(cfg config.Config) (ServerConfig, error) {
|
||||||
appConfig := cfg.ApplicationConfiguration
|
appConfig := cfg.ApplicationConfiguration
|
||||||
protoConfig := cfg.ProtocolConfiguration
|
protoConfig := cfg.ProtocolConfiguration
|
||||||
timePerBlock := protoConfig.TimePerBlock
|
timePerBlock := protoConfig.TimePerBlock
|
||||||
|
@ -94,11 +89,13 @@ func NewServerConfig(cfg config.Config) ServerConfig {
|
||||||
timePerBlock = time.Duration(protoConfig.SecondsPerBlock) * time.Second //nolint:staticcheck // SA1019: protoConfig.SecondsPerBlock is deprecated
|
timePerBlock = time.Duration(protoConfig.SecondsPerBlock) * time.Second //nolint:staticcheck // SA1019: protoConfig.SecondsPerBlock is deprecated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addrs, err := appConfig.GetAddresses()
|
||||||
|
if err != nil {
|
||||||
|
return ServerConfig{}, fmt.Errorf("failed to parse addresses: %w", err)
|
||||||
|
}
|
||||||
return ServerConfig{
|
return ServerConfig{
|
||||||
UserAgent: cfg.GenerateUserAgent(),
|
UserAgent: cfg.GenerateUserAgent(),
|
||||||
Address: appConfig.Address,
|
Addresses: addrs,
|
||||||
AnnouncedPort: appConfig.AnnouncedNodePort,
|
|
||||||
Port: appConfig.NodePort,
|
|
||||||
Net: protoConfig.Magic,
|
Net: protoConfig.Magic,
|
||||||
Relay: appConfig.Relay,
|
Relay: appConfig.Relay,
|
||||||
Seeds: protoConfig.SeedList,
|
Seeds: protoConfig.SeedList,
|
||||||
|
@ -115,5 +112,5 @@ func NewServerConfig(cfg config.Config) ServerConfig {
|
||||||
StateRootCfg: appConfig.StateRoot,
|
StateRootCfg: appConfig.StateRoot,
|
||||||
ExtensiblePoolSize: appConfig.ExtensiblePoolSize,
|
ExtensiblePoolSize: appConfig.ExtensiblePoolSize,
|
||||||
BroadcastFactor: appConfig.BroadcastFactor,
|
BroadcastFactor: appConfig.BroadcastFactor,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,13 +104,13 @@ func TestServerStartAndShutdown(t *testing.T) {
|
||||||
s.register <- p
|
s.register <- p
|
||||||
require.Eventually(t, func() bool { return 1 == s.PeerCount() }, time.Second, time.Millisecond*10)
|
require.Eventually(t, func() bool { return 1 == s.PeerCount() }, time.Second, time.Millisecond*10)
|
||||||
|
|
||||||
assert.True(t, s.transport.(*fakeTransp).started.Load())
|
assert.True(t, s.transports[0].(*fakeTransp).started.Load())
|
||||||
assert.Nil(t, s.txCallback)
|
assert.Nil(t, s.txCallback)
|
||||||
|
|
||||||
s.Shutdown()
|
s.Shutdown()
|
||||||
<-ch
|
<-ch
|
||||||
|
|
||||||
require.True(t, s.transport.(*fakeTransp).closed.Load())
|
require.True(t, s.transports[0].(*fakeTransp).closed.Load())
|
||||||
err, ok := p.droppedWith.Load().(error)
|
err, ok := p.droppedWith.Load().(error)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.True(t, errors.Is(err, errServerShutdown))
|
require.True(t, errors.Is(err, errServerShutdown))
|
||||||
|
@ -191,7 +191,7 @@ func TestGetBlocksByIndex(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testGetBlocksByIndex(t *testing.T, cmd CommandType) {
|
func testGetBlocksByIndex(t *testing.T, cmd CommandType) {
|
||||||
s := newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
s := newTestServer(t, ServerConfig{UserAgent: "/test/"})
|
||||||
start := s.chain.BlockHeight()
|
start := s.chain.BlockHeight()
|
||||||
if cmd == CMDGetHeaders {
|
if cmd == CMDGetHeaders {
|
||||||
start = s.chain.HeaderHeight()
|
start = s.chain.HeaderHeight()
|
||||||
|
@ -217,7 +217,7 @@ func testGetBlocksByIndex(t *testing.T, cmd CommandType) {
|
||||||
expectsCmd[i] = cmd
|
expectsCmd[i] = cmd
|
||||||
expectedHeight[i] = []uint32{start + 1}
|
expectedHeight[i] = []uint32{start + 1}
|
||||||
}
|
}
|
||||||
go s.transport.Accept()
|
go s.transports[0].Accept()
|
||||||
|
|
||||||
nonce := uint32(0)
|
nonce := uint32(0)
|
||||||
checkPingRespond := func(t *testing.T, peerIndex int, peerHeight uint32, hs ...uint32) {
|
checkPingRespond := func(t *testing.T, peerIndex int, peerHeight uint32, hs ...uint32) {
|
||||||
|
@ -250,16 +250,15 @@ func testGetBlocksByIndex(t *testing.T, cmd CommandType) {
|
||||||
|
|
||||||
func TestSendVersion(t *testing.T) {
|
func TestSendVersion(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
s = newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
s = newTestServer(t, ServerConfig{UserAgent: "/test/"})
|
||||||
p = newLocalPeer(t, s)
|
p = newLocalPeer(t, s)
|
||||||
)
|
)
|
||||||
// we need to set listener at least to handle dynamic port correctly
|
// we need to set listener at least to handle dynamic port correctly
|
||||||
s.transport.Accept()
|
s.transports[0].Accept()
|
||||||
p.messageHandler = func(t *testing.T, msg *Message) {
|
p.messageHandler = func(t *testing.T, msg *Message) {
|
||||||
// listener is already set, so Address() gives us proper address with port
|
// listener is already set, so Addresses(nil) gives us proper address with port
|
||||||
_, p, err := net.SplitHostPort(s.transport.Address())
|
_, prt := s.transports[0].HostPort()
|
||||||
assert.NoError(t, err)
|
port, err := strconv.ParseUint(prt, 10, 16)
|
||||||
port, err := strconv.ParseUint(p, 10, 16)
|
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, CMDVersion, msg.Command)
|
assert.Equal(t, CMDVersion, msg.Command)
|
||||||
assert.IsType(t, msg.Payload, &payload.Version{})
|
assert.IsType(t, msg.Payload, &payload.Version{})
|
||||||
|
@ -390,7 +389,7 @@ func (s *Server) testHandleMessage(t *testing.T, p Peer, cmd CommandType, pl pay
|
||||||
|
|
||||||
func startTestServer(t *testing.T, protocolCfg ...func(*config.ProtocolConfiguration)) *Server {
|
func startTestServer(t *testing.T, protocolCfg ...func(*config.ProtocolConfiguration)) *Server {
|
||||||
var s *Server
|
var s *Server
|
||||||
srvCfg := ServerConfig{Port: 0, UserAgent: "/test/"}
|
srvCfg := ServerConfig{UserAgent: "/test/"}
|
||||||
if protocolCfg != nil {
|
if protocolCfg != nil {
|
||||||
s = newTestServerWithCustomCfg(t, srvCfg, protocolCfg[0])
|
s = newTestServerWithCustomCfg(t, srvCfg, protocolCfg[0])
|
||||||
} else {
|
} else {
|
||||||
|
@ -849,7 +848,7 @@ func TestHandleMPTData(t *testing.T) {
|
||||||
|
|
||||||
t.Run("good", func(t *testing.T) {
|
t.Run("good", func(t *testing.T) {
|
||||||
expected := [][]byte{{1, 2, 3}, {2, 3, 4}}
|
expected := [][]byte{{1, 2, 3}, {2, 3, 4}}
|
||||||
s := newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
s := newTestServer(t, ServerConfig{UserAgent: "/test/"})
|
||||||
s.config.P2PStateExchangeExtensions = true
|
s.config.P2PStateExchangeExtensions = true
|
||||||
s.stateSync = &fakechain.FakeStateSync{
|
s.stateSync = &fakechain.FakeStateSync{
|
||||||
AddMPTNodesFunc: func(nodes [][]byte) error {
|
AddMPTNodesFunc: func(nodes [][]byte) error {
|
||||||
|
@ -1044,7 +1043,7 @@ func TestVerifyNotaryRequest(t *testing.T) {
|
||||||
bc := fakechain.NewFakeChain()
|
bc := fakechain.NewFakeChain()
|
||||||
bc.MaxVerificationGAS = 10
|
bc.MaxVerificationGAS = 10
|
||||||
bc.NotaryContractScriptHash = util.Uint160{1, 2, 3}
|
bc.NotaryContractScriptHash = util.Uint160{1, 2, 3}
|
||||||
s, err := newServerFromConstructors(ServerConfig{}, bc, new(fakechain.FakeStateSync), zaptest.NewLogger(t), newFakeTransp, newTestDiscovery)
|
s, err := newServerFromConstructors(ServerConfig{Addresses: []config.AnnounceableAddress{{Address: ":0"}}}, bc, new(fakechain.FakeStateSync), zaptest.NewLogger(t), newFakeTransp, newTestDiscovery)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
newNotaryRequest := func() *payload.P2PNotaryRequest {
|
newNotaryRequest := func() *payload.P2PNotaryRequest {
|
||||||
return &payload.P2PNotaryRequest{
|
return &payload.P2PNotaryRequest{
|
||||||
|
@ -1123,3 +1122,33 @@ func TestTryInitStateSync(t *testing.T) {
|
||||||
s.tryInitStateSync()
|
s.tryInitStateSync()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServer_Port(t *testing.T) {
|
||||||
|
s := newTestServer(t, ServerConfig{
|
||||||
|
Addresses: []config.AnnounceableAddress{
|
||||||
|
{Address: "1.2.3.4:10"}, // some random address
|
||||||
|
{Address: ":1"}, // listen all IPs
|
||||||
|
{Address: "127.0.0.1:2"}, // address without announced port
|
||||||
|
{Address: "123.123.0.123:3", AnnouncedPort: 123}}, // address with announced port
|
||||||
|
})
|
||||||
|
|
||||||
|
// Default addr => first port available
|
||||||
|
actual, err := s.Port(nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint16(10), actual)
|
||||||
|
|
||||||
|
// Specified address with direct match => port of matched address
|
||||||
|
actual, err = s.Port(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 123})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint16(2), actual)
|
||||||
|
|
||||||
|
// No address match => 0.0.0.0's port
|
||||||
|
actual, err = s.Port(&net.TCPAddr{IP: net.IPv4(5, 6, 7, 8), Port: 123})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint16(1), actual)
|
||||||
|
|
||||||
|
// Specified address with match on announceable address => announced port
|
||||||
|
actual, err = s.Port(&net.TCPAddr{IP: net.IPv4(123, 123, 0, 123), Port: 123})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, uint16(123), actual)
|
||||||
|
}
|
||||||
|
|
|
@ -307,7 +307,7 @@ func (p *TCPPeer) IsFullNode() bool {
|
||||||
|
|
||||||
// SendVersion checks for the handshake state and sends a message to the peer.
|
// SendVersion checks for the handshake state and sends a message to the peer.
|
||||||
func (p *TCPPeer) SendVersion() error {
|
func (p *TCPPeer) SendVersion() error {
|
||||||
msg, err := p.server.getVersionMsg()
|
msg, err := p.server.getVersionMsg(p.conn.LocalAddr())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,9 @@ func TestPeerHandshake(t *testing.T) {
|
||||||
server, client := net.Pipe()
|
server, client := net.Pipe()
|
||||||
|
|
||||||
tcpS := NewTCPPeer(server, "", newTestServer(t, ServerConfig{}))
|
tcpS := NewTCPPeer(server, "", newTestServer(t, ServerConfig{}))
|
||||||
|
tcpS.server.transports[0].Accept() // properly initialize the address list
|
||||||
tcpC := NewTCPPeer(client, "", newTestServer(t, ServerConfig{}))
|
tcpC := NewTCPPeer(client, "", newTestServer(t, ServerConfig{}))
|
||||||
|
tcpC.server.transports[0].Accept()
|
||||||
|
|
||||||
// Something should read things written into the pipe.
|
// Something should read things written into the pipe.
|
||||||
go connReadStub(tcpS.conn)
|
go connReadStub(tcpS.conn)
|
||||||
|
|
|
@ -15,17 +15,32 @@ type TCPTransport struct {
|
||||||
server *Server
|
server *Server
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
bindAddr string
|
bindAddr string
|
||||||
|
hostPort hostPort
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
quit bool
|
quit bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type hostPort struct {
|
||||||
|
Host string
|
||||||
|
Port string
|
||||||
|
}
|
||||||
|
|
||||||
// NewTCPTransport returns a new TCPTransport that will listen for
|
// NewTCPTransport returns a new TCPTransport that will listen for
|
||||||
// new incoming peer connections.
|
// new incoming peer connections.
|
||||||
func NewTCPTransport(s *Server, bindAddr string, log *zap.Logger) *TCPTransport {
|
func NewTCPTransport(s *Server, bindAddr string, log *zap.Logger) *TCPTransport {
|
||||||
|
host, port, err := net.SplitHostPort(bindAddr)
|
||||||
|
if err != nil {
|
||||||
|
// Only host can be provided, it's OK.
|
||||||
|
host = bindAddr
|
||||||
|
}
|
||||||
return &TCPTransport{
|
return &TCPTransport{
|
||||||
log: log,
|
log: log,
|
||||||
server: s,
|
server: s,
|
||||||
bindAddr: bindAddr,
|
bindAddr: bindAddr,
|
||||||
|
hostPort: hostPort{
|
||||||
|
Host: host,
|
||||||
|
Port: port,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +70,8 @@ func (t *TCPTransport) Accept() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
t.listener = l
|
t.listener = l
|
||||||
|
t.bindAddr = l.Addr().String()
|
||||||
|
t.hostPort.Host, t.hostPort.Port, _ = net.SplitHostPort(t.bindAddr) // no error expected as l.Addr() is a valid address.
|
||||||
t.lock.Unlock()
|
t.lock.Unlock()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -66,7 +83,7 @@ func (t *TCPTransport) Accept() {
|
||||||
if errors.Is(err, net.ErrClosed) && quit {
|
if errors.Is(err, net.ErrClosed) && quit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
t.log.Warn("TCP accept error", zap.Error(err))
|
t.log.Warn("TCP accept error", zap.String("address", l.Addr().String()), zap.Error(err))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p := NewTCPPeer(conn, "", t.server)
|
p := NewTCPPeer(conn, "", t.server)
|
||||||
|
@ -89,12 +106,10 @@ func (t *TCPTransport) Proto() string {
|
||||||
return "tcp"
|
return "tcp"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Address implements the Transporter interface.
|
// HostPort implements the Transporter interface.
|
||||||
func (t *TCPTransport) Address() string {
|
func (t *TCPTransport) HostPort() (string, string) {
|
||||||
t.lock.RLock()
|
t.lock.RLock()
|
||||||
defer t.lock.RUnlock()
|
defer t.lock.RUnlock()
|
||||||
if t.listener != nil {
|
|
||||||
return t.listener.Addr().String()
|
return t.hostPort.Host, t.hostPort.Port
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,6 @@ type Transporter interface {
|
||||||
Dial(addr string, timeout time.Duration) (AddressablePeer, error)
|
Dial(addr string, timeout time.Duration) (AddressablePeer, error)
|
||||||
Accept()
|
Accept()
|
||||||
Proto() string
|
Proto() string
|
||||||
Address() string
|
HostPort() (string, string)
|
||||||
Close()
|
Close()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1923,9 +1923,10 @@ func TestClient_Iterator_SessionConfigVariations(t *testing.T) {
|
||||||
cfg.ApplicationConfiguration.RPC.SessionEnabled = true
|
cfg.ApplicationConfiguration.RPC.SessionEnabled = true
|
||||||
cfg.ApplicationConfiguration.RPC.SessionBackedByMPT = true
|
cfg.ApplicationConfiguration.RPC.SessionBackedByMPT = true
|
||||||
})
|
})
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig, err := network.NewServerConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.6-test")
|
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.6-test")
|
||||||
serverConfig.Port = 0
|
serverConfig.Addresses = []config.AnnounceableAddress{{Address: ":0"}}
|
||||||
server, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), logger)
|
server, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), logger)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
errCh := make(chan error, 2)
|
errCh := make(chan error, 2)
|
||||||
|
|
|
@ -717,7 +717,7 @@ func (s *Server) getBlockHash(reqParams params.Params) (interface{}, *neorpc.Err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) getVersion(_ params.Params) (interface{}, *neorpc.Error) {
|
func (s *Server) getVersion(_ params.Params) (interface{}, *neorpc.Error) {
|
||||||
port, err := s.coreServer.Port()
|
port, err := s.coreServer.Port(nil) // any port will suite
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, neorpc.NewInternalServerError(fmt.Sprintf("cannot fetch tcp port: %s", err))
|
return nil, neorpc.NewInternalServerError(fmt.Sprintf("cannot fetch tcp port: %s", err))
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,9 +116,10 @@ func initClearServerWithServices(t testing.TB, needOracle bool, needNotary bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
func wrapUnitTestChain(t testing.TB, chain *core.Blockchain, orc *oracle.Oracle, cfg config.Config, logger *zap.Logger) (*core.Blockchain, *Server, *httptest.Server) {
|
func wrapUnitTestChain(t testing.TB, chain *core.Blockchain, orc *oracle.Oracle, cfg config.Config, logger *zap.Logger) (*core.Blockchain, *Server, *httptest.Server) {
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig, err := network.NewServerConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.6-test")
|
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.6-test")
|
||||||
serverConfig.Port = 0
|
serverConfig.Addresses = []config.AnnounceableAddress{{Address: ":0"}}
|
||||||
server, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), logger)
|
server, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), logger)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
errCh := make(chan error, 2)
|
errCh := make(chan error, 2)
|
||||||
|
|
|
@ -3278,7 +3278,8 @@ func TestEscapeForLog(t *testing.T) {
|
||||||
func BenchmarkHandleIn(b *testing.B) {
|
func BenchmarkHandleIn(b *testing.B) {
|
||||||
chain, orc, cfg, logger := getUnitTestChain(b, false, false, false)
|
chain, orc, cfg, logger := getUnitTestChain(b, false, false, false)
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig, err := network.NewServerConfig(cfg)
|
||||||
|
require.NoError(b, err)
|
||||||
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.6-test")
|
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.6-test")
|
||||||
serverConfig.LogLevel = zapcore.FatalLevel
|
serverConfig.LogLevel = zapcore.FatalLevel
|
||||||
server, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), logger)
|
server, err := network.NewServer(serverConfig, chain, chain.GetStateSyncModule(), logger)
|
||||||
|
|
Loading…
Reference in a new issue