共識演算法-PoW

super_lixiang發表於2018-09-17
  • Proof-of-Work 簡稱 PoW,即為工作量證明
  • 通過計算一個數值,使得拼揍上交易資料後內容的值滿足規定的上限,在節點成功 找到滿足的 Hash 值之後,會馬上對全網進行廣播打包區塊,網路的節點收到廣播 打包區塊,會立刻對其進行驗證
  • 網路中只有最快解密的區塊,才會新增的賬本中,其他的節點進行復制,這樣就保 證了整個賬本的唯一性
  • 假如節點有任何的作弊行為,都會導致網路的節點驗證不通過,直接丟棄其打包的 區塊,這個區塊就無法記錄到總賬本中,作弊的節點耗費的成本就白費了,因此在 巨大的挖礦成本下,也使得礦工自覺自願的遵守比特幣系統的共識協議,也就確保 了整個系統的安全 

安裝依賴

  • go get github.com/davecgh/go-spew/spew

在cmd或控制檯格式化輸出相應的結果

  • go get github.com/gorilla/mux

編寫web處理程式的軟體包

  • go get github.com/joho/godotenv

可以從專案根目錄讀取 .env結束的檔案,讀取檔案中的資料,如果在linux開發,.env檔案放在專案的根目錄下即可,如果windows和mac開發,.env是放在GOPATH/src下

PoW總結

  • 優點
  1. 挖礦機制本身比較複雜,難度的自動調整,區塊獎勵逐步減半,這些是基於經濟學原理,能吸引和鼓勵更多人蔘與其中
  2. 越先參與的獲得越多,會促使加密貨幣初始階段迅速發展,網路節點迅速擴大,比特幣吸引了N多人蔘與挖礦
  3. 通過挖礦,發行新幣,把比特幣分散給了個人,實現了相對的公平
  • 缺點
  1. 算力是計算機硬體提供的,直接耗費電力,對能源的直接消耗
  2. 隨著發展,算力已經不是單純CPU能搞定的了,GPU,FPGA,以及ASIC礦機,這些可能不是個人能輕鬆實現的,導致算力中心化,長遠來看,與去中心和背道而馳,網路的安全受到威脅
  3. 比特幣區塊獎勵每4年減半,挖礦成本越來越高,當挖礦成本高於挖礦收益時,挖礦的積極性降低,整體網路不穩定

程式碼

@定義區塊

第一步:定義區塊

type Block struct {
	//上一個區塊的雜湊
	PreHash string
	//當前區塊的雜湊
	HashCode string
	//時間戳
	TimeStamp string
	//難度係數
	Diff int
	//交易資訊
	Data string
	//區塊高度
	Index int
	//隨機值
	Nonce int
}

第二步:定義第一個區塊(創世區塊)

//第一個區塊:創世區塊
func GenerateFirstBlock(data string) Block {
	//建立第一個Block
	var firstblock Block
	firstblock.PreHash = "0"
	firstblock.TimeStamp = time.Now().String()
	//暫設為4
	firstblock.Diff = 4
	//交易資訊
	firstblock.Data = data
	firstblock.Index = 1
	firstblock.Nonce = 0
	//通過sha256得到自己的雜湊
	firstblock.HashCode = GenerationHashValue(firstblock)
	return firstblock
}

//生成區塊的雜湊值
func GenerationHashValue(block Block) string {
	//按照比特幣的寫法,將區塊的所有屬性拼接後做雜湊運算
	//int轉為字串
	var hashdata = strconv.Itoa(block.Index) + strconv.Itoa(block.Nonce) +
		strconv.Itoa(block.Diff) + block.TimeStamp
	//算雜湊
	var sha = sha256.New()
	sha.Write([]byte(hashdata))
	hashed := sha.Sum(nil)
	return hex.EncodeToString(hashed)
}

第三步:定義PoW演算法

//pow演算法
func pow(diff int, block *Block) string {
	//實現不停地去挖礦
	for {
		//認為是挖了一次礦了
		hash := GenerationHashValue(*block)
		//挖礦過程的雜湊列印
		fmt.Println(hash)
		//判斷雜湊值前導0是否為diff個0
		//strings.Repeat:判斷hash是否有diff個0,寫1,就判斷為有多少個1
		if strings.HasPrefix(hash, strings.Repeat("0", diff)) {
			//挖礦成功
			fmt.Println("挖礦成功")
			return hash
		} else {
			//沒挖到
			//隨機值自增
			block.Nonce++
		}
	}
}

第四步:建立新的區塊

//產生新的區塊
func GenerateNextBlock(data string, oldBolock Block) Block {
	//產生一個新的區塊
	var newBlock Block
	newBlock.TimeStamp = time.Now().String()
	//難度係數
	newBlock.Diff = 5
	//高度
	newBlock.Index = 2
	newBlock.Data = data
	newBlock.PreHash = oldBolock.HashCode
	newBlock.Nonce = 0

	//建立pow()演算法的方法
	//計算前導0為4個的雜湊值
	newBlock.HashCode = pow(newBlock.Diff, &newBlock)
	return newBlock
}

第五步:主函式

func main() {
	//測試建立創世區塊
	var firstBlock = GenerateFirstBlock("創世區塊")
	fmt.Println(firstBlock)
	fmt.Println(firstBlock.Data)

	//需要生成下一個區塊
	GenerateNextBlock("第二區塊", firstBlock)
}

@定義區塊鏈,用連結串列實現區塊鏈的鏈

第一步:定義區塊鏈

//定義區塊鏈
type Node struct {
	//指標域
	NextNode *Node
	//資料域
	Data *Block.Block
}

第二步:建立頭節點

//建立頭節點,儲存創世區塊
func CreateHeaderNode(data *Block.Block) *Node {
	//先去初始化
	var headerNode = new(Node)
	//指標域指向nil
	headerNode.NextNode = nil
	//資料域
	headerNode.Data = data
	//返回頭節點,後面再新增
	return headerNode
}

第三步:新增區塊,新增節點

func AddNode(data *Block.Block, node *Node) *Node {
	//建立新節點
	var newNode = new(Node)
	//指標域指向nil
	newNode.NextNode = nil
	newNode.Data = data
	//連結串列連起來
	node.NextNode = newNode
	return newNode
}

第四步:檢視連結串列中的資料

func ShowNodes(node *Node) {
	//接收node
	n := node
	for {
		//如果下個節點為nil
		if n.NextNode == nil {
			fmt.Println(n.Data)
			break
		} else {
			fmt.Println(n.Data)
			n = n.NextNode
		}
	}
}

第五步:定義主函式

func main() {
	var first = Block.GenerateFirstBlock("創世區塊")
	var second = Block.GenerateNextBlock("第二區塊", first)

	//建立連結串列
	//頭節點儲存創世區塊
	var header = Blockchain.CreateHeaderNode(&first)
	//將第二區塊加入連結串列
	Blockchain.AddNode(&second, header)
	//檢視連結串列資訊
	Blockchain.ShowNodes(header)
}

 

 

相關文章