Decoding & encoding transactions and blocks with the API Client

The API of a blockchain node typically returns all requested transactions and blocks encoded. To be readable, they need to be decoded into JS or JSON objects.

Blocks and transactions can be decoded conveniently with the The apiClient library of the Lisk SDK.

Connecting a node with the API client

Before the API client can be used, it needs to connect to a blockchain node. This can be achieved either via a WebSocket (on the local and remote server), or an IPC (only on the local server) connection.

In most scenarios it is beneficial to have a local node running (for example the Hello World application) to which the client can send the API requests. The RPC options in the config should be enabled and configured accordingly, see RPC configuration of a node.

The apiClient is also included in the NPM package @liskhq/lisk-client.
const { apiClient } = require('@liskhq/lisk-client');
let clientCache;
const nodeAPIURL = 'ws://localhost:8080/ws';

const getClient = async () => {
	if (!clientCache) {
        // Connect to the specified blockchain node
		clientCache = await apiClient.createWSClient(nodeAPIURL);
	}
	return clientCache;
};

Decoding & encoding blocks and their included transactions

The following script shows how to decode & encode a block by a given ID.

getBlockById.js:
const { apiClient } = require('@liskhq/lisk-client');
let clientCache;
const nodeAPIURL = 'ws://localhost:8080/ws';

const getClient = async () => {
	if (!clientCache) {
		clientCache = await apiClient.createWSClient(nodeAPIURL);
	}
	return clientCache;
};

if (process.argv.length < 3) {
	console.error("Please provide the block ID to be decoded.")
	process.exit(1);
}
const blockId = process.argv[2];


getClient().then((client) => {
	client.invoke("app:getBlockByID", {
		id: blockId
	}).then(res => {
		const decodedBlock = client.block.decode(res);
		const blockJSON = client.block.toJSON(decodedBlock);
		const blockObject = client.block.fromJSON(blockJSON);
		const encodedBlockObject = client.block.encode(blockObject);
		const encodedBlockAsHexString = encodedBlockObject.toString('hex');
		console.log("Encoded block: ", res)
		console.log("Decoded block: ", decodedBlock);
		console.log("Block as JSON: ", blockJSON);
		if (blockJSON.payload && blockJSON.payload.length > 0) {
			console.log(blockJSON.payload[0].asset);
		}
		console.log("Block from JSON to Object: ", blockObject);
		console.log("Encoded block object: ", encodedBlockObject);
		console.log("Encoded block as hex string: ", encodedBlockAsHexString)
		console.log("res = encodedBlockAsHexString? - ", (res == encodedBlockAsHexString));
		process.exit(0);
	});
});

Assuming you wish to decode a block with the ID 52303f33684f5ffae4d307747db36d86bde6e14d76958e197cb82eeab5ca6f92, then execute the script with the block ID as the parameter:

node getBlockById.js 52303f33684f5ffae4d307747db36d86bde6e14d76958e197cb82eeab5ca6f92

The decoded block JSON will look similar to the following, as shown below:

Block and transaction payload as JSON
{
  header: {
    version: 2,
    timestamp: 1641301752,
    height: 3445,
    previousBlockID: 'ac4d1c2af42f7c596c65e172d5ac68cd47e7c3d539979b648b0778910181cb7a',
    transactionRoot: 'eb3dc80f04a469b9c6224c2e69c3b22b01a81e8986cf42037dc5b8ff768f0e8c',
    generatorPublicKey: 'e8a9c5bb058377aee7ba833fe9f5cf4de3bd02fd9ec6fe749b00542d93b44ca0',
    reward: '500000000',
    signature: '3a0bdd57baa6a79d80c6004dcfa96420398fcb2da9fe75f5883ce9f7767692c290dd1f3f70509d0f5c62970567dc496fe7491f5c88f15a4b83067d7bd7440204',
    asset: {
      maxHeightPreviouslyForged: 3406,
      maxHeightPrevoted: 3356,
      seedReveal: '0445aab446d7bcfc533a40bad1056986'
    },
    id: '1dd06d95755984741260be1a7b07c512ddb8a1a1fb5c422d7f5b14995f8a85aa'
  },
  payload: [
    {
      moduleID: 2,
      assetID: 0,
      nonce: '2',
      fee: '141000',
      senderPublicKey: '5133af7944acf5278b0310a11c06134f80ab4546d77d1b0e027c8430a7d2bb92',
      signatures: [Array],
      id: '2dd42458cd3255bb2db9f19a32519e9dd7705d273683114822fbcfd85a1cea00',
      asset: [Object]
    }
  ]
}
{
  amount: '100000000',
  recipientAddress: 'ed86183c22f8399f7aa28f7d2c2f1680224f7281',
  data: ''
}

Decoding & encoding transactions

The transaction ID is returned every time a transaction is sent to the node.

Write a simple script that decodes the transaction. Create a new file getTxById.js:

Example for decoding a transaction by a given ID
const { apiClient } = require('@liskhq/lisk-client');
let clientCache;
const nodeAPIURL = 'ws://localhost:8080/ws';

const getClient = async () => {
	if (!clientCache) {
		clientCache = await apiClient.createWSClient(nodeAPIURL);
	}
	return clientCache;
};

if (process.argv.length < 3) {
	console.error("Please provide the transaction ID to be decoded.")
	process.exit(1);
}
const txId = process.argv[2];

getClient().then((client) => {
	client.invoke("app:getTransactionByID", {
		id: txId
	}).then(res => {
		const decodedTx = client.transaction.decode(res);
		const txJSON = client.transaction.toJSON(decodedTx);
		const txObject = client.transaction.fromJSON(txJSON);
		const encodedTxObject = client.transaction.encode(txObject)
		const encodedTxAsHexString = encodedTxObject.toString('hex')
		console.log("Encoded tx: ", res)
		console.log("Decoded tx: ", decodedTx);
		console.log("Tx as JSON: ", txJSON);
		console.log("Tx from JSON to Object: ", txObject);
		console.log("Encoded tx object: ", encodedTxObject);
		console.log("Encoded tx as hex string: ", encodedTxAsHexString)
		console.log("res = encodedTxAsHexString? - ", (res == encodedTxAsHexString));
		process.exit(0);
	});
});

Assuming you wish to decode a transaction with the ID 130227fa63ac60edbbacb6dae709cf9304ab0181ef7ea28105764f6240d012f2, then execute the script with the transaction ID as the parameter:

node getTxById.js 130227fa63ac60edbbacb6dae709cf9304ab0181ef7ea28105764f6240d012f2

The decoded transaction JSON will look similar to the following, as shown below:

Transaction as JSON
{
  moduleID: 2,
  assetID: 0,
  nonce: '1',
  fee: '142000',
  senderPublicKey: '5133af7944acf5278b0310a11c06134f80ab4546d77d1b0e027c8430a7d2bb92',
  signatures: [
    'c6df8ccf2a50662cfea83660977b0093f7315b77a476f6e9b654d1c8296cd04afaa66f0225862a85fc50116b6ded743e245b5975df5b5ead2139382aa2c84002'
  ],
  asset: {
    amount: '1000000000',
    recipientAddress: 'ed86183c22f8399f7aa28f7d2c2f1680224f7281',
    data: ''
  },
  id: 'a0217443d5b9c427fcc5e89b71c3dd0b87cb516976a7683f52b5cb04eb46eb9b'
}