如何使用Go實現(xiàn)區(qū)塊鏈
本文轉(zhuǎn)載自微信公眾號「區(qū)塊鏈研究實驗室」,作者鏈三豐。轉(zhuǎn)載本文請聯(lián)系區(qū)塊鏈研究實驗室公眾號。
自互聯(lián)網(wǎng)以來,鎖鏈技術(shù)已被某些人稱為最有影響力的發(fā)明。盡管公眾將區(qū)塊鏈與投機性加密貨幣同義解釋,但區(qū)塊鏈實際上在現(xiàn)代世界中具有不可思議的廣泛應(yīng)用。實際上,加密貨幣只是區(qū)塊鏈領(lǐng)域的一小部分,生產(chǎn)中的許多解決方案都是由私人組織領(lǐng)導(dǎo)來實現(xiàn)的。
隨著區(qū)塊鏈技術(shù)的迅速發(fā)展,技術(shù)領(lǐng)域的專業(yè)人員越來越需要了解區(qū)塊鏈的基礎(chǔ)知識及其技術(shù)影響力。
畢竟,實現(xiàn)自己的區(qū)塊鏈實際上并不像聽起來那樣復(fù)雜。本文中,我們將使用2021年最流行的編程語言之一GoLang實現(xiàn)基本的區(qū)塊鏈。那么,讓我們開始吧!
了解區(qū)塊鏈
區(qū)塊鏈是名稱符合其含義的少數(shù)技術(shù)之一。我們可以將區(qū)塊鏈視為通過哈希相互連接的信息塊,哈希是從輸入數(shù)據(jù)生成的加密的固定輸出。由于每個塊都通過哈希相互引用,因此如果不大幅度更改鏈的其余部分,就不可能更改鏈的任何部分。
區(qū)塊鏈中的每個塊都可以包含幾乎任何內(nèi)容的數(shù)據(jù)。一個基本框架將包括每個塊的過去交易的所有記錄。比特幣以類似的方式工作,這就是為什么您可以一直跟蹤比特幣交易直至Satoshi首次進行加密貨幣交易的原因。
下面我們有三個區(qū)塊來創(chuàng)建區(qū)塊鏈。第一塊是創(chuàng)世塊。由于之前沒有任何內(nèi)容,因此前一個哈希字段為空。我們?nèi)匀皇褂脮r間戳記屬性和初始事務(wù)作為哈希算法的輸入。該算法將吐出一大串?dāng)?shù)字和字母,這些數(shù)字和字母代表了創(chuàng)世紀塊的哈希值。
轉(zhuǎn)到塊2,我們將創(chuàng)世塊的哈希值用作塊2先前哈希值。這個動作將創(chuàng)世塊與第2塊聯(lián)系起來!接下來,我們將時間戳,交易列表和先前的哈希值作為我們的哈希算法的輸入。該算法將為我們提供一個新的哈希值來表示塊2。
我們將繼續(xù)重復(fù)該過程任意多次,除了區(qū)塊的有效性以及存儲區(qū)塊鏈的能力(比特幣的區(qū)塊鏈約為330 GB)之外,沒有任何其他限制。
在Go中創(chuàng)建一個簡單的區(qū)塊鏈
創(chuàng)建我們的區(qū)塊鏈的第一步是定義什么是區(qū)塊。Go使我們的生活更輕松地創(chuàng)建自定義類型,我們可以Block使用以下代碼來定義類型。在這里,該Block結(jié)構(gòu)具有四個字段以匹配我們上面的圖。
- type Block struct {
- timestamp time.Time
- transactions []string
- prevHash []byte
- Hash []byte
- }
下一步是創(chuàng)建構(gòu)造函數(shù)的Go版本,以創(chuàng)建新的塊。該函數(shù)的輸入將使用一個字符串?dāng)?shù)組來表示事務(wù),以及一個字節(jié)數(shù)組來表示先前制作的塊所對應(yīng)的先前的哈希值。下一個要研究的NewHash()功能是我們下一步將實現(xiàn)的功能。
- func NewBlock(transactions []string, prevHash []byte) *Block {
- currentTime := time.Now()
- return &Block {
- timestamp: currentTime,
- transactions: transactions,
- prevHash: prevHash,
- Hash: NewHash(currentTime, transactions, prevHash),
- }
- }
該NewHash()函數(shù)將時間,事務(wù)列表和以前的哈希作為我們的輸入?yún)?shù),同時返回一個字節(jié)數(shù)組來表示新生成的哈希值。在此功能中,我們基本上只是將所有輸入都混入一個稱為的單個字節(jié)數(shù)組中input。我們這樣做是使用append()功能的附加time參數(shù),prevHash通過轉(zhuǎn)換time為string用...,以追加作為后綴time片的prevHash切片。
然后,我們遍歷transactions并將每個個體附加transaction到input數(shù)據(jù)blob。有趣的語法string(rune(transaction))...只是Go中將其中的每個元素轉(zhuǎn)換transactions為可以附加到的切片的一種方法input。它正在輸入垃圾內(nèi)容,因此,如果您真的想要,請深入研究。
- func NewHash(time time.Time, transactions []string, prevHash []byte) []byte {
- input := append(prevHash, time.String()...)
- for transaction := range transactions {
- input = append(input, string(rune(transaction))...)
- }
- hash := sha256.Sum256(input)
- return hash[:]
- }
最后,我們使用crypto包轉(zhuǎn)到電話sha256.Sum256()與input作為它的參數(shù)。這將為我們的所有數(shù)據(jù)輸入提供新的哈希表示。我們返回時hash[:]使用的[:]語法將hash在返回時切成適當(dāng)?shù)拈L度。
這實際上是我們開始鏈接我們的區(qū)塊鏈所需的全部。當(dāng)然,我們希望在程序中看到某種輸出,以便在打印時可以使用一些輔助方法:
- func printBlockInformation(block *Block) {
- fmt.Printf("\ttime: %s\n", block.timestamp.String())
- fmt.Printf("\tprevHash: %x\n", block.prevHash)
- fmt.Printf("\tHash: %x\n", block.Hash)
- printTransactions(block)
- }
- func printTransactions(block *Block) {
- fmt.Println("\tTransactions:")
- for i, transaction := range block.transactions {
- fmt.Printf("\t\t%v: %q\n", i, transaction)
- }
- }
現(xiàn)在剩下的就是創(chuàng)建新的事務(wù),塊和哈希。我們可以通過我們的主要方法來做到這一點。我們定義了一個字符串?dāng)?shù)組來記錄我們的區(qū)塊鏈中的交易。另請注意,我們?nèi)绾蝹鬟f一個空字節(jié)數(shù)組NewBlock()來生成名為的第一個塊genesisBlock。
- func main() {
- genesisTransactions := []string{"Izzy sent Will 50 bitcoin", "Will sent Izzy 30 bitcoin"}
- genesisBlock := NewBlock(genesisTransactions, []byte{})
- fmt.Println("--- First Block ---")
- printBlockInformation(genesisBlock)
- block2Transactions := []string{"John sent Izzy 30 bitcoin"}
- block2 := NewBlock(block2Transactions, genesisBlock.Hash)
- fmt.Println("--- Second Block ---")
- printBlockInformation(block2)
- block3Transactions := []string{"Will sent Izzy 45 bitcoin", "Izzy sent Will 10 bitcoin"}
- block3 := NewBlock(block3Transactions, block2.Hash)
- fmt.Println("--- Third Block ---")
- printBlockInformation(block3)
- }
為了創(chuàng)建新的區(qū)塊,我們將前一個區(qū)塊的哈希值NewBlock()與對應(yīng)的交易歷史記錄一起傳遞。如果您想在一個地方查看整個程序,則為:
- package main
- import (
- "crypto/sha256"
- "fmt"
- "time"
- )
- type Block struct {
- timestamp time.Time
- transactions []string
- prevHash []byte
- Hash []byte
- }
- func main() {
- genesisTransactions := []string{"Izzy sent Will 50 bitcoin", "Will sent Izzy 30 bitcoin"}
- genesisBlock := NewBlock(genesisTransactions, []byte{})
- fmt.Println("--- First Block ---")
- printBlockInformation(genesisBlock)
- block2Transactions := []string{"John sent Izzy 30 bitcoin"}
- block2 := NewBlock(block2Transactions, genesisBlock.Hash)
- fmt.Println("--- Second Block ---")
- printBlockInformation(block2)
- block3Transactions := []string{"Will sent Izzy 45 bitcoin", "Izzy sent Will 10 bitcoin"}
- block3 := NewBlock(block3Transactions, block2.Hash)
- fmt.Println("--- Third Block ---")
- printBlockInformation(block3)
- }
- func NewBlock(transactions []string, prevHash []byte) *Block {
- currentTime := time.Now()
- return &Block {
- timestamp: currentTime,
- transactions: transactions,
- prevHash: prevHash,
- Hash: NewHash(currentTime, transactions, prevHash),
- }
- }
- func NewHash(time time.Time, transactions []string, prevHash []byte) []byte {
- input := append(prevHash, time.String()...)
- for transaction := range transactions {
- input = append(input, string(rune(transaction))...)
- }
- hash := sha256.Sum256(input)
- return hash[:]
- }
- func printBlockInformation(block *Block) {
- fmt.Printf("\ttime: %s\n", block.timestamp.String())
- fmt.Printf("\tprevHash: %x\n", block.prevHash)
- fmt.Printf("\tHash: %x\n", block.Hash)
- printTransactions(block)
- }
- func printTransactions(block *Block) {
- fmt.Println("\tTransactions:")
- for i, transaction := range block.transactions {
- fmt.Printf("\t\t%v: %q\n", i, transaction)
- }
- }
如果要運行此程序,將得到以下輸出:
- $ go run example.go
- --- First Block ---
- time: 2021-04-05 15:12:18.813294 -0600 MDT m=+0.000074939
- prevHash:
- Hash: 43ec51c50d2b9565f221155a29d8b72307247b08eaf6731cca
- Transactions:
- 0: "Izzy sent Will 50 bitcoin"
- 1: "Will sent Izzy 30 bitcoin"
- --- Second Block ---
- time: 2021-04-05 15:12:18.813477 -0600 MDT m=+0.000257244
- prevHash: 43ec51c50d2b9565f221155a29d8b72307247b08eaf6731cca
- Hash: fcce5323a35cb67b45fe75866582db00fd32baeb92aac448c7
- Transactions:
- 0: "John sent Izzy 30 bitcoin"
- --- Third Block ---
- time: 2021-04-05 15:12:18.813488 -0600 MDT m=+0.000269168
- prevHash: fcce5323a35cb67b45fe75866582db00fd32baeb92aac448c7
- Hash: fc1d3eee286970d85812b47c3a5bf016ae8c1de4f86b8ace972ffa
- Transactions:
- 0: "Will sent Izzy 45 bitcoin"
- 1: "Izzy sent Will 10 bitcoin"
過程可能會很粗糙,但這是創(chuàng)建自己的區(qū)塊鏈的基礎(chǔ)!