Gentry Demchak

Gentry Demchak

image

Bitcoin Progress

A twitter bot that posts regular updates about the quadrennial block subsidy halvening event.

I created this twitter bot to help educate folks about Bitcoins programatic supply cap of 21 million coins (or to be more precise 2,100,000,000,000,000 sats, the smallest unit.).

The Bitcoin protocol was initilized to subsidize1 miners 50 bitcoin for every block they found. The subsidy is halved every 210,000 blocks that are mined until it reaches 0. This simple algorithm is how Bitcoin will eventually arrive at the 21 million supply cap.

formula for bitcoin supply

Architecture for the bot

A few things were needed for this bot to function:

  • Access to the Twitter API, creation of a twitter account and app, along with keys / tokens / secrets for auth so the bot can post updates to twitter.
  • A way to check the current block height so we can derive our progress toward the next subsidy halving. For that we can simply and freely poll https://blockchain.info/q/getblockcount from the blockchain.com Query API.
  • A service to post from. AWS Lambda serverless is a fantastic option as this bot isn't doing any heavy or frequent computation that would warrant an entire server instance. Plus it's free for the amount of usage this bot requires!
  • A language and library to interact with the Twitter API: Python and Tweepy are easy to use and well documented.
  • Finally, a trigger that invokes the Lambda function on a regular interval. For simplicity, Amazon EventBridge can be used to call a service based on some simple rules.

General outline

  1. Follow the Twitter Development Platform getting started guide. Get API keys and create an app.
  2. Setup an AWS account.
  3. Create a new Lambda function.
  4. Add twitter access token + token secret + consumer key + consumer secret from the twitter app to the Lambda environment variables so the Lambda function will have authorization to post to Twitter.
  5. Install AWS CLI
  6. Setup a git repository for the project.
  7. Create a local python virtualenv.
  8. Write code!
  9. Create a deployment package by zipping up the python function and all package dependencies.
  10. Deploy package to the lambda function utilizing AWS CLI update-function-code
  11. Setup EventBridge trigger to invoke the Lambda function every 5 minutes. (bitcoin blocks are mined, on average, every 10 minutes, so we need to check for a new block height at least every 10 minutes). If the computed value is different than the last time we checked, then we can post an update to twitter!
  12. 🤑 Profit

Result

A bot that publishes regular updates on progress toward the next bitcoin subsidy halvening!

Improvements

  1. The iteration loop (develop => deploy => test) was a bit of an arduous process as it involves zipping the the project, deploying to AWS via the CLI, invoking the function to see if it would work, etc. Eventually, I started editing the Lamda function directly from the AWS Lambda IDE 🙊. Alternatively, I could explore configuring a CI/CD system leveraging github actions.

  2. I don't like that it polls the blockchain.com API every 5 minutes. I'd like to find a way to subscribe to a websocket that notifies me when a new block is mined. I'm not sure if any bitcoin RPC APIs offer this functionality, but I'll look into it.

Interesting bits of code / challenges

Deriving subsidy:

There are a couple ways to derive subsidy. One way is to look at the data from the current block and simply subtract the total output value from the total input value. The difference will give you the subsidy. This data can be found using the blockchair.com api by first retrieving the latest block, and then looking up https://api.blockchair.com/bitcoin/dashboards/block/776555

Alternatively, if we know a few constants and know the current block height, then we can derive the value ourself with a simple formula.

The bitcoin protocol has defined a few consensus critical constants that we can use:

COIN = 100000000

nSubsidy = 50

nSubsidyHalvingInterval = 210000

Given these constants and a known blockheight, we can use a simple function:

def block_subsidy(self):
    subsidy_era = self.subsidy_era()
    # use a bitwise right shift to halve the subsidy based on the era
    subsidy = ( self.INIT_MINING_SUBSIDY >> subsidy_era - 1 ) / self.COIN
    return subsidy

Footnotes

  1. Some argue the subsidy should be called a reward, however, as the subsidy eventually reaches 0 and the network is intended to utlimately be fully supported by transaction fees, it makes more sense to call it a subsidy.