neo-go/pkg/config/application_config.go
Roman Khimov 7589733017 config: add a special Blockchain type to configure Blockchain
And include some node-specific configurations there with backwards
compatibility. Note that in the future we'll remove Ledger's
fields from the ProtocolConfiguration and it'll be possible to access them in
Blockchain directly (not via .Ledger).

The other option tried was using two configuration types separately, but that
incurs more changes to the codebase, single structure that behaves almost like
the old one is better for backwards compatibility.

Fixes #2676.
2022-12-07 17:35:53 +03:00

203 lines
8.3 KiB
Go

package config
import (
"fmt"
"net"
"sort"
"strconv"
"strings"
"github.com/nspcc-dev/neo-go/pkg/core/storage/dbconfig"
)
// ApplicationConfiguration config specific to the node.
type ApplicationConfiguration struct {
Ledger `yaml:",inline"`
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.
Address *string `yaml:"Address,omitempty"`
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.
AnnouncedNodePort *uint16 `yaml:"AnnouncedPort,omitempty"`
// Deprecated: this option is moved to the P2P section.
AttemptConnPeers int `yaml:"AttemptConnPeers"`
// BroadcastFactor is the factor (0-100) controlling gossip fan-out number optimization.
//
// Deprecated: this option is moved to the P2P section.
BroadcastFactor int `yaml:"BroadcastFactor"`
DBConfiguration dbconfig.DBConfiguration `yaml:"DBConfiguration"`
// Deprecated: this option is moved to the P2P section.
DialTimeout int64 `yaml:"DialTimeout"`
LogLevel string `yaml:"LogLevel"`
LogPath string `yaml:"LogPath"`
// Deprecated: this option is moved to the P2P section.
MaxPeers int `yaml:"MaxPeers"`
// Deprecated: this option is moved to the P2P section.
MinPeers int `yaml:"MinPeers"`
// Deprecated: please, use Addresses field of P2P section instead, this field will be removed in future versions.
NodePort *uint16 `yaml:"NodePort,omitempty"`
P2P P2P `yaml:"P2P"`
// Deprecated: this option is moved to the P2P section.
PingInterval int64 `yaml:"PingInterval"`
// Deprecated: this option is moved to the P2P section.
PingTimeout int64 `yaml:"PingTimeout"`
Pprof BasicService `yaml:"Pprof"`
Prometheus BasicService `yaml:"Prometheus"`
// Deprecated: this option is moved to the P2P section.
ProtoTickInterval int64 `yaml:"ProtoTickInterval"`
Relay bool `yaml:"Relay"`
Consensus Consensus `yaml:"Consensus"`
RPC RPC `yaml:"RPC"`
UnlockWallet Wallet `yaml:"UnlockWallet"`
Oracle OracleConfiguration `yaml:"Oracle"`
P2PNotary P2PNotary `yaml:"P2PNotary"`
StateRoot StateRoot `yaml:"StateRoot"`
// ExtensiblePoolSize is the maximum amount of the extensible payloads from a single sender.
//
// Deprecated: this option is moved to the P2P section.
ExtensiblePoolSize int `yaml:"ExtensiblePoolSize"`
}
// EqualsButServices returns true when the o is the same as a except for services
// (Oracle, P2PNotary, Pprof, Prometheus, RPC, StateRoot and UnlockWallet sections)
// and LogLevel field.
func (a *ApplicationConfiguration) EqualsButServices(o *ApplicationConfiguration) bool {
if len(a.P2P.Addresses) != len(o.P2P.Addresses) {
return false
}
aCp := make([]string, len(a.P2P.Addresses))
oCp := make([]string, len(o.P2P.Addresses))
copy(aCp, a.P2P.Addresses)
copy(oCp, o.P2P.Addresses)
sort.Strings(aCp)
sort.Strings(oCp)
for i := range aCp {
if aCp[i] != oCp[i] {
return false
}
}
if a.Address != o.Address || //nolint:staticcheck // SA1019: a.Address is deprecated
a.AnnouncedNodePort != o.AnnouncedNodePort || //nolint:staticcheck // SA1019: a.AnnouncedNodePort is deprecated
a.AttemptConnPeers != o.AttemptConnPeers || //nolint:staticcheck // SA1019: a.AttemptConnPeers is deprecated
a.P2P.AttemptConnPeers != o.P2P.AttemptConnPeers ||
a.BroadcastFactor != o.BroadcastFactor || //nolint:staticcheck // SA1019: a.BroadcastFactor is deprecated
a.P2P.BroadcastFactor != o.P2P.BroadcastFactor ||
a.DBConfiguration != o.DBConfiguration ||
a.DialTimeout != o.DialTimeout || //nolint:staticcheck // SA1019: a.DialTimeout is deprecated
a.P2P.DialTimeout != o.P2P.DialTimeout ||
a.ExtensiblePoolSize != o.ExtensiblePoolSize || //nolint:staticcheck // SA1019: a.ExtensiblePoolSize is deprecated
a.P2P.ExtensiblePoolSize != o.P2P.ExtensiblePoolSize ||
a.LogPath != o.LogPath ||
a.MaxPeers != o.MaxPeers || //nolint:staticcheck // SA1019: a.MaxPeers is deprecated
a.P2P.MaxPeers != o.P2P.MaxPeers ||
a.MinPeers != o.MinPeers || //nolint:staticcheck // SA1019: a.MinPeers is deprecated
a.P2P.MinPeers != o.P2P.MinPeers ||
a.NodePort != o.NodePort || //nolint:staticcheck // SA1019: a.NodePort is deprecated
a.PingInterval != o.PingInterval || //nolint:staticcheck // SA1019: a.PingInterval is deprecated
a.P2P.PingInterval != o.P2P.PingInterval ||
a.PingTimeout != o.PingTimeout || //nolint:staticcheck // SA1019: a.PingTimeout is deprecated
a.P2P.PingTimeout != o.P2P.PingTimeout ||
a.ProtoTickInterval != o.ProtoTickInterval || //nolint:staticcheck // SA1019: a.ProtoTickInterval is deprecated
a.P2P.ProtoTickInterval != o.P2P.ProtoTickInterval ||
a.Relay != o.Relay {
return false
}
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.P2P.Addresses)+1)
if a.Address != nil || a.NodePort != nil || a.AnnouncedNodePort != nil { //nolint:staticcheck // SA1019: a.Address is deprecated
var (
host string
nodePort uint16
)
if a.Address != nil { //nolint:staticcheck // SA1019: a.Address is deprecated
host = *a.Address //nolint:staticcheck // SA1019: a.Address is deprecated
}
if a.NodePort != nil { //nolint:staticcheck // SA1019: a.NodePort is deprecated
nodePort = *a.NodePort //nolint:staticcheck // SA1019: a.NodePort is deprecated
}
addr := AnnounceableAddress{Address: net.JoinHostPort(host, strconv.Itoa(int(nodePort)))}
if a.AnnouncedNodePort != nil { //nolint:staticcheck // SA1019: a.AnnouncedNodePort is deprecated
addr.AnnouncedPort = *a.AnnouncedNodePort //nolint:staticcheck // SA1019: a.AnnouncedNodePort is deprecated
}
addrs = append(addrs, addr)
}
for i, addrStr := range a.P2P.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
}