Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid transaction version #392

Closed
boyswan opened this issue Jan 13, 2022 · 14 comments
Closed

Invalid transaction version #392

boyswan opened this issue Jan 13, 2022 · 14 comments

Comments

@boyswan
Copy link
Contributor

boyswan commented Jan 13, 2022

Subxt is failing to submit a signed hex extrinsic generated from the polkadot JS api. Both sides are using transaction_version: 9 and spec_version: 9140 however api.rpc().submit_extrinsic(tx) is always failing with

Rpc error: JSON-RPC request error: "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":1002,\"message\":\"Verification Error: Runtime error: Execution failed: ApiError(FailedToConvertParameter { function: \\\"validate_transaction\\\", parameter: \\\"tx\\\", error: Error { cause: None, desc: \\\"Invalid transaction version\\\" } })\",\"data\":\"RuntimeApi(\\\"Execution failed: ApiError(FailedToConvertParameter { function: \\\\\\\"validate_transaction\\\\\\\", parameter: \\\\\\\"tx\\\\\\\", error: Error { cause: None, desc: \\\\\\\"Invalid transaction version\\\\\\\" } })\\\")\"},\"id\":5}"

@jsdw
Copy link
Collaborator

jsdw commented Jan 13, 2022

The usual cause of issues like this is that the subxt interface you've generated (I assume via the subxt macro) is out of date w.r.t the node itself. Please make sure that you're using the latest metadata from the node in question.

If you ensure that you're using the latest metadata and still have an issue, would you be able to post the steps to you took to reproduce the issue here?

@boyswan
Copy link
Contributor Author

boyswan commented Jan 13, 2022

I've used the latest metadata from a local node for use in subxt

Run node
./bin/polkadot --dev --alice --tmp --rpc-cors all

Generate metadata
subxt metadata -f bytes > metadata.scale

Generate extrinsic

const wsProvider = new WsProvider("ws://127.0.0.1:9944");
const injector = await web3FromSource(account.source);
const api = await ApiPromise.create({
  provider: wsProvider,
  signer: injector?.signer,
});

const transfer = await api.tx.balances.transfer(dest, value);
await transfer.signAsync(address);
let signature = transfer.toHex();

Submit extrinsic

let api = ClientBuilder::new()
    .build::<DefaultConfig>()
    .await
    .unwrap();

api.rpc().submit_extrinsic(signature).await

I've also tried converting to a runtime api with
.to_runtime_api::<polkadot::RuntimeApi<DefaultConfig, DefaultExtra<DefaultConfig>>>()

@boyswan
Copy link
Contributor Author

boyswan commented Jan 14, 2022

I've now tested with generating a TX using txwrapper-polkadot, also usingAlice instead of an injected address. No matter what I do I'm still getting the same Invalid transaction version message...

@niklasad1
Copy link
Member

Some of the subxt deps are using substrate master and these might not be compatible with the latest polkadot release, or which release or tag are you using on the polkadot node?

@boyswan
Copy link
Contributor Author

boyswan commented Jan 14, 2022

I'm using version 0.9.13-d5818b2033-x86_64-macos

@lamafab
Copy link
Contributor

lamafab commented Jan 14, 2022

@niklasad1 Not sure if this is related, but there seems to be a mismatch between the RuntimeVersion of subxt and the latest polkadot release from three days ago (0.9.15)runtime:

$ wscat -c localhost:9944
Connected (press CTRL+C to quit)
> {"id":1, "jsonrpc":"2.0", "method": "system_version", "params":[]}
< {"jsonrpc":"2.0","result":"0.9.15-53dc81cddc-x86_64-linux-gnu","id":1}
> {"id":1, "jsonrpc":"2.0", "method": "state_getRuntimeVersion", "params":[]}
< {"jsonrpc":"2.0","result":{"apis":[["0xdf6acb689907609b",3],["0x37e397fc7c91f5e4",1],["0x40fe3ad401f8959a",5],["0xd2bc9897eed08f15",3],["0xf78b278be53f454c",2],["0xaf2c0297a23e6d3d",1],["0x49eaaf1b548a0cb0",1],["0x91d5df18b0d2cf58",1],["0xed99c5acb25eedf5",3],["0xcbca25e39f142387",2],["0x687ad44ad37f03c2",1],["0xab3c0572291feb8b",1],["0xbc9d89904f5b923f",1],["0x37c8bb1350a9a2a8",1]],"authoringVersion":0,"implName":"parity-polkadot","implVersion":0,"specName":"polkadot","specVersion":9140,"transactionVersion":9},"id":1}

