挖矿机源代码
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
}
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()
}
浙公网安备 33010602011771号