Published on

Building blockchain in Go. Part 1: Basic Prototype

Authors
Table of Contents

Introduction

Bitcoin was introduced to the world under a cloud of mystery in January 2009. A white paper, Bitcoin: A Peer-to-Peer Electronic Cash System, published in 2008 under the pseudonym of Satoshi Nakamoto, outlined the concept; to date, the authorship of the paper remains unknown. What is known is that the underlining technology, the blockchain, has implications for the accounting profession. Many are still wondering what blockchain means for the accounting profession more than 10 years after its introduction.

Block

Let's start with the "block" part of "blockchain". In blockchain it's blocks that store valuable information. For example, bitcoin blocks store transactions, the essence of any cryptocurrency. Besides this, a block contains some technical information, like its version, current timestamp and the hash of the previous block.

In this post we're not going to implement the block as it's described in blockchain or Bitcoin specifications, but rather a reduced version of it that contains just important information. This is how it appears:

type Block struct {
	Timestamp     int64
	Data          []byte
	PrevBlockHash []byte
	Hash          []byte
}

Timestamp is the current timestamp (when the block is created), Data is the actual valuable information containing in the block, PrevBlockHash stores the hash of the previous block, and Hash is the hash of the block. In Bitcoin specification Timestamp, PrevBlockHash, and Hash are block headers, which form a separate data structure, and transactions (Data in our case) is a separate data structure. So we're mixing them here for simplicity.

So, how do we compute hashes? The method by which hashes are calculated is a critical component of blockchain, and it is this property that makes blockchain secure. The problem is that computing a hash is a computationally demanding activity that takes time even on fast computers (which is why people buy powerful GPUs to mine Bitcoin). This is a purposeful architectural style that makes adding new blocks difficult, prohibiting them from being modified after they are added.

For now, we'll just take block fields, concatenate them, and calculate a SHA-256 hash on the concatenated combination. Let's do this in SetHash method:

func (b *Block) SetHash() {
	timestamp := []byte(strconv.FormatInt(b.Timestamp, 10))
	headers := bytes.Join([][]byte{b.PrevBlockHash, b.Data, timestamp}, []byte{})
	hash := sha256.Sum256(headers)

	b.Hash = hash[:]
}

Next, following a Golang convention, we'll implement a function that'll simplify the creation of a block:

func NewBlock(data string, prevBlockHash []byte) *Block {
	block := &Block{
		Timestamp:     time.Now().Unix(),
		Data:          []byte(data),
		PrevBlockHash: prevBlockHash,
		Hash:          []byte{},
	}
	block.SetHash()
	return block
}

And that's it for the block!

Blockchain

Now let's implement a blockchain. In its essence blockchain is just a database with certain structure: it's an ordered, back-linked list. Which means that blocks are stored in the insertion order and that each block is linked to the previous one. This structure allows to quickly get the latest block in a chain and to (efficiently) get a block by its hash.

In Golang this structure can be implemented by using an array and a map: the array would keep ordered hashes (arrays are ordered in Go), and the map would keep hash → block pairs (maps are unordered). But for our blockchain prototype we'll just use an array, because we don't need to get blocks by their hash for now.

type Blockchain struct {
	blocks []*Block
}

Now let's make it possible to add blocks to it:

func (bc *Blockchain) AddBlock(data string) {
	prevBlock := bc.blocks[len(bc.blocks)-1]
	newBlock := NewBlock(data, prevBlock.Hash)
	bc.blocks = append(bc.blocks, newBlock)
}

To add a new block we need an existing block, but there're not blocks in our blockchain! So, in any blockchain, there must be at least one block, and such block, the first in the chain, is called genesis block. Let's implement a method that creates such a block:

func NewGenesisBlock() *Block {
	return NewBlock("Genesis Block", []byte{})
}

Now, we can implement a function that creates a blockchain with the genesis block:

func NewBlockchain() *Blockchain {
	return &Blockchain{
		blocks: []*Block{NewGenesisBlock()},
	}
}

Let's check that the blockchain works correctly:

func main() {
	bc := NewBlockchain()

	bc.AddBlock("Send 1 BTC to Ivan")
	bc.AddBlock("Send 2 more BTC to Ivan")

	for _, block := range bc.blocks {
		fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
		fmt.Printf("Data: %s\n", block.Data)
		fmt.Printf("Hash: %x\n", block.Hash)
		fmt.Println()
	}
}

Output:

Prev. hash:
Data: Genesis Block
Hash: 087cc5e3492e75ea05cb01a2852982b8b6c6d672c6eda2d3b65958fa387f0a8c

Prev. hash: 087cc5e3492e75ea05cb01a2852982b8b6c6d672c6eda2d3b65958fa387f0a8c
Data: Send 1 BTC to Ivan
Hash: 55c566c351b5e391208adcf9ee99c4d734bd83359b2667058bc736379aa5dbd8

Prev. hash: 55c566c351b5e391208adcf9ee99c4d734bd83359b2667058bc736379aa5dbd8
Data: Send 2 more BTC to Ivan
Hash: a8e8ce10de294fd4dc18a7a533302eb4c8822168776ad6002b5d4b5d6de1bfa4

That's it!

Conclusion

We built a very simple blockchain prototype: it's just an array of blocks, with each block having a connection to the previous one. The actual blockchain is much more complex though. In our blockchain adding new blocks is easy and fast, but in real blockchain adding new blocks requires some work: one has to perform some heavy computations before getting a permission to add block (this mechanism is called Proof-of-Work). Also, blockchain is a distributed database that has no single decision maker. Thus, a new block must be confirmed and approved by other participants of the network (this mechanism is called consensus). And there're no transactions in our blockchain yet!

In future posts we'll cover each of these features.

References:

Full Source Code

An Introduction to Blockchain

Building Blockchain in Go