zoukankan      html  css  js  c++  java
  • 实现一个简易的区块链

    环境
    系统环境:Win10
    编程语言:Go 1.17
    知识点:

    • Go语言结构体定义及初始化
    • 序列化与反序列化
    • bolt.DB 数据库
    • 哈希算法
    • pow工作量证明创建区块
      功能:
      实现一个简单的区块链,采用作量证明(PoW)方式创建新的区块;数据序列化与反序列化;持久化存储(存入数据库中)
      PoW:就要定义一个挖矿难度,hash(data)<pow.target,并要验证该获得哈希是否有效
      序列化与反序列化:序列化是便于数据的传输与存储,反序列化是方便人去查看数据
      采用的技术是Go语言中encode包中gob("encode/gob")
      持久化存储:即存储至数据库中,数据库采用的是bolt

    数据的流程大致如下:

    具体实现
    区块结构体定义:

    type Block struct {
    	//时间戳,创建区块的时间
    	TimeStamp int64
    	//上个区块的hash
    	PrevBlockHash []byte
    	//Data 交易数据
    	Data []byte
    	// Hash 当前区块的hash
    	Hash []byte
    	// Nonce随机数
    	Nonce int
    }
    

    序列化与反序列化:

    func (b *Block) Serialize() []byte {
    	var result bytes.Buffer
    	encoder := gob.NewEncoder(&result)
    
    	err := encoder.Encode(b)
    	if err != nil {
    		log.Panic(err)
    	}
    	return result.Bytes()
    }
    
    func DeSerialBlock(d []byte) *Block {
    	var block Block
    
    	decoder := gob.NewDecoder(bytes.NewReader(d))
    	err := decoder.Decode(&block)
    	if err != nil {
    		log.Panic(err)
    	}
    	return &block
    }
    

    工作量证明POW:

    package BLC
    
    import (
    	"fmt"
    	"math/big"
    	"bytes"
    	"math"
    	"crypto/sha256"
    )
    
    var (
    	//define Nonce max
    	maxNonce = math.MaxInt64
    )
    
    const targetBits = 20
    
    type ProofOfWork struct{
    	block *Block 	//current block to validate
    	target *big.Int	//Big number storage, block difficulty
    }
    
    func (pow *ProofOfWork) prepareData(nonce int) []byte{
    	data := bytes.Join(
    		[][]byte{
    			pow.block.PrevBlockHash,
    			pow.block.Data,
    			IntToHex(pow.block.TimeStamp),
    			IntToHex(int64(targetBits)),
    			IntToHex(int64(nonce)),
    		},
    		[]byte{},
    	)
    
    	return data
    }
    
    // ProofOfWork object function
    func (pow *ProofOfWork) Run() (int, []byte){
    	
    	fmt.Printf("RUN....")
    
    	var hashInt big.Int
    	var hash [32]byte
    	nonce := 0
    	fmt.Printf("Mining the block containing \"%s\"\n",pow.block.Data)
    
    	for nonce < maxNonce{
    		data := pow.prepareData(nonce)
    		hash = sha256.Sum256(data)
    		fmt.Printf("\r%x",hash)
    		hashInt.SetBytes(hash[:])
    		if hashInt.Cmp(pow.target) == -1 {
    			break
    		}else{
    			nonce++
    		}
    	}
    	fmt.Printf("\n\n")
    
    	return nonce,hash[:]
    }
    
    func NewProofOfWork(block *Block) *ProofOfWork{
    	target := big.NewInt(1)
    	// fmt.Printf("--------------")
    	// fmt.Printf("%b\n", target)
    	//fmt.Printf("--------------")
    
    	target.Lsh(target,uint(256-targetBits))
    	//fmt.Printf("------target.Lsh------")
    	//fmt.Printf("%b\n", target)
    
    	pow := &ProofOfWork{block,target}
    
    	return pow
    }
    

    哈希验证:

    func (pow *ProofOfWork) Validate() bool{
    	var hashInt big.Int
    
    	data := pow.prepareData(pow.block.Nonce)
    	hash := sha256.Sum256(data)
    	hashInt.SetBytes(hash[:])
    
    	isValid := hashInt.Cmp(pow.target) == -1
    	return isValid
    }
    

    新增区块并存储至boltdb中:

    //新增区块
    func (blockChain *BlockChain) AddBlock(data string) {
    	//1、创建区块
    	newBlock := NewBlock(data, blockChain.Tip)
    	//2、update数据
    	err := blockChain.DB.Update(func(tx *bolt.Tx) error {
    		//获取数据表
    		b := tx.Bucket([]byte(blocksBucket))
    		if b != nil {
    			err := b.Put(newBlock.Hash, newBlock.Serialize())
    			if err != nil {
    				log.Panic(err)
    			}
    			//更新l对应的hash
    			err = b.Put([]byte("l"), newBlock.Hash)
    			if err != nil {
    				log.Panic(err)
    			}
    			//将最新的区块的hash存储到blockchain的Tip中
    			blockChain.Tip = newBlock.Hash
    			return nil
    		} else {
    			fmt.Println("AddBlock failed ....")
    			return nil
    		}
    	})
    	if err != nil {
    		log.Panic(err)
    	}
    }
    

    查询数据库中数据:通过迭代器访问

    //迭代器
    type BlockchainIterator struct {
    	CurrentHash []byte   // 当前正在遍历的区块的Hash
    	DB          *bolt.DB // 数据库
    }
    
    //迭代器
    func (blockchain *BlockChain) Iterator() *BlockchainIterator {
    	return &BlockchainIterator{blockchain.Tip, blockchain.DB}
    }
    
    //下一个迭代器
    func (bi *BlockchainIterator) Next() *BlockchainIterator {
    	var nextHash []byte
    	//查询数据
    	err := bi.DB.View(func(tx *bolt.Tx) error {
    		//获取表
    		b := tx.Bucket([]byte(blocksBucket))
    		//通过当前的hash获取Block
    		currentHashbytes := b.Get(bi.CurrentHash)
    		//反序列化
    		currentBlock := DeSerialBlock(currentHashbytes)
    		nextHash = currentBlock.PrevBlockHash
    		return nil
    	})
    	if err != nil {
    		log.Panic(err)
    	}
    	return &BlockchainIterator{nextHash, bi.DB}
    }
    

    在main.go中调用:

    var blockchainIterator *BLC.BlockchainIterator
    	blockchainIterator = blockchain.Iterator()
    
    	var hashInt big.Int
    
    	for {
    
    		fmt.Printf("%x\n", blockchainIterator.CurrentHash)
    
    		// 获取下一个迭代器
    		blockchainIterator = blockchainIterator.Next()
    
    		// 将迭代器中的hash存储到hashInt
    		hashInt.SetBytes(blockchainIterator.CurrentHash)
    
    		/*
    			// Cmp compares x and y and returns:
    			//
    			//   -1 if x <  y
    			//    0 if x == y
    			//   +1 if x >  y
    		*/
    		if hashInt.Cmp(big.NewInt(0)) == 0 {
    			break
    		}
    
    	}
    

    详细代码可参考:https://github.com/NGLHarry/Blockchainer/tree/main/part13-seriAndDeserialBlock_cli_queryDatabase

  • 相关阅读:
    Hoeffding Inequality 证明过程
    机器学习-1
    Java多线程安全问题的解决方式
    List<? extends T>和List<? super T>之间的区别
    关于禁用cookie后无法使用session的解决方案
    class.forName和classloader的区别
    在Js中使程序睡眠的sleep方法
    Java到底是值传递还是引用传递?
    Thymeleaf 绝对路径
    jdk1.8 Unsafe类 park和unpark方法解析
  • 原文地址:https://www.cnblogs.com/whiteBear/p/15554085.html
Copyright © 2011-2022 走看看