For those developing a Hive

in HiveDevs9 months ago

Beekeeper

Hello ❗

This article is addressed to everyone interested in a simplified way of operating with Hive blockchain (what should allow you to drop the beekeeping suit from the picture above). 😊

Here is a wax, the library which allows you to perform API calls, build transactions, then use another tool beekeeper (responsible for holding your keys) to sign them and finally do broadcast.

The library contains several parts:

  1. Core C++ layer which wraps hive::protocol code (directly shared to Hived repo). Here you can find a specific code to transaction/operation serialization (JSON and binary), transaction static validation (a step performed also by Hived node before transaction is evaluated) as well as finally a code able to calculate sig-digest, TAPOS and transaction signatures by executing exactly the same code C++ as Hive Protocol does.
    The code for HP APR calculation is also put here, receiving accounts manabar specific values and standard asset representation - all very internal Hived aspects often used by frontends/client libraries and frequently causing problems too.
    All the above C++ code (core-wasm and beekeeper parts) is published to TypeScript/JavaScript environment by using a WebAssembly technology. The Python part is addressed by built dedicated Cython extension.
  2. Cross language representation of Hive operations written by using Google ProtoBuf which enabled us to generate a similar code (containing the comments describing operation details) for Python and Typescript environments. All such operations are defined close to Hive operation main definitions inside the hive::protocol library
    https://gitlab.syncad.com/hive/hive/-/tree/develop/libraries/protocol/proto?ref_type=heads
  3. Dedicated Typescript Object Oriented wrapper simplifies Wax library usage and makes it much more Intellisense compliant.
  4. Python layer that is mostly used by another Hive project: clive - this part of Wax library is to be improved soon (hopefully). It also makes it possible to build intuitive and natural programming interface as it has already been done for Typescript.

So let's focus on Typescript version.

We have decided to create two layers in the Typescript implementation of Wax:

  • the first one which can be used offline and provides the basic set of features like converting operations to textual form, building assets, transactions, processing transaction signatures (recalculating public keys used to sign them): you can find all the provided functionality in the IWaxBaseInterface. The instance of this interface can be acquired by calling a createWaxFoundation function.
  • the second one supporting online features like automatic filling the transaction with TAPOS (while using provided TransactionBuilder) and it allows performing API calls together with enabled request and response verification. All its functionality can be found in this interface definition: IHiveChainInterface which also extends a IWaxBaseInterface to provide its methods too. One of the advanced usage scenarios is extending a set of APIs being supported by Hive Chain which can provide you an IDE support while calling their methods. It also allows to verify request and response.

You can find some examples presenting the usage at some interesting scenarios here: Wax-NPM.

Wax library supports both: direct webbrowser as well as NodeJS environments.

An Important note: before playing with this library, you probably need to define/change your local .npmrc file to resolve package registry address correctly .

echo @hive:registry=https://gitlab.syncad.com/api/v4/packages/npm/ >> .npmrc

I'd like to discuss one scenario in deeper details: where we're creating a transaction: https://gitlab.syncad.com/hive/wax/-/blob/develop/npm.ts.md#create-a-signed-transaction

Beekeeper

In the very beginning. we're performing the setup of another tool: beekeeper, which initially has imported a private key 🔑 (next to be used to sign your transaction). This part is actually out of Wax library scope, but we decided to put it here to show a complete operation flow needed to build, sign and broadcast transaction.
Another thing that is worth mentioning is the fact that this step can be made separately since beekeeper finally stores imported private keys (inside a defined wallet) and next it only allows to use them (i.e. to generate a signature). It is impossible to read private keys back (using beekeeper API) from its encrypted storage. Before accessing the wallet, you have to unlock it (and provide initialy configured password) 🔓.

import beekeeperFactory from '@hive/beekeeper';
/// Build the beekeeper instance
const beekeeper = await beekeeperFactory();
/// First thing to start operating with beekeeper is establishing a session, which is additionally secured by specified salt.
const session = beekeeper.createSession("salt");
/// Once we got session, it's a time to create a wallet. Wallets are persisted to the WebBrower storage (IndexDB) or in NodeJS case to local filesystem.
const { wallet } = await session.createWallet("w0");
const myWifPrivateKey: string = '5JkFnXrLM2ap9t3AmAxBJvQHF7xSKtnTrCTginQCkhzU5S7ecPT'
/// Last action - we need to import private key
const publicKey = await wallet.importKey(myWifPrivateKey);

