From 7a5deec2159dcd9910aebecacaea3257abfde3cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ecl=C3=A9sio=20Junior?= Date: Fri, 15 Oct 2021 08:05:56 -0400 Subject: [PATCH] feat(rpc): Implement `payment_queryInfo` RPC call (#1826) * chore: adding payment rpc module * chore: adding unit test to runtime call * chore: use defined extrinsic * chore: add Payment Query Info * chore: add unit test to runtime layer * chore: add unit tests * chore: resolve uint128 * chore: fix lint warns * chore: put condition back * chore: use pkg/scale uint128 * chore: fix unit tests * chore: remove debug from config.toml * fix: lint * chore: remove tests from wasmtime and life * chore: resolving conflicts * chore: remove life impl form payment query info * chore: simplify chain_test function * chore: ignore unused meth receiver --- chain/dev/config.toml | 2 +- chain/dev/defaults.go | 2 +- chain/gssmr/config.toml | 2 +- chain/gssmr/defaults.go | 2 +- chain/kusama/config.toml | 2 +- chain/kusama/defaults.go | 2 +- chain/polkadot/config.toml | 2 +- chain/polkadot/defaults.go | 2 +- dot/rpc/http.go | 2 + dot/rpc/modules/api.go | 1 + dot/rpc/modules/chain_test.go | 18 +++- dot/rpc/modules/mocks/block_api.go | 25 ++++- dot/rpc/modules/payment.go | 69 ++++++++++++++ dot/rpc/modules/payment_test.go | 142 +++++++++++++++++++++++++++++ dot/rpc/service.go | 2 + dot/types/tx.go | 12 +++ lib/common/common.go | 4 +- lib/runtime/constants.go | 2 + lib/runtime/interface.go | 1 + lib/runtime/life/exports.go | 7 ++ lib/runtime/life/exports_test.go | 1 - lib/runtime/mocks/instance.go | 116 ++++++++++++++++------- lib/runtime/wasmer/exports.go | 20 ++++ lib/runtime/wasmer/exports_test.go | 63 +++++++++++++ pkg/scale/uint128.go | 5 + 25 files changed, 461 insertions(+), 45 deletions(-) create mode 100644 dot/rpc/modules/payment.go create mode 100644 dot/rpc/modules/payment_test.go diff --git a/chain/dev/config.toml b/chain/dev/config.toml index f19fa63578..c8f686d79a 100644 --- a/chain/dev/config.toml +++ b/chain/dev/config.toml @@ -35,5 +35,5 @@ enabled = true ws = true port = 8545 host = "localhost" -modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"] +modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"] ws-port = 8546 diff --git a/chain/dev/defaults.go b/chain/dev/defaults.go index b6db6ec7e9..40134204d0 100644 --- a/chain/dev/defaults.go +++ b/chain/dev/defaults.go @@ -87,7 +87,7 @@ var ( // DefaultRPCHTTPPort rpc port DefaultRPCHTTPPort = uint32(8545) // DefaultRPCModules rpc modules - DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"} + DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"} // DefaultRPCWSPort rpc websocket port DefaultRPCWSPort = uint32(8546) // DefaultRPCEnabled enables the RPC server diff --git a/chain/gssmr/config.toml b/chain/gssmr/config.toml index 6419e8cec1..532a14e565 100644 --- a/chain/gssmr/config.toml +++ b/chain/gssmr/config.toml @@ -35,5 +35,5 @@ discovery-interval = 10 enabled = false port = 8545 host = "localhost" -modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"] +modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"] ws-port = 8546 diff --git a/chain/gssmr/defaults.go b/chain/gssmr/defaults.go index 0cdc3d2d35..cee187b338 100644 --- a/chain/gssmr/defaults.go +++ b/chain/gssmr/defaults.go @@ -92,7 +92,7 @@ var ( // DefaultRPCHTTPPort rpc port DefaultRPCHTTPPort = uint32(8545) // DefaultRPCModules rpc modules - DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"} + DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"} // DefaultRPCWSPort rpc websocket port DefaultRPCWSPort = uint32(8546) ) diff --git a/chain/kusama/config.toml b/chain/kusama/config.toml index dd3261fde6..035cad0c37 100644 --- a/chain/kusama/config.toml +++ b/chain/kusama/config.toml @@ -35,7 +35,7 @@ enabled = false external = false port = 8545 host = "localhost" -modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"] +modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"] ws-port = 8546 ws = false ws-external = false diff --git a/chain/kusama/defaults.go b/chain/kusama/defaults.go index 8902a46297..ed8f3365fd 100644 --- a/chain/kusama/defaults.go +++ b/chain/kusama/defaults.go @@ -83,7 +83,7 @@ var ( // DefaultRPCHTTPPort rpc port DefaultRPCHTTPPort = uint32(8545) // DefaultRPCModules rpc modules - DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"} + DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"} // DefaultRPCWSPort rpc websocket port DefaultRPCWSPort = uint32(8546) ) diff --git a/chain/polkadot/config.toml b/chain/polkadot/config.toml index 98f3291e1b..440f0b12bd 100644 --- a/chain/polkadot/config.toml +++ b/chain/polkadot/config.toml @@ -34,5 +34,5 @@ nomdns = false enabled = false port = 8545 host = "localhost" -modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"] +modules = ["system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"] ws-port = 8546 \ No newline at end of file diff --git a/chain/polkadot/defaults.go b/chain/polkadot/defaults.go index dbc0dd8e2b..31853bb83a 100644 --- a/chain/polkadot/defaults.go +++ b/chain/polkadot/defaults.go @@ -84,7 +84,7 @@ var ( // DefaultRPCHTTPPort rpc port DefaultRPCHTTPPort = uint32(8545) // DefaultRPCModules rpc modules - DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate"} + DefaultRPCModules = []string{"system", "author", "chain", "state", "rpc", "grandpa", "offchain", "childstate", "payment"} // DefaultRPCWSPort rpc websocket port DefaultRPCWSPort = uint32(8546) ) diff --git a/dot/rpc/http.go b/dot/rpc/http.go index 76fa52b06d..57388903c2 100644 --- a/dot/rpc/http.go +++ b/dot/rpc/http.go @@ -129,6 +129,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 "payment": + srvc = modules.NewPaymentModule(h.serverConfig.BlockAPI) default: h.logger.Warn("Unrecognised module", "module", mod) continue diff --git a/dot/rpc/modules/api.go b/dot/rpc/modules/api.go index 20f134b083..a62026146b 100644 --- a/dot/rpc/modules/api.go +++ b/dot/rpc/modules/api.go @@ -45,6 +45,7 @@ type BlockAPI interface { SubChain(start, end common.Hash) ([]common.Hash, error) RegisterRuntimeUpdatedChannel(ch chan<- runtime.Version) (uint32, error) UnregisterRuntimeUpdatedChannel(id uint32) bool + GetRuntime(hash *common.Hash) (runtime.Instance, error) } // NetworkAPI interface for network state methods diff --git a/dot/rpc/modules/chain_test.go b/dot/rpc/modules/chain_test.go index 849e33f3da..04fd5d559f 100644 --- a/dot/rpc/modules/chain_test.go +++ b/dot/rpc/modules/chain_test.go @@ -19,6 +19,7 @@ package modules import ( "io/ioutil" "math/big" + "path/filepath" "testing" "github.com/ChainSafe/gossamer/dot/state" @@ -26,10 +27,13 @@ import ( "github.com/ChainSafe/gossamer/lib/common" "github.com/ChainSafe/gossamer/lib/genesis" "github.com/ChainSafe/gossamer/lib/runtime" + "github.com/ChainSafe/gossamer/lib/runtime/wasmer" "github.com/ChainSafe/gossamer/lib/trie" + "github.com/ChainSafe/gossamer/lib/utils" "github.com/ChainSafe/gossamer/pkg/scale" database "github.com/ChainSafe/chaindb" + rtstorage "github.com/ChainSafe/gossamer/lib/runtime/storage" log "github.com/ChainSafe/log15" "github.com/stretchr/testify/require" ) @@ -350,7 +354,19 @@ func newTestStateService(t *testing.T) *state.Service { err = stateSrvc.Start() require.NoError(t, err) - rt, err := stateSrvc.CreateGenesisRuntime(genTrie, gen) + rtCfg := &wasmer.Config{} + + rtCfg.Storage, err = rtstorage.NewTrieState(genTrie) + require.NoError(t, err) + + if stateSrvc != nil { + rtCfg.NodeStorage.BaseDB = stateSrvc.Base + } else { + rtCfg.NodeStorage.BaseDB, err = utils.SetupDatabase(filepath.Join(testDatadirPath, "offline_storage"), false) + require.NoError(t, err) + } + + rt, err := wasmer.NewRuntimeFromGenesis(gen, rtCfg) require.NoError(t, err) err = loadTestBlocks(t, genesisHeader.Hash(), stateSrvc.Block, rt) diff --git a/dot/rpc/modules/mocks/block_api.go b/dot/rpc/modules/mocks/block_api.go index cf6d9382cf..f6d43d496e 100644 --- a/dot/rpc/modules/mocks/block_api.go +++ b/dot/rpc/modules/mocks/block_api.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.8.0. DO NOT EDIT. +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. package mocks @@ -214,6 +214,29 @@ func (_m *MockBlockAPI) GetJustification(hash common.Hash) ([]byte, error) { return r0, r1 } +// GetRuntime provides a mock function with given fields: hash +func (_m *MockBlockAPI) GetRuntime(hash *common.Hash) (runtime.Instance, error) { + ret := _m.Called(hash) + + var r0 runtime.Instance + if rf, ok := ret.Get(0).(func(*common.Hash) runtime.Instance); ok { + r0 = rf(hash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(runtime.Instance) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(*common.Hash) error); ok { + r1 = rf(hash) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // HasJustification provides a mock function with given fields: hash func (_m *MockBlockAPI) HasJustification(hash common.Hash) (bool, error) { ret := _m.Called(hash) diff --git a/dot/rpc/modules/payment.go b/dot/rpc/modules/payment.go new file mode 100644 index 0000000000..91757c7125 --- /dev/null +++ b/dot/rpc/modules/payment.go @@ -0,0 +1,69 @@ +package modules + +import ( + "net/http" + + "github.com/ChainSafe/gossamer/lib/common" +) + +// PaymentQueryInfoRequest represents the request to get the fee of an extrinsic in a given block +type PaymentQueryInfoRequest struct { + // hex SCALE encoded extrinsic + Ext string + // hex optional block hash indicating the state + Hash *common.Hash +} + +// PaymentQueryInfoResponse holds the response fields to the query info RPC method +type PaymentQueryInfoResponse struct { + Weight uint64 `json:"weight"` + Class int `json:"class"` + PartialFee string `json:"partialFee"` +} + +// PaymentModule holds all the RPC implementation of polkadot payment rpc api +type PaymentModule struct { + blockAPI BlockAPI +} + +// NewPaymentModule returns a pointer to PaymentModule +func NewPaymentModule(blockAPI BlockAPI) *PaymentModule { + return &PaymentModule{ + blockAPI: blockAPI, + } +} + +// QueryInfo query the known data about the fee of an extrinsic at the given block +func (p *PaymentModule) QueryInfo(_ *http.Request, req *PaymentQueryInfoRequest, res *PaymentQueryInfoResponse) error { + var hash common.Hash + if req.Hash == nil { + hash = p.blockAPI.BestBlockHash() + } else { + hash = *req.Hash + } + + r, err := p.blockAPI.GetRuntime(&hash) + if err != nil { + return err + } + + ext, err := common.HexToBytes(req.Ext) + if err != nil { + return err + } + + encQueryInfo, err := r.PaymentQueryInfo(ext) + if err != nil { + return err + } + + if encQueryInfo != nil { + *res = PaymentQueryInfoResponse{ + Weight: encQueryInfo.Weight, + Class: encQueryInfo.Class, + PartialFee: encQueryInfo.PartialFee.String(), + } + } + + return nil +} diff --git a/dot/rpc/modules/payment_test.go b/dot/rpc/modules/payment_test.go new file mode 100644 index 0000000000..b29c790732 --- /dev/null +++ b/dot/rpc/modules/payment_test.go @@ -0,0 +1,142 @@ +package modules + +import ( + "errors" + "testing" + + "github.com/ChainSafe/gossamer/dot/rpc/modules/mocks" + "github.com/ChainSafe/gossamer/dot/types" + "github.com/ChainSafe/gossamer/pkg/scale" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/ChainSafe/gossamer/lib/common" + mocksruntime "github.com/ChainSafe/gossamer/lib/runtime/mocks" +) + +func TestPaymentQueryInfo(t *testing.T) { + state := newTestStateService(t) + bestBlockHash := state.Block.BestBlockHash() + + t.Run("When there is no errors", func(t *testing.T) { + mockedQueryInfo := &types.TransactionPaymentQueryInfo{ + Weight: 0, + Class: 0, + PartialFee: scale.MaxUint128, + } + + expected := PaymentQueryInfoResponse{ + Weight: 0, + Class: 0, + PartialFee: scale.MaxUint128.String(), + } + + runtimeMock := new(mocksruntime.MockInstance) + runtimeMock.On("PaymentQueryInfo", mock.AnythingOfType("[]uint8")).Return(mockedQueryInfo, nil) + + blockAPIMock := new(mocks.MockBlockAPI) + blockAPIMock.On("BestBlockHash").Return(bestBlockHash) + + blockAPIMock.On("GetRuntime", mock.AnythingOfType("*common.Hash")).Return(runtimeMock, nil) + + mod := &PaymentModule{ + blockAPI: blockAPIMock, + } + + var req PaymentQueryInfoRequest + req.Ext = "0x0001" + req.Hash = nil + + var res PaymentQueryInfoResponse + err := mod.QueryInfo(nil, &req, &res) + + require.NoError(t, err) + require.Equal(t, expected, res) + + // should be called because req.Hash is nil + blockAPIMock.AssertCalled(t, "BestBlockHash") + blockAPIMock.AssertCalled(t, "GetRuntime", mock.AnythingOfType("*common.Hash")) + runtimeMock.AssertCalled(t, "PaymentQueryInfo", mock.AnythingOfType("[]uint8")) + }) + + t.Run("When could not get runtime", func(t *testing.T) { + blockAPIMock := new(mocks.MockBlockAPI) + blockAPIMock.On("BestBlockHash").Return(bestBlockHash) + + blockAPIMock.On("GetRuntime", mock.AnythingOfType("*common.Hash")). + Return(nil, errors.New("mocked problems")) + + mod := &PaymentModule{ + blockAPI: blockAPIMock, + } + + var req PaymentQueryInfoRequest + req.Ext = "0x0011" + req.Hash = nil + + var res PaymentQueryInfoResponse + err := mod.QueryInfo(nil, &req, &res) + + require.Error(t, err) + require.Equal(t, res, PaymentQueryInfoResponse{}) + + blockAPIMock.AssertCalled(t, "BestBlockHash") + blockAPIMock.AssertCalled(t, "GetRuntime", mock.AnythingOfType("*common.Hash")) + }) + + t.Run("When PaymentQueryInfo returns error", func(t *testing.T) { + runtimeMock := new(mocksruntime.MockInstance) + runtimeMock.On("PaymentQueryInfo", mock.AnythingOfType("[]uint8")).Return(nil, errors.New("mocked error")) + + blockAPIMock := new(mocks.MockBlockAPI) + blockAPIMock.On("GetRuntime", mock.AnythingOfType("*common.Hash")).Return(runtimeMock, nil) + + mod := &PaymentModule{ + blockAPI: blockAPIMock, + } + + mockedHash := common.NewHash([]byte{0x01, 0x02}) + var req PaymentQueryInfoRequest + req.Ext = "0x0000" + req.Hash = &mockedHash + + var res PaymentQueryInfoResponse + err := mod.QueryInfo(nil, &req, &res) + + require.Error(t, err) + require.Equal(t, res, PaymentQueryInfoResponse{}) + + // should be called because req.Hash is nil + blockAPIMock.AssertNotCalled(t, "BestBlockHash") + blockAPIMock.AssertCalled(t, "GetRuntime", mock.AnythingOfType("*common.Hash")) + runtimeMock.AssertCalled(t, "PaymentQueryInfo", mock.AnythingOfType("[]uint8")) + }) + + t.Run("When PaymentQueryInfo returns a nil info", func(t *testing.T) { + runtimeMock := new(mocksruntime.MockInstance) + runtimeMock.On("PaymentQueryInfo", mock.AnythingOfType("[]uint8")).Return(nil, nil) + + blockAPIMock := new(mocks.MockBlockAPI) + blockAPIMock.On("GetRuntime", mock.AnythingOfType("*common.Hash")).Return(runtimeMock, nil) + + mod := &PaymentModule{ + blockAPI: blockAPIMock, + } + + mockedHash := common.NewHash([]byte{0x01, 0x02}) + var req PaymentQueryInfoRequest + req.Ext = "0x0020" + req.Hash = &mockedHash + + var res PaymentQueryInfoResponse + err := mod.QueryInfo(nil, &req, &res) + + require.NoError(t, err) + require.Equal(t, res, PaymentQueryInfoResponse{}) + + // should be called because req.Hash is nil + blockAPIMock.AssertNotCalled(t, "BestBlockHash") + blockAPIMock.AssertCalled(t, "GetRuntime", mock.AnythingOfType("*common.Hash")) + runtimeMock.AssertCalled(t, "PaymentQueryInfo", mock.AnythingOfType("[]uint8")) + }) +} diff --git a/dot/rpc/service.go b/dot/rpc/service.go index 6d34ee7db2..2ea764a7b5 100644 --- a/dot/rpc/service.go +++ b/dot/rpc/service.go @@ -63,11 +63,13 @@ func (s *Service) BuildMethodNames(rcvr interface{}, name string) { if mtype.NumIn() != 4 { continue } + // First argument must be a pointer and must be http.Request. reqType := mtype.In(1) if reqType.Kind() != reflect.Ptr || reqType.Elem() != typeOfRequest { continue } + // Second argument must be a pointer and must be exported. args := mtype.In(2) if args.Kind() != reflect.Ptr || !isExportedOrBuiltIn(args) { diff --git a/dot/types/tx.go b/dot/types/tx.go index 4ca52ab7af..dace7b682c 100644 --- a/dot/types/tx.go +++ b/dot/types/tx.go @@ -16,6 +16,10 @@ package types +import ( + "github.com/ChainSafe/gossamer/pkg/scale" +) + // TransactionSource represents source of Transaction type TransactionSource uint8 @@ -41,3 +45,11 @@ const ( // for instance received over the network or RPC. TxnExternal ) + +// TransactionPaymentQueryInfo represents the basic information of a given encoded extrinsic +type TransactionPaymentQueryInfo struct { + Weight uint64 + // Class could be Normal (0), Operational (1), Mandatory (2) + Class int + PartialFee *scale.Uint128 +} diff --git a/lib/common/common.go b/lib/common/common.go index fea9e961f6..ac4370e0c0 100644 --- a/lib/common/common.go +++ b/lib/common/common.go @@ -72,7 +72,7 @@ func HexToBytes(in string) ([]byte, error) { } // Ensure we have an even length, otherwise hex.DecodeString will fail and return zero hash if len(in)%2 != 0 { - return nil, errors.New("cannot decode a odd length string") + return nil, errors.New("cannot decode an odd length string") } in = in[2:] out, err := hex.DecodeString(in) @@ -92,7 +92,7 @@ func MustHexToBytes(in string) []byte { // Ensure we have an even length, otherwise hex.DecodeString will fail and return zero hash if len(in)%2 != 0 { - panic("cannot decode a odd length string") + panic("cannot decode an odd length string") } in = in[2:] diff --git a/lib/runtime/constants.go b/lib/runtime/constants.go index 5d6e143aa2..6ec52b29ed 100644 --- a/lib/runtime/constants.go +++ b/lib/runtime/constants.go @@ -79,6 +79,8 @@ var ( BlockBuilderFinalizeBlock = "BlockBuilder_finalize_block" // DecodeSessionKeys is the runtime API call SessionKeys_decode_session_keys DecodeSessionKeys = "SessionKeys_decode_session_keys" + // TransactionPaymentApiQueryInfo returns information of a given extrinsic + TransactionPaymentApiQueryInfo = "TransactionPaymentApi_query_info" ) // GrandpaAuthoritiesKey is the location of GRANDPA authority data in the storage trie for LEGACY_NODE_RUNTIME and NODE_RUNTIME diff --git a/lib/runtime/interface.go b/lib/runtime/interface.go index 399c17f67a..f0f2b24067 100644 --- a/lib/runtime/interface.go +++ b/lib/runtime/interface.go @@ -49,6 +49,7 @@ type Instance interface { FinalizeBlock() (*types.Header, error) ExecuteBlock(block *types.Block) ([]byte, error) DecodeSessionKeys(enc []byte) ([]byte, error) + PaymentQueryInfo(ext []byte) (*types.TransactionPaymentQueryInfo, error) // TODO: parameters and return values for these are undefined in the spec CheckInherents() diff --git a/lib/runtime/life/exports.go b/lib/runtime/life/exports.go index a25475853b..6b398c3b8d 100644 --- a/lib/runtime/life/exports.go +++ b/lib/runtime/life/exports.go @@ -2,6 +2,7 @@ package life import ( "bytes" + "errors" "fmt" "strings" @@ -164,6 +165,12 @@ func (in *Instance) DecodeSessionKeys(enc []byte) ([]byte, error) { return in.Exec(runtime.DecodeSessionKeys, enc) } +// PaymentQueryInfo returns information of a given extrinsic +func (*Instance) PaymentQueryInfo([]byte) (*types.TransactionPaymentQueryInfo, error) { + // TODO: implement the payment query info (see issue #1892) + return nil, errors.New("not implemented yet") +} + func (in *Instance) CheckInherents() {} //nolint func (in *Instance) RandomSeed() {} //nolint func (in *Instance) OffchainWorker() {} //nolint diff --git a/lib/runtime/life/exports_test.go b/lib/runtime/life/exports_test.go index 88a9dcb628..71581f0943 100644 --- a/lib/runtime/life/exports_test.go +++ b/lib/runtime/life/exports_test.go @@ -13,7 +13,6 @@ import ( "github.com/ChainSafe/gossamer/lib/runtime/storage" "github.com/ChainSafe/gossamer/lib/trie" "github.com/ChainSafe/gossamer/pkg/scale" - "github.com/stretchr/testify/require" ) diff --git a/lib/runtime/mocks/instance.go b/lib/runtime/mocks/instance.go index 056286b1f4..2a1cb0e1d5 100644 --- a/lib/runtime/mocks/instance.go +++ b/lib/runtime/mocks/instance.go @@ -1,4 +1,4 @@ -// Code generated by mockery v2.8.0. DO NOT EDIT. +// Code generated by mockery v0.0.0-dev. DO NOT EDIT. package mocks @@ -27,8 +27,10 @@ func (_m *MockInstance) ApplyExtrinsic(data types.Extrinsic) ([]byte, error) { var r0 []byte if rf, ok := ret.Get(0).(func(types.Extrinsic) []byte); ok { r0 = rf(data) - } else if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } } var r1 error @@ -48,9 +50,10 @@ func (_m *MockInstance) BabeConfiguration() (*types.BabeConfiguration, error) { var r0 *types.BabeConfiguration if rf, ok := ret.Get(0).(func() *types.BabeConfiguration); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.BabeConfiguration) - + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.BabeConfiguration) + } } var r1 error @@ -75,8 +78,10 @@ func (_m *MockInstance) CheckRuntimeVersion(_a0 []byte) (runtime.Version, error) var r0 runtime.Version if rf, ok := ret.Get(0).(func([]byte) runtime.Version); ok { r0 = rf(_a0) - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(runtime.Version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(runtime.Version) + } } var r1 error @@ -96,8 +101,10 @@ func (_m *MockInstance) DecodeSessionKeys(enc []byte) ([]byte, error) { var r0 []byte if rf, ok := ret.Get(0).(func([]byte) []byte); ok { r0 = rf(enc) - } else if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } } var r1 error @@ -117,8 +124,10 @@ func (_m *MockInstance) Exec(function string, data []byte) ([]byte, error) { var r0 []byte if rf, ok := ret.Get(0).(func(string, []byte) []byte); ok { r0 = rf(function, data) - } else if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } } var r1 error @@ -138,8 +147,10 @@ func (_m *MockInstance) ExecuteBlock(block *types.Block) ([]byte, error) { var r0 []byte if rf, ok := ret.Get(0).(func(*types.Block) []byte); ok { r0 = rf(block) - } else if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } } var r1 error @@ -159,8 +170,10 @@ func (_m *MockInstance) FinalizeBlock() (*types.Header, error) { var r0 *types.Header if rf, ok := ret.Get(0).(func() *types.Header); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.Header) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.Header) + } } var r1 error @@ -185,8 +198,10 @@ func (_m *MockInstance) GetCodeHash() common.Hash { var r0 common.Hash if rf, ok := ret.Get(0).(func() common.Hash); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(common.Hash) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(common.Hash) + } } return r0 @@ -199,8 +214,10 @@ func (_m *MockInstance) GrandpaAuthorities() ([]types.Authority, error) { var r0 []types.Authority if rf, ok := ret.Get(0).(func() []types.Authority); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).([]types.Authority) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]types.Authority) + } } var r1 error @@ -220,8 +237,10 @@ func (_m *MockInstance) InherentExtrinsics(data []byte) ([]byte, error) { var r0 []byte if rf, ok := ret.Get(0).(func([]byte) []byte); ok { r0 = rf(data) - } else if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } } var r1 error @@ -255,8 +274,10 @@ func (_m *MockInstance) Keystore() *keystore.GlobalKeystore { var r0 *keystore.GlobalKeystore if rf, ok := ret.Get(0).(func() *keystore.GlobalKeystore); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(*keystore.GlobalKeystore) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*keystore.GlobalKeystore) + } } return r0 @@ -269,8 +290,10 @@ func (_m *MockInstance) Metadata() ([]byte, error) { var r0 []byte if rf, ok := ret.Get(0).(func() []byte); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).([]byte) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]byte) + } } var r1 error @@ -290,8 +313,10 @@ func (_m *MockInstance) NetworkService() runtime.BasicNetwork { var r0 runtime.BasicNetwork if rf, ok := ret.Get(0).(func() runtime.BasicNetwork); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(runtime.BasicNetwork) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(runtime.BasicNetwork) + } } return r0 @@ -316,6 +341,29 @@ func (_m *MockInstance) OffchainWorker() { _m.Called() } +// PaymentQueryInfo provides a mock function with given fields: ext +func (_m *MockInstance) PaymentQueryInfo(ext []byte) (*types.TransactionPaymentQueryInfo, error) { + ret := _m.Called(ext) + + var r0 *types.TransactionPaymentQueryInfo + if rf, ok := ret.Get(0).(func([]byte) *types.TransactionPaymentQueryInfo); ok { + r0 = rf(ext) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*types.TransactionPaymentQueryInfo) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func([]byte) error); ok { + r1 = rf(ext) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // RandomSeed provides a mock function with given fields: func (_m *MockInstance) RandomSeed() { _m.Called() @@ -352,8 +400,10 @@ func (_m *MockInstance) ValidateTransaction(e types.Extrinsic) (*transaction.Val var r0 *transaction.Validity if rf, ok := ret.Get(0).(func(types.Extrinsic) *transaction.Validity); ok { r0 = rf(e) - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(*transaction.Validity) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*transaction.Validity) + } } var r1 error @@ -387,8 +437,10 @@ func (_m *MockInstance) Version() (runtime.Version, error) { var r0 runtime.Version if rf, ok := ret.Get(0).(func() runtime.Version); ok { r0 = rf() - } else if ret.Get(0) != nil { - r0 = ret.Get(0).(runtime.Version) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(runtime.Version) + } } var r1 error diff --git a/lib/runtime/wasmer/exports.go b/lib/runtime/wasmer/exports.go index 6e4ed7e526..602ea0d38d 100644 --- a/lib/runtime/wasmer/exports.go +++ b/lib/runtime/wasmer/exports.go @@ -190,6 +190,26 @@ func (in *Instance) DecodeSessionKeys(enc []byte) ([]byte, error) { return in.exec(runtime.DecodeSessionKeys, enc) } +// PaymentQueryInfo returns information of a given extrinsic +func (in *Instance) PaymentQueryInfo(ext []byte) (*types.TransactionPaymentQueryInfo, error) { + encLen, err := scale.Marshal(uint32(len(ext))) + if err != nil { + return nil, err + } + + resBytes, err := in.exec(runtime.TransactionPaymentApiQueryInfo, append(ext, encLen...)) + if err != nil { + return nil, err + } + + i := new(types.TransactionPaymentQueryInfo) + if err = scale.Unmarshal(resBytes, i); err != nil { + return nil, err + } + + return i, nil +} + func (in *Instance) CheckInherents() {} //nolint func (in *Instance) RandomSeed() {} //nolint func (in *Instance) OffchainWorker() {} //nolint diff --git a/lib/runtime/wasmer/exports_test.go b/lib/runtime/wasmer/exports_test.go index 1a3c3eeee8..3f83dc241b 100644 --- a/lib/runtime/wasmer/exports_test.go +++ b/lib/runtime/wasmer/exports_test.go @@ -2,6 +2,8 @@ package wasmer import ( "encoding/json" + "errors" + "fmt" "io/ioutil" "math/big" "testing" @@ -1070,6 +1072,67 @@ func TestInstance_DecodeSessionKeys(t *testing.T) { require.Len(t, *decodedKeys, 4) } +func TestInstance_PaymentQueryInfo(t *testing.T) { + tests := []struct { + extB []byte + ext string + err error + expect *types.TransactionPaymentQueryInfo + }{ + { + // Was made with @polkadot/api on https://github.com/danforbes/polkadot-js-scripts/tree/create-signed-tx + ext: "0xd1018400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01bc2b6e35929aabd5b8bc4e5b0168c9bee59e2bb9d6098769f6683ecf73e44c776652d947a270d59f3d37eb9f9c8c17ec1b4cc473f2f9928ffdeef0f3abd43e85d502000000012844616e20466f72626573", + err: nil, + expect: &types.TransactionPaymentQueryInfo{ + Weight: 1973000, + Class: 0, + PartialFee: &scale.Uint128{ + Upper: 0, + Lower: uint64(1180126973000), + }, + }, + }, + { + // incomplete extrinsic + ext: "0x4ccde39a5684e7a56da23b22d4d9fbadb023baa19c56495432884d0640000000000000000000000000000000", + err: errors.New("Failed to call the `TransactionPaymentApi_query_info` exported function."), //nolint + }, + { + // incomplete extrinsic + extB: nil, + err: errors.New("Failed to call the `TransactionPaymentApi_query_info` exported function."), //nolint + }, + } + + for _, test := range tests { + var err error + var extBytes []byte + + if test.ext == "" { + extBytes = test.extB + } else { + extBytes, err = common.HexToBytes(test.ext) + require.NoError(t, err) + } + + ins := NewTestInstance(t, runtime.NODE_RUNTIME) + info, err := ins.PaymentQueryInfo(extBytes) + + if test.err != nil { + require.Error(t, err) + require.Equal(t, err.Error(), test.err.Error()) + continue + } + + fmt.Println(info.PartialFee.String()) + fmt.Println(test.expect.PartialFee.String()) + + require.NoError(t, err) + require.NotNil(t, info) + require.Equal(t, test.expect, info) + } +} + func newTrieFromPairs(t *testing.T, filename string) *trie.Trie { data, err := ioutil.ReadFile(filename) require.NoError(t, err) diff --git a/pkg/scale/uint128.go b/pkg/scale/uint128.go index cf11ddc51c..4804bbd0a9 100644 --- a/pkg/scale/uint128.go +++ b/pkg/scale/uint128.go @@ -108,6 +108,11 @@ func (u *Uint128) Bytes(order ...binary.ByteOrder) (b []byte) { return } +// String returns the string format from the Uint128 value +func (u *Uint128) String() string { + return fmt.Sprintf("%d", big.NewInt(0).SetBytes(u.Bytes())) +} + // Compare returns 1 if the receiver is greater than other, 0 if they are equal, and -1 otherwise. func (u *Uint128) Compare(other *Uint128) int { switch {