如何從0構(gòu)建區(qū)塊鏈之一
本文轉(zhuǎn)載自微信公眾號「區(qū)塊鏈研究實驗室」,作者鏈三豐。轉(zhuǎn)載本文請聯(lián)系區(qū)塊鏈研究實驗室公眾號。
什么是區(qū)塊鏈?建造一個難嗎?從哪里開始?使用哪種編程語言?
相信我,在遇到對區(qū)塊鏈技術(shù)感興趣的人時,我經(jīng)常會遇到這些問題,您也可能遇到其中的一些問題。
在線上有大量的區(qū)塊鏈資源,但是將它們理解為這項蓬勃發(fā)展的技術(shù)的新手,這讓人感到不知所措。
在這篇文章中,我將step by step給你展示,你就會明白blockchain以及如何的基本概念,采用方案一的Python,Javascript,或Golang 。
我選擇這些語言是因為大多數(shù)人都熟悉它們,尤其是Javascript和Python。但是出于速度,耐用性和安全性的考慮,大多數(shù)區(qū)塊鏈核心引擎都是內(nèi)置的c / c ++(比特幣,EOS),Go(超級賬本結(jié)構(gòu),以太坊),Java(以太坊),Rust,Haskell和/或Ruby(以太坊)然后提供與其他易于使用的編程語言。
此外,一些區(qū)塊鏈引擎結(jié)合了多種編程語言,以實現(xiàn)健壯性并易于開發(fā)人員使用,以太坊是最佳用例。
先決條件:
- 網(wǎng)絡(luò)
- 密碼學
- 數(shù)據(jù)結(jié)構(gòu)與算法
- 分布式系統(tǒng)
- Javascript / Go / Python
您只需要基本概念即可對拳頭區(qū)塊鏈原型進行編程。
什么是區(qū)塊鏈?
讓我們先了解一下,區(qū)塊鏈不是比特幣,區(qū)塊鏈不是數(shù)字貨幣, 區(qū)塊鏈是一套已經(jīng)存在的不同技術(shù)。
讓我們通過舉一個例子來簡化事情,因為工程師對數(shù)字的理解會更好。讓我們來看一個存儲一些信息的MySQL數(shù)據(jù)庫。
使用上述數(shù)據(jù)庫,我們可以:
- 做一些CRUD(創(chuàng)建,檢索,更新和刪除)操作,
- 將相同的信息存儲兩次,
- 刪除整個數(shù)據(jù)庫,
- 我們不能與他人共享敏感信息,
- 數(shù)據(jù)庫可以集中化(單點故障,安全問題),
- 無法信任存儲在其中的所有內(nèi)容。
- 一些數(shù)據(jù)庫可以允許表之間的關(guān)系(例如RDBMS),而另一些數(shù)據(jù)庫則不能容忍這種關(guān)系(例如NoSQL數(shù)據(jù)庫),
- 惡意的人可能會炸毀數(shù)據(jù)庫
- 需要一名數(shù)據(jù)庫管理員(他/她可以更改或泄露信息)
- 用戶無法控制自己的數(shù)據(jù)
- 等等…
那么,為什么我們需要不同的東西,可靠的東西,獨立于人的東西,自動的東西,不可變的東西呢?那就是區(qū)塊鏈開始的地方。
區(qū)塊鏈是一個安全,可信的去中心化數(shù)據(jù)庫和網(wǎng)絡(luò)。
“Truth can only be found in one place: the code. ”
區(qū)塊鏈是一連串的區(qū)塊,區(qū)塊類似于數(shù)據(jù)庫中的表,但是它們不能被刪除或更新,區(qū)塊包含稱為交易的信息和其他附加數(shù)據(jù)。這些區(qū)塊經(jīng)過密碼驗證并鏈接形成一個不變的區(qū)塊鏈,稱為區(qū)塊鏈或分類賬。
然后,同一條鏈通過P2P網(wǎng)絡(luò)分布到整個網(wǎng)絡(luò)中的所有節(jié)點。
因此,代替集中式數(shù)據(jù)庫,跨節(jié)點共享的所有事務(wù)(數(shù)據(jù))都包含在塊中,這些塊鏈接在一起以創(chuàng)建分類帳。該分類賬代表區(qū)塊鏈中的所有數(shù)據(jù)。分類賬中的所有數(shù)據(jù)均通過加密哈希和數(shù)字簽名進行保護,并通過共識算法進行驗證。網(wǎng)絡(luò)上的節(jié)點參與以確保跨網(wǎng)絡(luò)分布的所有數(shù)據(jù)副本都是相同的。
在區(qū)塊鏈生態(tài)系統(tǒng)中要記住的5個關(guān)鍵概念:
- 加密哈希和數(shù)字簽名
- 不變的分類帳
- P2P網(wǎng)絡(luò)
- 共識算法(PoW,PoS,PBFT,ETc…)
- 塊驗證(采礦,鍛造等)
我們將繼續(xù)詳細解釋這些概念。
使用區(qū)塊鏈的好處:
- 刪除中介組織
- 不變的分類帳
- 透明度
- 安全
何時使用區(qū)塊鏈?
區(qū)塊鏈不是靈丹妙藥,因此在以下情況下使用它:
- 存儲的數(shù)據(jù)無需修改(存在證明)
- 數(shù)據(jù)不能被其所有者拒絕(不可否認)
- 你想權(quán)力下放
- 你想要一個真理的源頭
- 您想要高安全性
- 您不必擔心速度(例如,比特幣平均需要10分鐘才能驗證一筆交易)。
但是某些區(qū)塊鏈速度更快,因為它們使用除PoW之外的不同共識算法
我們稍后再討論。
區(qū)塊鏈用例
區(qū)塊鏈應(yīng)用領(lǐng)域
- 房地產(chǎn):土地所有權(quán)
- 醫(yī)療保?。喊踩涗浕颊叩臄?shù)據(jù)
- 財務(wù):減少稅收和中介機構(gòu),反洗錢,跨境支付
- 供應(yīng)鏈:跟蹤從供應(yīng)商到客戶的商品(真實性,原創(chuàng)內(nèi)容的創(chuàng)建)
- 網(wǎng)絡(luò)安全:DDOS攻擊
- 將權(quán)力交還給用戶:擁有數(shù)據(jù)并與所需的人安全地共享(DID)
- 加密貨幣兌換
- 投票機制
區(qū)塊鏈平臺和應(yīng)用
- 比特幣
- 以太坊
- 織物
- EOS
- 鏈環(huán)
- 卡爾達諾
- 等等…
區(qū)塊鏈類型
- 私有:僅在內(nèi)部使用,并且在我們更了解用戶的情況下使用(例如Hyperledger Fabric)
- 公開:每個人都可以看到正在發(fā)生的事情(比特幣,以太坊)
- 混合:合并前兩個。
“Talk is cheap. Show me the code.”
有兩種方法可以構(gòu)建區(qū)塊鏈:
- 一種簡單的方法是使用現(xiàn)有的預(yù)先構(gòu)建的區(qū)塊鏈開源資源,例如以太坊,F(xiàn)abric,EOS等…
- 如果它們都不符合您的要求,那么請從頭開始構(gòu)建
在本系列中,我們將從頭開始構(gòu)建一個,以便您可以徹底了解區(qū)塊鏈的狀態(tài)機。
如何建立區(qū)塊鏈?
好的,現(xiàn)在讓我們用三種不同的編程語言Go,Python和Javascript創(chuàng)建第一個小區(qū)塊鏈demo。這些原型可以幫助您理解我們前面介紹的概念。
首先,我們將創(chuàng)建一個塊,第二,我們將添加數(shù)據(jù)(標題和正文)給它,第三,我們將散列塊,和最后但并非最不重要,我們將鏈中的所有塊了。
一個塊包含前面提到的信息,但是為了簡化起見,我們將刪除一些信息。讓我們深入研究細節(jié)!
希望您像我之前提到的那樣熟悉Go編程,如果不嘗試學習基礎(chǔ)知識:函數(shù),方法,數(shù)據(jù)類型,結(jié)構(gòu),流控制,迭代等…
創(chuàng)建一個文件夾并向其中添加2個文件, main.go and block.go
資料夾結(jié)構(gòu):
- go // the folder
- main.go // file 1
- block.go // file 2
main.go
- // use the main package
- package main
- //import the fmt package
- import (
- "fmt"
- )
- func main(){
- fmt.Println("I am building my first blockchain") // print this
- CreateBlock("The hearder will be shown here", "the body will be shown here") // call the function that will create the block and pass some parameters in it.
- }
如果您運行此程序,則由于該CreateBlock函數(shù)尚未定義,因此將顯示錯誤消息,因此請繼續(xù)在其中創(chuàng)建它block.go:
block.go
- package main
- import (
- "fmt" // this will help us to print on the screen
- )
- func CreateBlock(Header, Body string){
- fmt.Println(Header ,"\n", Body) // Show me the block content
- }
Go的優(yōu)點在于您不必導(dǎo)入或?qū)С龊瘮?shù),只需使用大寫字母聲明它們,Go就會為您找到它們。現(xiàn)在打開終端并移至您創(chuàng)建的文件夾,run go build然后.\go在Windows,./goLinux和Macbook上運行。
我們剛剛創(chuàng)建了一個簡單的Go程序,該程序調(diào)用一個函數(shù)并傳遞一些字符串數(shù)據(jù)。讓我們繼續(xù)做更多美好的事情。讓我們添加2個文件,blockchain.go而structures.go現(xiàn)在我們有4個文件:main.go, block.go, structures.go, and blockchain.go
我將在代碼的每一行中添加一些注釋,以使您了解我在做什么。
structures.go
- package main //Import the main package
- // Create the Block data structure
- // A block contains this info:
- type Block struct {
- Timestamp int64 // the time when the block was created
- PreviousBlockHash []byte // the hash of the previous block
- MyBlockHash []byte // the hash of the current block
- AllData []byte // the data or transactions (body info)
- }
- // Prepare the Blockchain data structure :
- type Blockchain struct {
- Blocks []*Block // remember a blockchain is a series of blocks
- }
block.go
- package main
- import (
- // We will need these libraries:
- "bytes" // need to convert data into byte in order to be sent on the network, computer understands better the byte(8bits)language
- "crypto/sha256" //crypto library to hash the data
- "strconv" // for conversion
- "time" // the time for our timestamp
- )
- // Now let's create a method for generating a hash of the block
- // We will just concatenate all the data and hash it to obtain the block hash
- func (block *Block) SetHash() {
- timestamp := []byte(strconv.FormatInt(block.Timestamp, 10)) // get the time and convert it into a unique series of digits
- headers := bytes.Join([][]byte{timestamp, block.PreviousBlockHash, block.AllData}, []byte{}) // concatenate all the block data
- hash := sha256.Sum256(headers) // hash the whole thing
- block.MyBlockHash = hash[:] // now set the hash of the block
- }
- // Create a function for new block generation and return that block
- func NewBlock(data string, prevBlockHash []byte) *Block {
- block := &Block{time.Now().Unix(), prevBlockHash, []byte{}, []byte(data)} // the block is received
- block.SetHash() // the block is hashed
- return block // the block is returned with all the information in it
- }
- /* let's now create the genesis block function that will return the first block. The genesis block is the first block on the chain */
- func NewGenesisBlock() *Block {
- return NewBlock("Genesis Block", []byte{}) // the genesis block is made with some data in it
- }
blockchain.go
- package main
- // create the method that adds a new block to a blockchain
- func (blockchain *Blockchain) AddBlock(data string) {
- PreviousBlock := blockchain.Blocks[len(blockchain.Blocks)-1] // the previous block is needed, so let's get it
- newBlock := NewBlock(data, PreviousBlock.MyBlockHash) // create a new block containing the data and the hash of the previous block
- blockchain.Blocks = append(blockchain.Blocks, newBlock) // add that block to the chain to create a chain of blocks
- }
- /* Create the function that returns the whole blockchain and add the genesis to it first. the genesis block is the first ever mined block, so let's create a function that will return it since it does not exist yet */
- func NewBlockchain() *Blockchain { // the function is created
- return &Blockchain{[]*Block{NewGenesisBlock()}} // the genesis block is added first to the chain
- }
main.go
- //Time to put everything together and test
- package main
- import (
- "fmt" // just for printing something on the screen
- )
- func main() {
- newblockchain := NewBlockchain() // Initialize the blockchain
- // create 2 blocks and add 2 transactions
- newblockchain.AddBlock("first transaction") // first block containing one tx
- newblockchain.AddBlock("Second transaction") // second block containing one tx
- // Now print all the blocks and their contents
- for _, block := range newblockchain.Blocks { // iterate on each block
- fmt.Printf("Hash of the block %x\n", block.MyBlockHash) // print the hash of the block
- fmt.Printf("Hash of the previous Block: %x\n", block.PreviousBlockHash) // print the hash of the previous block
- fmt.Printf("All the transactions: %s\n", block.AllData) // print the transactions
- } // our blockchain will be printed
- }
讓我們現(xiàn)在運行它,go build然后.\go
我們在區(qū)塊鏈中的區(qū)塊沒有任何ID和時間戳,因此讓我們通過修改main.go文件來添加該信息,并在中添加這兩行for loop:
- fmt.Printf("Block ID : %d \n", i)
- fmt.Printf("Timestamp : %d \n", block.Timestamp+int64(i))
- //Time to put everything together and test
- package main
- import (
- "fmt" // just for printing something on the screen
- )
- func main() {
- newblockchain := NewBlockchain() // Initialize the blockchain
- // create 2 blocks and add 2 transactions
- newblockchain.AddBlock("first transaction") // first block containing one tx
- newblockchain.AddBlock("Second transaction") // second block containing one tx
- // Now print all the blocks and their contents
- for i, block := range newblockchain.Blocks { // iterate on each block
- fmt.Printf("Block ID : %d \n", i) // print the block ID
- fmt.Printf("Timestamp : %d \n", block.Timestamp+int64(i)) // print the timestamp of the block, to make them different, we just add a value i
- fmt.Printf("Hash of the block : %x\n", block.MyBlockHash) // print the hash of the block
- fmt.Printf("Hash of the previous Block : %x\n", block.PreviousBlockHash) // print the hash of the previous block
- fmt.Printf("All the transactions : %s\n", block.AllData) // print the transactions
- } // our blockchain will be printed
- }
讓我們保存代碼,go build然后再次運行它,然后./go
如您所見,區(qū)塊鏈結(jié)構(gòu)良好。除創(chuàng)世塊外,每個塊均包含其哈希值和上一個塊的哈希值,這使其不可變,如果更改了該塊中的數(shù)據(jù),則哈希值將自動更改,并且該塊將被丟棄。創(chuàng)世塊沒有任何先前的哈希,因為它是第一個哈希,沒有先前的塊。
全部完成!恭喜,您剛剛在Go created中創(chuàng)建了自己的區(qū)塊鏈DEMO!