Skip to content

Instantly share code, notes, and snippets.

@bitcoinwarrior1
Last active August 18, 2021 04:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bitcoinwarrior1/840b77de13ef897f6683f47d3d6466f8 to your computer and use it in GitHub Desktop.
Save bitcoinwarrior1/840b77de13ef897f6683f47d3d6466f8 to your computer and use it in GitHub Desktop.
Getting balances from a substrate node using RPC
// UPDATED THANK YOU @al3mart
util_crypto.xxhashAsHex("System", 128)
> "0x26aa394eea5630e07c48ae0c9558cef7"
util_crypto.xxhashAsHex("Account", 128)
> "0xb99d880ec681799c0cf30e8886371da9"
// https://westend.subscan.io/account/5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY
util_crypto.blake2AsHex(keyring.decodeAddress("5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY"), 128)
> "0xbb08f275d00049b315666c2c44130a10"
// Get the account ID from the pubkey
subkey inspect 5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY
> Account ID: 0x6648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342
// System + Account + hash_of_key + raw_key
0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9bb08f275d00049b315666c2c44130a106648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342
curl -H "Content-Type: application/json" -d '{"id":1,"jsonrpc":"2.0","method":"state_getStorage","params":["0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9bb08f275d00049b315666c2c44130a106648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342"]}' https://westend-rpc.polkadot.io/
> {"jsonrpc":"2.0","result":"0xda000000000000000100000000000000f86be7c3bd31870300000000000000008094d54ee900000000000000000000000000000000000000000000000000000000000000000000000000000000000000","id":1}
// SKALE decode the raw output
// https://www.shawntabrizi.com/substrate-js-utilities/codec/
// custom type:
{ "Balances": "(u64, u64, u64, u64, u64)" }
// decoded output
> [218,1,"0x038731bdc3e76bf8",0,1002050000000]
// 218 == the account nonce
// 1 (maybe the account index?)
// 0x038731bdc3e76bf8 == 254226595075025912 == the account total balance
// 0 which probably equals the locked balance
// 1002050000000 == the reserved balance
@daniel-flex
Copy link

Issue might be the onfinality RPC not having the correct whitelist. Maybe try with a public RPC?

@bitcoinwarrior1
Copy link
Author

Issue might be the onfinality RPC not having the correct whitelist. Maybe try with a public RPC?

same issue with https://westend-rpc.polkadot.io and a few other RPC's... still investigating

@al3mart
Copy link

al3mart commented Aug 12, 2021

I would say that you are missing the storage item you want to query "inside" Balances. As in the example

util_crypto.xxhashAsHex("FreeBalance", 128)

> "0x6482b9ade7bc6657aaca787ba1add3b4"

Anyway, is good to test against your local node where you have control of everything your node is exposing

@bitcoinwarrior1
Copy link
Author

bitcoinwarrior1 commented Aug 12, 2021

I would say that you are missing the storage item you want to query "inside" Balances. As in the example

util_crypto.xxhashAsHex("FreeBalance", 128)

> "0x6482b9ade7bc6657aaca787ba1add3b4"

Anyway, is good to test against your local node where you have control of everything your node is exposing

Hi, thanks for the reply!

I added that hash in but still the same result but no error either?

curl -H "Content-Type: application/json" -d '{"id":1,"jsonrpc":"2.0","method":"state_getStorage","params":["0xc2261276cc9d1f8598ea4b6a74b15c2f**6482b9ade7bc6657aaca787ba1add3b4**1a27c953ba92f8a42f88a3c036ca0ee89a9d4f52cae8c85a79502ab0bf636ea8"]}' https://westend-rpc.polkadot.io
{"jsonrpc":"2.0","result":null,"id":1}

@al3mart
Copy link

al3mart commented Aug 13, 2021

Oh, yes, maybe I didn't explained myself correctly. I didn't mean to use that one exactly, but one of the storage items that you can query from Balance if that is the module you want to query items from. Maybe too wide of a response.
A good place for checking which modules, items and its keys are available is in the metadata, that you can query at the RPC state.getMetadata or use https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/rpc for having a more friendly look at it.

I would recommend to read this other post https://www.shawntabrizi.com/substrate/transparent-keys-in-substrate/ after which I believe you will be able to complete these queries successfully :)

After checking again your snippet there is a bunch of stuff that you might want to correct, and you can get the lacking information checking the metadata and reading the post I shared with you there.

A trie path end up looking like

