Skip to content

Commit

Permalink
dot/rpc: Implement RPC system_name, system_version, system_chain (#849)
Browse files Browse the repository at this point in the history
* implement RPC call system_name, system_version

* implement RPC call system_chain

* added tests

* save commit, refactoring rpc module

* move system rpc api to it's own package

* treat system_properties response as map

instead of go struct so that it can be build dynamically later based on
genesis definition.

* make system service implement Service interface
  • Loading branch information
edwardmack authored May 20, 2020
1 parent fc96f4f commit 87cabef
Show file tree
Hide file tree
Showing 20 changed files with 265 additions and 54 deletions.
25 changes: 23 additions & 2 deletions cmd/gossamer/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,11 @@ import (
"strconv"
"strings"

database "github.com/ChainSafe/chaindb"
"github.com/ChainSafe/gossamer/dot"
"github.com/ChainSafe/gossamer/dot/state"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/genesis"

database "github.com/ChainSafe/chaindb"
log "github.com/ChainSafe/log15"
"github.com/urfave/cli"
)
Expand Down Expand Up @@ -95,6 +94,9 @@ func createDotConfig(ctx *cli.Context) (cfg *dot.Config, err error) {
setDotNetworkConfig(ctx, &cfg.Network)
setDotRPCConfig(ctx, &cfg.RPC)

// set system info
setSystemInfoConfig(ctx, cfg)

return cfg, nil
}

Expand All @@ -112,6 +114,9 @@ func createInitConfig(ctx *cli.Context) (cfg *dot.Config, err error) {
// set init configuration values
setDotInitConfig(ctx, &cfg.Init)

// set system info
setSystemInfoConfig(ctx, cfg)

// ensure configuration values match genesis and overwrite with genesis
updateDotConfigFromGenesisJSON(ctx, cfg)

Expand All @@ -137,6 +142,9 @@ func createExportConfig(ctx *cli.Context) (cfg *dot.Config) {
setDotNetworkConfig(ctx, &cfg.Network)
setDotRPCConfig(ctx, &cfg.RPC)

// set system info
setSystemInfoConfig(ctx, cfg)

return cfg
}

Expand Down Expand Up @@ -332,6 +340,19 @@ func setDotRPCConfig(ctx *cli.Context, cfg *dot.RPCConfig) {
)
}

func setSystemInfoConfig(ctx *cli.Context, cfg *dot.Config) {
// load system information
if ctx.App != nil {
cfg.System.SystemName = ctx.App.Name
cfg.System.SystemVersion = ctx.App.Version
}

// TODO lookup system properties from genesis file and set here (See issue #865)
cfg.System.NodeName = cfg.Global.Name
props := make(map[string]interface{})
cfg.System.SystemProperties = props
}

// updateDotConfigFromGenesisJSON updates the configuration based on the genesis file values
func updateDotConfigFromGenesisJSON(ctx *cli.Context, cfg *dot.Config) {

Expand Down
5 changes: 4 additions & 1 deletion cmd/gossamer/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,7 @@ func TestUpdateConfigFromGenesisJSON(t *testing.T) {
Core: testCfg.Core,
Network: testCfg.Network,
RPC: testCfg.RPC,
System: testCfg.System,
}

cfg, err := createDotConfig(ctx)
Expand Down Expand Up @@ -585,6 +586,7 @@ func TestUpdateConfigFromGenesisJSON_Default(t *testing.T) {
Core: testCfg.Core,
Network: testCfg.Network,
RPC: testCfg.RPC,
System: testCfg.System,
}

cfg, err := createDotConfig(ctx)
Expand Down Expand Up @@ -626,7 +628,8 @@ func TestUpdateConfigFromGenesisData(t *testing.T) {
NoBootstrap: testCfg.Network.NoBootstrap,
NoMDNS: testCfg.Network.NoMDNS,
},
RPC: testCfg.RPC,
RPC: testCfg.RPC,
System: testCfg.System,
}

cfg, err := createDotConfig(ctx)
Expand Down
23 changes: 16 additions & 7 deletions dot/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,22 @@ import (
"reflect"
"unicode"

"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/node/gssmr"
"github.com/ChainSafe/gossamer/node/ksmcc"

log "github.com/ChainSafe/log15"
"github.com/naoina/toml"
)

// Config is a collection of configurations throughout the system
type Config struct {
Global GlobalConfig `toml:"global"`
Init InitConfig `toml:"init"`
Account AccountConfig `toml:"account"`
Core CoreConfig `toml:"core"`
Network NetworkConfig `toml:"network"`
RPC RPCConfig `toml:"rpc"`
Global GlobalConfig `toml:"global"`
Init InitConfig `toml:"init"`
Account AccountConfig `toml:"account"`
Core CoreConfig `toml:"core"`
Network NetworkConfig `toml:"network"`
RPC RPCConfig `toml:"rpc"`
System types.SystemInfo `toml:"-"`
}

// GlobalConfig is to marshal/unmarshal toml global config vars
Expand Down Expand Up @@ -132,6 +133,10 @@ func GssmrConfig() *Config {
Modules: gssmr.DefaultRPCModules,
WSPort: gssmr.DefaultRPCWSPort,
},
System: types.SystemInfo{
NodeName: gssmr.DefaultName,
SystemProperties: make(map[string]interface{}),
},
}
}

