Skip to content

Commit 69a0104

Browse files
committed
rpcsrv: add hardforks to getversion response
Port neo-project/neo-modules#823. Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
1 parent b284b90 commit 69a0104

File tree

5 files changed

+77
-3
lines changed

5 files changed

+77
-3
lines changed

pkg/neorpc/result/version.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ package result
22

33
import (
44
"encoding/json"
5+
"fmt"
6+
"strings"
57

8+
"github.com/nspcc-dev/neo-go/pkg/config"
69
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
710
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
811
)
@@ -29,6 +32,8 @@ type (
2932
MemoryPoolMaxTransactions int
3033
ValidatorsCount byte
3134
InitialGasDistribution fixedn.Fixed8
35+
// Hardforks is the map of network hardforks with the enabling height.
36+
Hardforks map[config.Hardfork]uint32
3237

3338
// Below are NeoGo-specific extensions to the protocol that are
3439
// returned by the server in case they're enabled.
@@ -54,16 +59,36 @@ type (
5459
MemoryPoolMaxTransactions int `json:"memorypoolmaxtransactions"`
5560
ValidatorsCount byte `json:"validatorscount"`
5661
InitialGasDistribution int64 `json:"initialgasdistribution"`
62+
Hardforks []hardforkAux `json:"hardforks"`
5763

5864
CommitteeHistory map[uint32]uint32 `json:"committeehistory,omitempty"`
5965
P2PSigExtensions bool `json:"p2psigextensions,omitempty"`
6066
StateRootInHeader bool `json:"staterootinheader,omitempty"`
6167
ValidatorsHistory map[uint32]uint32 `json:"validatorshistory,omitempty"`
6268
}
69+
70+
// hardforkAux is an auxiliary struct used for Hardfork JSON marshalling.
71+
hardforkAux struct {
72+
Name string `json:"name"`
73+
Height uint32 `json:"blockheight"`
74+
}
6375
)
6476

77+
// prefixHardfork is a prefix used for hardfork names in C# node.
78+
const prefixHardfork = "HF_"
79+
6580
// MarshalJSON implements the JSON marshaler interface.
6681
func (p Protocol) MarshalJSON() ([]byte, error) {
82+
// Keep hardforks sorted by name in the result.
83+
hfs := make([]hardforkAux, 0, len(p.Hardforks))
84+
for _, hf := range config.Hardforks {
85+
if h, ok := p.Hardforks[hf]; ok {
86+
hfs = append(hfs, hardforkAux{
87+
Name: hf.String(),
88+
Height: h,
89+
})
90+
}
91+
}
6792
aux := protocolMarshallerAux{
6893
AddressVersion: p.AddressVersion,
6994
Network: p.Network,
@@ -74,6 +99,7 @@ func (p Protocol) MarshalJSON() ([]byte, error) {
7499
MemoryPoolMaxTransactions: p.MemoryPoolMaxTransactions,
75100
ValidatorsCount: p.ValidatorsCount,
76101
InitialGasDistribution: int64(p.InitialGasDistribution),
102+
Hardforks: hfs,
77103

78104
CommitteeHistory: p.CommitteeHistory,
79105
P2PSigExtensions: p.P2PSigExtensions,
@@ -104,5 +130,21 @@ func (p *Protocol) UnmarshalJSON(data []byte) error {
104130
p.ValidatorsHistory = aux.ValidatorsHistory
105131
p.InitialGasDistribution = fixedn.Fixed8(aux.InitialGasDistribution)
106132

133+
// Filter out unknown hardforks.
134+
for i := range aux.Hardforks {
135+
aux.Hardforks[i].Name = strings.TrimPrefix(aux.Hardforks[i].Name, prefixHardfork)
136+
if !config.IsHardforkValid(aux.Hardforks[i].Name) {
137+
return fmt.Errorf("unexpected hardfork: %s", aux.Hardforks[i].Name)
138+
}
139+
}
140+
p.Hardforks = make(map[config.Hardfork]uint32, len(aux.Hardforks))
141+
for _, cfgHf := range config.Hardforks {
142+
for _, auxHf := range aux.Hardforks {
143+
if auxHf.Name == cfgHf.String() {
144+
p.Hardforks[cfgHf] = auxHf.Height
145+
}
146+
}
147+
}
148+
107149
return nil
108150
}

pkg/neorpc/result/version_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"encoding/json"
55
"testing"
66

7+
"github.com/nspcc-dev/neo-go/pkg/config"
78
"github.com/nspcc-dev/neo-go/pkg/encoding/fixedn"
89
"github.com/stretchr/testify/require"
910
)
@@ -38,7 +39,8 @@ func TestVersion_MarshalUnmarshalJSON(t *testing.T) {
3839
"memorypoolmaxtransactions": 50000,
3940
"msperblock": 15000,
4041
"network": 860833102,
41-
"validatorscount": 7
42+
"validatorscount": 7,
43+
"hardforks": [{"name": "Aspidochelone", "blockheight": 123}, {"name": "Basilisk", "blockheight": 1234}]
4244
},
4345
"tcpport": 10333,
4446
"useragent": "/NEO-GO:0.98.6/",
@@ -55,7 +57,8 @@ func TestVersion_MarshalUnmarshalJSON(t *testing.T) {
5557
"memorypoolmaxtransactions": 50000,
5658
"msperblock": 15000,
5759
"network": 860833102,
58-
"validatorscount": 7
60+
"validatorscount": 7,
61+
"hardforks": [{"name": "HF_Aspidochelone", "blockheight": 123}, {"name": "HF_Basilisk", "blockheight": 1234}]
5962
},
6063
"tcpport": 10333,
6164
"useragent": "/Neo:3.1.0/",
@@ -78,6 +81,7 @@ func TestVersion_MarshalUnmarshalJSON(t *testing.T) {
7881
// Unmarshalled InitialGasDistribution should always be a valid Fixed8 for both old and new clients.
7982
InitialGasDistribution: fixedn.Fixed8FromInt64(52000000),
8083
StateRootInHeader: false,
84+
Hardforks: map[config.Hardfork]uint32{config.HFAspidochelone: 123, config.HFBasilisk: 1234},
8185
},
8286
}
8387
t.Run("MarshalJSON", func(t *testing.T) {

pkg/rpcclient/rpc_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
"github.com/gorilla/websocket"
1717
"github.com/nspcc-dev/neo-go/internal/testserdes"
18+
"github.com/nspcc-dev/neo-go/pkg/config"
1819
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
1920
"github.com/nspcc-dev/neo-go/pkg/core/block"
2021
"github.com/nspcc-dev/neo-go/pkg/core/state"
@@ -1031,7 +1032,8 @@ var rpcClientTestCases = map[string][]rpcClientTestCase{
10311032
Nonce: 2153672787,
10321033
UserAgent: "/NEO-GO:0.73.1-pre-273-ge381358/",
10331034
Protocol: result.Protocol{
1034-
Network: netmode.UnitTestNet,
1035+
Network: netmode.UnitTestNet,
1036+
Hardforks: map[config.Hardfork]uint32{},
10351037
},
10361038
}
10371039
},

pkg/services/rpcsrv/client_test.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2356,3 +2356,20 @@ func TestClient_GetStorageHistoric(t *testing.T) {
23562356
_, err = c.GetStorageByHashHistoric(earlyRoot.Root, h, key)
23572357
require.ErrorIs(t, neorpc.ErrUnknownStorageItem, err)
23582358
}
2359+
2360+
func TestClient_GetVersion_Hardforks(t *testing.T) {
2361+
chain, rpcSrv, httpSrv := initServerWithInMemoryChain(t)
2362+
defer chain.Close()
2363+
defer rpcSrv.Shutdown()
2364+
2365+
c, err := rpcclient.New(context.Background(), httpSrv.URL, rpcclient.Options{})
2366+
require.NoError(t, err)
2367+
require.NoError(t, c.Init())
2368+
2369+
v, err := c.GetVersion()
2370+
require.NoError(t, err)
2371+
expected := map[config.Hardfork]uint32{
2372+
config.HFAspidochelone: 25,
2373+
}
2374+
require.InDeltaMapValues(t, expected, v.Protocol.Hardforks, 0)
2375+
}

pkg/services/rpcsrv/server.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -839,6 +839,14 @@ func (s *Server) getVersion(_ params.Params) (any, *neorpc.Error) {
839839
}
840840

841841
cfg := s.chain.GetConfig()
842+
hfs := make(map[config.Hardfork]uint32, len(cfg.Hardforks))
843+
for _, cfgHf := range config.Hardforks {
844+
height, ok := cfg.Hardforks[cfgHf.String()]
845+
if !ok {
846+
continue
847+
}
848+
hfs[cfgHf] = height
849+
}
842850
return &result.Version{
843851
TCPPort: port,
844852
Nonce: s.coreServer.ID(),
@@ -853,6 +861,7 @@ func (s *Server) getVersion(_ params.Params) (any, *neorpc.Error) {
853861
MemoryPoolMaxTransactions: cfg.MemPoolSize,
854862
ValidatorsCount: byte(cfg.GetNumOfCNs(s.chain.BlockHeight())),
855863
InitialGasDistribution: cfg.InitialGASSupply,
864+
Hardforks: hfs,
856865

857866
CommitteeHistory: cfg.CommitteeHistory,
858867
P2PSigExtensions: cfg.P2PSigExtensions,

0 commit comments

Comments
 (0)