twox128(module) + twox128(storagename) + hasher(key1) + hasher(key2)

note that the number of keys depends on the map (if single or double).
Here the hasher to choose depends on the one used on the pallet to store that value, and that is something easy to check at the metadata. Also, for security reasons concat hashers are widely used within substrate, and the result of them is something like hash_of_key + raw_key. But how these keys and hashers work is better explained in the blog post I linked before.

Another thing I can tell you is that right now all the account info and its balance is living under System pallet because of its wide use, so it would be easier for you to check System.Account for having the balances info of an Account. Balance.FreeBalance I think is no longer living by its own

Your code is good, just need a few little changes, for example, my node is using Blake2_128Concat as a hasher for System.Account so I changed this line of yours to use the 128 version instead of the 256.
You can see which hasher is being used either from the metadata or checking the pallet source

Likely you will end up with:

util_crypto.xxhashAsHex("System", 128)
> "0x26aa394eea5630e07c48ae0c9558cef7"

util_crypto.xxhashAsHex("Account", 128)
> "0xb99d880ec681799c0cf30e8886371da9"

util_crypto.blake2AsHex(keyring.decodeAddress("5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY"), 128)
> "0xbb08f275d00049b315666c2c44130a10"

subkey inspect 5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY
> Account ID: 0x6648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342

System + Account + hash_of_key + raw_key
0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9bb08f275d00049b315666c2c44130a106648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342

I wanted to comment that the concept of prefix exist, so you could query state_getKeys of System+Account to get all the entries under that node of the trie.

I encourage your to read the post I mentioned before as will make you understand this perfectly :D hope it helps

@al3mart
Copy link

al3mart commented Aug 13, 2021

For next issues I highly encourage you to join our substrate technical channel at matrix, there you will find a more direct communication with the community and devs

@bitcoinwarrior1
Copy link
Author

Oh, yes, maybe I didn't explained myself correctly. I didn't mean to use that one exactly, but one of the storage items that you can query from Balance if that is the module you want to query items from. Maybe too wide of a response.
A good place for checking which modules, items and its keys are available is in the metadata, that you can query at the RPC state.getMetadata or use https://polkadot.js.org/apps/?rpc=ws%3A%2F%2F127.0.0.1%3A9944#/rpc for having a more friendly look at it.

I would recommend to read this other post https://www.shawntabrizi.com/substrate/transparent-keys-in-substrate/ after which I believe you will be able to complete these queries successfully :)

After checking again you snippet there is a bunch of stuff that you might want to correct, and you can get the lacking information checking the metadata and reading the post I shared with you there.

A trie path end up looking like

twox128(module) + twox128(storagename) + hasher(key1) + hasher(key2)

note that the number of keys depends on the map (if single or double).
Here the hasher to choose depends on the one used on the pallet to store that value, and that is something easy to check at the metadata. Also, for security reasons concat hashers are widely used within substrate, and the result of them is something like hash_of_key + raw_key. But how these keys and hashers work is better explained in the blog post I linked before.

Another thing I can tell you is that right now all the account info and its balance is living under System pallet because of its wide use, so it would be easier for you to check System.Account for having the balances info of an Account. Balance.FreeBalance I think is no longer living by its own

Your code is good, just need a few little changes, for example, my node is using Blake2_128Concat as a hasher for System.Account so I changed this line of yours to use the 128 version instead of the 256.
You can see which hasher is being used either from the metadata or checking the pallet source

Likely you will end up with:

util_crypto.xxhashAsHex("System", 128)
> "0x26aa394eea5630e07c48ae0c9558cef7"

util_crypto.xxhashAsHex("Account", 128)
> "0xb99d880ec681799c0cf30e8886371da9"

util_crypto.blake2AsHex(keyring.decodeAddress("5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY"), 128)
> "0xbb08f275d00049b315666c2c44130a10"

subkey inspect 5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY
> Account ID: 0x6648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342

System + Account + hash_of_key + raw_key
0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9bb08f275d00049b315666c2c44130a106648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342

I wanted to comment that the concept of prefix exist, so you could query state_getKeys of System+Account to get all the entries under that node of the trie.

I encourage your to read the post I mentioned before as will make you understand this perfectly :D hope it helps

@al3mart thank you so much for this reply! I am still figuring out the decoding of the output but this puts me on the right track. Cheers mate!

@daniel-flex
Copy link

^^ yeah boi

@bitcoinwarrior1
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment