Closed AlexZhenWang closed 4 years ago
Another strange thing here is if I don't use the API instance created with historical metadata like showing above
const api = await createApi({
metadata: {
[`${genesisHash}-${latestSpecVersion}`]: metadata.toHex(),
},
});
but use the API instance with current latest block metadata like
const apiForPrepare = await createApi();
the api.rpc.payment.queryInfo
won't throw that error, but I think I should use historical metadata.
It turns out we have a CodeUpdated system event at block #705466. If we set the metadata of any block number smaller than 705466, we can successfully decode all the events of the block 705492 plus the payment info. This suggests there is a gap (here 27 blocks) between the place where the metadata had been updated and where it should be used. I will share more details as I learn more about this situation.
Thank you @alexsednz 👍
If the tricky workaround in @AlexZhenWang's code above is replaced with the right spec version for the same block that we have obtained the metadata from, then this issue is solved. However, it would then cause #158 to re-emerge. So I'm tending to say instead of fixing this issue we should probably be working on #158 and assume the suggested workaround there is problematic. I'm saying that because the spec version is an important tag in the metadata. It's not acceptable to use the latest spec version for any historical block.
Thank you for checking @alexsednz!
But as I have known, if we use the spec version for the same block that we have obtained the metadata from, the metadata for that specific block is actually not used by the API instance. so it's same as if we don't pass any metadata as I mentioned above, which feels like maybe the error is just muted but not solved because the data from the chain is not even correctly decoded(check #158).
The reason I said the metadata for that specific block is actually not used by API instance if we don't use latest spec version, is that as I have seen, when the API instance initializes, it will check the spec version, and if that version is not the latest version, it will fetch metadata of latest version and replace the metadata you passed in. I found this when solving #158 on the CENNZnet Scan project. This is also why I use that tricky workaround.
Also, if we don't use my tricky workaround, we need to find another way to solve #158 as well...
Em.. just thinking. Maybe can try and test: Find the place where API instance checks spec version. Hardcode to use metadata for block 705492 after the check(So the spec version check won't impact us. By this way, we can use metadata for block 705492 without changing spec version).
If this doesn't work, means the issue is just muted and maybe is not related to which spec version that we pass in. If this works, can add a flag to @cennznet/api to skip the spec version check. So we can pass in the metadata with the current spec version.
I would prefer to address the root cause. I'm now focused on a function in the API which is called metaFromChain. I think the issue of not loading the correct metadata when the spec version is correctly specified should be there.
I believe the root cause is in the following code in the version of the Polkadot that we are using:
async metaFromChain(optMetadata) {
const {
typesChain,
typesSpec
} = this._options;
const [genesisHash, runtimeVersion, chain, chainProps] = await Promise.all([this._rpcCore.chain.getBlockHash(0).toPromise(), this._rpcCore.state.getRuntimeVersion().toPromise(), this._rpcCore.system.chain().toPromise(), this._rpcCore.system.properties().toPromise()]); // based on the node spec & chain, inject specific type overrides
this.registerTypes((0, _known.getChainTypes)(chain, runtimeVersion, typesChain, typesSpec)); // filter the RPC methods (this does an rpc-methods call)
await this.filterRpc(); // retrieve metadata, either from chain or as pass-in via options
const metadataKey = "".concat(genesisHash, "-").concat(runtimeVersion.specVersion);
const metadata = metadataKey in optMetadata ? new _types.Metadata(this.registry, optMetadata[metadataKey]) : await this._rpcCore.state.getMetadata().toPromise(); // set our chain version & genesisHash as returned
this._genesisHash = genesisHash;
this._runtimeVersion = runtimeVersion; // set the global ss58Format as detected by the chain
(0, _utilCrypto.setSS58Format)(chainProps.ss58Format.unwrapOr(new _types.u32(this.registry, _defaults.default.prefix)).toNumber()); // get unique types & validate
metadata.getUniqTypes(false);
return metadata;
}
metadataKey is made out of the latest runtime version, irrespective of the metadata (optMetadata) that you provide for the API. Then if it doesn't find metadataKey in the provided metadata, it will discard them and fetch the latest metadata from the chain instead.
Finally here is the underlying issue https://github.com/cennznet/cennznet/issues/264 which is already fixed and tested by using the following docker tag cennznet/cennznet:develop-6b1402
@AlexZhenWang Please remember to pass in the blockhash to api.rpc.payment.queryInfo(extrinsic, blockhash)
in your code.
Thanks, @alexsednz!
Hi, I can successfully query payment info at block 705492 now.
But when using image cennznet/cennznet:develop-6b1402
, the node stopped syncing at block 1,749,753.
When I am using a workaround to query historical data, I got an error when querying data at block 705492. It works for all blocks before 705492, but get an error at the block 705492.
SDK version:
@cennznet/api 1.2.1
Environment:node 12.18.3
Error message:queryInfo(extrinsic: Bytes, at?: BlockHash): RuntimeDispatchInfo:: 2: Unable to query dispatch info.: Error decoding field Call :: CennzxSpot.0
How to reproduce: