rpc: support InitialGasDistribution response from old Neo-Go nodes
https://github.com/nspcc-dev/neo-go/pull/2435 breaks compatibility between newer RPC clients and older RPC servers with the following error: ``` failed to get network magic: json: cannot unmarshal string into Go struct field Protocol.protocol.initialgasdistribution of type int64 ``` This behaviour is expected, but we can't allow this radical change. Thus, the following solution is implemented: 1. RPC server responds with proper non-stringified InitialGasDistribution value. The value represents an integral of fixed8 multiplied by the decimals. 2. RPC client is able to distinguish older and newer responses. For older one the stringified value without decimals part is expected. For newer responses the int64 value with decimal part is expected. The cludge will be present in the code for a while until nodes of version <=0.98.3 become completely absolete.
This commit is contained in:
parent
c042c5bb63
commit
9862b40f2c
9 changed files with 316 additions and 14 deletions
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -137,6 +138,7 @@ func newTestChain(t *testing.T, f func(*config.Config), run bool) (*core.Blockch
|
||||||
}
|
}
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
|
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)
|
||||||
cons, err := consensus.NewService(consensus.Config{
|
cons, err := consensus.NewService(consensus.Config{
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -3,6 +3,7 @@ module github.com/nspcc-dev/neo-go
|
||||||
require (
|
require (
|
||||||
github.com/btcsuite/btcd v0.22.0-beta
|
github.com/btcsuite/btcd v0.22.0-beta
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||||
|
github.com/coreos/go-semver v0.3.0
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -52,6 +52,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
|
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||||
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
|
|
@ -9,7 +9,14 @@ import (
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const userAgentFormat = "/NEO-GO:%s/"
|
const (
|
||||||
|
// UserAgentWrapper is a string that user agent string should be wrapped into.
|
||||||
|
UserAgentWrapper = "/"
|
||||||
|
// UserAgentPrefix is a prefix used to generate user agent string.
|
||||||
|
UserAgentPrefix = "NEO-GO:"
|
||||||
|
// UserAgentFormat is a formatted string used to generate user agent string.
|
||||||
|
UserAgentFormat = UserAgentWrapper + UserAgentPrefix + "%s" + UserAgentWrapper
|
||||||
|
)
|
||||||
|
|
||||||
// Version the version of the node, set at build time.
|
// Version the version of the node, set at build time.
|
||||||
var Version string
|
var Version string
|
||||||
|
@ -23,7 +30,7 @@ type Config struct {
|
||||||
|
|
||||||
// GenerateUserAgent creates user agent string based on build time environment.
|
// GenerateUserAgent creates user agent string based on build time environment.
|
||||||
func (c Config) GenerateUserAgent() string {
|
func (c Config) GenerateUserAgent() string {
|
||||||
return fmt.Sprintf(userAgentFormat, Version)
|
return fmt.Sprintf(UserAgentFormat, Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load attempts to load the config from the given
|
// Load attempts to load the config from the given
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
package result
|
package result
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/coreos/go-semver/semver"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
)
|
)
|
||||||
|
@ -11,19 +17,47 @@ type (
|
||||||
Version struct {
|
Version struct {
|
||||||
// Magic contains network magic.
|
// Magic contains network magic.
|
||||||
// Deprecated: use Protocol.StateRootInHeader instead
|
// Deprecated: use Protocol.StateRootInHeader instead
|
||||||
|
Magic netmode.Magic
|
||||||
|
TCPPort uint16
|
||||||
|
WSPort uint16
|
||||||
|
Nonce uint32
|
||||||
|
UserAgent string
|
||||||
|
Protocol Protocol
|
||||||
|
// StateRootInHeader is true if state root is contained in block header.
|
||||||
|
// Deprecated: use Protocol.StateRootInHeader instead
|
||||||
|
StateRootInHeader bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protocol represents network-dependent parameters.
|
||||||
|
Protocol struct {
|
||||||
|
AddressVersion byte
|
||||||
|
Network netmode.Magic
|
||||||
|
MillisecondsPerBlock int
|
||||||
|
MaxTraceableBlocks uint32
|
||||||
|
MaxValidUntilBlockIncrement uint32
|
||||||
|
MaxTransactionsPerBlock uint16
|
||||||
|
MemoryPoolMaxTransactions int
|
||||||
|
ValidatorsCount byte
|
||||||
|
InitialGasDistribution fixedn.Fixed8
|
||||||
|
// StateRootInHeader is true if state root is contained in block header.
|
||||||
|
StateRootInHeader bool
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
// versionMarshallerAux is an auxiliary struct used for Version JSON marshalling.
|
||||||
|
versionMarshallerAux struct {
|
||||||
Magic netmode.Magic `json:"network"`
|
Magic netmode.Magic `json:"network"`
|
||||||
TCPPort uint16 `json:"tcpport"`
|
TCPPort uint16 `json:"tcpport"`
|
||||||
WSPort uint16 `json:"wsport,omitempty"`
|
WSPort uint16 `json:"wsport,omitempty"`
|
||||||
Nonce uint32 `json:"nonce"`
|
Nonce uint32 `json:"nonce"`
|
||||||
UserAgent string `json:"useragent"`
|
UserAgent string `json:"useragent"`
|
||||||
Protocol Protocol `json:"protocol"`
|
Protocol protocolMarshallerAux `json:"protocol"`
|
||||||
// StateRootInHeader is true if state root is contained in block header.
|
|
||||||
// Deprecated: use Protocol.StateRootInHeader instead
|
|
||||||
StateRootInHeader bool `json:"staterootinheader,omitempty"`
|
StateRootInHeader bool `json:"staterootinheader,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Protocol represents network-dependent parameters.
|
// protocolMarshallerAux is an auxiliary struct used for Protocol JSON marshalling.
|
||||||
Protocol struct {
|
protocolMarshallerAux struct {
|
||||||
AddressVersion byte `json:"addressversion"`
|
AddressVersion byte `json:"addressversion"`
|
||||||
Network netmode.Magic `json:"network"`
|
Network netmode.Magic `json:"network"`
|
||||||
MillisecondsPerBlock int `json:"msperblock"`
|
MillisecondsPerBlock int `json:"msperblock"`
|
||||||
|
@ -32,8 +66,117 @@ type (
|
||||||
MaxTransactionsPerBlock uint16 `json:"maxtransactionsperblock"`
|
MaxTransactionsPerBlock uint16 `json:"maxtransactionsperblock"`
|
||||||
MemoryPoolMaxTransactions int `json:"memorypoolmaxtransactions"`
|
MemoryPoolMaxTransactions int `json:"memorypoolmaxtransactions"`
|
||||||
ValidatorsCount byte `json:"validatorscount"`
|
ValidatorsCount byte `json:"validatorscount"`
|
||||||
InitialGasDistribution fixedn.Fixed8 `json:"initialgasdistribution"`
|
InitialGasDistribution int64 `json:"initialgasdistribution"`
|
||||||
// StateRootInHeader is true if state root is contained in block header.
|
StateRootInHeader bool `json:"staterootinheader,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// versionUnmarshallerAux is an auxiliary struct used for Version JSON unmarshalling.
|
||||||
|
versionUnmarshallerAux struct {
|
||||||
|
Magic netmode.Magic `json:"network"`
|
||||||
|
TCPPort uint16 `json:"tcpport"`
|
||||||
|
WSPort uint16 `json:"wsport,omitempty"`
|
||||||
|
Nonce uint32 `json:"nonce"`
|
||||||
|
UserAgent string `json:"useragent"`
|
||||||
|
Protocol protocolUnmarshallerAux `json:"protocol"`
|
||||||
|
StateRootInHeader bool `json:"staterootinheader,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// protocolUnmarshallerAux is an auxiliary struct used for Protocol JSON unmarshalling.
|
||||||
|
protocolUnmarshallerAux struct {
|
||||||
|
AddressVersion byte `json:"addressversion"`
|
||||||
|
Network netmode.Magic `json:"network"`
|
||||||
|
MillisecondsPerBlock int `json:"msperblock"`
|
||||||
|
MaxTraceableBlocks uint32 `json:"maxtraceableblocks"`
|
||||||
|
MaxValidUntilBlockIncrement uint32 `json:"maxvaliduntilblockincrement"`
|
||||||
|
MaxTransactionsPerBlock uint16 `json:"maxtransactionsperblock"`
|
||||||
|
MemoryPoolMaxTransactions int `json:"memorypoolmaxtransactions"`
|
||||||
|
ValidatorsCount byte `json:"validatorscount"`
|
||||||
|
InitialGasDistribution json.RawMessage `json:"initialgasdistribution"`
|
||||||
StateRootInHeader bool `json:"staterootinheader,omitempty"`
|
StateRootInHeader bool `json:"staterootinheader,omitempty"`
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// latestNonBreakingVersion is a latest NeoGo revision that keeps older RPC
|
||||||
|
// clients compatibility with newer RPC servers (https://github.com/nspcc-dev/neo-go/pull/2435).
|
||||||
|
var latestNonBreakingVersion = *semver.New("0.98.2")
|
||||||
|
|
||||||
|
// MarshalJSON implements the json marshaller interface.
|
||||||
|
func (v *Version) MarshalJSON() ([]byte, error) {
|
||||||
|
aux := versionMarshallerAux{
|
||||||
|
Magic: v.Magic,
|
||||||
|
TCPPort: v.TCPPort,
|
||||||
|
WSPort: v.WSPort,
|
||||||
|
Nonce: v.Nonce,
|
||||||
|
UserAgent: v.UserAgent,
|
||||||
|
Protocol: protocolMarshallerAux{
|
||||||
|
AddressVersion: v.Protocol.AddressVersion,
|
||||||
|
Network: v.Protocol.Network,
|
||||||
|
MillisecondsPerBlock: v.Protocol.MillisecondsPerBlock,
|
||||||
|
MaxTraceableBlocks: v.Protocol.MaxTraceableBlocks,
|
||||||
|
MaxValidUntilBlockIncrement: v.Protocol.MaxValidUntilBlockIncrement,
|
||||||
|
MaxTransactionsPerBlock: v.Protocol.MaxTransactionsPerBlock,
|
||||||
|
MemoryPoolMaxTransactions: v.Protocol.MemoryPoolMaxTransactions,
|
||||||
|
ValidatorsCount: v.Protocol.ValidatorsCount,
|
||||||
|
InitialGasDistribution: int64(v.Protocol.InitialGasDistribution),
|
||||||
|
StateRootInHeader: v.Protocol.StateRootInHeader,
|
||||||
|
},
|
||||||
|
StateRootInHeader: v.StateRootInHeader,
|
||||||
|
}
|
||||||
|
return json.Marshal(aux)
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON implements the json unmarshaller interface.
|
||||||
|
func (v *Version) UnmarshalJSON(data []byte) error {
|
||||||
|
var aux versionUnmarshallerAux
|
||||||
|
err := json.Unmarshal(data, &aux)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
v.Magic = aux.Magic
|
||||||
|
v.TCPPort = aux.TCPPort
|
||||||
|
v.WSPort = aux.WSPort
|
||||||
|
v.Nonce = aux.Nonce
|
||||||
|
v.UserAgent = aux.UserAgent
|
||||||
|
v.Protocol.AddressVersion = aux.Protocol.AddressVersion
|
||||||
|
v.Protocol.Network = aux.Protocol.Network
|
||||||
|
v.Protocol.MillisecondsPerBlock = aux.Protocol.MillisecondsPerBlock
|
||||||
|
v.Protocol.MaxTraceableBlocks = aux.Protocol.MaxTraceableBlocks
|
||||||
|
v.Protocol.MaxValidUntilBlockIncrement = aux.Protocol.MaxValidUntilBlockIncrement
|
||||||
|
v.Protocol.MaxTransactionsPerBlock = aux.Protocol.MaxTransactionsPerBlock
|
||||||
|
v.Protocol.MemoryPoolMaxTransactions = aux.Protocol.MemoryPoolMaxTransactions
|
||||||
|
v.Protocol.ValidatorsCount = aux.Protocol.ValidatorsCount
|
||||||
|
v.Protocol.StateRootInHeader = aux.Protocol.StateRootInHeader
|
||||||
|
v.StateRootInHeader = aux.StateRootInHeader
|
||||||
|
if len(aux.Protocol.InitialGasDistribution) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(v.UserAgent, config.UserAgentWrapper+config.UserAgentPrefix) {
|
||||||
|
ver, err := userAgentToVersion(v.UserAgent)
|
||||||
|
if err == nil && ver.Compare(latestNonBreakingVersion) <= 0 {
|
||||||
|
err := json.Unmarshal(aux.Protocol.InitialGasDistribution, &v.Protocol.InitialGasDistribution)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal InitialGASDistribution into fixed8: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var val int64
|
||||||
|
err = json.Unmarshal(aux.Protocol.InitialGasDistribution, &val)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to unmarshal InitialGASDistribution into int64: %w", err)
|
||||||
|
}
|
||||||
|
v.Protocol.InitialGasDistribution = fixedn.Fixed8(val)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func userAgentToVersion(userAgent string) (*semver.Version, error) {
|
||||||
|
verStr := strings.Trim(userAgent, config.UserAgentWrapper)
|
||||||
|
verStr = strings.TrimPrefix(verStr, config.UserAgentPrefix)
|
||||||
|
ver, err := semver.NewVersion(verStr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("can't retrieve neo-go version from UserAgent: %w", err)
|
||||||
|
}
|
||||||
|
return ver, nil
|
||||||
|
}
|
||||||
|
|
143
pkg/rpc/response/result/version_test.go
Normal file
143
pkg/rpc/response/result/version_test.go
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
package result
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVersion_MarshalUnmarshalJSON(t *testing.T) {
|
||||||
|
responseFromGoOld := `{
|
||||||
|
"network": 860833102,
|
||||||
|
"nonce": 1677922561,
|
||||||
|
"protocol": {
|
||||||
|
"addressversion": 53,
|
||||||
|
"initialgasdistribution": "52000000",
|
||||||
|
"maxtraceableblocks": 2102400,
|
||||||
|
"maxtransactionsperblock": 512,
|
||||||
|
"maxvaliduntilblockincrement": 5760,
|
||||||
|
"memorypoolmaxtransactions": 50000,
|
||||||
|
"msperblock": 15000,
|
||||||
|
"network": 860833102,
|
||||||
|
"validatorscount": 7
|
||||||
|
},
|
||||||
|
"tcpport": 10333,
|
||||||
|
"useragent": "/NEO-GO:0.98.2/",
|
||||||
|
"wsport": 10334
|
||||||
|
}`
|
||||||
|
responseFromGoNew := `{
|
||||||
|
"network": 860833102,
|
||||||
|
"nonce": 1677922561,
|
||||||
|
"protocol": {
|
||||||
|
"addressversion": 53,
|
||||||
|
"initialgasdistribution": 5200000000000000,
|
||||||
|
"maxtraceableblocks": 2102400,
|
||||||
|
"maxtransactionsperblock": 512,
|
||||||
|
"maxvaliduntilblockincrement": 5760,
|
||||||
|
"memorypoolmaxtransactions": 50000,
|
||||||
|
"msperblock": 15000,
|
||||||
|
"network": 860833102,
|
||||||
|
"validatorscount": 7
|
||||||
|
},
|
||||||
|
"tcpport": 10333,
|
||||||
|
"useragent": "/NEO-GO:0.98.3/",
|
||||||
|
"wsport": 10334
|
||||||
|
}`
|
||||||
|
responseFromSharp := `{
|
||||||
|
"nonce": 1677922561,
|
||||||
|
"protocol": {
|
||||||
|
"addressversion": 53,
|
||||||
|
"initialgasdistribution": 5200000000000000,
|
||||||
|
"maxtraceableblocks": 2102400,
|
||||||
|
"maxtransactionsperblock": 512,
|
||||||
|
"maxvaliduntilblockincrement": 5760,
|
||||||
|
"memorypoolmaxtransactions": 50000,
|
||||||
|
"msperblock": 15000,
|
||||||
|
"network": 860833102,
|
||||||
|
"validatorscount": 7
|
||||||
|
},
|
||||||
|
"tcpport": 10333,
|
||||||
|
"useragent": "/Neo:3.1.0/",
|
||||||
|
"wsport": 10334
|
||||||
|
}`
|
||||||
|
v := &Version{
|
||||||
|
Magic: 860833102,
|
||||||
|
TCPPort: 10333,
|
||||||
|
WSPort: 10334,
|
||||||
|
Nonce: 1677922561,
|
||||||
|
UserAgent: "/NEO-GO:0.98.3/",
|
||||||
|
Protocol: Protocol{
|
||||||
|
AddressVersion: 53,
|
||||||
|
Network: 860833102,
|
||||||
|
MillisecondsPerBlock: 15000,
|
||||||
|
MaxTraceableBlocks: 2102400,
|
||||||
|
MaxValidUntilBlockIncrement: 5760,
|
||||||
|
MaxTransactionsPerBlock: 512,
|
||||||
|
MemoryPoolMaxTransactions: 50000,
|
||||||
|
ValidatorsCount: 7,
|
||||||
|
// Unmarshalled InitialGasDistribution should always be a valid Fixed8 for both old and new clients.
|
||||||
|
InitialGasDistribution: fixedn.Fixed8FromInt64(52000000),
|
||||||
|
StateRootInHeader: false,
|
||||||
|
},
|
||||||
|
StateRootInHeader: false,
|
||||||
|
}
|
||||||
|
t.Run("MarshalJSON", func(t *testing.T) {
|
||||||
|
actual, err := json.Marshal(v)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.JSONEq(t, responseFromGoNew, string(actual))
|
||||||
|
})
|
||||||
|
t.Run("UnmarshalJSON", func(t *testing.T) {
|
||||||
|
t.Run("Go node response", func(t *testing.T) {
|
||||||
|
t.Run("old RPC server", func(t *testing.T) {
|
||||||
|
actual := &Version{}
|
||||||
|
require.NoError(t, json.Unmarshal([]byte(responseFromGoOld), actual))
|
||||||
|
expected := new(Version)
|
||||||
|
*expected = *v
|
||||||
|
expected.UserAgent = "/NEO-GO:0.98.2/"
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
})
|
||||||
|
t.Run("new RPC server", func(t *testing.T) {
|
||||||
|
actual := &Version{}
|
||||||
|
require.NoError(t, json.Unmarshal([]byte(responseFromGoNew), actual))
|
||||||
|
require.Equal(t, v, actual)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
t.Run("Sharp node response", func(t *testing.T) {
|
||||||
|
actual := &Version{}
|
||||||
|
require.NoError(t, json.Unmarshal([]byte(responseFromSharp), actual))
|
||||||
|
expected := new(Version)
|
||||||
|
*expected = *v
|
||||||
|
expected.UserAgent = "/Neo:3.1.0/"
|
||||||
|
expected.Magic = 0 // No magic in C#.
|
||||||
|
require.Equal(t, expected, actual)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionFromUserAgent(t *testing.T) {
|
||||||
|
type testCase struct {
|
||||||
|
success bool
|
||||||
|
cmpWithBreaking int
|
||||||
|
}
|
||||||
|
var testcases = map[string]testCase{
|
||||||
|
"/Neo:3.1.0/": {success: false},
|
||||||
|
"/NEO-GO:0.98.4": {success: true, cmpWithBreaking: 1},
|
||||||
|
"/NEO-GO:0.98.4-pre-12344/": {success: true, cmpWithBreaking: 1},
|
||||||
|
"/NEO-GO:0.98.3/": {success: true, cmpWithBreaking: 1},
|
||||||
|
"/NEO-GO:0.98.3-pre-123/": {success: true, cmpWithBreaking: 1},
|
||||||
|
"/NEO-GO:0.98.2/": {success: true, cmpWithBreaking: 0},
|
||||||
|
"/NEO-GO:0.98.2-pre-12345/": {success: true, cmpWithBreaking: -1},
|
||||||
|
"/NEO-GO:123456": {success: false},
|
||||||
|
}
|
||||||
|
for str, tc := range testcases {
|
||||||
|
ver, err := userAgentToVersion(str)
|
||||||
|
if tc.success {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ver.Compare(latestNonBreakingVersion), tc.cmpWithBreaking)
|
||||||
|
} else {
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -536,7 +536,7 @@ func (s *Server) getVersion(_ request.Params) (interface{}, *response.Error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := s.chain.GetConfig()
|
cfg := s.chain.GetConfig()
|
||||||
return result.Version{
|
return &result.Version{
|
||||||
Magic: s.network,
|
Magic: s.network,
|
||||||
TCPPort: port,
|
TCPPort: port,
|
||||||
Nonce: s.coreServer.ID(),
|
Nonce: s.coreServer.ID(),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
|
@ -101,6 +102,7 @@ func initClearServerWithServices(t testing.TB, needOracle bool, needNotary bool)
|
||||||
chain, orc, cfg, logger := getUnitTestChain(t, needOracle, needNotary)
|
chain, orc, cfg, logger := getUnitTestChain(t, needOracle, needNotary)
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
|
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.3-test")
|
||||||
serverConfig.Port = 0
|
serverConfig.Port = 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)
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testchain"
|
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||||
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
"github.com/nspcc-dev/neo-go/internal/testserdes"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/config"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
"github.com/nspcc-dev/neo-go/pkg/core/block"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
"github.com/nspcc-dev/neo-go/pkg/core/fee"
|
||||||
|
@ -849,7 +850,7 @@ var rpcTestCases = map[string][]rpcTestCase{
|
||||||
check: func(t *testing.T, e *executor, ver interface{}) {
|
check: func(t *testing.T, e *executor, ver interface{}) {
|
||||||
resp, ok := ver.(*result.Version)
|
resp, ok := ver.(*result.Version)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.Equal(t, "/NEO-GO:/", resp.UserAgent)
|
require.Equal(t, "/NEO-GO:0.98.3-test/", resp.UserAgent)
|
||||||
|
|
||||||
cfg := e.chain.GetConfig()
|
cfg := e.chain.GetConfig()
|
||||||
require.EqualValues(t, address.NEO3Prefix, resp.Protocol.AddressVersion)
|
require.EqualValues(t, address.NEO3Prefix, resp.Protocol.AddressVersion)
|
||||||
|
@ -2605,6 +2606,7 @@ func BenchmarkHandleIn(b *testing.B) {
|
||||||
chain, orc, cfg, logger := getUnitTestChain(b, false, false)
|
chain, orc, cfg, logger := getUnitTestChain(b, false, false)
|
||||||
|
|
||||||
serverConfig := network.NewServerConfig(cfg)
|
serverConfig := network.NewServerConfig(cfg)
|
||||||
|
serverConfig.UserAgent = fmt.Sprintf(config.UserAgentFormat, "0.98.3-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)
|
||||||
require.NoError(b, err)
|
require.NoError(b, err)
|
||||||
|
|
Loading…
Reference in a new issue