api: [Bug] Runtime API Call Decoding incorrect with Custom Types
-
I’m submitting a …
- Bug report
- Feature request
- Support request
- Other
-
What is the current behavior and expected behavior?
Current: In our case, calling a custom RPC and its runtime API clone with the same input value does not result in the same return value: One field is decoded incorrectly. The RPC returns the right value and encodes the amount to a number, while the runtime API returns a different account (probably a double encoding), and a HEX-encoded value for the deposit amount.
struct Deposit {
owner: AccountId,
amount: u128
}
❌ Runtime Api: didApi.queryByW3n("williamfreude")
owner: 4nv4phaiCRnr6JSfhawcDZp7LzmvtWvabyCxkML7NPrr8eHV
amount: 8,589,934,592,000,000,154,110,983
✅ DID RPC: did.queryByW3n("williamfreude")
owner: 4qTuS5ymocwsPJ3uK5FKG7d2nVhV3CawDMwhWyKz2FBXq2gX
amount: 2,000,000,000,000,000
We tried out numerous varations, with and without custom serde
(de-) serialization. Nothing worked until we used minimal custom type declarations, see below.
Expected
When calling the exact same method with the same input and same custom type declarations, it should lead to the same result.
We fixed the issue for the runtime API call by referring to augmented api types, see this PR for changing our custom type declaration However, this augmented type definition matches exactly the custom one which we provided:
interface DidDidDetails extends Struct {
readonly authenticationKey: H256;
readonly keyAgreementKeys: BTreeSet<H256>;
readonly delegationKey: Option<H256>;
readonly attestationKey: Option<H256>;
readonly publicKeys: BTreeMap<H256, DidDidDetailsDidPublicKeyDetails>;
readonly lastTxCounter: u64;
readonly deposit: KiltSupportDeposit;
}
export interface RawDidDetails extends Struct {
readonly authenticationKey: Hash;
readonly keyAgreementKeys: BTreeSet<Hash>;
readonly delegationKey: Option<Hash>;
readonly attestationKey: Option<Hash>;
readonly publicKeys: BTreeMap<Hash, DidDidDetailsDidPublicKeyDetails>;
readonly lastTxCounter: BlockNumber;
readonly deposit: KiltSupportDeposit;
}
- What is the motivation for changing the behavior?
Others shouldn’t need to spend time debugging this unexpected behavior in the future.
- Please tell us about your environment:
I tested both in the Polkadot Apps as well as a custom (Type)script.
-
Version:
9.4.1
and9.6.1
-
Environment:
- Node.js (
node v16.13.2 (npm v8.3.1)
) - Browser (Polkadot Apps
apps v0.121.2-118-x
and Chrome106.0.5249.119
. Both also with earlier versions, ca. 2 week range) - Other (limited support for other environments)
- Node.js (
-
Language:
- JavaScript
- TypeScript
4.8.3
- Other: Polkadot Apps
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 23 (13 by maintainers)
Commits related to this issue
- #5298 — committed to lilsunny243/api by lilsunny243 a year ago
Only runtimes 9 & 10 have
BlockNumber: 'u64'
overrides in https://github.com/KILTprotocol/sdk-js/tree/develop/packages/type-definitions/src(Latest, looking at the imports and following the trail, never apply any such override)
TL;DR We are still looking at mismatched types here as supplied - the API will decode based on what it is fed and for anything RPC or runtime call related, it needs to have all the types, as used, correctly specified (at least for runtime calls that pain will go away at some point in the future once it gets into the metadata… hopefully…)
Let’s focus on the topic at-hand after my little outbursts 😃
Anyway, looking at Augmented/Custom above -
Hash
===H256
so all oku64
!==BlockNumber
(lastTxCounter
field) the latter isu32
, seeObviously is decoding via runtime, it really needs to match - in JSON you can get away with mismatched types since the input comes in a text, not binary
So it would seem that if you swapped your runtime to the first version that the field type was actually incorrect, and correct with the replaced version.
And indeed, looking at your Rust types, it needs to be
u64
, notBlockNumber
, akaTL;DR Looking at the struct above, it make sense why it fails on
lastTxCounter: 'BlockNumber'
and works onlastTxCounter: 'u64'
, so would say that it operates as expected with the supplied definitions, i.e. yielding invalid results when incorrect.(At least for the runtime a future Substrate update will start making all the APIs and types available in the metadata - so unlike RPCs which will remain manual forever, when we get that update there would be no need to supply manual types for runtime calls)
What’s the point of substrate if custom apis don’t work (JS side, which is the 90% or use cases)… shocked to see this issue still open… everyone still using old deprecated RPCs? Or?
i’ll be keeping this active as long as it is not resolved 😃
i’ll be keeping this active as long as it is not resolved 😃
this is still an actual issue; we are seeing it too