Run a steem-js bot as AWS Lambda function

What Will I Learn?

In this tutorial

  • You will learn to embed a steem-js bot into an AWS Lambda
  • You will learn to configure an AWS Lambda to be triggered periodically
  • You will learn to protect your Steem key with KMS

Requirements

To follow this tutorial you need

  • node.js installed
  • an Amazon AWS account
  • AWS CLI installed and configured for your account

Difficulty

Intermediate

Tutorial Contents

This tutorial will show how to create a steem-js bot, that runs as AWS Lambda. The bot will be triggered periodically. Further this tutorial will show how you encrypt your Steem key with KMS, such that it is not necessary to include it as plain text in the bot's source code.

What is AWS Lambda?

AWS Lambda is a compute service that lets you run code without provisioning or managing servers. AWS Lambda executes your code only when needed and scales automatically, from a few requests per day to thousands per second.

(from the AWS Documentation)

Why AWS Lambda?

AWS Lambda functions are the only AWS service that offers a free contingent, even after the first 12 months (where Amazon offers a limited set of its AWS services for free). Every month up to one million Lambda calls are included with up to 400.000 GB/s per month. The second metric is a bit confusing, basically it it means that the overall runtime of your Lambda multiplied with its memory consumption must be less than 400.000 GB/s per month to stay within the free contingent. The lowest available memory tier is 128 MB. This is sufficient for a typical steem-js bot, such that it may run up to 3.2 million seconds per month. Hence if one execution of a bot run takes less about 3 seconds we are bound by the one million free calls per month, such that the bot may run more than 1000 times per hour, which should be totally sufficient for most applications.

Long story short, you don't need to pay for a dedicated server, if you run your bot as AWS Lambda function.

Project setup

Setup a new node project and add steem-js as dependency with

npm init
npm install steem --save-dev

Be sure to select index.js as main entry point.

I separate the project into three source files: bot.js that includes all the logic for the bot, index.jswith the extra logic for the AWS Lambda, and app.js to test the bot locally.

files.PNG

Implementation of the bot

The bot itself is pretty simple, as this is not the main focus of the tutorial. It's purpose is to look for new posts in utopian-io and to vote for the first tutorial it finds. The key required for the vote is passed as parameter to the bot function, while other settings are directly configurable in bot.js. The full source code of bot.js is shown below.

"use strict";
const steem = require("steem");

/* settings */
var my_account = "nafestw";
var vote_weight = 10000;

module.exports = function(wif) {
  steem.api.getDiscussionsByCreated(
    { tag: "utopian-io", limit: 100 },
    (err, result) => {
      // filter everything but tutorials
      let candidates = result.filter(res => {
        if (!res.json_metadata) return false;
        return res.json_metadata.indexOf('"type":"tutorial') !== -1;
      });

      if (candidates.length > 0) {
        let target = candidates[0];
        // vote for the first one
        steem.broadcast.vote(
          wif,
          my_account,
          target.author,
          target.permlink,
          vote_weight,
          function(err, result) {
            if (err) console.log(err);
            else console.log(result);
          }
        );
      }
    }
  );
};

The implementation of app.js is trivial and just calls the function exported by bot.js with the Steem key:

"use strict";

const bot = require("./bot");

var wif = "ENTER_STEEM_KEY_HERE";

bot(wif);
Encryption of the Steem key

As state above, it is not a good practice to include your key in plain text in source code that is uploaded to a server. AWS provides an encryption mechanisms to solve this, such that an encrypted version of the key can be stored with the Lambda function.

iam.PNG

Create a Role

Log into the AWS Management console and select IAM under "Security, Identity & Compliance". First you need to setup a role. This role will be needed for the key and to create the Lambda function:

  • Select Roles -> Create Role.
  • Select Lambda and press Next
  • Select AWSLambdaBasicExecutionRole and press Next
  • Enter a name for the role: steem_bot_role
Create the encryption key

On the left, select the last point: "Encryption Keys". Now it's necessary to select the region, which will also be the region you will use for your Lambda later. You can find all regions that support Lambdas here. Next, select "Create Key", enter an alias for the key and select next step. Adding tags is optional and can be skipped by selecting "Next Step". Next select the users that may administer the new key. Now, for the usage permissions, select the role created before. Review your settings and press Finish. The next page shows the Key ID required for encryption in the next step.

The encrypt your Steem key, go to the command line and encrypt your key with

aws kms encrypt --key-id <kms_key_id> --plaintext "<YOUR_STEEM_KEY>" --query CiphertextBlob --output text | base64 -D > encrypted_secret

Replace <kms_key_id> with the key id from the AWS management console and <YOUR_STEEM_KEY> with your Steem key. The aws kms encrypt command outputs the encrpyted string in base64 encoding. To decrypt it, it must be in binary form. Hence it is piped to base64 -D and written to the file encrypted_secret which should be stored next to the bot's source code.

Call the bot function from the Lambda handler

Using AWS Lambdas to execute your code requires that it is encapsulated in a handler function. This function must be exported to exports.handler and receives three parameters (event, context, callback), which we ignore, because we don't need them. On default AWS Lambda expects export.handler to be defined in index.js (you can change that in the AWS management console).
The encrypted key is loaded from file and decrypted with kms.decrypt before it is passed to the bot function. The full implementation of index.js is:

"use strict";
const bot = require("./bot");

var fs = require("fs");
var AWS = require("aws-sdk");
var kms = new AWS.KMS({ region: "us-west-2" });

var secretPath = "./encrypted_secret";
var encryptedSecret = fs.readFileSync(secretPath);

var params = {
  CiphertextBlob: encryptedSecret
};

exports.handler = (event, context, callback) => {
  kms.decrypt(params, function(err, data) {
    if (err) console.log(err, err.stack);
    else {
      let wif = data["Plaintext"].toString();
      bot(wif);
    }
  });
};

Deploy the Lambda

To deploy the Lambda, all code and assets (as encrypted_secret) including the node_modules folder must be added to a ZIP file. (Smaller Lambdas without extra dependencies can be edited online). If you have the ZIP file ready, go to the AWS Management Console and select Lambda and then Create function. In the following form keep "Author from scratch" selected, enter a name for the function, keep the NodeJS Runtime, and choose the steem_bot_role that has been created before. Then press "Create Function".

new_lambda_function.PNG

In the section "Function code", select "Upload .ZIP file" as "Code Entry Type", press "Upload" and select the ZIP file with your bot's code.

upload_zip.PNG

Finally, it is necessary to add a trigger for the Lambda function. The steem_bot should be triggered periodically, so select CloudWatch Events and "Create New rule" for a new rule. The rule must be named and a expression for the actual schedule must be specified. The simplest rules are in the form rate(5 minutes), which runs the Lambda function every five minutes. If everything is entered, press Add.

add_trigger.PNG

Amazon AWS Lambdas are terminated after a configurable timeout, which is three seconds on default. Depending on what your bot does, you may need to adapt this setting. You can find it on the lamba's page further below under "Basic Settings".

That's it. If you press Save on the top right, the ZIP file is uploaded and your Lambda is saved. You can test it immediately by selecting "Test" or just wait for its first automatic invocation. If something doesn't work as expected, you can extend your Lambda's code with console.log() statements, which are accessible through the monitoring functions of AWS Lambda.

This concludes the tutorial on running a steem-js bot as AWS Lambda function.



Posted on Utopian.io - Rewarding Open Source Contributors

H2
H3
H4
3 columns
2 columns
1 column
Join the conversation now