There's no stateVersion, which is on the latest master: https://github.com/paritytech/substrate/blob/master/primitives/version/src/lib.rs#L212 :

	// ...

	/// All existing dispatches are fully compatible when this number doesn't change. If this
	/// number changes, then `spec_version` must change, also.
	///
	/// This number must change when an existing dispatchable (module ID, dispatch ID) is changed,
	/// either through an alteration in its user-level semantics, a parameter
	/// added/removed/changed, a dispatchable being removed, a module being removed, or a
	/// dispatchable/module changing its index.
	///
	/// It need *not* change when a new module is added or when a dispatchable is added.
	pub transaction_version: u32,

	/// Version of the state implementation used by this runtime.
	/// Use of an incorrect version is consensus breaking.
	pub state_version: u8,

transaction_version comes right before. Looks like the polkadot node (which also includes 0.9.13 as stated by @boyswan) has not been updated the latest sp-version package yet.

@lamafab
Copy link
Contributor

lamafab commented Jan 14, 2022

Actually this must be done by the Polkadot runtime, not the node itself.

@boyswan
Copy link
Contributor Author

boyswan commented Jan 14, 2022

Just noticed this too. Client fails when trying to connect to any rpc socket (ie. wss://rpc.polkadot.io:443)

Rpc(ParseError(Error("missing field 'stateVersion'", line: 0, column: 0)))'

@niklasad1
Copy link
Member

exactly @lamafab

this PR needs to included a new polkadot release to work I guess....

@boyswan
Copy link
Contributor Author

boyswan commented Jan 15, 2022

I finally managed to get this working by bypassing the api.rpc().submit_extrinsic(tx) and using the RpcClient direclty.

It looks like when trying to send a signed hex extrinsic, the encoding to bytes is causing the issue.

/// Create and submit an extrinsic and return corresponding Hash if successful
pub async fn submit_extrinsic<E: Encode>(
    &self,
    extrinsic: E,
) -> Result<T::Hash, Error> {
    let bytes: Bytes = extrinsic.encode().into();
    let params = &[to_json_value(bytes)?];
    let xt_hash = self
        .client
        .request("author_submitExtrinsic", params)
        .await?;
    Ok(xt_hash)
}

Instead submitting the tx as a json string works

let params: &[serde_json::Value; 1] = &[tx.into()];
let hash: Result<_, subxt::Error> = client.request("author_submitExtrinsic", params).await;

The tx submits successfully, however if connecting using ws, it throws an error:
Rpc error: The background task been terminated because: Custom error: Unparsable response; restart required

Whilst connecting using http throws:
Rpc error: Parse error: data did not match any variant of untagged enum Id at line 1 column 145

EDIT:

Looks like the RPC error is with the jsonrc lib rather than subxt

@niklasad1
Copy link
Member

The error is that the response not be decoded/deserialized as T::Hash because it's used by jsonrpsee under the hood to decode the response.

You could try let hash: Result<serde_json::Value, subxt::Error> = client.request("author_submitExtrinsic", params).await; or enable logging on jsonrpsee to see what the node responded with. It could be a jsonrpsee issue but not my hunch...

@boyswan
Copy link
Contributor Author

boyswan commented Jan 16, 2022

The error happens regardless of parsing manually or not:

let api = ClientBuilder::new().build::<DefaultConfig>().await.unwrap();
let version = api.rpc().runtime_version(None).await;

Rpc(RestartNeeded("Custom error: Unparsable response"))

Definitely seems like a jsonrpsee issue, will close this issue.

@boyswan boyswan closed this as completed Jan 16, 2022
@niklasad1
Copy link
Member

No, it's not a jsonrpsee issue it's just that the RuntimeVersion type has different serialization format in polkadot node vs subxt because the stateVersion is missing and jsonrpsee fails to decode the response as RuntimeVersion.

To workaround this in subxt, you can change RuntimeVersion -> serde_json::Value and it will work....

@jsdw
Copy link
Collaborator

jsdw commented Jan 17, 2022

Ah this lack of stateVersion is a known thing (I dug into it a little on Friday); I have very conservatively duplicated the RuntimeVersion struct with what subxt needs in 940c770 as part of #394, but if that PR doesn't merge in a couple of days we may want to cherry pick that and merge it separately.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants