From 5b71abfe80f8e20b9cdbb5bf281ccf0ed3f5ecce Mon Sep 17 00:00:00 2001 From: Jaco Greeff Date: Tue, 14 Apr 2020 08:48:14 +0200 Subject: [PATCH] Make a start at a cookbook... still loads to go (#2160) --- docs/.vuepress/config.js | 11 ++++++++++ docs/README.md | 11 ++-------- docs/cookbook/README.md | 19 ++++++++++++++++ docs/cookbook/blocks.md | 23 ++++++++++++++++++++ docs/cookbook/storage.md | 29 +++++++++++++++++++++++++ docs/cookbook/tx.md | 47 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 131 insertions(+), 9 deletions(-) create mode 100644 docs/cookbook/README.md create mode 100644 docs/cookbook/blocks.md create mode 100644 docs/cookbook/storage.md create mode 100644 docs/cookbook/tx.md diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index c80fef3fee..e5e0717348 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -50,6 +50,17 @@ module.exports = { ['start/FAQ.md', 'FAQ'] ] }, + { + title: 'Cookbook', + path: '/cookbook/', + collapsable: false, + sidebarDepth: 0, + children: [ + ['cookbook/blocks.md', 'Blocks'], + ['cookbook/storage.md', 'Storage'], + ['cookbook/tx.md', 'Transactions'] + ] + }, { title: 'Examples (Promise API)', path: '/examples/promise/', diff --git a/docs/README.md b/docs/README.md index c150cf4ff6..02e76a7a58 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,7 +13,7 @@ features: - title: Types details: Various type interfaces to make using returned values from API calls transparent in your code. -footer: Apache-2 Licensed | Copyright © 2017-2019 polkadot-js authors and contributors +footer: Apache-2 Licensed | Copyright © 2017-2020 polkadot-js authors and contributors --- ## Welcome @@ -21,16 +21,9 @@ footer: Apache-2 Licensed | Copyright © 2017-2019 polkadot-js authors and contr The API provides application developers the ability to query a node and interact with the Polkadot or Substrate chains using Javascript. Here you will find documentation and examples to get you started. ::: tip Getting started & Examples -[Jump right in](/start/) and get an overview on using the API in your projects, from installation all the way through to making it do magic. Already understand how things work and just want the examples? [The ApiPromise examples](/examples/promise/) provide some basic recipies. +[Jump right in](/start/) and get an overview on using the API in your projects, from installation all the way through to making it do magic. Already understand how things work and just want the examples? [The ApiPromise examples](/examples/promise/) provide some basic examples. ::: -## Available packages - -This repository split up into a number of internal packages, namely - - -- [api](api/README.md) Promise and RxJS-based APIs -- [types](types/README.md) Type encoding and decoding wrappers - ## The Polkadot Project You can read more about the Polkadot Network at [https://polkadot.network/](https://polkadot.network/) and more about the polkadot-js projects at [https://polkadot.js.org](https://polkadot.js.org) diff --git a/docs/cookbook/README.md b/docs/cookbook/README.md new file mode 100644 index 0000000000..d2f1e25ce3 --- /dev/null +++ b/docs/cookbook/README.md @@ -0,0 +1,19 @@ +# Cookbook + +The cookbook hosts small code snippets in a question-answer format. It does not walk you through the whole setup, like the [basic examples](../examples/), but rather aims to answer some questions around specific uses. It also does not replace the [getting started FAQ](../start/FAQ.md), rather this is focussed explicitly on code samples, instead of general trouble-shooting for common mishaps. + +These questions are added as they do come up and the hope is that the snippets here is will be useful to others, instead of just the original person who asked on a specific use-case. As of today, it is only making a start and not fully comprehensive yet - check back early, check back often. + +## Sections + +The following cookbook sections are available - + +- (Blocks)[blocks.md] - Snippets around working with blocks and headers +- (Storage)[storage.md] - Snippets for working with storage +- (Transactions)[tx.md] - Snippets for working with transactions + +... more to come. + +## Contribute + +And as always, if you have an addition to make, or a question to ask any (any PRs)[https://github.com/polkadot-js/api/tree/master/docs] or (issues)[https://github.com/polkadot-js/api/issues] are appreciated. The initial content was generate from exactly such questions, either in Riot chat or as submitted as issues. diff --git a/docs/cookbook/blocks.md b/docs/cookbook/blocks.md new file mode 100644 index 0000000000..79eb33b978 --- /dev/null +++ b/docs/cookbook/blocks.md @@ -0,0 +1,23 @@ +# Blocks + +The building blocks for each blockchain. As such there are a number of examples for working with blocks and headers, that could be useful. + +## How do I retrieve the header/extrinsic hash from blocks? + +A block hash refers to the hash over the header, the extrinsic hash refers to the hash of the encoded extrinsic. Since all objects returned by the API implements the `.hash => Hash` getter, we can simply use this to view the actual hash. + +```js +// returns Hash +const blockHash = await this.api.rpc.chain.getBlockHash(blockNumber); +// returns SignedBlock +const signedBlock = await this.api.rpc.chain.getBlock(blockHash); + +// the hash for the block, always via header (Hash -> toHex()) - will be the same as +// blockHash above (also available on any header retrieved, subscription or once-off) +console.log(signedBlock.header.hash.toHex()); + +// the hash for each extrinsic in the block +signedBlock.block.extrinsics.forEach((ex, index) => { + console.log(index, ex.hash.toHex()); +}); +``` diff --git a/docs/cookbook/storage.md b/docs/cookbook/storage.md new file mode 100644 index 0000000000..7bc822ae2f --- /dev/null +++ b/docs/cookbook/storage.md @@ -0,0 +1,29 @@ +# Storage + +Here you will find snippets for working with storage. + +## How do I check for storage existence? + +In the metadata, for each storage item a fallback is provided. This means that when an entry does not exist, the fallback (which is the default value for the type) will be provided. This means, that querying for a non-existent key (unless an option), will ield a value - + +```js +// retrieve Option +const ledger = await api.query.staking.ledger('EoukLS2Rzh6dZvMQSkqFy4zGvqeo14ron28Ue3yopVc8e3Q'); +// retrieve ValidatorPrefs (will yield the default value) +const prefs = await api.query.staking.validators('EoukLS2Rzh6dZvMQSkqFy4zGvqeo14ron28Ue3yopVc8e3Q'); + +console.log(ledger.isNone, ledger.isSome); // true, false +console.log(JSON.stringify(prefs.toHuman())); // {"commission":"0"} +``` + +In the second case, the non-existent prefs returns the default/fallback value for the storage item. So in this case we don't know if the value is set to 0 or unset. Existence can be checked by using the storage size, which would be zero if nothing is stored. + +```js +// exists +const sizeY = await api.query.staking.validators.size('DB2mp5nNhbFN86J9hxoAog8JALMhDXgwvWMxrRMLNUFMEY4'); +// non existent +const sizeN = await api.query.staking.validators.size('EoukLS2Rzh6dZvMQSkqFy4zGvqeo14ron28Ue3yopVc8e3Q'); + +console.log(sizeY.isZero(), sizeY.toNumber()); // false 4 +console.log(sizeN.isZero(), sizeY.toNumber()); // true 0 +``` diff --git a/docs/cookbook/tx.md b/docs/cookbook/tx.md new file mode 100644 index 0000000000..17a953fc67 --- /dev/null +++ b/docs/cookbook/tx.md @@ -0,0 +1,47 @@ +# Transactions + +A blockchain is no fun if you are not submitting transactions. Or at least if somebody is not submitting any. Here you will find some snippets for dealing with some common issues. + +## How do I estimate the transaction fees? + +In addition to the `signAndSend` helper on transactions, `.paymentInfo` (with the exact same parameters) are also exposed. Using the same sender, it applies a dummy signature to the transaction and then gets the fee estimation via RPC. + +```js +// estimate the fees as RuntimeDispatchInfo, using the signer (either address or locked/unlocked keypair) +// (When overrides are applied, e.g. nonce, the format would be `paymentInfo(sender, { nonce })`) +const info = await api.tx.balances + .transfer(recipient, 123) + .paymentInfo(sender); + +// log relevant info, partialFee is Balance, estmated for current conditions +console.log(`class=${class.toString()}, weight=${weight.toString()}, partialFee=${partialFee.toHuman()}`); +``` + +## How do I get the decoded enum for an ExtrinsicFailed event? + +Assuming you are sending a tx via `.signAndSend`, the callback yields information around the tx pool status as well as any events when `isInBlock` or `isFinalized`. If an extrinsic fails via `system.ExtrinsicFailed` event, you can retrieve the error, if defined as an enum on a module. + +```js +api.tx.balances + .transfer(recipient, 123) + .signAndSend(sender, ({ status, events }) => { + if (status.isInBlock || status.isFinalized) { + events + // find/filter for failed events + .filter(({ section, method }) => section === 'system' && method === 'ExtrinsicFailed') + // we know that data for system.ExtrinsicFailed is (DispatchError, DispatchInfo) + .forEach(({ data: [dispatchError, dispatchInfo] }) => { + + if (dispatchError.isModule) { + // for module errors, we have the section indexed, lookup + const { documentation, name, section } = this.api.registry.findMetaError(dispatchError.asModule); + + console.log(`${section}.${name}: ${documentation.join(' ')}`); + } else { + // Other, CannotLookup, BadOrigin, no extra info + console.log(dispatchError.toString()); + } + }); + } + }); +```