Expand Down Expand Up @@ -167,6 +172,10 @@ func KsmccConfig() *Config {
Modules: ksmcc.DefaultRPCModules,
WSPort: ksmcc.DefaultRPCWSPort,
},
System: types.SystemInfo{
NodeName: ksmcc.DefaultName,
SystemProperties: make(map[string]interface{}),
},
}
}

Expand Down
8 changes: 7 additions & 1 deletion dot/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,19 @@ func NewNode(cfg *Config, ks *keystore.Keystore) (*Node, error) {

}

// System Service

// create system service and append to node services
sysSrvc := createSystemService(&cfg.System)
nodeSrvcs = append(nodeSrvcs, sysSrvc)

// RPC Service

// check if rpc service is enabled
if enabled := RPCServiceEnabled(cfg); enabled {

// create rpc service and append rpc service to node services
rpcSrvc := createRPCService(cfg, stateSrvc, coreSrvc, networkSrvc, rt)
rpcSrvc := createRPCService(cfg, stateSrvc, coreSrvc, networkSrvc, rt, sysSrvc)
nodeSrvcs = append(nodeSrvcs, rpcSrvc)

} else {
Expand Down
3 changes: 2 additions & 1 deletion dot/rpc/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type HTTPServerConfig struct {
RuntimeAPI modules.RuntimeAPI
TransactionQueueAPI modules.TransactionQueueAPI
RPCAPI modules.RPCAPI
SystemAPI modules.SystemAPI
Host string
RPCPort uint32
WSEnabled bool
Expand Down Expand Up @@ -81,7 +82,7 @@ func (h *HTTPServer) RegisterModules(mods []string) {
var srvc interface{}
switch mod {
case "system":
srvc = modules.NewSystemModule(h.serverConfig.NetworkAPI)
srvc = modules.NewSystemModule(h.serverConfig.NetworkAPI, h.serverConfig.SystemAPI)
case "author":
srvc = modules.NewAuthorModule(h.serverConfig.CoreAPI, h.serverConfig.RuntimeAPI, h.serverConfig.TransactionQueueAPI)
case "chain":
Expand Down
15 changes: 11 additions & 4 deletions dot/rpc/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,23 @@ import (
"time"

"github.com/ChainSafe/gossamer/dot/core"
"github.com/ChainSafe/gossamer/dot/system"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/stretchr/testify/require"
)

func TestNewHTTPServer(t *testing.T) {
coreAPI := core.NewTestService(t, nil)
si := &types.SystemInfo{
SystemName: "gossamer",
}
sysAPI := system.NewService(si)
cfg := &HTTPServerConfig{
Modules: []string{"system"},
RPCPort: 8545,
RPCAPI: NewService(),
CoreAPI: coreAPI,
Modules: []string{"system"},
RPCPort: 8545,
RPCAPI: NewService(),
CoreAPI: coreAPI,
SystemAPI: sysAPI,
}

s := NewHTTPServer(cfg)
Expand Down
8 changes: 8 additions & 0 deletions dot/rpc/modules/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,11 @@ type RPCAPI interface {
type RuntimeAPI interface {
ValidateTransaction(e types.Extrinsic) (*transaction.Validity, error)
}

// SystemAPI is the interface for handling system methods
type SystemAPI interface {
SystemName() string
SystemVersion() string
NodeName() string
Properties() map[string]interface{}
}
39 changes: 11 additions & 28 deletions dot/rpc/modules/system.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,10 @@ import (
"github.com/ChainSafe/gossamer/lib/common"
)

// NOT_IMPLEMENTED used as placeholder for not implemented yet funcs
const NOT_IMPLEMENTED = "not yet implemented"

// SystemModule is an RPC module providing access to core API points
type SystemModule struct {
networkAPI NetworkAPI
systemAPI SystemAPI
}

// EmptyRequest represents an RPC request with no fields
Expand All @@ -51,50 +49,35 @@ type SystemPeersResponse struct {
Peers []common.PeerInfo `json:"peers"`
}

// SystemPropertiesResponse struct to marshal json
type SystemPropertiesResponse struct {
Ss58Format int `json:"ss58Format"`
TokenDecimals int `json:"tokenDecimals"`
TokenSymbol string `json:"tokenSymbol"`
}

// NewSystemModule creates a new API instance
func NewSystemModule(net NetworkAPI) *SystemModule {
func NewSystemModule(net NetworkAPI, sys SystemAPI) *SystemModule {
return &SystemModule{
networkAPI: net, // TODO: migrate to network state
systemAPI: sys,
}
}

// Chain returns the runtime chain
func (sm *SystemModule) Chain(r *http.Request, req *EmptyRequest, res *StringResponse) error {
// TODO implement lookup of value
*res = "Development"
func (sm *SystemModule) Chain(r *http.Request, req *EmptyRequest, res *string) error {
*res = sm.systemAPI.NodeName()
return nil
}

// Name returns the runtime name
func (sm *SystemModule) Name(r *http.Request, req *EmptyRequest, res *StringResponse) error {
// TODO implement lookup of value
*res = "gossamer v0.0"
func (sm *SystemModule) Name(r *http.Request, req *EmptyRequest, res *string) error {
*res = sm.systemAPI.SystemName()
return nil
}

// Properties returns the runtime properties
func (sm *SystemModule) Properties(r *http.Request, req *EmptyRequest, res *SystemPropertiesResponse) error {
// TODO implement lookup of this value
sp := SystemPropertiesResponse{
Ss58Format: 2,
TokenDecimals: 12,
TokenSymbol: "KSM",
}
*res = sp
func (sm *SystemModule) Properties(r *http.Request, req *EmptyRequest, res *interface{}) error {
*res = sm.systemAPI.Properties()
return nil
}

// Version returns the runtime version
func (sm *SystemModule) Version(r *http.Request, req *EmptyRequest, res *StringResponse) error {
// TODO implement lookup of this
*res = "0.0.0"
func (sm *SystemModule) Version(r *http.Request, req *EmptyRequest, res *string) error {
*res = sm.systemAPI.SystemVersion()
return nil
}

Expand Down
6 changes: 3 additions & 3 deletions dot/rpc/modules/system_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func newNetworkService(t *testing.T) *network.Service {
// Test RPC's System.Health() response
func TestSystemModule_Health(t *testing.T) {
net := newNetworkService(t)
sys := NewSystemModule(net)
sys := NewSystemModule(net, nil)

res := &SystemHealthResponse{}
sys.Health(nil, nil, res)
Expand All @@ -72,7 +72,7 @@ func TestSystemModule_Health(t *testing.T) {
// Test RPC's System.NetworkState() response
func TestSystemModule_NetworkState(t *testing.T) {
net := newNetworkService(t)
sys := NewSystemModule(net)
sys := NewSystemModule(net, nil)

res := &SystemNetworkStateResponse{}
sys.NetworkState(nil, nil, res)
Expand All @@ -87,7 +87,7 @@ func TestSystemModule_NetworkState(t *testing.T) {
// Test RPC's System.Peers() response
func TestSystemModule_Peers(t *testing.T) {
net := newNetworkService(t)
sys := NewSystemModule(net)
sys := NewSystemModule(net, nil)

res := &SystemPeersResponse{}
sys.Peers(nil, nil, res)
Expand Down
4 changes: 3 additions & 1 deletion dot/rpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ type Service struct {

// NewService create a new instance of Service
func NewService() *Service {
return &Service{rpcMethods: []string{}}
return &Service{
rpcMethods: []string{},
}
}

// Methods returns list of methods available via RPC call
Expand Down
2 changes: 1 addition & 1 deletion dot/rpc/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestService_Methods(t *testing.T) {
qtyAuthorMethods := 6

rpcService := NewService()
sysMod := modules.NewSystemModule(nil)
sysMod := modules.NewSystemModule(nil, nil)
rpcService.BuildMethodNames(sysMod, "system")
m := rpcService.Methods()
require.Equal(t, qtySystemMethods, len(m)) // check to confirm quantity for methods is correct
Expand Down
9 changes: 8 additions & 1 deletion dot/rpc/websocket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"time"

"github.com/ChainSafe/gossamer/dot/core"
"github.com/ChainSafe/gossamer/dot/system"
"github.com/ChainSafe/gossamer/dot/types"
"github.com/gorilla/websocket"
"github.com/stretchr/testify/require"
)
Expand All @@ -17,21 +19,26 @@ var testCalls = []struct {
call []byte
expected []byte
}{
{[]byte(`{"jsonrpc":"2.0","method":"system_name","params":[],"id":1}`), []byte(`{"id":1,"jsonrpc":"2.0","result":"gossamer v0.0"}` + "\n")}, // working request
{[]byte(`{"jsonrpc":"2.0","method":"system_name","params":[],"id":1}`), []byte(`{"id":1,"jsonrpc":"2.0","result":"gossamer"}` + "\n")}, // working request
{[]byte(`{"jsonrpc":"2.0","method":"unknown","params":[],"id":1}`), []byte(`{"error":{"code":-32000,"data":null,"message":"rpc error method unknown not found"},"id":1,"jsonrpc":"2.0"}` + "\n")}, // unknown method
{[]byte{}, []byte(`{"jsonrpc":"2.0","error":{"code":-32600,"message":"Invalid request"},"id":null}` + "\n")}, // empty request
{[]byte(`{"jsonrpc":"2.0","method":"chain_subscribeNewHeads","params":[],"id":1}`), []byte(`{"jsonrpc":"2.0","result":1,"id":1}` + "\n")},
}

func TestNewWebSocketServer(t *testing.T) {
coreAPI := core.NewTestService(t, nil)
si := &types.SystemInfo{
SystemName: "gossamer",
}
sysAPI := system.NewService(si)
cfg := &HTTPServerConfig{
Modules: []string{"system", "chain"},
RPCPort: 8545,
WSPort: 8546,
WSEnabled: true,
RPCAPI: NewService(),
CoreAPI: coreAPI,
SystemAPI: sysAPI,
}

s := NewHTTPServer(cfg)
Expand Down
Loading

0 comments on commit 87cabef

Please sign in to comment.