#区块的定义和操作
#链的定义和操作
#工作量证明
//main.go
package main
import "fmt"
func main(){
fmt.Println("=======================")
bc := NewBlockChain()
t1 := Transactions{[]byte("111"),[]byte("a send b 1 BTC")}
t2 := Transactions{[]byte("222"),[]byte("b send c 1 BTC")}
bc.AddBlock(&t1)
bc.AddBlock(&t2)
fmt.Println()
bc.Print()
}
//chain.go
package main
import "fmt"
type BlockChain struct{
blocks []*Block
}
func NewBlockChain() *BlockChain{
block := NewGenesisBlock()
chain := BlockChain{
blocks:[]*Block{block},
}
return &chain
}
func (chain *BlockChain) AddBlock(body *Transactions){
prevBlockHash := chain.blocks[len(chain.blocks)-1].Hash
block := NewBlock(string(body.Coinbase),string(body.Data),prevBlockHash)
chain.blocks = append(chain.blocks,block)
}
func (chain *BlockChain) Print(){
for _,data := range chain.blocks{
fmt.Printf("Version %d\n",data.Version)
fmt.Printf("PrevBlockHash %x\n",string(data.PrevBlockHash))
fmt.Printf("MerKelRoot %x\n",string(data.MerKelRoot))
fmt.Printf("TimeStamp %d\n",data.TimeStamp)
fmt.Printf("Bits %d\n",data.Bits)
fmt.Printf("Nonce %d\n",data.Nonce)
fmt.Printf("Hash %x\n",string(data.Hash))
fmt.Printf("Coinbase %s\n",string(data.Coinbase))
fmt.Printf("Data %s\n",string(data.Data))
fmt.Printf("IsValid %v\n",NewProofWork(data).IsValid())
fmt.Println("\r\n")
}
}
//block.go
package main
import "time"
//定义区块头结构体
type BlockHeader struct{
//版本
//区块版本号,表示本区块遵守的验证规则
Version int64
//前一区块的哈希值
//SHA256
PrevBlockHash []byte
//梅克尔根
//该区块中交易的梅克尔树根的哈希值 SHA256
MerKelRoot []byte
//时间戳
//区块生成时间
TimeStamp int64
//难度值
//该区块工作量证明的难度目标
Bits int64
//随机值
//挖矿找到的满足难度目标的随机值
Nonce int64
//*当前区块哈希值
//实际上,区块不存储哈希值,节点接收区块后独立计算并存储在本地
Hash []byte
}
//定义区块体结构体
type Transactions struct{
//第一条交易 矿工挖矿奖励
Coinbase []byte
//普通交易信息
//每笔交易包括(付款方、收款方、金额、手续费等)
Data []byte
}
//定义区块结构体
type Block struct{
BlockHeader
Transactions
}
//创建区块
func NewBlock(coinbase,data string,prevBlockHash []byte) *Block{
var block Block
block.Version = 1
block.PrevBlockHash = prevBlockHash
block.MerKelRoot = []byte{}
block.TimeStamp = time.Now().Unix()
block.Bits = TargetBits
block.Coinbase = []byte(coinbase)
block.Data = []byte(data)
pow := NewProofWork(&block)
nonce,hash := pow.Run()
block.Nonce = nonce
block.Hash = hash
return &block
}
//创建创世块
func NewGenesisBlock() *Block{
return NewBlock("Genesis Block","",[]byte{})
}
//pow.go
package main
import (
"bytes"
"crypto/sha256"
"fmt"
"math"
"math/big"
"time"
)
const TargetBits = 24
//定义工作量证明结构
type ProofOfWork struct{
block *Block
//目标值
target *big.Int
}
//创建POW(PROOF OF WORK)的函数
func NewProofWork(block *Block) *ProofOfWork{
//0x000000000000...01
target := big.NewInt(1)
//0x000000100000...00
target.Lsh(target,256-uint(block.Bits))
return &ProofOfWork{block,target}
}
//寻找随机数 计算哈希
func (pow *ProofOfWork)Run()(int64,[]byte){
fmt.Println("开始挖矿...")
fmt.Printf("target < hash: [ %x]\n",pow.target.Bytes())
var nonce int64 = 0
var hash [32]byte
var hashInt big.Int
for nonce < math.MaxInt64{
data := pow.prepare(nonce)
hash = sha256.Sum256(data)
hashInt.SetBytes(hash[:])
if hashInt.Cmp(pow.target) == -1{
fmt.Printf("found nonce // [%x] %d\n",hash,nonce)
break
}else{
nonce++
}
}
//返回找到的随机数nonce和算出的哈希
return nonce,hash[:]
}
//校验计算结果
func (pow *ProofOfWork)IsValid() bool{
data := pow.prepare(pow.block.Nonce)
hash := sha256.Sum256(data)
var hashInt big.Int
hashInt.SetBytes(hash[:])
if hashInt.Cmp(pow.target) == -1{
fmt.Printf("%x",hash[:])
return true
}else{
return false
}
}
func (pow *ProofOfWork)prepare(nonce int64) []byte{
pow.block.TimeStamp = time.Now().Unix()
block := pow.block
tmp := [][]byte{
Int2Bytes(block.Version),
block.PrevBlockHash,
block.MerKelRoot,
Int2Bytes(block.TimeStamp),
Int2Bytes(TargetBits),
Int2Bytes(nonce),
block.Coinbase,
block.Data,
}
data := bytes.Join(tmp,[]byte{})
return data
}
//utils.go
package main
import (
"bytes"
"encoding/binary"
)
func Int2Bytes(i int64) []byte{
var buf bytes.Buffer
err := binary.Write(&buf,binary.BigEndian,i)
if err != nil{
panic(-1)
}
return buf.Bytes()
}