Building Bitcoin in JavaScript

I figure the best way to learn about something is to try to build it from scratch and see what happens.

For this year’s JS@PayPal conference, I thought it would be an interesting exercise to live-code Bitcoin in a 30 minute talk. I’ve never attempted a live-coding talk, so I figured I would throw myself in the deep end!

Here’s the full-length video I recorded before the conference, with in-depth explanations of everything I did:

How I did it

First, I decided to cover the core Bitcoin concepts in a simplified way:

To do this, I decided to vastly simplify everything:

A picture paints a thousand words here:

Bitcoin is the Mona Lisa, with laser eyes. What I’m building is… that thing on the right.

Some Basic Principles

It’s good to understand some Bitcoin Basics before we get started.

To learn more about these fundamentals, I strongly recommend starting here.

The Block Chain Interface

First, I came up with some types for the public interface of the block chain.

The important elements here are:

Blocks will contain:

Defining the rules

Next, let’s define some constants for how the block chain will work.

We have some really important stuff here:

The meaning of each of these should hopefully become clearer as we use them in our code.

Stubbing out the block chain

Next, let’s stub out the block chain. This will be our ‘database’ or system-of-record for all blocks and transactions.

Now we can start actually implementing some of these functions!

Defining the block chain data structure

First, the data structure for the blockchain itself:

You might think a block chain like Bitcoin is a linked-list, where each block is a node in the list.

Actually, a block chain is more like a tree of blocks.

There can be many competing branches of this tree. How do we know which branch to trust? Easy! We pick the longest branch, since that is the branch that took the most computational effort to create. The longer the branch, the more confidence we can have that no other branch can overtake it.

So, we use a tree data structure in memory to represent our block chain, because that allows us to easily calculate the longest branch at any given time.

We pass in GENESIS_BLOCK as the root of this tree, since that will always be the first block. Hard-coding this makes things easier and offers no particular disadvantage.

Mining Blocks

Next, let’s write some code to mine a new block. This will be the most challenging exercise of the day.

To mine a block, we need three things to start:

Most of this is easy. We insert the miner public key, the id, the parent id, the time, the index, and the transactions into the new block.

We’re going to re-validate the transactions here to make sure they’re correctly signed. Every other node will do the same before they accept the new block, and we want to maximize our chances of our block being accepted without giving anyone a good excuse to reject it.

The next tricky part is dealing with the reward.

We want to halve the reward every 20 blocks. So we calculate what the current reward will be, for the current block index, assuming the reward starts at 1024 and halves each 20 blocks. Some quick math here to achieve that, by checking if the current block index is divisible by 20, and if so, halving the reward. Otherwise we keep the same reward.

Next, we need to calculate the new difficulty for the block.

In reality, Bitcoin recalculates difficulty once every 2016 blocks, or approximately every 2 weeks. For simplicity, we’re going to recalculate the difficulty for every single new block so we can demo this in real time.

This is an extremely naive way of calculating the difficulty, but it works for this example.

This means that we’re constantly re-calibrating how difficult is is to create the next block, based on how long it took us to create the previous block. This keeps blocks being created at an approximately-constant rate, on average, no matter how many miners there are trying to mine new blocks.

The more miners you have, the higher the ‘hash rate’, which is a measure of how much computational power is currently being used across the world to mine new coins.

So either you have:

This means that Hash-Rate / Difficulty should always be a constant number, which keeps the average time for each new block relatively constant.

Once we’ve created a new block, we’re still not done . The block will only be accepted by the network if the difficulty is correct, based on the previous block.

We check this difficulty in a pretty naive way here. We hash the block, turn that hash into a number, and if the number is evenly divisible by the difficulty, with no remainder, we allow it to pass.

This means as the difficulty number gets higher, there is a smaller and smaller chance that the block will pass the difficulty check, and we will have to make more and more guesses to generate a new block. This takes more computational power, and more time.

The opposite is also true. If the difficulty number gets lower, there is a higher chance that a new block will pass the difficulty check, and it will take fewer guesses to generate a new block. This takes less computational power, and less time.

This simple version of a difficulty check works because it is more likely that a number is divisible by a low number like 2 than by a higher number like 17. So it is easier to generate a block whose hash happens to be divisible by 2, and harder to generate a block whose hash happens to be divisible by 17.

Adding the block to the block chain

When a new block is propagated to the network, we need to be able to add it to our tree data structure.

First, we want to verify the block matches its hash, and all of the transactions within the block are correctly signed.

Then, we want to verify the block passed all of the correct rules. For now, we’re just checking the difficulty matches. In reality, we would want to check every single field of the block and validate it completely. We can’t trust any other node on the network, so we want to validate every single thing.

If a block is not valid, at this point it will be rejected by the node. Since the entire network follows the exact same set of decentralized rules, every node will accept the exact same valid blocks, and reject the exact same invalid blocks, without needing a central authority to tell them which blocks are valid.

So not only do attackers need to spend a large amount of money for electricity to run the computations to create new blocks — they also would have an extremely hard time bending the rules that are set by every other node on the network for the integrity of a block.

Finally, we just need to find the parent block specified by the new block, and add the new block as a child node to that parent. This extends the existing tree with the new block, so we can use it later to calculate everyone’s current balances.

Calculating Balances

The final thing we need to do is have some way to take all of the following:

And calculate the final balances for each wallet on the chain based on those values in each block.

We do this by finding the longest chain at any given time, and adding up all of the balances, fees, and block rewards. All of the data we need to do this is contained in each block.

You’ll notice transactions are a zero-sum-game. Each amount is subtracted from one account and added to another account. The same goes for each fee. So transactions can only use coins that are already present on the network, they can not create or destroy coins. (Of course, you can send coins to a dead address or lose your private key in a boating accident. This does not destroy coins though, it only makes them permanently inaccessible).

Rewards, however, are not a zero-sum-game — we’re adding new coins to the network, without ever taking them away. This is actually the source of all new Bitcoins. This is also how Bitcoins eventually reach their fixed cap. Eventually, the block reward halves and halves and halves down to zero. At which point no new Bitcoins can ever be added or subtracted from the system, and we end up with a fixed cap of 21 million.

This halving schedule gives Bitcoin its S2F value, which programs its price to rise like clockwork every four years. Just kidding.

Done with the block chain!

We’re now done with the data-structure / database side of things. We have a block chain, we’re able to create new blocks, add them to the tree, and calculate the final balance of each wallet based on the longest chain of blocks in the tree.

But we’re not done quite yet!

Bitcoin doesn’t just run on a single computer or server. We need a way to connect to a peer-to-peer network, share these blocks with others, and publish new transactions to the network. So we need a node!

Getting started with the Node

Again, we need to define some types and stubs for our Node, so we have something to code against.

There are a few concepts here:

Now we can start implementing these functions!

Blockchain, Credentials, and Network Access

First, we’re going to instantiate the stuff we need to run the node:

Listening for new transactions

We’ll need to be able to listen for transactions being sent from any other nodes on the network:

At this point we just push the transaction into the mempool. We could and probably should validate it at this point — but we’re already doing that before including the transactions into a block, so we’ll skip it for now.

The mempool is a staging area for new transactions. They aren’t final or ‘real’ yet and nobody should rely on these mempool transactions to see if they got paid. To become final, the transactions will need to be included in a newly mined block.

Sending a new transaction

We of course want to be able to send our own new transactions:

To do this, we create a signed message using our private key. This contains the sender address, the receiver address, the amount we want to send, and the fee we want to attach to the transaction (to give it priority on the network).

Only the person with the corresponding private key to the public key (public address) can sign a transaction like this. Without your private key, nobody can send transactions on your behalf. And of course the private key is never shared to anyone else on the network.

Once we’ve created and signed this transaction, all that remains to do is to broadcast it to the network, so it can be picked up by any other node that is listening, and added to their mempool.

Listening for new blocks

Blocks can be created by any other node on the network, and this is where most blocks will come from in the real world. So we need to be able to listen for new blocks from others, and add them to our blockchain.

We’ve already defined the logic to validate the block’s integrity in addBlock, so we’re just going to invoke that method here. If the block gets rejected, no big deal, we’ll just continue on as usual.

We also are going to blank out the current mempool. In reality, we probably want to only filter out the transactions from the mempool that actually appeared in the new block, but we’re going to take a shortcut here for simplicity.

Running the node and mining new blocks

Finally, we actually want to run the node, and attempt to mine new blocks:

To avoid killing my browser, I’m running this in an asynchronous loop which runs every 500ms. In the loop, we pull out a limited number of transactions from the mempool (based on the block size limit we defined earlier), and we attempt to mine a new block which includes those transactions.

In reality, we would normally search for the transactions with the highest fees, so we get the maximum reward for mining the block. Here, for simplicity, we’re just taking them in the order they are added to the mempool.

If we’re successful in mining a new block, we publish that block to the network to be consumed by other nodes.

If someone else mines a new block before we do, we start over, and try mining a new block on top of that block instead — since createBlock will always try to mine on top of the longest chain of blocks at any given time.

And that’s it!

You can find the code for this and run it here:

The most important files are:

When you run this project, my partner Jill has created an awesome UI to help you visualize what is going on, as nodes mine new blocks and send transactions back and forth:

Thanks!

I hope this was useful, to help you understand some of the principles used to power Bitcoin!

Remember, this is a vast simplification of the real Bitcoin node and mining software. It’s intended for learning purposes only, and nothing more.

Cheers! — Daniel