Skip to content

Commit

Permalink
feat(dot/rpc): implement sync_state_genSyncSpec RPC call (#1827)
Browse files Browse the repository at this point in the history
  • Loading branch information
kishansagathiya authored Oct 22, 2021
1 parent 7abcce6 commit 2186caf
Show file tree
Hide file tree
Showing 19 changed files with 182 additions and 23 deletions.
2 changes: 1 addition & 1 deletion chain/dev/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ enabled = true
ws = true
port = 8545
host = "localhost"
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"]
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"]
ws-port = 8546
2 changes: 1 addition & 1 deletion chain/dev/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ var (
// DefaultRPCHTTPPort rpc port
DefaultRPCHTTPPort = uint32(8545)
// DefaultRPCModules rpc modules
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"}
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"}
// DefaultRPCWSPort rpc websocket port
DefaultRPCWSPort = uint32(8546)
// DefaultRPCEnabled enables the RPC server
Expand Down
2 changes: 1 addition & 1 deletion chain/gssmr/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,5 @@ min-peers = 1
enabled = false
port = 8545
host = "localhost"
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"]
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"]
ws-port = 8546
2 changes: 1 addition & 1 deletion chain/gssmr/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ var (
// DefaultRPCHTTPPort rpc port
DefaultRPCHTTPPort = uint32(8545)
// DefaultRPCModules rpc modules
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"}
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"}
// DefaultRPCWSPort rpc websocket port
DefaultRPCWSPort = uint32(8546)
)
2 changes: 1 addition & 1 deletion chain/kusama/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ enabled = false
external = false
port = 8545
host = "localhost"
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"]
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"]
ws-port = 8546
ws = false
ws-external = false
2 changes: 1 addition & 1 deletion chain/kusama/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ var (
// DefaultRPCHTTPPort rpc port
DefaultRPCHTTPPort = uint32(8545)
// DefaultRPCModules rpc modules
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"}
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"}
// DefaultRPCWSPort rpc websocket port
DefaultRPCWSPort = uint32(8546)
)
2 changes: 1 addition & 1 deletion chain/polkadot/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ nomdns = false
enabled = false
port = 8545
host = "localhost"
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"]
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"]
ws-port = 8546
2 changes: 1 addition & 1 deletion chain/polkadot/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ var (
// DefaultRPCHTTPPort rpc port
DefaultRPCHTTPPort = uint32(8545)
// DefaultRPCModules rpc modules
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"}
DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate", "payment"}
// DefaultRPCWSPort rpc websocket port
DefaultRPCWSPort = uint32(8546)
)
6 changes: 1 addition & 5 deletions dot/build_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,9 @@ func BuildFromDB(path string) (*BuildSpec, error) {
}
tmpGen.Name = gData.Name
tmpGen.ID = gData.ID
tmpGen.Bootnodes = make([]string, len(gData.Bootnodes))
tmpGen.Bootnodes = common.BytesToStringArray(gData.Bootnodes)
tmpGen.ProtocolID = gData.ProtocolID

for i, bn := range gData.Bootnodes {
tmpGen.Bootnodes[i] = string(bn)
}

bs := &BuildSpec{
genesis: tmpGen,
}
Expand Down
7 changes: 6 additions & 1 deletion dot/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (

"github.com/ChainSafe/gossamer/dot/metrics"
"github.com/ChainSafe/gossamer/dot/network"
"github.com/ChainSafe/gossamer/dot/rpc"
"github.com/ChainSafe/gossamer/dot/state"
"github.com/ChainSafe/gossamer/dot/state/pruner"
"github.com/ChainSafe/gossamer/dot/telemetry"
Expand Down Expand Up @@ -313,7 +314,11 @@ func NewNode(cfg *Config, ks *keystore.GlobalKeystore, stopFunc func()) (*Node,

// check if rpc service is enabled
if enabled := cfg.RPC.isRPCEnabled() || cfg.RPC.isWSEnabled(); enabled {
rpcSrvc := createRPCService(cfg, ns, stateSrvc, coreSrvc, networkSrvc, bp, sysSrvc, fg)
var rpcSrvc *rpc.HTTPServer
rpcSrvc, err = createRPCService(cfg, ns, stateSrvc, coreSrvc, networkSrvc, bp, sysSrvc, fg)
if err != nil {
return nil, fmt.Errorf("failed to create rpc service: %s", err)
}
nodeSrvcs = append(nodeSrvcs, rpcSrvc)
} else {
logger.Debug("rpc service disabled by default", "rpc", enabled)
Expand Down
4 changes: 3 additions & 1 deletion dot/rpc/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ type HTTPServerConfig struct {
TransactionQueueAPI modules.TransactionStateAPI
RPCAPI modules.RPCAPI
SystemAPI modules.SystemAPI
SyncStateAPI modules.SyncStateAPI
NodeStorage *runtime.NodeStorage
RPC bool
RPCExternal bool
Expand Down Expand Up @@ -129,6 +130,8 @@ func (h *HTTPServer) RegisterModules(mods []string) {
srvc = modules.NewOffchainModule(h.serverConfig.NodeStorage)
case "childstate":
srvc = modules.NewChildStateModule(h.serverConfig.StorageAPI, h.serverConfig.BlockAPI)
case "syncstate":
srvc = modules.NewSyncStateModule(h.serverConfig.SyncStateAPI)
case "payment":
srvc = modules.NewPaymentModule(h.serverConfig.BlockAPI)
default:
Expand All @@ -137,7 +140,6 @@ func (h *HTTPServer) RegisterModules(mods []string) {
}

err := h.rpcServer.RegisterService(srvc, mod)

if err != nil {
h.logger.Warn("Failed to register module", "mod", mod, "err", err)
}
Expand Down
4 changes: 2 additions & 2 deletions dot/rpc/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import (
func TestRegisterModules(t *testing.T) {
rpcapiMocks := new(mocks.MockRPCAPI)

mods := []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"}
mods := []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "syncstate"}

for _, modName := range mods {
rpcapiMocks.On("BuildMethodNames", mock.Anything, modName).Once()
Expand Down Expand Up @@ -125,7 +125,7 @@ func TestNewHTTPServer(t *testing.T) {

func TestUnsafeRPCProtection(t *testing.T) {
cfg := &HTTPServerConfig{
Modules: []string{"system", "author", "chain", "state", "rpc", "grandpa", "dev"},
Modules: []string{"system", "author", "chain", "state", "rpc", "grandpa", "dev", "syncstate"},
RPCPort: 7878,
RPCAPI: NewService(),
RPCUnsafe: false,
Expand Down
6 changes: 6 additions & 0 deletions dot/rpc/modules/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto"
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
"github.com/ChainSafe/gossamer/lib/genesis"
"github.com/ChainSafe/gossamer/lib/grandpa"
"github.com/ChainSafe/gossamer/lib/runtime"
"github.com/ChainSafe/gossamer/lib/transaction"
Expand Down Expand Up @@ -122,3 +123,8 @@ type RuntimeStorageAPI interface {
GetLocal(k []byte) ([]byte, error)
GetPersistent(k []byte) ([]byte, error)
}

// SyncStateAPI is the interface to interact with sync state.
type SyncStateAPI interface {
GenSyncSpec(raw bool) (*genesis.Genesis, error)
}
102 changes: 102 additions & 0 deletions dot/rpc/modules/sync_state.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright 2019 ChainSafe Systems (ON) Corp.
// This file is part of gossamer.
//
// The gossamer library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The gossamer library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the gossamer library. If not, see <http://www.gnu.org/licenses/>.

package modules

import (
"net/http"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/genesis"
)

// GenSyncSpecRequest represents request to get chain specification.
type GenSyncSpecRequest struct {
Raw bool
}

// SyncStateModule is an RPC module to interact with sync state methods.
type SyncStateModule struct {
syncStateAPI SyncStateAPI
}

// NewSyncStateModule creates an instance of SyncStateModule given SyncStateAPI.
func NewSyncStateModule(syncStateAPI SyncStateAPI) *SyncStateModule {
return &SyncStateModule{syncStateAPI: syncStateAPI}
}

// GenSyncSpec returns the JSON serialised chain specification running the node
// (i.e. the current state state), with a sync state.
func (ss *SyncStateModule) GenSyncSpec(_ *http.Request, req *GenSyncSpecRequest, res *genesis.Genesis) error {
g, err := ss.syncStateAPI.GenSyncSpec(req.Raw)
if err != nil {
return err
}

*res = *g
return nil
}

// syncState implements SyncStateAPI.
type syncState struct {
chainSpecification *genesis.Genesis
}

// NewStateSync creates an instance of SyncStateAPI given a chain specification.
func NewStateSync(gData *genesis.Data, storageAPI StorageAPI) (SyncStateAPI, error) {
tmpGen := &genesis.Genesis{
Name: "",
ID: "",
Bootnodes: nil,
ProtocolID: "",
Genesis: genesis.Fields{
Runtime: nil,
},
}
tmpGen.Genesis.Raw = make(map[string]map[string]string)
tmpGen.Genesis.Runtime = make(map[string]map[string]interface{})

// set genesis fields data
ent, err := storageAPI.Entries(nil)
if err != nil {
return nil, err
}

err = genesis.BuildFromMap(ent, tmpGen)
if err != nil {
return nil, err
}

tmpGen.Name = gData.Name
tmpGen.ID = gData.ID
tmpGen.Bootnodes = common.BytesToStringArray(gData.Bootnodes)
tmpGen.ProtocolID = gData.ProtocolID

return syncState{chainSpecification: tmpGen}, nil
}

// GenSyncSpec returns the JSON serialised chain specification running the node
// (i.e. the current state), with a sync state.
func (s syncState) GenSyncSpec(raw bool) (*genesis.Genesis, error) {
if raw {
err := s.chainSpecification.ToRaw()
if err != nil {
return nil, err
}
}

return s.chainSpecification, nil
}
35 changes: 35 additions & 0 deletions dot/rpc/modules/sync_state_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package modules

import (
"encoding/json"
"io/ioutil"
"path/filepath"
"testing"

"github.com/ChainSafe/gossamer/lib/genesis"
"github.com/stretchr/testify/require"
)

const GssmrGenesisPath = "../../../chain/gssmr/genesis.json"

func TestSyncStateModule(t *testing.T) {
fp, err := filepath.Abs(GssmrGenesisPath)
require.NoError(t, err)

data, err := ioutil.ReadFile(filepath.Clean(fp))
require.NoError(t, err)

g := new(genesis.Genesis)
err = json.Unmarshal(data, g)
require.NoError(t, err)

module := NewSyncStateModule(syncState{chainSpecification: g})

req := GenSyncSpecRequest{
Raw: true,
}
var res genesis.Genesis

err = module.GenSyncSpec(nil, &req, &res)
require.NoError(t, err)
}
2 changes: 1 addition & 1 deletion dot/rpc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ var (
)

// BuildMethodNames takes receiver interface and populates rpcMethods array with available
// method names
// method names
func (s *Service) BuildMethodNames(rcvr interface{}, name string) {
rcvrType := reflect.TypeOf(rcvr)
for i := 0; i < rcvrType.NumMethod(); i++ {
Expand Down
15 changes: 13 additions & 2 deletions dot/services.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func createNetworkService(cfg *Config, stateSrvc *state.Service) (*network.Servi
// RPC Service

// createRPCService creates the RPC service from the provided core configuration
func createRPCService(cfg *Config, ns *runtime.NodeStorage, stateSrvc *state.Service, coreSrvc *core.Service, networkSrvc *network.Service, bp modules.BlockProducerAPI, sysSrvc *system.Service, finSrvc *grandpa.Service) *rpc.HTTPServer {
func createRPCService(cfg *Config, ns *runtime.NodeStorage, stateSrvc *state.Service, coreSrvc *core.Service, networkSrvc *network.Service, bp modules.BlockProducerAPI, sysSrvc *system.Service, finSrvc *grandpa.Service) (*rpc.HTTPServer, error) {
logger.Info(
"creating rpc service...",
"host", cfg.RPC.Host,
Expand All @@ -304,6 +304,16 @@ func createRPCService(cfg *Config, ns *runtime.NodeStorage, stateSrvc *state.Ser
)
rpcService := rpc.NewService()

genesisData, err := stateSrvc.Base.LoadGenesisData()
if err != nil {
return nil, fmt.Errorf("failed to load genesis data: %s", err)
}

syncStateSrvc, err := modules.NewStateSync(genesisData, stateSrvc.Storage)
if err != nil {
return nil, fmt.Errorf("failed to create sync state service: %s", err)
}

rpcConfig := &rpc.HTTPServerConfig{
LogLvl: cfg.Log.RPCLvl,
BlockAPI: stateSrvc.Block,
Expand All @@ -315,6 +325,7 @@ func createRPCService(cfg *Config, ns *runtime.NodeStorage, stateSrvc *state.Ser
BlockFinalityAPI: finSrvc,
TransactionQueueAPI: stateSrvc.Transaction,
RPCAPI: rpcService,
SyncStateAPI: syncStateSrvc,
SystemAPI: sysSrvc,
RPC: cfg.RPC.Enabled,
RPCExternal: cfg.RPC.External,
Expand All @@ -330,7 +341,7 @@ func createRPCService(cfg *Config, ns *runtime.NodeStorage, stateSrvc *state.Ser
Modules: cfg.RPC.Modules,
}

return rpc.NewHTTPServer(rpcConfig)
return rpc.NewHTTPServer(rpcConfig), nil
}

// createSystemService creates a systemService for providing system related information
Expand Down
6 changes: 4 additions & 2 deletions dot/services_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ func TestCreateRPCService(t *testing.T) {
sysSrvc, err := createSystemService(&cfg.System, stateSrvc)
require.NoError(t, err)

rpcSrvc := createRPCService(cfg, ns, stateSrvc, coreSrvc, networkSrvc, nil, sysSrvc, nil)
rpcSrvc, err := createRPCService(cfg, ns, stateSrvc, coreSrvc, networkSrvc, nil, sysSrvc, nil)
require.NoError(t, err)
require.NotNil(t, rpcSrvc)
}

Expand Down Expand Up @@ -342,7 +343,8 @@ func TestNewWebSocketServer(t *testing.T) {
sysSrvc, err := createSystemService(&cfg.System, stateSrvc)
require.NoError(t, err)

rpcSrvc := createRPCService(cfg, ns, stateSrvc, coreSrvc, networkSrvc, nil, sysSrvc, nil)
rpcSrvc, err := createRPCService(cfg, ns, stateSrvc, coreSrvc, networkSrvc, nil, sysSrvc, nil)
require.NoError(t, err)
err = rpcSrvc.Start()
require.Nil(t, err)

Expand Down
2 changes: 1 addition & 1 deletion tests/data/db/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ nomdns = false
enabled = false
port = 8545
host = "localhost"
modules = ["system", "author", "chain", "state", "rpc", "grandpa"]
modules = ["system", "author", "chain", "state", "rpc", "grandpa", "syncstate"]
ws-port = 8546

0 comments on commit 2186caf

Please sign in to comment.