2020-03-25 15:30:21 +00:00
|
|
|
package config
|
|
|
|
|
|
|
|
import (
|
2022-11-29 14:43:08 +00:00
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
|
2022-07-08 16:42:06 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
|
2020-03-25 15:30:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// ApplicationConfiguration config specific to the node.
|
|
|
|
type ApplicationConfiguration struct {
|
2022-11-29 14:43:08 +00:00
|
|
|
// Deprecated: please, use Addresses instead, this field will be removed in future versions.
|
|
|
|
Address *string `yaml:"Address,omitempty"`
|
|
|
|
// 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"`
|
2022-10-13 19:14:14 +00:00
|
|
|
// BroadcastFactor is the factor (0-100) controlling gossip fan-out number optimization.
|
2022-11-29 14:43:08 +00:00
|
|
|
BroadcastFactor int `yaml:"BroadcastFactor"`
|
|
|
|
DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"`
|
|
|
|
DialTimeout int64 `yaml:"DialTimeout"`
|
|
|
|
LogLevel string `yaml:"LogLevel"`
|
|
|
|
LogPath string `yaml:"LogPath"`
|
|
|
|
MaxPeers int `yaml:"MaxPeers"`
|
|
|
|
MinPeers int `yaml:"MinPeers"`
|
|
|
|
// Deprecated: please, use Addresses instead, this field will be removed in future versions.
|
|
|
|
NodePort *uint16 `yaml:"NodePort,omitempty"`
|
|
|
|
PingInterval int64 `yaml:"PingInterval"`
|
|
|
|
PingTimeout int64 `yaml:"PingTimeout"`
|
|
|
|
Pprof BasicService `yaml:"Pprof"`
|
|
|
|
Prometheus BasicService `yaml:"Prometheus"`
|
|
|
|
ProtoTickInterval int64 `yaml:"ProtoTickInterval"`
|
|
|
|
Relay bool `yaml:"Relay"`
|
|
|
|
RPC RPC `yaml:"RPC"`
|
|
|
|
UnlockWallet Wallet `yaml:"UnlockWallet"`
|
|
|
|
Oracle OracleConfiguration `yaml:"Oracle"`
|
|
|
|
P2PNotary P2PNotary `yaml:"P2PNotary"`
|
|
|
|
StateRoot StateRoot `yaml:"StateRoot"`
|
2021-05-04 14:54:16 +00:00
|
|
|
// ExtensiblePoolSize is the maximum amount of the extensible payloads from a single sender.
|
|
|
|
ExtensiblePoolSize int `yaml:"ExtensiblePoolSize"`
|
2020-03-25 15:30:21 +00:00
|
|
|
}
|
2022-07-26 13:16:48 +00:00
|
|
|
|
|
|
|
// EqualsButServices returns true when the o is the same as a except for services
|
2022-12-05 11:58:16 +00:00
|
|
|
// (Oracle, P2PNotary, Pprof, Prometheus, RPC, StateRoot and UnlockWallet sections)
|
|
|
|
// and LogLevel field.
|
2022-07-26 13:16:48 +00:00
|
|
|
func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration) bool {
|
2022-11-29 14:43:08 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
2022-07-26 13:16:48 +00:00
|
|
|
if a.Address != o.Address ||
|
|
|
|
a.AnnouncedNodePort != o.AnnouncedNodePort ||
|
|
|
|
a.AttemptConnPeers != o.AttemptConnPeers ||
|
2022-10-13 19:14:14 +00:00
|
|
|
a.BroadcastFactor != o.BroadcastFactor ||
|
2022-07-26 13:16:48 +00:00
|
|
|
a.DBConfiguration != o.DBConfiguration ||
|
|
|
|
a.DialTimeout != o.DialTimeout ||
|
|
|
|
a.ExtensiblePoolSize != o.ExtensiblePoolSize ||
|
|
|
|
a.LogPath != o.LogPath ||
|
|
|
|
a.MaxPeers != o.MaxPeers ||
|
|
|
|
a.MinPeers != o.MinPeers ||
|
|
|
|
a.NodePort != o.NodePort ||
|
|
|
|
a.PingInterval != o.PingInterval ||
|
|
|
|
a.PingTimeout != o.PingTimeout ||
|
|
|
|
a.ProtoTickInterval != o.ProtoTickInterval ||
|
|
|
|
a.Relay != o.Relay {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2022-11-29 14:43:08 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|