🔗 Wax HiveChain interface

Once beekeeper is ready to operate, we can start to play with Wax interfaces itself. Let's use a mentioned above IHiveChainInterface:
The purpose of this interface is to join static parts together (provided by IWaxBaseInterface) and online Hive features (mostly available by Hive APIs).

import { createHiveChain } from '@hive/wax';
/// Here important thing to note: there are (default) parameters passed to `createHiveChain` function: pointing default Hive API node instance used for communication (api.hive.blog)
const chain = await createHiveChain();

🛠 Transaction builder tool

To make transaction processing simpler, the Wax library provides a TransactionBuilder tool which can build a transaction for you and provide its several intresting properties like id, sigDigest as well.
Accessing its instance from the chain interface level, allows you to have automatically filled several important transaction properties as described below:

/** Now let's create a transaction builder. Important things:
 * - getTransactionBuilder takes optional `expirationTime parameter`
 * - getTransactionBuilder implicitly reads current Hive head block and correctly configures TAPOS for transaction you want to build
 */
const txBuilder = await chain.getTransactionBuilder();

/// Now let's add some operation to internally held transaction and at the end validate it:
txBuilder.push({
  vote: {
    voter: "otom",
    author: "c0ff33a",
    permlink: "ewxhnjbj",
    weight: 2200
  }
}).validate();

It is worth noting that TransactionBuilder offers much more operation building features (than specifying them as Typescipt object). To encapsulate blockchain complexity and allow seamless use of this interface the Wax library offers several complex operation builders whose description is probably a good opportunity for another post 📜.

🖆 Signature generation

// Build and sign the transaction object. Here is passed a **public key** to identify previously imported private one.
const signedTx = txBuilder.build(wallet, publicKey);

Behind the scenes, several important things happen - very specific to blockchain internals:

  • the created transaction is finally formed
  • it is passed to the Wax library internals, which then try to deserialize it directly into hive::protocol::signed_transaction object
  • once it succeeds, regular Hive Protocol functions are used to binary serialize transaction, calculate transaction id (hash), its sigDigest (basing also on passed chain-id)
  • the last step is producing a signature from internally passed sigDigest, by calling IBeekeeperUnlockedWaller.signDigest
  • then produced signature is appended to the signature list in the transaction held by builder instance

📣 Broadcast

Once transaction has been signed, you can broadcast it by (of course) using a chain object:

/** First let's create a broadcast request: it can be built in 2 ways:
 * - by passing a transaction builder object already holding your signed transaction (like in this example)
 * - by passing a signed transaction object directly
 */
const request = new BroadcastTransactionRequest(txBuilder);

// Transmit
await chain.api.network_broadcast_api.broadcast_transaction(request);

🏁 Thats all ❗ Thanks for reading 🏅. We are waiting for your comments ;-)

Sort:  

Note to myself: we should add this post to a list of useful resources / examples / tutorials.

Gret tool, would love to implement in my project..

Congratulations @thebeedevs! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)

You distributed more than 1500 upvotes.
Your next target is to reach 1750 upvotes.
You received more than 2250 upvotes.
Your next target is to reach 2500 upvotes.

You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word STOP

Check out our last posts:

Rebuilding HiveBuzz: The Challenges Towards Recovery

Hello thebeedevs!

It's nice to let you know that your article won 🥇 place.
Your post is among the best articles voted 7 days ago by the @hive-lu | King Lucoin Curator by szejq

You and your curator receive 0.4141 Lu (Lucoin) investment token and a 17.49% share of the reward from Daily Report 230. Additionally, you can also receive a unique LUGOLD token for taking 1st place. All you need to do is reblog this report of the day with your winnings.

2.png


Invest in the Lu token (Lucoin) and get paid. With 50 Lu in your wallet, you also become the curator of the @hive-lu which follows your upvote.
Buy Lu on the Hive-Engine exchange | World of Lu created by @szejq

If you no longer want to receive notifications, reply to this comment with the word STOP or to resume write a word START