Blockchain on Go. Part 1: Prototype

Original author: Ivan Kuznetsov
  • Transfer
  • Tutorial

Content


  1. Blockchain on Go. Part 1: Prototype
  2. Blockchain on Go. Part 2: Proof-of-Work
  3. Blockchain on Go. Part 3: read-only memory and command line interface
  4. Blockchain on Go. Part 4: Transactions, Part 1
  5. Blockchain on Go. Part 5: Addresses
  6. Blockchain on Go. Part 6: Transactions, Part 2
  7. Blockchain on Go. Part 7: Network

Blockchain is one of the most revolutionary technologies of the 21st century, which still has not realized its full potential. In essence, a blockchain is simply a distributed database. What makes it unique? This database is completely open and is stored at each participant with a full or partial copy. A new record is created only with the consent of all who store the database. Thanks to this, there are such things as cryptocurrency and smart contracts.


In this series of lessons, we will create a blockchain-based, simplified cryptocurrency. We use Go as the language.


Block


Let's start with the “block” of the “blockchain” part. In the blockchain, blocks store useful information. For example, in bitcoin blocks store transactions, the essence of any cryptocurrency. In addition to useful information, the block contains service information: version, creation date in the form of timestamp and hash of the previous block. In this article, we will create a simplified block containing only relevant information. We describe it as a go structure.


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

Timestampthis is the block creation time, Datathis useful information contained in the block PrevBlockHashstores the hash of the previous block, and finally Hashcontains the block hash. In the bitcoin specification Timestamp, PrevBlockHashthey Hashform a block header and form a Datastructure separate from transactions (in our case ). We mixed them for simplicity.


How are hashes calculated? The calculation of hashes is one of the important properties of the blockchain, thanks to it it is considered safe. That's because hash calculation is a rather complicated operation (that is why miners bought powerful video cards to mine bitcoin). This was specifically designed to prevent the entire chain from changing.


We will discuss this in the next article, but now we just connect all the fields of the block and cache the result in SHA-256:


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, create a “constructor” for our block


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

The block is ready!


Blockchain


Now let's write a blockchain. In essence, a blockchain is a database of a certain structure: an ordered linked list. This means that the blocks are stored in insertion order, with each block associated with the previous one. This structure allows you to get the last block in the chain and effectively get the block by its hash.


In Golang, this structure can be implemented using an array (array) and a map (map): the array will contain an ordered list of hashes (arrays are ordered in Go), and maps will store pairs hash -> block(maps are not ordered). But for our prototype, we will only use arrays because we do not need to get a block by its hash.


type Blockchain struct {
    blocks []*Block
}

This is our first blockchain! I never thought it was that easy :)


Add the ability 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 the first block, we need an existing one, but our blockchain is empty! Thus, in any blockchain, there must be at least one block called a genesisblock. We implement a method that creates such a block.


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

And now we implement the function creating a blockchain with a genesisblock.


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

Let's check that the blockchain is working 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()
    }
}

This code will output


Prev. hash:
Data: Genesis Block
Hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Prev. hash: aff955a50dc6cd2abfe81b8849eab15f99ed1dc333d38487024223b5fe0f1168
Data: Send 1 BTC to Ivan
Hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Prev. hash: d75ce22a840abb9b4e8fc3b60767c4ba3f46a0432d3ea15b71aef9fde6a314e1
Data: Send 2 more BTC to Ivan
Hash: 561237522bb7fcfbccbc6fe0e98bbbde7427ffe01c6fb223f7562288ca2295d1

Our prototype works!


Conclusion


We just built a very simple blockchain prototype: a simple array of blocks, each of which is associated with the previous one. The real blockchain is much more complicated. Our blockchain adds new blocks very easily and quickly, but in a real blockchain, adding new blocks requires some work: performing complex calculations before obtaining the right to add a block (this mechanism is called Prof-of-Work). In addition, blockchain is a distributed base that does not have a single decision center. Thus, the new block must be confirmed and approved by other network participants (this mechanism is called консенсусом). Well, actually, we don’t have the transactions themselves yet.


We will consider all these properties in future articles.


References


The source code for the article .


Also popular now: