Skip to content

Commit

Permalink
Implement TransactionPaymentCallApi Runtime APIs (#2889)
Browse files Browse the repository at this point in the history
  • Loading branch information
edwardmack authored Oct 24, 2022
1 parent 69031a6 commit 57168fc
Show file tree
Hide file tree
Showing 17 changed files with 945 additions and 746 deletions.
2 changes: 1 addition & 1 deletion dot/core/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type RuntimeInstance interface {
FinalizeBlock() (*types.Header, error)
ExecuteBlock(block *types.Block) ([]byte, error)
DecodeSessionKeys(enc []byte) ([]byte, error)
PaymentQueryInfo(ext []byte) (*types.TransactionPaymentQueryInfo, error)
PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error)
CheckInherents()
RandomSeed()
OffchainWorker()
Expand Down
4 changes: 2 additions & 2 deletions dot/core/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dot/rpc/modules/payment_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func TestPaymentQueryInfo(t *testing.T) {
bestBlockHash := state.Block.BestBlockHash()

t.Run("When there is no errors", func(t *testing.T) {
mockedQueryInfo := &types.TransactionPaymentQueryInfo{
mockedQueryInfo := &types.RuntimeDispatchInfo{
Weight: 0,
Class: 0,
PartialFee: scale.MaxUint128,
Expand Down
2 changes: 1 addition & 1 deletion dot/rpc/modules/payment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func TestPaymentModule_QueryInfo(t *testing.T) {
blockErrorAPIMock2.On("GetRuntime", &testHash).Return(nil, errors.New("GetRuntime error"))

runtimeMock.On("PaymentQueryInfo", common.MustHexToBytes("0x0000")).Return(nil, nil)
runtimeMock2.On("PaymentQueryInfo", common.MustHexToBytes("0x0000")).Return(&types.TransactionPaymentQueryInfo{
runtimeMock2.On("PaymentQueryInfo", common.MustHexToBytes("0x0000")).Return(&types.RuntimeDispatchInfo{
Weight: uint64(21),
Class: 21,
PartialFee: u,
Expand Down
2 changes: 1 addition & 1 deletion dot/sync/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type RuntimeInstance interface {
FinalizeBlock() (*types.Header, error)
ExecuteBlock(block *types.Block) ([]byte, error)
DecodeSessionKeys(enc []byte) ([]byte, error)
PaymentQueryInfo(ext []byte) (*types.TransactionPaymentQueryInfo, error)
PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error)
CheckInherents()
RandomSeed()
OffchainWorker()
Expand Down
4 changes: 2 additions & 2 deletions dot/sync/mocks_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 16 additions & 2 deletions dot/types/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,24 @@ const (
TxnExternal
)

// TransactionPaymentQueryInfo represents the basic information of a given encoded extrinsic
type TransactionPaymentQueryInfo struct {
// RuntimeDispatchInfo represents information related to a dispatchable's class, weight, and fee that can be queried
// from the runtime
type RuntimeDispatchInfo struct {
Weight uint64
// Class could be Normal (0), Operational (1), Mandatory (2)
Class int
PartialFee *scale.Uint128
}

// InclusionFee represent base fee and adjusted weight and length fees
type InclusionFee struct {
BaseFee *scale.Uint128
LenFee *scale.Uint128
AdjustedWeightFee *scale.Uint128
}

// FeeDetails composed of InclusionFee and Tip
type FeeDetails struct {
InclusionFee InclusionFee
Tip *scale.Uint128
}
4 changes: 2 additions & 2 deletions lib/blocktree/mock_instance_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions lib/runtime/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ const (
DEV_RUNTIME = "dev_runtime"
DEV_RUNTIME_FP = "dev_runtime.compact.wasm"
DEV_RUNTIME_URL = "https://github.com/noot/substrate/blob/noot/v0.8-dev-runtime/target/wasm32-unknown-unknown/release/wbuild/node-runtime/node_runtime.compact.wasm?raw=true" //nolint:lll

// v0.9.29 polkadot
POLKADOT_RUNTIME_v0929 = "polkadot_runtime-v929"
POLKADOT_RUNTIME_V0929_FP = "polkadot_runtime-v929.compact.wasm"
POLKADOT_RUNTIME_V0929_URL = "https://github.com/paritytech/polkadot/releases/download/v0.9." +
"29/polkadot_runtime-v9290.compact.compressed.wasm?raw=true"

// v0.9.29 westend
WESTEND_RUNTIME_v0929 = "westend_runtime-v929"
WESTEND_RUNTIME_V0929_FP = "westend_runtime-v929.compact.wasm"
WESTEND_RUNTIME_V0929_URL = "https://github.com/paritytech/polkadot/releases/download/v0.9." +
"29/westend_runtime-v9290.compact.compressed.wasm?raw=true"
)

const (
Expand Down Expand Up @@ -71,4 +83,8 @@ const (
DecodeSessionKeys = "SessionKeys_decode_session_keys"
// TransactionPaymentAPIQueryInfo returns information of a given extrinsic
TransactionPaymentAPIQueryInfo = "TransactionPaymentApi_query_info"
// TransactionPaymentCallAPIQueryCallInfo returns call query call info
TransactionPaymentCallAPIQueryCallInfo = "TransactionPaymentCallApi_query_call_info"
// TransactionPaymentCallAPIQueryCallFeeDetails returns call query call fee details
TransactionPaymentCallAPIQueryCallFeeDetails = "TransactionPaymentCallApi_query_call_fee_details"
)
2 changes: 1 addition & 1 deletion lib/runtime/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,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)
PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error)

CheckInherents() // TODO: use this in block verification process (#1873)

Expand Down
8 changes: 4 additions & 4 deletions lib/runtime/mocks/instance.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions lib/runtime/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ func GetRuntime(ctx context.Context, runtime string) (
case DEV_RUNTIME:
runtimeFilename = DEV_RUNTIME_FP
url = DEV_RUNTIME_URL
case POLKADOT_RUNTIME_v0929:
runtimeFilename = POLKADOT_RUNTIME_V0929_FP
url = POLKADOT_RUNTIME_V0929_URL
case WESTEND_RUNTIME_v0929:
runtimeFilename = WESTEND_RUNTIME_V0929_FP
url = WESTEND_RUNTIME_V0929_URL
default:
return "", fmt.Errorf("%w: %s", ErrRuntimeUnknown, runtime)
}
Expand Down
48 changes: 44 additions & 4 deletions lib/runtime/wasmer/exports.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ func (in *Instance) DecodeSessionKeys(enc []byte) ([]byte, error) {
}

// PaymentQueryInfo returns information of a given extrinsic
func (in *Instance) PaymentQueryInfo(ext []byte) (*types.TransactionPaymentQueryInfo, error) {
func (in *Instance) PaymentQueryInfo(ext []byte) (*types.RuntimeDispatchInfo, error) {
encLen, err := scale.Marshal(uint32(len(ext)))
if err != nil {
return nil, err
Expand All @@ -175,12 +175,52 @@ func (in *Instance) PaymentQueryInfo(ext []byte) (*types.TransactionPaymentQuery
return nil, err
}

i := new(types.TransactionPaymentQueryInfo)
if err = scale.Unmarshal(resBytes, i); err != nil {
dispatchInfo := new(types.RuntimeDispatchInfo)
if err = scale.Unmarshal(resBytes, dispatchInfo); err != nil {
return nil, err
}

return i, nil
return dispatchInfo, nil
}

// QueryCallInfo returns information of a given extrinsic
func (in *Instance) QueryCallInfo(ext []byte) (*types.RuntimeDispatchInfo, error) {
encLen, err := scale.Marshal(uint32(len(ext)))
if err != nil {
return nil, err
}

resBytes, err := in.Exec(runtime.TransactionPaymentCallAPIQueryCallInfo, append(ext, encLen...))
if err != nil {
return nil, err
}

dispatchInfo := new(types.RuntimeDispatchInfo)
if err = scale.Unmarshal(resBytes, dispatchInfo); err != nil {
return nil, err
}

return dispatchInfo, nil
}

// QueryCallFeeDetails returns call fee details for given call
func (in *Instance) QueryCallFeeDetails(ext []byte) (*types.FeeDetails, error) {
encLen, err := scale.Marshal(uint32(len(ext)))
if err != nil {
return nil, err
}

resBytes, err := in.Exec(runtime.TransactionPaymentCallAPIQueryCallFeeDetails, append(ext, encLen...))
if err != nil {
return nil, err
}

dispatchInfo := new(types.FeeDetails)
if err = scale.Unmarshal(resBytes, dispatchInfo); err != nil {
return nil, err
}

return dispatchInfo, nil
}

func (in *Instance) CheckInherents() {} //nolint:revive
Expand Down
127 changes: 125 additions & 2 deletions lib/runtime/wasmer/exports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1011,12 +1011,12 @@ func TestInstance_PaymentQueryInfo(t *testing.T) {
extB []byte
ext string
errMessage string
expect *types.TransactionPaymentQueryInfo
expect *types.RuntimeDispatchInfo
}{
{
// Was made with @polkadot/api on https://github.com/danforbes/polkadot-js-scripts/tree/create-signed-tx
ext: "0xd1018400d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d01bc2b6e35929aabd5b8bc4e5b0168c9bee59e2bb9d6098769f6683ecf73e44c776652d947a270d59f3d37eb9f9c8c17ec1b4cc473f2f9928ffdeef0f3abd43e85d502000000012844616e20466f72626573", //nolint:lll
expect: &types.TransactionPaymentQueryInfo{
expect: &types.RuntimeDispatchInfo{
Weight: 1973000,
Class: 0,
PartialFee: &scale.Uint128{
Expand Down Expand Up @@ -1087,3 +1087,126 @@ func newTrieFromPairs(t *testing.T, filename string) *trie.Trie {
require.NoError(t, err)
return &tr
}

func TestInstance_TransactionPaymentCallApi_QueryCallInfo(t *testing.T) {
t.Parallel()
ins := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0929)
tests := []struct {
callHex string
errMessage string
expect *types.RuntimeDispatchInfo
}{
{
// call generated by using palkadot.js/api v9.5.1: api.tx.system.remark("Ed")
// and removing first byte (encoding) and second byte (unknown)
callHex: "0x0001084564",
expect: &types.RuntimeDispatchInfo{
Weight: 0,
Class: 0,
PartialFee: &scale.Uint128{
Upper: 0,
Lower: uint64(1500000000),
},
},
},
{
// call removing encoding (first byte), polkadot.js/api v9.5.1: api.tx.system.remark("Ed")
// polkadot.js/api returns error: RPC-CORE: call(method: Text, data: Bytes, at?: BlockHash):
// Bytes:: -32000: Client error: Execution failed: Execution aborted due to trap: wasm trap: wasm
//`unreachable` instruction executed
callHex: "0x040001084564",
errMessage: "running runtime function: " +
"Failed to call the `TransactionPaymentCallApi_query_call_info` exported function.",
},
{
// call without removing any bytes, polkadot.js/api v9.5.1: api.tx.system.remark("Ed test")
// polkadot.js/api returns error: Error: createType(Call):: findMetaCall: Unable to find Call with index
// [44, 4]/[44,4]
callHex: "0x2c0400011c45642074657374",
errMessage: "running runtime function: " +
"Failed to call the `TransactionPaymentCallApi_query_call_info` exported function.",
},
}

for _, test := range tests {
var err error
var callBytes []byte

callBytes, err = common.HexToBytes(test.callHex)
require.NoError(t, err)

info, err := ins.QueryCallInfo(callBytes)

if test.errMessage != "" {
assert.EqualError(t, err, test.errMessage)
continue
}

require.NoError(t, err)
require.NotNil(t, info)
require.Equal(t, test.expect, info)
}
}

func TestInstance_TransactionPaymentCallApi_QueryCallFeeDetails(t *testing.T) {
t.Parallel()
ins := NewTestInstance(t, runtime.WESTEND_RUNTIME_v0929)
tests := []struct {
callHex string
errMessage string
expect *types.FeeDetails
}{
{
// call generated by using palkadot.js/api v9.5.1: api.tx.system.remark("Ed")
// and removing first byte (encoding) and second byte (unknown)
callHex: "0x0001084564",
expect: &types.FeeDetails{
InclusionFee: types.InclusionFee{
BaseFee: &scale.Uint128{
Upper: 0,
Lower: uint64(256000000001),
},
LenFee: &scale.Uint128{
Upper: 0,
Lower: uint64(128000000000),
},
AdjustedWeightFee: &scale.Uint128{},
},
Tip: &scale.Uint128{},
},
},
{
// call removing encoding (first byte), polkadot.js/api v9.5.1: api.tx.system.remark("Ed")
// when calling polkadot node (v0.9.29) with polkadot.js/api the node returns error: RPC-CORE: call(
// method: Text, data: Bytes, at?: BlockHash): Bytes:: -32000: Client error: Execution failed:
// Execution aborted due to trap: wasm trap: wasm `unreachable` instruction executed
callHex: "0x040001084564",
errMessage: "running runtime function: " +
"Failed to call the `TransactionPaymentCallApi_query_call_fee_details` exported function.",
},
{
// call without removing any bytes, polkadot.js/api v9.5.1: api.tx.system.remark("Ed test")
// when calling polkadot (v0.9.29) with polkadot.js/api the node returns error: Error: createType(
//Call):: findMetaCall: Unable to find Call with index [44, 4]/[44,4]
callHex: "0x18040001084564",
errMessage: "running runtime function: " +
"Failed to call the `TransactionPaymentCallApi_query_call_fee_details` exported function.",
},
}

for _, test := range tests {
extBytes, err := common.HexToBytes(test.callHex)
require.NoError(t, err)

details, err := ins.QueryCallFeeDetails(extBytes)

if test.errMessage != "" {
assert.EqualError(t, err, test.errMessage)
continue
}

require.NoError(t, err)
require.NotNil(t, details)
require.Equal(t, test.expect, details)
}
}
Loading

0 comments on commit 57168fc

Please sign in to comment.