挖矿机源代码

block.go

package core

import (
	"bytes"
	"encoding/gob"
	"log"
	"time"
)

/**
 * 区块结构体
 */
type Block struct {
	Timestamp int64
	PreBlockHash []byte
	Hash []byte
	Data []byte
	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 CreateNewBlock(preBlockHash []byte, data string) *Block{
	//初始化数组并赋值
	newBlock := &Block{time.Now().Unix(),preBlockHash,[]byte{},[]byte(data),0}
	//创建工作量证明
	pow := NewProofOfWork(newBlock)
	//运行工作量证明
	nonce, hash := pow.Run()
	newBlock.Hash = hash[:]
	newBlock.Nonce = nonce
	//newBlock.setHash()
	return newBlock
}

/**
 *构建创世区块函数,由于创世区块没有前驱,所以preblockhash传空
 */
func CreateGenesisBlcok() *Block{
	return CreateNewBlock([]byte{}, "This is the genesisblock!")
}

blockchain.go

package core

import (
	"fmt"
	"github.com/boltdb/bolt"
	"log"
)

const dbFile  = "blockchain.db"
const blockBucket  = "blcoks"
/**
 *区块链结构体,以文件存储的形式存放区块,理论上可以建立无数个区块
 */
type Blcokchain struct {
	tip []byte
	DB *bolt.DB
}
/**
 *添加区块函数
 */
func (bc *Blcokchain)AddBlock(data string){

}
/**
 * 创建区块链,并创建创世函数
 */
func CreateNewBlcokchain() *Blcokchain{
	var tip []byte
	db, err := bolt.Open(dbFile, 0600, nil)
	if err != nil {
		log.Panic(err)
	}

	err = db.Update(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(blockBucket))

		if b == nil {
			fmt.Println("No existing	blockchain found. Create a new one ...")
			genesis := CreateGenesisBlcok()

			b, err := tx.CreateBucket([]byte(blockBucket))
			if err != nil {
				log.Panic(err)
			}

			err = b.Put(genesis.Hash, genesis.Serialize())
			if err != nil {
				log.Panic(err)
			}

			err = b.Put([]byte("1"), genesis.Hash)
			if err != nil {
				log.Panic(err)
			}

			tip = genesis.Hash
		}else {
			tip = b.Get([]byte("1"))
		}
		return nil
	})

	if err != nil {
		log.Panic(err)
	}
	bc := Blcokchain{tip, db}
	return  &bc
}

  cli.go

package core

import (
	"flag"
	"fmt"
	"log"
	"os"
)

type CLI struct {
	Bc *Blcokchain
}

func (cli *CLI)showUsage() {
	fmt.Println("Usage:")
	fmt.Println("  addblock -data BLOCK_DATA     *add a blcok to blockchain")
	fmt.Println("  showchain                     *show all the blocks of the blcokchain")
}

func (cli *CLI)validateArgs() {
	if len(os.Args) < 2 {
		cli.showUsage()
		os.Exit(1)
	}
}

func (cli *CLI) addBlock(data string){
	cli.Bc.AddBlock(data)
	fmt.Println("Success!")
}

func (cli *CLI) showBlcokchain(){

}

func (cli *CLI)Run() {
	cli.validateArgs()

	addBlockCmd := flag.NewFlagSet("addBlcok", flag.ExitOnError)
	showBlockchainCmd := flag.NewFlagSet("showBlockchain", flag.ExitOnError)

	addBlockData := addBlockCmd.String("data", "", "Block data")

	switch os.Args[1] {
		case "addBlock":
			err := addBlockCmd.Parse(os.Args[2:])
			if err != nil {
				log.Panic(err)
			}
		case "showBlockchain":
			err := showBlockchainCmd.Parse(os.Args[2:])
			if err != nil {
				log.Panic(err)
			}
		default:
			cli.showUsage()
			os.Exit(1)
	}

	if addBlockCmd.Parsed() {
		if *addBlockData == "" {
			addBlockCmd.Usage()
			os.Exit(1)
		}
		cli.addBlock(*addBlockData)
	}

	if showBlockchainCmd.Parsed() {
		cli.showUsage()
	}

}

  proofofwork.go

package core

import (
	"bytes"
	"crypto/sha256"
	"fmt"
	"math"
	"math/big"
)

var (
	//定义工作量证明最大值为64位整数的最大值
	maxNonce = math.MaxInt64
)
//目标
const targetBits = 20
//定义工作量结构体
type ProofOfWork struct {
	//被计算的区块
	block *Block
	//目标,对区块计算要满足这个目标
	target *big.Int
}
/**
 * 创建工作量证明函数
 */
func NewProofOfWork(b *Block) *ProofOfWork {
	target := big.NewInt(1)
	//对整数target前面的比特位进行移位操作,因为target是1,移位后前面的字节变为0
	target.Lsh(target, uint(256 - targetBits))
	//创建工作量证明并返回
	pow := &ProofOfWork{b,target}
	return  pow
}
/**
 *运行工作量证明的过程
 */
func (pow *ProofOfWork)Run() (int, []byte) {
	var hashInt big.Int
	var hash [32]byte
	nonce := 0
	//提示,显示这个区块值
	fmt.Printf("Mining the block containing\"%s\"\n ", pow.block.Data)
	//通过循环反复计算
	for nonce < maxNonce {
		//获取拼装好的byte数组格式的数据块
		data := pow.prepareData(nonce)
		//对数据块进行加密返回byte字节数组
		hash = sha256.Sum256(data)
		//显示这个hash值
		fmt.Printf("\r%x", hash)
		//将hash转换为hash整数
		hashInt.SetBytes(hash[:])
		//使用这个hash整数与target进行对比
		if hashInt.Cmp(pow.target) == -1{
			break
		}else {
			nonce ++
		}
	}
	fmt.Printf("\n\n")
 	return nonce, hash[:]
}

//将各个数据拼凑大数据返回byte数组
func (pow *ProofOfWork)prepareData(nonce int) []byte{
	data := bytes.Join(
		[][]byte{
			pow.block.PreBlockHash,
			pow.block.Data,
			IntToHex(pow.block.Timestamp),
			IntToHex(int64(targetBits)),
			//nonce为可变值,所以循环中每轮的hash都不同
			IntToHex(int64(nonce)),
		},
		[]byte{},
		)
	return data
}

func (pow *ProofOfWork)Validate() bool{
	var hashInt big.Int
	data := pow.prepareData(pow.block.Nonce)
	hash := sha256.Sum256(data)
	hashInt.SetBytes(hash[:])

	isValidate := hashInt.Cmp(pow.target) == -1

	return isValidate
}

  utils.go

package core

import (
	"bytes"
	"encoding/binary"
	"log"
)

// 将一个 int64 转化为一个字节数组(byte array)
func IntToHex(num int64) []byte {
	buff := new(bytes.Buffer)
	err := binary.Write(buff, binary.BigEndian, num)
	if err != nil {
		log.Panic(err)
	}

	return buff.Bytes()
}

  

  

posted on 2018-10-09 10:14  微先锋  阅读(1921)  评论(0编辑  收藏  举报

导航