From b9e5263333f06981dfd0ea6d4b464ccf1f7aae34 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Tue, 9 Feb 2021 11:26:18 -0500 Subject: [PATCH 01/10] stub AccountNextIndex --- dot/rpc/modules/system.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dot/rpc/modules/system.go b/dot/rpc/modules/system.go index 11dd0090f0..9de5dcdc40 100644 --- a/dot/rpc/modules/system.go +++ b/dot/rpc/modules/system.go @@ -135,3 +135,7 @@ func (sm *SystemModule) NodeRoles(r *http.Request, req *EmptyRequest, res *[]int *res = resultArray return nil } + +func (sm *SystemModule) AccountNextIndex(r *http.Request, req *EmptyRequest, res *[]interface{}) error { + return nil +} \ No newline at end of file From 77060cadf42c6162b9de9603b5693becad09e385 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Tue, 9 Feb 2021 16:39:53 -0500 Subject: [PATCH 02/10] implement rpc system_accountNextIndex --- dot/rpc/http.go | 3 +- dot/rpc/modules/system.go | 54 +++++++++++++++++++++++++--- dot/rpc/modules/system_test.go | 66 +++++++++++++++++++++++++++++----- 3 files changed, 109 insertions(+), 14 deletions(-) diff --git a/dot/rpc/http.go b/dot/rpc/http.go index a479f0fb03..e9a897321a 100644 --- a/dot/rpc/http.go +++ b/dot/rpc/http.go @@ -103,7 +103,8 @@ func (h *HTTPServer) RegisterModules(mods []string) { var srvc interface{} switch mod { case "system": - srvc = modules.NewSystemModule(h.serverConfig.NetworkAPI, h.serverConfig.SystemAPI) + srvc = modules.NewSystemModule(h.serverConfig.NetworkAPI, h.serverConfig.SystemAPI, + h.serverConfig.CoreAPI, h.serverConfig.StorageAPI) case "author": srvc = modules.NewAuthorModule(h.logger, h.serverConfig.CoreAPI, h.serverConfig.RuntimeAPI, h.serverConfig.TransactionQueueAPI) case "chain": diff --git a/dot/rpc/modules/system.go b/dot/rpc/modules/system.go index 9de5dcdc40..e5120e9e89 100644 --- a/dot/rpc/modules/system.go +++ b/dot/rpc/modules/system.go @@ -17,15 +17,20 @@ package modules import ( - "net/http" - + "errors" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/crypto" + "github.com/ChainSafe/gossamer/lib/scale" + "github.com/centrifuge/go-substrate-rpc-client/v2/types" + "net/http" ) // SystemModule is an RPC module providing access to core API points type SystemModule struct { networkAPI NetworkAPI systemAPI SystemAPI + coreAPI CoreAPI + storageAPI StorageAPI } // EmptyRequest represents an RPC request with no fields @@ -51,11 +56,19 @@ type SystemNetworkStateResponse struct { // SystemPeersResponse struct to marshal json type SystemPeersResponse []common.PeerInfo +type U64Response uint64 + +type StringRequest struct { + String string +} + // NewSystemModule creates a new API instance -func NewSystemModule(net NetworkAPI, sys SystemAPI) *SystemModule { +func NewSystemModule(net NetworkAPI, sys SystemAPI, core CoreAPI, storage StorageAPI) *SystemModule { return &SystemModule{ networkAPI: net, // TODO: migrate to network state systemAPI: sys, + coreAPI: core, + storageAPI: storage, } } @@ -136,6 +149,39 @@ func (sm *SystemModule) NodeRoles(r *http.Request, req *EmptyRequest, res *[]int return nil } -func (sm *SystemModule) AccountNextIndex(r *http.Request, req *EmptyRequest, res *[]interface{}) error { +func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, res *U64Response) error { + // todo (ed) check pending transactions + + // get metadata to build storage storageKey + rawMeta, err := sm.coreAPI.GetMetadata(nil) + if err != nil { + return err + } + sdMeta, err := scale.Decode(rawMeta, []byte{}) + if err != nil { + return err + } + var metadata types.Metadata + err = types.DecodeFromBytes(sdMeta.([]byte), &metadata) + if err != nil { + return err + } + + if req == nil || len(req.String) == 0 { + return errors.New("Account address must be valid") + } + addressPubKey := crypto.PublicAddressToByteArray(common.Address(req.String)) + + storageKey, err := types.CreateStorageKey(&metadata, "System", "Account", addressPubKey, nil) + if err != nil { + return err + } + + accountRaw, err := sm.storageAPI.GetStorage(nil, storageKey) + + var accountInfo types.AccountInfo + types.DecodeFromBytes(accountRaw, &accountInfo) + + *res = U64Response(accountInfo.Nonce) return nil } \ No newline at end of file diff --git a/dot/rpc/modules/system_test.go b/dot/rpc/modules/system_test.go index 79cbf7065c..aa44d6c987 100644 --- a/dot/rpc/modules/system_test.go +++ b/dot/rpc/modules/system_test.go @@ -17,6 +17,7 @@ package modules import ( + "github.com/ChainSafe/gossamer/lib/scale" "math/big" "os" "path" @@ -96,7 +97,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, nil) + sys := NewSystemModule(net, nil, nil, nil) res := &SystemHealthResponse{} err := sys.Health(nil, nil, res) @@ -110,7 +111,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, nil) + sys := NewSystemModule(net, nil, nil, nil) res := &SystemNetworkStateResponse{} err := sys.NetworkState(nil, nil, res) @@ -126,7 +127,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, nil) + sys := NewSystemModule(net, nil, nil, nil) res := &SystemPeersResponse{} err := sys.Peers(nil, nil, res) @@ -139,7 +140,7 @@ func TestSystemModule_Peers(t *testing.T) { func TestSystemModule_NodeRoles(t *testing.T) { net := newNetworkService(t) - sys := NewSystemModule(net, nil) + sys := NewSystemModule(net, nil, nil, nil) expected := []interface{}{"Full"} var res []interface{} @@ -187,7 +188,7 @@ func (api *mockSystemAPI) ChainType() string { } func TestSystemModule_Chain(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI()) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) res := new(string) err := sys.Chain(nil, nil, res) @@ -198,7 +199,7 @@ func TestSystemModule_Chain(t *testing.T) { func TestSystemModule_ChainType(t *testing.T) { api := newMockSystemAPI() - sys := NewSystemModule(nil, api) + sys := NewSystemModule(nil, api, nil, nil) res := new(string) sys.ChainType(nil, nil, res) @@ -206,7 +207,7 @@ func TestSystemModule_ChainType(t *testing.T) { } func TestSystemModule_Name(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI()) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) res := new(string) err := sys.Name(nil, nil, res) @@ -215,7 +216,7 @@ func TestSystemModule_Name(t *testing.T) { } func TestSystemModule_Version(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI()) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) res := new(string) err := sys.Version(nil, nil, res) @@ -224,10 +225,57 @@ func TestSystemModule_Version(t *testing.T) { } func TestSystemModule_Properties(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI()) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) res := new(interface{}) err := sys.Properties(nil, nil, res) require.NoError(t, err) require.Equal(t, testSystemInfo.SystemProperties, *res) } + +func TestSystemModule_AccountNextIndex(t *testing.T) { + sys := setupSystemModule(t) + expected := U64Response(uint64(10)) + + res := new (U64Response) + req := StringRequest{ + String: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + } + err := sys.AccountNextIndex(nil, &req, res) + require.NoError(t, err) + + require.Equal(t, expected, *res) + +} + +func setupSystemModule(t *testing.T) (*SystemModule) { + // setup service + net := newNetworkService(t) + chain := newTestStateService(t) + // init storage with test data + ts, err := chain.Storage.TrieState(nil) + require.NoError(t, err) + + aliceAcctStoKey, err := common.HexToBytes("0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d") + require.NoError(t, err) + aliceAcctInfo := types.AccountInfo{ + Nonce: 10, + RefCount: 0, + Data: struct { + Free common.Uint128 + Reserved common.Uint128 + MiscFrozen common.Uint128 + FreeFrozen common.Uint128 +}{}, + } + aliceAcctEncoded, err := scale.Encode(aliceAcctInfo) + require.NoError(t, err) + err = ts.Set(aliceAcctStoKey, aliceAcctEncoded) + require.NoError(t, err) + + err = chain.Storage.StoreTrie(ts) + require.NoError(t, err) + + core := newCoreService(t, chain) + return NewSystemModule(net, nil, core, chain.Storage) +} From 36b128b4b40da3332b1468ce6a2baecedf127d8f Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Tue, 9 Feb 2021 16:53:17 -0500 Subject: [PATCH 03/10] lint --- dot/rpc/modules/system.go | 20 +++++++++++++++----- dot/rpc/modules/system_test.go | 18 +++++++++--------- dot/rpc/service_test.go | 2 +- 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/dot/rpc/modules/system.go b/dot/rpc/modules/system.go index e5120e9e89..1221b3ad22 100644 --- a/dot/rpc/modules/system.go +++ b/dot/rpc/modules/system.go @@ -18,18 +18,19 @@ package modules import ( "errors" + "net/http" + "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto" "github.com/ChainSafe/gossamer/lib/scale" "github.com/centrifuge/go-substrate-rpc-client/v2/types" - "net/http" ) // SystemModule is an RPC module providing access to core API points type SystemModule struct { networkAPI NetworkAPI systemAPI SystemAPI - coreAPI CoreAPI + coreAPI CoreAPI storageAPI StorageAPI } @@ -56,8 +57,10 @@ type SystemNetworkStateResponse struct { // SystemPeersResponse struct to marshal json type SystemPeersResponse []common.PeerInfo +// U64Response holds U64 response type U64Response uint64 +// StringRequest holds string request type StringRequest struct { String string } @@ -67,7 +70,7 @@ func NewSystemModule(net NetworkAPI, sys SystemAPI, core CoreAPI, storage Storag return &SystemModule{ networkAPI: net, // TODO: migrate to network state systemAPI: sys, - coreAPI: core, + coreAPI: core, storageAPI: storage, } } @@ -149,6 +152,7 @@ func (sm *SystemModule) NodeRoles(r *http.Request, req *EmptyRequest, res *[]int return nil } +// AccountNextIndex Returns the next valid index (aka. nonce) for given account. func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, res *U64Response) error { // todo (ed) check pending transactions @@ -178,10 +182,16 @@ func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, re } accountRaw, err := sm.storageAPI.GetStorage(nil, storageKey) + if err != nil { + return err + } var accountInfo types.AccountInfo - types.DecodeFromBytes(accountRaw, &accountInfo) + err = types.DecodeFromBytes(accountRaw, &accountInfo) + if err != nil { + return err + } *res = U64Response(accountInfo.Nonce) return nil -} \ No newline at end of file +} diff --git a/dot/rpc/modules/system_test.go b/dot/rpc/modules/system_test.go index aa44d6c987..60436935d4 100644 --- a/dot/rpc/modules/system_test.go +++ b/dot/rpc/modules/system_test.go @@ -17,7 +17,6 @@ package modules import ( - "github.com/ChainSafe/gossamer/lib/scale" "math/big" "os" "path" @@ -26,6 +25,7 @@ import ( "github.com/ChainSafe/gossamer/dot/network" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/scale" "github.com/stretchr/testify/require" ) @@ -237,7 +237,7 @@ func TestSystemModule_AccountNextIndex(t *testing.T) { sys := setupSystemModule(t) expected := U64Response(uint64(10)) - res := new (U64Response) + res := new(U64Response) req := StringRequest{ String: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", } @@ -248,7 +248,7 @@ func TestSystemModule_AccountNextIndex(t *testing.T) { } -func setupSystemModule(t *testing.T) (*SystemModule) { +func setupSystemModule(t *testing.T) *SystemModule { // setup service net := newNetworkService(t) chain := newTestStateService(t) @@ -262,11 +262,11 @@ func setupSystemModule(t *testing.T) (*SystemModule) { Nonce: 10, RefCount: 0, Data: struct { - Free common.Uint128 - Reserved common.Uint128 - MiscFrozen common.Uint128 - FreeFrozen common.Uint128 -}{}, + Free common.Uint128 + Reserved common.Uint128 + MiscFrozen common.Uint128 + FreeFrozen common.Uint128 + }{}, } aliceAcctEncoded, err := scale.Encode(aliceAcctInfo) require.NoError(t, err) @@ -277,5 +277,5 @@ func setupSystemModule(t *testing.T) (*SystemModule) { require.NoError(t, err) core := newCoreService(t, chain) - return NewSystemModule(net, nil, core, chain.Storage) + return NewSystemModule(net, nil, core, chain.Storage) } diff --git a/dot/rpc/service_test.go b/dot/rpc/service_test.go index 7a74e4b636..37fa729430 100644 --- a/dot/rpc/service_test.go +++ b/dot/rpc/service_test.go @@ -38,7 +38,7 @@ func TestService_Methods(t *testing.T) { qtyAuthorMethods := 7 rpcService := NewService() - sysMod := modules.NewSystemModule(nil, nil) + sysMod := modules.NewSystemModule(nil, nil, nil, nil) rpcService.BuildMethodNames(sysMod, "system") m := rpcService.Methods() require.Equal(t, qtySystemMethods, len(m)) // check to confirm quantity for methods is correct From 36dee2a0aaff1f2cb55c60180616f2d810cd705f Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Tue, 9 Feb 2021 17:40:08 -0500 Subject: [PATCH 04/10] update testService_Methods --- dot/rpc/service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dot/rpc/service_test.go b/dot/rpc/service_test.go index 37fa729430..a081509033 100644 --- a/dot/rpc/service_test.go +++ b/dot/rpc/service_test.go @@ -33,7 +33,7 @@ func TestNewService(t *testing.T) { } func TestService_Methods(t *testing.T) { - qtySystemMethods := 9 + qtySystemMethods := 10 qtyRPCMethods := 1 qtyAuthorMethods := 7 From 9ee96c8ef2e7b832d51a2428ebad9c6353b187c3 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Thu, 11 Feb 2021 10:34:49 -0500 Subject: [PATCH 05/10] move parmeter check --- dot/rpc/modules/system.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dot/rpc/modules/system.go b/dot/rpc/modules/system.go index 1221b3ad22..9ddb40a861 100644 --- a/dot/rpc/modules/system.go +++ b/dot/rpc/modules/system.go @@ -156,6 +156,10 @@ func (sm *SystemModule) NodeRoles(r *http.Request, req *EmptyRequest, res *[]int func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, res *U64Response) error { // todo (ed) check pending transactions + if req == nil || len(req.String) == 0 { + return errors.New("Account address must be valid") + } + // get metadata to build storage storageKey rawMeta, err := sm.coreAPI.GetMetadata(nil) if err != nil { @@ -171,9 +175,6 @@ func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, re return err } - if req == nil || len(req.String) == 0 { - return errors.New("Account address must be valid") - } addressPubKey := crypto.PublicAddressToByteArray(common.Address(req.String)) storageKey, err := types.CreateStorageKey(&metadata, "System", "Account", addressPubKey, nil) From 6ec24a44ff32ee2d7391824f48bf5a6efca0b7d5 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Fri, 12 Feb 2021 10:44:20 -0500 Subject: [PATCH 06/10] add TransactionStateAPI to RPC systemModule --- dot/rpc/http.go | 2 +- dot/rpc/modules/system.go | 8 +++++--- dot/rpc/modules/system_test.go | 20 ++++++++++---------- dot/rpc/service_test.go | 2 +- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/dot/rpc/http.go b/dot/rpc/http.go index e9a897321a..d6e603694b 100644 --- a/dot/rpc/http.go +++ b/dot/rpc/http.go @@ -104,7 +104,7 @@ func (h *HTTPServer) RegisterModules(mods []string) { switch mod { case "system": srvc = modules.NewSystemModule(h.serverConfig.NetworkAPI, h.serverConfig.SystemAPI, - h.serverConfig.CoreAPI, h.serverConfig.StorageAPI) + h.serverConfig.CoreAPI, h.serverConfig.StorageAPI, h.serverConfig.TransactionQueueAPI) case "author": srvc = modules.NewAuthorModule(h.logger, h.serverConfig.CoreAPI, h.serverConfig.RuntimeAPI, h.serverConfig.TransactionQueueAPI) case "chain": diff --git a/dot/rpc/modules/system.go b/dot/rpc/modules/system.go index 9ddb40a861..896d3d2240 100644 --- a/dot/rpc/modules/system.go +++ b/dot/rpc/modules/system.go @@ -32,6 +32,7 @@ type SystemModule struct { systemAPI SystemAPI coreAPI CoreAPI storageAPI StorageAPI + txStateAPI TransactionStateAPI } // EmptyRequest represents an RPC request with no fields @@ -66,12 +67,14 @@ type StringRequest struct { } // NewSystemModule creates a new API instance -func NewSystemModule(net NetworkAPI, sys SystemAPI, core CoreAPI, storage StorageAPI) *SystemModule { +func NewSystemModule(net NetworkAPI, sys SystemAPI, core CoreAPI, + storage StorageAPI, txAPI TransactionStateAPI) *SystemModule { return &SystemModule{ networkAPI: net, // TODO: migrate to network state systemAPI: sys, coreAPI: core, storageAPI: storage, + txStateAPI: txAPI, } } @@ -159,6 +162,7 @@ func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, re if req == nil || len(req.String) == 0 { return errors.New("Account address must be valid") } + addressPubKey := crypto.PublicAddressToByteArray(common.Address(req.String)) // get metadata to build storage storageKey rawMeta, err := sm.coreAPI.GetMetadata(nil) @@ -175,8 +179,6 @@ func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, re return err } - addressPubKey := crypto.PublicAddressToByteArray(common.Address(req.String)) - storageKey, err := types.CreateStorageKey(&metadata, "System", "Account", addressPubKey, nil) if err != nil { return err diff --git a/dot/rpc/modules/system_test.go b/dot/rpc/modules/system_test.go index 60436935d4..1d850efd60 100644 --- a/dot/rpc/modules/system_test.go +++ b/dot/rpc/modules/system_test.go @@ -97,7 +97,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, nil, nil, nil) + sys := NewSystemModule(net, nil, nil, nil, nil) res := &SystemHealthResponse{} err := sys.Health(nil, nil, res) @@ -111,7 +111,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, nil, nil, nil) + sys := NewSystemModule(net, nil, nil, nil, nil) res := &SystemNetworkStateResponse{} err := sys.NetworkState(nil, nil, res) @@ -127,7 +127,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, nil, nil, nil) + sys := NewSystemModule(net, nil, nil, nil, nil) res := &SystemPeersResponse{} err := sys.Peers(nil, nil, res) @@ -140,7 +140,7 @@ func TestSystemModule_Peers(t *testing.T) { func TestSystemModule_NodeRoles(t *testing.T) { net := newNetworkService(t) - sys := NewSystemModule(net, nil, nil, nil) + sys := NewSystemModule(net, nil, nil, nil, nil) expected := []interface{}{"Full"} var res []interface{} @@ -188,7 +188,7 @@ func (api *mockSystemAPI) ChainType() string { } func TestSystemModule_Chain(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil, nil) res := new(string) err := sys.Chain(nil, nil, res) @@ -199,7 +199,7 @@ func TestSystemModule_Chain(t *testing.T) { func TestSystemModule_ChainType(t *testing.T) { api := newMockSystemAPI() - sys := NewSystemModule(nil, api, nil, nil) + sys := NewSystemModule(nil, api, nil, nil, nil) res := new(string) sys.ChainType(nil, nil, res) @@ -207,7 +207,7 @@ func TestSystemModule_ChainType(t *testing.T) { } func TestSystemModule_Name(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil, nil) res := new(string) err := sys.Name(nil, nil, res) @@ -216,7 +216,7 @@ func TestSystemModule_Name(t *testing.T) { } func TestSystemModule_Version(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil, nil) res := new(string) err := sys.Version(nil, nil, res) @@ -225,7 +225,7 @@ func TestSystemModule_Version(t *testing.T) { } func TestSystemModule_Properties(t *testing.T) { - sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil) + sys := NewSystemModule(nil, newMockSystemAPI(), nil, nil, nil) res := new(interface{}) err := sys.Properties(nil, nil, res) @@ -277,5 +277,5 @@ func setupSystemModule(t *testing.T) *SystemModule { require.NoError(t, err) core := newCoreService(t, chain) - return NewSystemModule(net, nil, core, chain.Storage) + return NewSystemModule(net, nil, core, chain.Storage, nil) } diff --git a/dot/rpc/service_test.go b/dot/rpc/service_test.go index a081509033..d6c6cbed3a 100644 --- a/dot/rpc/service_test.go +++ b/dot/rpc/service_test.go @@ -38,7 +38,7 @@ func TestService_Methods(t *testing.T) { qtyAuthorMethods := 7 rpcService := NewService() - sysMod := modules.NewSystemModule(nil, nil, nil, nil) + sysMod := modules.NewSystemModule(nil, nil, nil, nil, nil) rpcService.BuildMethodNames(sysMod, "system") m := rpcService.Methods() require.Equal(t, qtySystemMethods, len(m)) // check to confirm quantity for methods is correct From 68a50560ae86063b2ca571be46c288aed323bb29 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Fri, 12 Feb 2021 16:45:43 -0500 Subject: [PATCH 07/10] add check of pending transactions ot accountNextIndex --- dot/rpc/modules/system.go | 46 +++++++++++++++++++---- tests/polkadotjs_test/test_transaction.js | 3 +- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/dot/rpc/modules/system.go b/dot/rpc/modules/system.go index 896d3d2240..4123a470d3 100644 --- a/dot/rpc/modules/system.go +++ b/dot/rpc/modules/system.go @@ -17,13 +17,16 @@ package modules import ( + "bytes" "errors" + "fmt" + "math/big" "net/http" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/crypto" "github.com/ChainSafe/gossamer/lib/scale" - "github.com/centrifuge/go-substrate-rpc-client/v2/types" + ctypes "github.com/centrifuge/go-substrate-rpc-client/v2/types" ) // SystemModule is an RPC module providing access to core API points @@ -157,13 +160,40 @@ func (sm *SystemModule) NodeRoles(r *http.Request, req *EmptyRequest, res *[]int // AccountNextIndex Returns the next valid index (aka. nonce) for given account. func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, res *U64Response) error { - // todo (ed) check pending transactions - if req == nil || len(req.String) == 0 { return errors.New("Account address must be valid") } addressPubKey := crypto.PublicAddressToByteArray(common.Address(req.String)) + // check pending transactions for extrinsics singed by addressPubKey + pending := sm.txStateAPI.Pending() + nonce := uint64(0) + found := false + for _, v := range pending { + var ext ctypes.Extrinsic + err := ctypes.DecodeFromBytes(v.Extrinsic[1:], &ext) + if err != nil { + return err + } + extSigner, err := common.HexToBytes(fmt.Sprintf("0x%x", ext.Signature.Signer.AsAccountID)) + if err != nil { + return err + } + if bytes.Equal(extSigner, addressPubKey) { + found = true + sigNonce := big.Int(ext.Signature.Nonce) + if sigNonce.Uint64() > nonce { + nonce = sigNonce.Uint64() + } + } + } + + if found { + *res = U64Response(nonce) + return nil + } + + // no extrinsic signed by request found in pending transactions, so look in storage // get metadata to build storage storageKey rawMeta, err := sm.coreAPI.GetMetadata(nil) if err != nil { @@ -173,13 +203,13 @@ func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, re if err != nil { return err } - var metadata types.Metadata - err = types.DecodeFromBytes(sdMeta.([]byte), &metadata) + var metadata ctypes.Metadata + err = ctypes.DecodeFromBytes(sdMeta.([]byte), &metadata) if err != nil { return err } - storageKey, err := types.CreateStorageKey(&metadata, "System", "Account", addressPubKey, nil) + storageKey, err := ctypes.CreateStorageKey(&metadata, "System", "Account", addressPubKey, nil) if err != nil { return err } @@ -189,8 +219,8 @@ func (sm *SystemModule) AccountNextIndex(r *http.Request, req *StringRequest, re return err } - var accountInfo types.AccountInfo - err = types.DecodeFromBytes(accountRaw, &accountInfo) + var accountInfo ctypes.AccountInfo + err = ctypes.DecodeFromBytes(accountRaw, &accountInfo) if err != nil { return err } diff --git a/tests/polkadotjs_test/test_transaction.js b/tests/polkadotjs_test/test_transaction.js index 1ff64e4474..9df903da38 100644 --- a/tests/polkadotjs_test/test_transaction.js +++ b/tests/polkadotjs_test/test_transaction.js @@ -9,7 +9,6 @@ async function main() { const api = await ApiPromise.create({ provider: wsProvider }); // Simple transaction - // TODO Issue: This currently fails with error: RPC-CORE: submitExtrinsic(extrinsic: Extrinsic): Hash:: -32000: validator: (nil *modules.Extrinsic): null const keyring = new Keyring({type: 'sr25519' }); const aliceKey = keyring.addFromUri('//Alice', { name: 'Alice default' }); console.log(`${aliceKey.meta.name}: has address ${aliceKey.address} with publicKey [${aliceKey.publicKey}]`); @@ -17,7 +16,7 @@ async function main() { const ADDR_Bob = '0x90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22'; const transfer = await api.tx.balances.transfer(ADDR_Bob, 12345) - .signAndSend(aliceKey, {era: 0, blockHash: '0x64597c55a052d484d9ff357266be326f62573bb4fbdbb3cd49f219396fcebf78', blockNumber:0, genesisHash: '0x64597c55a052d484d9ff357266be326f62573bb4fbdbb3cd49f219396fcebf78', nonce: 0, tip: 0, transactionVersion: 1}); + .signAndSend(aliceKey, {era: 0, blockHash: '0x64597c55a052d484d9ff357266be326f62573bb4fbdbb3cd49f219396fcebf78', blockNumber:0, genesisHash: '0x64597c55a052d484d9ff357266be326f62573bb4fbdbb3cd49f219396fcebf78', nonce: 1, tip: 0, transactionVersion: 1}); console.log(`hxHash ${transfer}`); From 5bf9f789223d06e835f1e259effe6176ca2197aa Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Fri, 12 Feb 2021 17:59:32 -0500 Subject: [PATCH 08/10] add test for pending tranactions --- dot/rpc/modules/system_test.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/dot/rpc/modules/system_test.go b/dot/rpc/modules/system_test.go index 1d850efd60..9fdf29cf8d 100644 --- a/dot/rpc/modules/system_test.go +++ b/dot/rpc/modules/system_test.go @@ -23,9 +23,11 @@ import ( "testing" "github.com/ChainSafe/gossamer/dot/network" + "github.com/ChainSafe/gossamer/dot/state" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/scale" + "github.com/ChainSafe/gossamer/lib/transaction" "github.com/stretchr/testify/require" ) @@ -235,7 +237,7 @@ func TestSystemModule_Properties(t *testing.T) { func TestSystemModule_AccountNextIndex(t *testing.T) { sys := setupSystemModule(t) - expected := U64Response(uint64(10)) + expectedStored := U64Response(uint64(3)) res := new(U64Response) req := StringRequest{ @@ -244,8 +246,20 @@ func TestSystemModule_AccountNextIndex(t *testing.T) { err := sys.AccountNextIndex(nil, &req, res) require.NoError(t, err) - require.Equal(t, expected, *res) + require.Equal(t, expectedStored, *res) + // extrinsic for transfer signed by alice, nonce 4 (created with polkadot.js/api test_transaction) + signedExt := common.MustHexToBytes("0x022d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018c35943da8a04f06a36db9fadc7b2f02ccdef38dd89f88835c0af16b5fce816b117d8073aca078984d5b81bcf86e89cfa3195e5ec3c457d4282370b854f430850010000600ff90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22e5c0") + vtx := &transaction.ValidTransaction{ + Extrinsic: types.NewExtrinsic(signedExt), + Validity: new(transaction.Validity), + } + expectedPending := U64Response(uint64(4)) + sys.txStateAPI.AddToPool(vtx) + + err = sys.AccountNextIndex(nil, &req, res) + require.NoError(t, err) + require.Equal(t, expectedPending, *res) } func setupSystemModule(t *testing.T) *SystemModule { @@ -259,7 +273,7 @@ func setupSystemModule(t *testing.T) *SystemModule { aliceAcctStoKey, err := common.HexToBytes("0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9de1e86a9a8c739864cf3cc5ec2bea59fd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d") require.NoError(t, err) aliceAcctInfo := types.AccountInfo{ - Nonce: 10, + Nonce: 3, RefCount: 0, Data: struct { Free common.Uint128 @@ -277,5 +291,7 @@ func setupSystemModule(t *testing.T) *SystemModule { require.NoError(t, err) core := newCoreService(t, chain) - return NewSystemModule(net, nil, core, chain.Storage, nil) + // TODO (ed) add transactions to txQueue and add test for those + txQueue := state.NewTransactionState() + return NewSystemModule(net, nil, core, chain.Storage, txQueue) } From 71502a3471adab3f70391890f44052aa7359357f Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Tue, 16 Feb 2021 17:51:40 -0500 Subject: [PATCH 09/10] run lint --- dot/rpc/modules/system_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dot/rpc/modules/system_test.go b/dot/rpc/modules/system_test.go index fed8033816..f738a2b956 100644 --- a/dot/rpc/modules/system_test.go +++ b/dot/rpc/modules/system_test.go @@ -26,9 +26,9 @@ import ( "github.com/ChainSafe/gossamer/dot/state" "github.com/ChainSafe/gossamer/dot/types" "github.com/ChainSafe/gossamer/lib/common" + "github.com/ChainSafe/gossamer/lib/genesis" "github.com/ChainSafe/gossamer/lib/scale" "github.com/ChainSafe/gossamer/lib/transaction" - "github.com/ChainSafe/gossamer/lib/genesis" "github.com/stretchr/testify/require" ) From ce88cc3ccd78cdecf44e72d9bda3d1955d9d20f2 Mon Sep 17 00:00:00 2001 From: Edward Mack Date: Wed, 17 Feb 2021 15:22:18 -0500 Subject: [PATCH 10/10] add tests --- dot/rpc/modules/system_test.go | 37 +++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/dot/rpc/modules/system_test.go b/dot/rpc/modules/system_test.go index f738a2b956..68dd972f46 100644 --- a/dot/rpc/modules/system_test.go +++ b/dot/rpc/modules/system_test.go @@ -243,7 +243,7 @@ func TestSystemModule_Properties(t *testing.T) { require.Equal(t, expected, *res) } -func TestSystemModule_AccountNextIndex(t *testing.T) { +func TestSystemModule_AccountNextIndex_StoragePending(t *testing.T) { sys := setupSystemModule(t) expectedStored := U64Response(uint64(3)) @@ -270,6 +270,41 @@ func TestSystemModule_AccountNextIndex(t *testing.T) { require.Equal(t, expectedPending, *res) } +func TestSystemModule_AccountNextIndex_Storage(t *testing.T) { + sys := setupSystemModule(t) + expectedStored := U64Response(uint64(3)) + + res := new(U64Response) + req := StringRequest{ + String: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + } + err := sys.AccountNextIndex(nil, &req, res) + require.NoError(t, err) + + require.Equal(t, expectedStored, *res) +} + +func TestSystemModule_AccountNextIndex_Pending(t *testing.T) { + sys := setupSystemModule(t) + res := new(U64Response) + req := StringRequest{ + String: "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY", + } + + // extrinsic for transfer signed by alice, nonce 4 (created with polkadot.js/api test_transaction) + signedExt := common.MustHexToBytes("0x022d0284ffd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d018c35943da8a04f06a36db9fadc7b2f02ccdef38dd89f88835c0af16b5fce816b117d8073aca078984d5b81bcf86e89cfa3195e5ec3c457d4282370b854f430850010000600ff90b5ab205c6974c9ea841be688864633dc9ca8a357843eeacf2314649965fe22e5c0") + vtx := &transaction.ValidTransaction{ + Extrinsic: types.NewExtrinsic(signedExt), + Validity: new(transaction.Validity), + } + expectedPending := U64Response(uint64(4)) + sys.txStateAPI.AddToPool(vtx) + + err := sys.AccountNextIndex(nil, &req, res) + require.NoError(t, err) + require.Equal(t, expectedPending, *res) +} + func setupSystemModule(t *testing.T) *SystemModule { // setup service net := newNetworkService(t)