diff --git a/ROADMAP.md b/ROADMAP.md index dbeabf41d..5804dda3e 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -114,3 +114,12 @@ for security reasons. Removal of these options from ProtocolConfiguration is scheduled for May-June 2023 (~0.103.0 release). + +## GetPeers RPC server response type changes and RPC client support + +GetPeers RPC command returns a list of Peers where the port type has changed from +string to uint16 to match C#. The RPC client currently supports unmarshalling both +formats. + +Removal of Peer unmarshalling with string based ports is scheduled for ~September 2023 +(~0.105.0 release). diff --git a/pkg/neorpc/result/peers.go b/pkg/neorpc/result/peers.go index 4a4c4f923..33051f71d 100644 --- a/pkg/neorpc/result/peers.go +++ b/pkg/neorpc/result/peers.go @@ -1,7 +1,9 @@ package result import ( - "strings" + "encoding/json" + "net" + "strconv" ) type ( @@ -18,7 +20,7 @@ type ( // Peer represents a peer. Peer struct { Address string `json:"address"` - Port string `json:"port"` + Port uint16 `json:"port"` } ) @@ -49,12 +51,50 @@ func (g *GetPeers) AddBad(addrs []string) { // addPeers adds a set of peers to the given peer slice. func (p *Peers) addPeers(addrs []string) { for i := range addrs { - addressParts := strings.Split(addrs[i], ":") + host, portStr, err := net.SplitHostPort(addrs[i]) + if err != nil { + continue + } + port, err := strconv.ParseUint(portStr, 10, 16) + if err != nil { + port = 0 + } peer := Peer{ - Address: addressParts[0], - Port: addressParts[1], + Address: host, + Port: uint16(port), } *p = append(*p, peer) } } + +func (p *Peer) UnmarshalJSON(data []byte) error { + type NewPeer Peer + var np NewPeer + + err := json.Unmarshal(data, &np) + if err == nil { + *p = Peer(np) + return nil + } + + type OldPeer struct { + Address string `json:"address"` + Port string `json:"port"` + } + var op OldPeer + + err = json.Unmarshal(data, &op) + if err == nil { + port, err := strconv.ParseUint(op.Port, 10, 16) + if err != nil { + return err + } + + *p = Peer{ + Address: op.Address, + Port: uint16(port), + } + } + return err +} diff --git a/pkg/neorpc/result/peers_test.go b/pkg/neorpc/result/peers_test.go index 6e5a9339e..8680ac207 100644 --- a/pkg/neorpc/result/peers_test.go +++ b/pkg/neorpc/result/peers_test.go @@ -1,6 +1,7 @@ package result import ( + "encoding/json" "testing" "github.com/stretchr/testify/require" @@ -13,14 +14,31 @@ func TestGetPeers(t *testing.T) { require.Equal(t, 0, len(gp.Bad)) gp.AddUnconnected([]string{"1.1.1.1:53", "8.8.8.8:53", "9.9.9.9:53"}) - gp.AddConnected([]string{"192.168.0.1:10333"}) - gp.AddBad([]string{"127.0.0.1:20333"}) + unsupportedFormat := "2001:DB0:0:123A:::30" + gp.AddConnected([]string{"192.168.0.1:10333", unsupportedFormat, "[2001:DB0:0:123A::]:30"}) + gp.AddBad([]string{"127.0.0.1:20333", "127.0.0.1:65536"}) require.Equal(t, 3, len(gp.Unconnected)) - require.Equal(t, 1, len(gp.Connected)) - require.Equal(t, 1, len(gp.Bad)) + require.Equal(t, 2, len(gp.Connected)) + require.Equal(t, 2, len(gp.Bad)) require.Equal(t, "192.168.0.1", gp.Connected[0].Address) - require.Equal(t, "10333", gp.Connected[0].Port) + require.Equal(t, uint16(10333), gp.Connected[0].Port) + require.Equal(t, uint16(30), gp.Connected[1].Port) require.Equal(t, "127.0.0.1", gp.Bad[0].Address) - require.Equal(t, "20333", gp.Bad[0].Port) + require.Equal(t, uint16(20333), gp.Bad[0].Port) + require.Equal(t, uint16(0), gp.Bad[1].Port) + + gps := GetPeers{} + oldPeerFormat := `{"unconnected": [{"address": "20.109.188.128","port": "10333"},{"address": "27.188.182.47","port": "10333"}],"connected": [{"address": "54.227.43.72","port": "10333"},{"address": "157.90.177.38","port": "10333"}],"bad": [{"address": "5.226.142.226","port": "10333"}]}` + err := json.Unmarshal([]byte(oldPeerFormat), &gps) + require.NoError(t, err) + newPeerFormat := `{"unconnected": [{"address": "20.109.188.128","port": 10333},{"address": "27.188.182.47","port": 10333}],"connected": [{"address": "54.227.43.72","port": 10333},{"address": "157.90.177.38","port": 10333}],"bad": [{"address": "5.226.142.226","port": 10333},{"address": "54.208.117.178","port": 10333}]}` + err = json.Unmarshal([]byte(newPeerFormat), &gps) + require.NoError(t, err) + badIntFormat := `{"unconnected": [{"address": "20.109.188.128","port": 65536}],"connected": [],"bad": []}` + err = json.Unmarshal([]byte(badIntFormat), &gps) + require.Error(t, err) + badStringFormat := `{"unconnected": [{"address": "20.109.188.128","port": "badport"}],"connected": [],"bad": []}` + err = json.Unmarshal([]byte(badStringFormat), &gps) + require.Error(t, err) } diff --git a/pkg/rpcclient/rpc_test.go b/pkg/rpcclient/rpc_test.go index 87092343d..3cf3b9f9b 100644 --- a/pkg/rpcclient/rpc_test.go +++ b/pkg/rpcclient/rpc_test.go @@ -700,25 +700,26 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{ invoke: func(c *Client) (any, error) { return c.GetPeers() }, - serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"unconnected":[{"address":"172.200.0.1","port":"20333"}],"connected":[{"address":"127.0.0.1","port":"20335"}],"bad":[{"address":"172.200.0.254","port":"20332"}]}}`, + serverResponse: `{"id":1,"jsonrpc":"2.0","result":{"unconnected":[{"address":"172.200.0.1","port":20333}],"connected":[{"address":"127.0.0.1","port":20335}],"bad":[{"address":"172.200.0.254","port":20332}]}}`, result: func(c *Client) any { + return &result.GetPeers{ Unconnected: result.Peers{ { Address: "172.200.0.1", - Port: "20333", + Port: 20333, }, }, Connected: result.Peers{ { Address: "127.0.0.1", - Port: "20335", + Port: 20335, }, }, Bad: result.Peers{ { Address: "172.200.0.254", - Port: "20332", + Port: 20332, }, }, }