Content
Blockchain is one of the most revolutionary technologies of the 21st century, which has not yet realized its full potential. In essence, a blockchain is simply a distributed database. What makes it unique? This database is fully open and is stored for each participant in full or partial copy. A new record is created only with the consent of all those who keep the database. Because of this, there are such things as cryptocurrency and smart contracts.
In this series of lessons we will create, based on the blockchain, a simplified cryptocurrency. We use Go as the language.
Let's start with the "block" part of the "blockchain". 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 the hash of the previous block. In this article we will create a simplified block containing only essential information. We describe it in the form of a go structure.
type Block struct { Timestamp int64 Data []byte PrevBlockHash []byte Hash []byte }
Timestamp
is the block creation time, Data
is useful information contained in the block, PrevBlockHash
stores the hash of the previous block, and finally, Hash
contains the hash of the block. In the bitcoin Timestamp
specification, PrevBlockHash
and Hash
form a block header and form a separate structure from transactions (in our case, it is Data
). We mixed them for simplicity.
How is hashes calculated? Calculation of hashes is one of the important features of the blockchain, thanks to him it is considered safe. This is because the calculation of the hash is a rather complicated operation (this is why miners bought powerful video cards for bitcoin mining). This was conceived on purpose, preventing change from the whole chain.
We will discuss this in the next article, and now we will simply 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 }
Block ready!
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 the order of insertion, 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 maps (map): an array will contain an ordered list of hashes (arrays are ordered in Go), and maps will store hash -> block
pairs (maps are not ordered). But for our prototype, we will use only 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, we should have at least one block in any blockchain, which is called the genesis
block. We implement a method that creates such a block.
func NewGenesisBlock() *Block { return NewBlock("Genesis Block", []byte{}) }
And now let's implement the function that creates the blockchain with the genesis
block.
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!
We have just built a very simple blockchain prototype: a simple array of blocks, each of which is associated with the previous one. This 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 getting the right to add blocks (this mechanism is called Prof-of-Work). In addition, the blockchain is a distributed base that does not have a single decision-making center. Thus, the new block must be confirmed and approved by other members of the network (this mechanism is called ). Well, actually we do not yet have the transactions themselves.
All these properties will be covered in future articles.
Source: https://habr.com/ru/post/348672/
All Articles