100行代码实现一个区块链!

废话不多说,开始跟我用golang搭建个迷你区块链:

首先,引入包:

package main

import (
  "bytes"
  "crypto/sha256"
  "encoding/binary"
  "fmt"
  "math"
  "math/big"
  "time"
)

设置一些常量,工作量证明难度系数dif,搜索上界INT64_MAX:

const (
  dif       = 20
  INT64_MAX = math.MaxInt64
)

然后我们设计一个简单的区块体和区块链体,每个区块呢有前个区块哈希,本区块哈希,数据,链长,时间戳和随机数:

type Block struct {
  PrevHash  []byte
  Hash      []byte
  Data      string
  Height    int64
  Timestamp int64
  Nonce     int
}

type BlockChain struct {
  Blocks []Block
}

实现一段工作量证明函数,这个工作量证明呢以后聊共识算法会细讲的,也就是这里实现了不可篡改(reigns最近被raft血虐的,TAT):

func IntToHex(num int64) []byte {
  buff := new(bytes.Buffer)
  err := binary.Write(buff, binary.BigEndian, num)
  if err != nil {
    panic(err)
  }
  return buff.Bytes()
}

func ProofOfWork(b Block, dif int) ([]byte, int) {
  target := big.NewInt(1)
  target.Lsh(target, uint(256-dif))
  nonce := 0
  for ; nonce < INT64_MAX; nonce++ {
    check := bytes.Join(
      [][]byte{b.PrevHash,
        []byte(b.Data),
        IntToHex(b.Height),
        IntToHex(b.Timestamp),
        IntToHex(int64(nonce))},
      []byte{})
    hash := sha256.Sum256(check)
    var hashInt big.Int
    hashInt.SetBytes(hash[:])
    if hashInt.Cmp(target) == -1 {
      return hash[:], nonce
    }
  }
  return []byte(""), nonce
}

然后呢这段函数实现生成创世块,也就是链头啦:

func GenesisBlock(data string) BlockChain {
  var bc BlockChain
  bc.Blocks = make([]Block, 1)
  bc.Blocks[0] = Block{
    PrevHash:  []byte(""),
    Data:      data,
    Height:    1,
    Timestamp: time.Now().Unix(),
  }
  bc.Blocks[0].Hash, bc.Blocks[0].Nonce = ProofOfWork(bc.Blocks[0], dif)
  return bc
}

这段呢是生成新的区块,也就是俗称的挖矿,当然了真实的挖矿可比这个复杂多了:

func GenerateBlock(bc *BlockChain, data string) {
  prevBlock := bc.Blocks[len(bc.Blocks)-1]
  block := Block{
    PrevHash:  prevBlock.Hash,
    Data:      data,
    Height:    prevBlock.Height + 1,
    Timestamp: time.Now().Unix(),
  }
  block.Hash, block.Nonce = ProofOfWork(block, dif)
  bc.Blocks = append(bc.Blocks, block)
}

再写个打印区块函数:

func Print(bc BlockChain) {
  for _, i := range bc.Blocks {
    fmt.Printf("PrevHash: %x\n", i.PrevHash)
    fmt.Printf("Hash: %x\n", i.Hash)
    fmt.Println("Block's Data: ", i.Data)
    fmt.Println("Current Height: ", i.Height)
    fmt.Println("Timestamp: ", i.Timestamp)
    fmt.Println("Nonce: ", i.Nonce)
  }
}

好啦,各个函数都写完了,不多不少99行

100行代码实现一个区块链!_第1张图片

写个main函数看看吧~

来,reigns开始挖矿,先挖个创世块,给alice转账2刀,然后再给alice转3刀,看看这几次次操作怎么记录在区块链中吧:

func main() {
  blockchain := GenesisBlock("i am reigns")
  GenerateBlock(&blockchain, "send 2$ to alice")
  GenerateBlock(&blockchain, "send 3$ to alice")
  Print(blockchain)
}

输出结果:

100行代码实现一个区块链!_第2张图片

由于创世块没有前面的区块,所以他的PrevHash就是空,记录给alice转账2刀的这个区块,它的PrevHash就是创世块了,后面的以此类推,得到一个不可篡改链。

也可以发现啊,区块生成并不是一下子执行完成的,三个区块用了接近7秒钟,这就是工作量证明算法起的作用了,防止恶意节点不劳而获,每个新的区块都需要付出一定计算力才能得到,当然这里没有设置很高的困难度(dif = 20),也没有根据时间动态增加难度,比特币网络中一般设置的挖矿难度都需要10分钟左右的,想想2009年的10分钟和2019的10分钟,难度提了多少~

怎么样,是不是了解了区块链的基本结构呢,当然了成熟的链使用的数据存储结构肯定不会是一个字符串,比如比特币用的是默克尔树,交易也不会这么随便就成功,都需要依靠一个叫做智能合约的东东进行约束的。

好啦,今天就讲这么多。

如果对区块链感兴趣,可以关注下面这个公众号哦,推送的全是区块链干货~

100行代码实现一个区块链!_第3张图片

你可能感兴趣的:(区块链)