Audio version of the article
Learn Bitcoin’s underlying data structure in 4 short steps
Blockchain — The million-dollar buzzword. We’ve all heard the stories of overnight crypto riches. But will cryptocurrencies like Bitcoin (or blockchain, their underlying data structure) revolutionize the world? Or will they remain a fascinating experiment in open-source? Nobody can say for sure.
Either way, they’re a lot of fun to write!
What is a blockchain? Skip ahead if you’re already familiar, but basically, a blockchain is open-source software that is shared between thousands of computers. These computers all follow a set of rules to track money that’s been sent from accounts tied to the blockchain software.
Each “block” is a group of data that says, for example, “Alice paid Bob $100 on Monday, February 15th.” On the blockchain, I can send you money without using a bank!
For this project you’ll only need Python. Keep in mind, our blockchain will be a simplified, high-level introduction…we won’t build the full-blown Bitcoin blockchain. Instead we’ll create functions to add blocks, transactions, and encryption so that our data’s tamper-proof. Let’s dive in!
Step #1: Create a Blockchain Class
First step: imports! We’ll need hashlib for the encryption, JSON to format our blocks, and time for each block’s timestamp.
Since we’ll be writing this with object-oriented programming in mind, let’s create a Blockchain class and initialize the following variables:
chain: an empty list that we’ll add blocks to. Quite literally our ‘block–chain’.
pending_transactions: when users send our coins to each other, their transactions will sit in this array until we approve & add them to a new block.
new_block: this is a method that we’ll define soon, and we’ll use it to add each block to the chain. Let’s borrow Satoshi’s message from the Bitcoin genesis block (the very first block ever mined) for inspiration 🙂
Step #2: Write a Function to Build New Blocks
Now that we have an empty chain, let’s add blocks to it! On line 16 we’ll add a block variable describing a JSON object with these properties:
index: Take the length of our blockchain and add 1 to it. We’ll use this to reference an individual block, so for example the genesis block has index = 1
timestamp: using our time() import, stamp the block when it’s created. Users can now check when their transaction was confirmed on-chain.
transactions: any transactions that are sitting in the ‘pending’ list will be included in our new block.
proof: this comes from our miner who thinks they found a valid “nonce”, or “proof”. We’ll talk about this some more in a bit.
previous_hash: a hashed version of the most recent approved block.
Ok, so every new block will contain those properties, and that’s all well and good, but we still need to add it to the chain! Lines 23 & 24 will take care of this: first we empty the pending list of transactions (since we added them to our new block on line 19), then add our new block to self.chain and return it.
Step #3: Write Functions to Create New Transactions & Get the Last Block
So far, so good! But without a list of transactions (ie. “Mike sent 1 BTC to reader”) this whole exercise is pretty pointless. Let’s first define a last_block() method, so that we can call our chain and receive the block that was added most recently (we’ll use this in a second for our new index).
Now let’s create a new_transaction() method with our three most important variables: sender, recipient, and amount. Without these included in each and every transaction, our users can’t spend, earn, or buy things with our newly-minted cryptocurrency! Just keep in mind that our transactions today are over-simplified, and don’t reflect what you’d find in a true cryptocurrency.
On line 42 we add our transaction JSON object to our pool of pending_transactions. These will sit in limbo until a new block is mined and added to our blockchain. And for future reference, let’s return the index of the block which our new transaction’s going to be added to.
Step #4: Write a Function to “Hash” Our Blocks
Ok, it’s time for the hoodie-wearing, Matrix-style hacker shit. Cryptography.
Bitcoin and many other blockchains use SHA-256, an encryption hash function, which takes in some text string (stored as a Unicode value) and spits out a 64-character long encrypted string. In a blockchain, the text that we encrypt is actually our block. For example, the encrypted string, or “hash”, of the Bitcoin genesis block looks like this:
Why do we care? Blockchains are considered “tamper-proof” because every single block contains a copy of the previous block’s hash. And since your new hash is derived from the previous block, you can’t change any aspect of a block without changing every single hash in front of it.
If I wanted to, I could download the Bitcoin blockchain to my computer, write “Satoshi sends Mike 7,235,900 Bitcoin!” into the genesis block, and broadcast this to the Bitcoin network and claim that I’m a secret billionaire. But as soon as any self-respecting miner compares their current copy of the blockchain, specifically the hash values stored in each block, with my copy of the chain, they’ll see that I’m a liar, refuse to validate it, and run me off the network.
Let’s look back at our code. Our hash() method on line 48 takes our new block and changes its key/value pairs all into strings. Line 49 turns that string into Unicode, which we pass into our SHA256 method from hashlib, and we create a hexidecimal string from its return value. Then we return our new hash!
Step #5: Create a new Blockchain & Send Some Money!
Let’s recap how much we’ve done. First, we created a class for our blockchain. Next, we wrote methods to build a new block and a new transaction, along with a custom method used to hash any block with SHA256 encryption.
So let’s build our chain! We initialize an instance of our Blockchain class on line 57. Then we add some dummy transactions, making sure to list them in some blocks that we add to our chain. All that’s left is to save the above lines of code into your text editor & run the file in your terminal.
Here’s our result:
Our blockchain includes 3 blocks right now: the genesis block (with an index of 1 and no transactions), plus the 2 that we added ourselves. You’ll notice that lines 15 and 24 include our encrypted hashes (derived from each preceding block), and that our timestamps don’t match each other. Granted, our computer built each block almost simultaneously since we ran this program and generated blocks at almost the same instant, but Bitcoin blocks are created *on average* every 10 minutes.
One more thing: do you notice any account balances?
Blockchains != banks and here’s a good example of the difference. A cryptocurrency wallet will calculate your balance by scanning the entire chain and adding up how many coins you received vs. how much you spent. We don’t need to trust a bank to tell us how much money’s in our account… we’re only trusting the network, instead of one mega-corporation. Cool, right?
So what did we accomplish, and more importantly, what’s still missing? We built a blockchain that we can fill with blocks full of cryptocurrency transactions, BUT this is not a secure network. First, we’re creating a block anytime somebody calls new_block() and there’s basically no conditions. Our new_block() method needs a parameter called proof but right now that can be anything: any number, or a “hello world” string, or anything really.
In the Bitcoin network, there’s a consensus mechanism in place called Proof of Work, which describes the rules by which security is achieved. A proof is a random number which is very difficult to find unless you have dedicated high-performance machines running around-the-clock.
We’re missing a ton of other detail as well: fees for the miners to collect, a transaction count, public/private keys, a merkle tree structure…it can get complicated pretty fast. But! Hopefully this walkthrough was helpful for you as a basic example of the moving parts in a blockchain.
This article has been published from the source link without modifications to the text. Only the headline has been changed.