api
api copied to clipboard
Question: identifying pallets in a runtime
The challenge at hand is t identify if pallet-balances
is in a runtime or not. My elementary way of solving this problem is testing something like api.query.balances !== undefined
.
This works in 99% of the cases, but it is fundamentally flawed, as it depends on the name given to pallet-balances by contruct_runtime!
.
Question is: is there a better, safer way to do this? I see efforts in substrate that expose the crate name in a Rust context. Seems like all we have to do is to expose the same thing over metadata. See: https://github.com/paritytech/substrate/pull/10053
There is no way atm. For chains with renamed instances (or multiples), we have been using a non-standard additional field in API instances to identify the mappings.
I believe this is used in Acala (treasury, etc.), InterBTC (balances, etc), and some others. (Could be wrong on this list, it really has been ages...)
EDIT: Found an example - https://github.com/AcalaNetwork/acala.js/blob/62f04e53ddcac0d25bb89023d96ea8673b7b98b8/packages/type-definitions/src/index.ts#L73-L75
EDIT2: This is how for instance balances are used in the API itself to extract all matching pallets based on the name - https://github.com/polkadot-js/api/blob/ea9cd6981d59710605e17855173cdd37ca8bd66d/packages/api-derive/src/balances/all.ts#L214 (Same would apply to eg. council as linked by Acala)
example from derive.balances.all
seems be quite close to what I want, but I am afraid it is itself outdated. If you try any of
console.log(api.registry.getModuleInstances(api.runtimeVersion.specName.toString(), "Balances"))
console.log(api.registry.getModuleInstances(api.runtimeVersion.specName.toString(), "balances"))
console.log(api.registry.getModuleInstances(api.runtimeVersion.specName.toString(), "system"))
they are return undefined
.
It is as-used. And yes, that return value would be correct. It would return an array of the different instances if anything is found, alternatively undefined
when no overrides are present.
This means the caller needs to apply their own defaults, e.g. in the case you mentioned it applies ['balances']
when nothing is found - https://github.com/polkadot-js/api/blob/12750bc83d8d7f01957896a80a7ba948ba3690b7/packages/api-derive/src/balances/all.ts#L153
(In this case balanceInstances: string[] = ['balances']
- this would be for the vast majority of the cases, like mentioned above, I can think of 2 chains off-hand that I know has overrides, although it is quite possible I lost track somewhere along the way)
So getModuleInstances
only returns something other than undefined
if there has been overrides?
If such, the general question is still open.
I haven't inspected the metadata exactly, but each pallet should ideally return both an instance name, and something more meta like "module name", so that the api can understand the relation between the two, e.g. api.query.balancesOther
and api.query.balances
both should have "module name": "balances", coming NOT from what the name of the instance is, but rather from the fact that it is coming from pallet-**balances**
.
Do you know if this data already exists in metadata? if so, let's keep this open as a TODO for you, else we first fix it in substrate.
There is the path on the Error, Event & Call types, and it is sane/simple to use it. (PR merged in to extend matching on path as well)
However, this still doesn't solve it completely - so if we have pallet_balances::pallet::Call
as a (prettified) path in most cases, we still have holes and the combo of API definitions & best-effort-extract is the only sane approach.
- the current instances can point e.g. generalCouncil -> council - just using collective here is not quite what we are after (so the per-config is the best approach if you need exact knowledge)
- obviously the balances one works... however some chains do rename stuff, so in the past we had issues where
pallet_democracy::*
doesn't exist, butdarwinia_democracy::*
does. (In this specific case a recent runtime upgrade did move it to "standard paths", so it may be an issue now that might exist and has in the past, but cannot actually be found in real deployments as of right now)
So have the match does move it closer, but it cannot get to 100%. So it will work... mostly.
I don't think we are talking about the same approach.
I don't think this path (e.g. pallet_balances::pallet::Call
) will be helpful in solving this. Or if it helps, it will still be hacky for all the reasons you mentioned.
What I think is the scalable approach is "including the name of the rust crate of every pallet instance in its metadata".
For example, api.qeury.balances.crateName()
would return pallet-balances
. If you have multiple instances, rename them or anything else, they all still return pallet-balances
.
As noted, it seems to me like this information is already in the metadata as of https://github.com/paritytech/substrate/pull/10053, but I have to double check this. Either way, it is technically possible.
Once this exists, it should be trivial to build the reverse map: give me all the instances of pallet-balances
, which returns [x, y, z]
and then you can do api.query.x
and api.query.y
and so on..
The name of the crate is where the above matches, the full path.
Over and above that, nothing more that will be done on the API. So it t stays as-is.
The name of the crate is where the above matches, the full path.
Where can I get this path for each pallet instance, e.g. for api.query.generalCouncil
?
This issue has been open for 21 days with no activity and is not labelled as an enhancement. It will be closed in 7 days.
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue if you think you have a related problem or query.