In part 1 of the Hedera and JavaScript blog series we set up our SDK, configured our environment, and managed to send our first transaction to the testnet. There was much rejoicing.
Let’s build on that success to send our first message to Hedera using the Hedera Consensus Service, or HCS. For those unfamiliar, HCS is really good (read: fast and cheap) for sending messages or events to the Hedera network. It follows a publish subscribe model where you define a topic to submit a message to and subscribe to receiving updates from a mirror node. Don’t worry, this is a lot easier than it sounds!
To receive subscription updates we’ll make use of a Hedera mirror node. For this case we’ll use the API Hedera currently provides, but you can find a full list of alternatives here. In the future, you’ll even be able to run your own.
/* ... Add a mirror node to your .env file ... */ MIRROR_NODE_IP_ADDRESS = "hcs.testnet.mirrornode.hedera.com:5600"
/* ... Add a mirror node to your .env file ... */
MIRROR_NODE_IP_ADDRESS = "hcs.testnet.mirrornode.hedera.com:5600"
With your JavaScript environment now set up (it should contain an Account ID, associated private key, and a mirror node to connect to), we’ll create a HCS topic, submit messages to it, and subscribe to the mirror node to receive updates.
Reminder, if you don't have an environment and node project already set up, please check out part 1 of this blog series. Also note that this tutorial uses version 1.1 of the Hedera JavaScript SDK, which may be updated by the time you're running this yourself. For the latest examples, please visit Hedera Docs.
Import transactions
We’ll start in our existing index.js file. As we did with the `CryptoTransferTransaction` already, we need to import the HCS transactions we want to use.
To use the Hedera Consensus Service, you’ll rely heavily on mirror nodes, which allow us to subscribe to updates. Let’s start by importing our `ConsensusTopicCreateTransaction`.
// Update your index.js file's imports -- // Require specific modules from the Hedera JavaScript SDK const { Client, CryptoTransferTransaction, ConsensusTopicCreateTransaction } = require("@hashgraph/sdk");
// Update your index.js file's imports --
// Require specific modules from the Hedera JavaScript SDK
const { Client, CryptoTransferTransaction, ConsensusTopicCreateTransaction } = require("@hashgraph/sdk");
Create topic transaction
We’ll put this import to work within our async main function.
/* ... index.js imports ... */ async function main() { // Build & execute our new Consensus Topic Create transaction const createTopicTransactionId = await new ConsensusTopicCreateTransaction().execute(client); // Get the receipt of our transaction, to see if it was successful! const createTopicReceipt = await createTopicTransactionId.getReceipt(client); // If it was successful, it will contain a new topic ID! const newTopicId = createTopicReceipt.getTopicId; console.log('Our topic:' + newTopicId); // ...
/* ... index.js imports ... */
async function main() {
// Build & execute our new Consensus Topic Create transaction
const createTopicTransactionId = await new ConsensusTopicCreateTransaction().execute(client);
// Get the receipt of our transaction, to see if it was successful!
const createTopicReceipt = await createTopicTransactionId.getReceipt(client);
// If it was successful, it will contain a new topic ID!
const newTopicId = createTopicReceipt.getTopicId;
console.log('Our topic:' + newTopicId);
// ...
To let you in on what we’re doing here, we want to first store the transaction ID; this helps us receive a receipt of the transaction to know it successfully reached consensus.
Because this transaction is creating a new “namespace” on the network for this entity, similar to accounts, files, or contracts, the receipt should contain the new Topic ID. Which means that a topic ID will look exactly like an account ID; when I ran the example above I created topic ID 0.0.180380.
A topic isn’t all that useful without messages going to it. We can fix that.
Starting with our imports, we’ll add ConsensusSubmitTransaction and MirrorConsensusTopicQuery to query our newly created topic.
// Update your index.js file's imports -- // Import additional modules from the Hedera JavaScript SDK const { Client, CryptoTransferTransaction, ConsensusTopicCreateTransaction, HederaMirrorClient, ConsensusSubmitTransaction, MirrorConsensusTopicQuery } = require("@hashgraph/sdk");
// Import additional modules from the Hedera JavaScript SDK
const { Client, CryptoTransferTransaction, ConsensusTopicCreateTransaction, HederaMirrorClient, ConsensusSubmitTransaction, MirrorConsensusTopicQuery } = require("@hashgraph/sdk");
And to send our first message, we will build it similarly to other transactions on Hedera.
// Build, specify topic ID, and send a new message to HCS const newHCSMessage = await new ConsensusSubmitTransaction() .setTopicId(newTopicId) .setMessage("ℏello future!") .execute(client); // Get the receipt of our message to confirm it was successful const messageReceipt = await newHCSMessage.getReceipt(client); console.log('Message receipt: ' + messageReceipt);
// Build, specify topic ID, and send a new message to HCS
const newHCSMessage = await new ConsensusSubmitTransaction()
.setTopicId(newTopicId)
.setMessage("ℏello future!")
.execute(client);
// Get the receipt of our message to confirm it was successful
const messageReceipt = await newHCSMessage.getReceipt(client);
console.log('Message receipt: ' + messageReceipt);
Each message we send to the topic will be put in a total order with a defined sequence number, timestamp and a tamper-proof running hash.
The final step of our initial HCS setup is going to be subscribing to a Hedera Mirror Node API, specifically one that supports gRPC pub/sub.
/* ... other imports / environment variable config ... */ const mirrorNodeAddress = process.env.MIRROR_NODE_IP_ADDRESS; const consensusClient = new MirrorClient(mirrorNodeAddress); // Subscribe to a Hedera Mirror Node (or multiple!) to get pub-sub messaging over HCS new MirrorConsensusTopicQuery() .setTopicId(newTopicId) .subscribe(process.env.MIRROR_NODE_IP_ADDRESS, response => { console.log(response); })
/* ... other imports / environment variable config ... */
const mirrorNodeAddress = process.env.MIRROR_NODE_IP_ADDRESS;
const consensusClient = new MirrorClient(mirrorNodeAddress);
// Subscribe to a Hedera Mirror Node (or multiple!) to get pub-sub messaging over HCS
new MirrorConsensusTopicQuery()
.subscribe(process.env.MIRROR_NODE_IP_ADDRESS, response => {
console.log(response);
})
Here’s the full, but minimum, setup of our Hedera Consensus Service pub-sub messaging.
// Import the modules we need from the Hedera JavaScript SDK const { Client, MirrorClient, MirrorConsensusTopicQuery, ConsensusTopicCreateTransaction, ConsensusSubmitMessageTransaction } = require("@hashgraph/sdk"); // Write our program in an asynchronous function async function main() { /* Get our environment variables (contained in a .env, or other way */ const operatorPrivateKey = process.env.OPERATOR_KEY; const operatorAccount = process.env.OPERATOR_ID; const mirrorNodeAddress = process.env.MIRROR_NODE_IP_ADDRESS; const nodeAddress = process.env.NODE_ADDRESS; // Create our Hedera Mainnet (or testnet) client const client = Client.forTestnet(); client.setOperator(operatorAccount, operatorPrivateKey); // Create our Mirror Node client const consensusClient = new MirrorClient(mirrorNodeAddress); // Build & execute our new Consensus Topic Create transaction const createTopicTransactionId = await new ConsensusTopicCreateTransaction() .setTopicMemo("Hello HCS Tutorial!") .setMaxTransactionFee(1000000) // defaults to tinybars .execute(client); // Get the receipt of our transaction, to see if it was successful! const createTopicReceipt = await createTopicTransactionId.getReceipt(client); // If it was successful, it will contain a new topic ID! const topicId = createTopicReceipt.getConsensusTopicId(); console.log(`topicId = ${topicId}`); // Subscribe to a Hedera Mirror Node (or multiple!) to get pub-sub messaging over HCS new MirrorConsensusTopicQuery() .setTopicId(topicId) .subscribe( consensusClient, (message) => console.log(message.toString()), (error) => console.log(`Error: ${error}`) ); // Build, specify topic ID, and send a new message to HCS const newHCSMessage = await new ConsensusSubmitTransaction() .setTopicId(newTopicId) .setMessage("ℏello future!") .execute(client); // Get the receipt of our message to confirm it was successful const hcsMessageReceipt = await newHCSMessage.getReceipt(client); console.log('Message receipt: ' + hcsMessageReceipt); } main();
// Import the modules we need from the Hedera JavaScript SDK
const {
Client,
MirrorClient,
MirrorConsensusTopicQuery,
ConsensusTopicCreateTransaction,
ConsensusSubmitMessageTransaction
} = require("@hashgraph/sdk");
// Write our program in an asynchronous function
/* Get our environment variables (contained in a .env, or other way */
const operatorPrivateKey = process.env.OPERATOR_KEY;
const operatorAccount = process.env.OPERATOR_ID;
const nodeAddress = process.env.NODE_ADDRESS;
// Create our Hedera Mainnet (or testnet) client
const client = Client.forTestnet();
client.setOperator(operatorAccount, operatorPrivateKey);
// Create our Mirror Node client
const createTopicTransactionId = await new ConsensusTopicCreateTransaction()
.setTopicMemo("Hello HCS Tutorial!")
.setMaxTransactionFee(1000000) // defaults to tinybars
const topicId = createTopicReceipt.getConsensusTopicId();
console.log(`topicId = ${topicId}`);
.setTopicId(topicId)
.subscribe(
consensusClient,
(message) => console.log(message.toString()),
(error) => console.log(`Error: ${error}`)
);
const hcsMessageReceipt = await newHCSMessage.getReceipt(client);
console.log('Message receipt: ' + hcsMessageReceipt);
}
main();
With that, you've successfully created your first Hedera Consensus Service topic, subscribed to a Hedera Mirror Node, and sent your first messages over the Hedera Consensus Service. Congratulations! In our next part, we'll show you how to start building your first web application that is decentralized on Hedera Hashgraph, using HCS.
Have any issues? Please let us know on Discord.
View full examples within Hedera docs.