專案 GitHub 位置: https://github.com/weiawesome/block-chain_go
經過一個禮拜多的努力 區塊鏈總算是成型了
現在只要將其啟動即可
以下分為幾點說明
檔案位置: "./main.go"
func main() {
DbAddress := "localhost:27017"
NodeAddr := "127.0.0.1:8080"
NodeAddresses := []string{}
Miners := 1
TransactionChannel := make(chan transaction.Transaction)
BroadcastTransactionChannel := make(chan transaction.Transaction)
BlockTransactionChannel := make(chan blockchain.BlockTransaction)
BroadcastBlockChannel := make(chan blockchain.Block)
MinersSuccessBlockChannel := make(chan blockchain.Block)
BlockChannel := make(chan blockchain.Block)
RefreshBlockChannel := make(chan blockchain.Block)
MinersBlockChannel := make(chan blockchain.Block)
CompleteBlockChannel := make(chan blockchain.Block)
err := utils.InitClient(DbAddress)
if err != nil {
return
}
go receive_validate_transaction.ReceiveValidateTransaction(TransactionChannel, BroadcastTransactionChannel, BlockTransactionChannel)
go receive_validate_block.ReceiveValidateBlock(BroadcastBlockChannel, MinersSuccessBlockChannel, BlockChannel, RefreshBlockChannel)
go refresh_block.RefreshBlock(BlockTransactionChannel, MinersBlockChannel, CompleteBlockChannel)
go refresh_db.RefreshDb(RefreshBlockChannel, CompleteBlockChannel)
go miners_leader.MinerLeader(Miners, MinersBlockChannel, MinersSuccessBlockChannel)
connection.BuildNode(NodeAddr, NodeAddresses, TransactionChannel, BlockChannel, BroadcastTransactionChannel, BroadcastBlockChannel)
}
變數名稱 | 含意 |
---|---|
DbAddress | Mongodb 的位置 |
NodeAddr | 基本的節點位置 |
NodeAddresses | 先連結的節點位置 |
首先對於 mongodb 可以使用 docker 建立容器並端口映射回本機
(方便未來多個節點使用 使用不同端口的資料庫即可)
# 映射回本機27017端口
docker run --name mongodb -p 27017:27017 -d mongo
(請先確保運行端口目前是空餘的 而且資料庫已成功運作在指定端口)
//在當前資料夾下的終端上輸入
go run main.go
會看到以上的結果 代表目前已成功建立節點在 127.0.0.1:8080 這個位置上
BN: BuildNode 節點建立程序
隨機產一筆公鑰與私鑰對
並且轉送金額給公私鑰相對應的地址
檔案位置: "./api_transaction_submit_free_random_addr.go"
func main() {
var Amount float64
Amount = 500
ConnectAddr := "127.0.0.1:8080"
pair, err := utils.GenerateKeyPair()
if err != nil {
return
}
key, err := utils.DecodePublicKey(pair.PublicKey)
if err != nil {
return
}
addr := utils.GetAddress(conseous.VersionPrefix, key)
fmt.Println("PublicKey: ", pair.PublicKey)
fmt.Println("PrivateKey: ", pair.PrivateKey)
fmt.Println("Address: ", addr)
clientAPI := api.ClientAPI{ConnectNodeAddr: ConnectAddr}
err = clientAPI.Connect()
if err != nil {
return
}
defer func() {
err := clientAPI.DisConnect()
if err != nil {
return
}
}()
err = clientAPI.SubmitFreeTransaction(Amount, addr)
if err != nil {
return
}
}
變數名稱 | 含意 |
---|---|
Amount | 轉送的金額 |
ConnectAddr | 連接的礦工節點 |
(請先確保 礦工程序(main.go)正在運行 且 在對應的節點位置 )
//在當前資料夾下的終端上輸入
go run api_transaction_submit_free_random_addr.go
執行完成後便會看到下效果
接下來看 礦工程序(main.go) 的窗口
以下為輸出結果按照順序解釋
檔案位置: "./api_transaction_submit_free.go"
func main() {
var Amount float64
Amount = 0
var Addr string
Addr = "Address"
ConnectAddr := "127.0.0.1:8080"
clientAPI := api.ClientAPI{ConnectNodeAddr: ConnectAddr}
err := clientAPI.Connect()
if err != nil {
return
}
defer func() {
err := clientAPI.DisConnect()
if err != nil {
return
}
}()
err = clientAPI.SubmitFreeTransaction(Amount, Addr)
if err != nil {
return
}
}
變數名稱 | 含意 |
---|---|
Amount | 轉送的金額 |
Addr | 轉送的地址 |
ConnectAddr | 連接的礦工節點 |
基本上 交易流程與上方都相同故省略
正常交易
由上方所產生的 公私鑰與地址 轉金額給自己
檔案位置: "./api_transaction_submit.go"
func main() {
var UTXOHash string
var Index int
var Address string
var Amount float64
var Fee float64
var PublicKey string
var PrivateKey string
UTXOHash = "UTXOHash"
Index = 0
Address = "Address"
Amount = 0
Fee = 0
PublicKey = "PublicKey"
PrivateKey = "PrivateKey"
ConnectAddr := "127.0.0.1:8080"
f := transaction.From{UTXOHash: UTXOHash, Index: Index}
t := transaction.To{Address: Address, Amount: Amount}
ts := transaction.Transaction{From: []transaction.From{f}, To: []transaction.To{t}, Fee: Fee, PublicKey: PublicKey}
privateKey, err := utils.DecodePrivateKey(PrivateKey)
if err != nil {
return
}
strVal, err := ts.ToString()
if err != nil {
return
}
signature, err := utils.Signature(strVal, privateKey)
if err != nil {
return
}
ts.Signature = signature
ts.TransactionHash = utils.HashSHA256(strVal)
fmt.Println("TransactionHash: ", ts.TransactionHash)
fmt.Println()
fmt.Println("From: ")
fmt.Println("PublicKey: ", PublicKey)
fmt.Println("PrivateKey: ", PrivateKey)
fmt.Println("UTXOHash: ", UTXOHash)
fmt.Println("Index: ", Index)
fmt.Println()
fmt.Println("To: ")
fmt.Println("Address: ", Address)
fmt.Println("Amount: ", Amount)
fmt.Println()
fmt.Println("Fee: ", Fee)
fmt.Println()
fmt.Println("Signature: ", signature)
clientAPI := api.ClientAPI{ConnectNodeAddr: ConnectAddr}
err = clientAPI.Connect()
if err != nil {
return
}
defer func() {
err := clientAPI.DisConnect()
if err != nil {
return
}
}()
err = clientAPI.SubmitTransaction(ts.From, ts.To, ts.Fee, ts.PublicKey, ts.Signature)
if err != nil {
fmt.Println(err)
return
}
}
變數名稱 | 含意 |
---|---|
UTXOHash | 上次交易的交易哈希 |
Index | 上次交易中接收的次序 |
Address | 交易接收地址 |
Amount | 交易接收金額 |
Fee | 交易的小費 |
PublicKey | 傳輸者的公鑰 |
PrivateKey | 傳輸者的私鑰 |
ConnectAddr | 連接的礦工節點 |
(請先確保 礦工程序(main.go)正在運行 且 在對應的節點位置 )
//在當前資料夾下的終端上輸入
go run api_transaction_submit.go
// 以上方第一次免費的交易為例
UTXOHash="a2fff3aec37712009693ef269ff04b716a3248290819d7a59f8b49ff1008a48a"
Address="1BFTNxqbCZzcV9xS6SUwA23YAt"
Index=0
Amount=150
Fee=50
PublicKey="BI/0HLw2PUacr2jIVy7U3G0mFlV2kDcnBSHv+JjcGFCttexgvZzneN+c6YadzqLIk6nSLjrMQiGhAAWlexjh10o="
PrivateKey="7/+xOoENHZ89xlZVkkMvJZ0ltEdHrLTYPCCFsbASg7I="
會看到以下的輸出結果
接下來看 礦工程序(main.go) 的窗口
以下為輸出結果按照順序解釋
首先 區塊哈希 與觀察紀錄相同
再來 區塊標頭 上 也與上方記錄相同(Nonce=27)等等
最後看到 區塊交易
第一筆 為礦工紀錄交易 證明該個區塊是這名礦工計算的
(此區塊的獎勵也歸這名礦工擁有)
第二筆 為上方提交交易 交易哈希也符合
(資訊也符合 金額 150 小費 50)
查詢 BlockHash 等於 上筆區塊哈希
與上方或的相同效果
查詢 區塊高度 為 0 的第一個區塊
確實為創世區塊資訊
首先在 區塊哈希 上 符合上方紀錄
在 BlockMeta 亦有留下 我對創世區塊的留言
另外在 區塊標頭 上 也符合紀錄 (Nonce=2)
最後在 交易紀錄 上 就是最前一面第一筆 免費獲得500的紀錄
首先透過 docker 建立一個不同端口的 mongodb
//映射為本機27018端口
docker run --name mongodb -p 27018:27017 -d mongo
// main.go 內容修正
DbAddress := "localhost:27018"
NodeAddr := "127.0.0.1:8081"
NodeAddresses := []string{"127.0.0.1:8080"}
接下執行 go run main.go
(確保先前 main.go 程序還在執行)
就會得到以上結果
接下來 不論是在 區塊獲取 或是 提交交易 都可以獲得相同結果
// 例如 api_block_get_by_block_height 進行修正
ConnectAddr := "127.0.0.1:8081"
都可以或的相同的資訊 達到真實的去中心化
其他方式也都可以達到相同的結果!!!
感覺今天講述的範圍很廣
如果想實際體驗一次 可以在GitHub上Clone專案在本地跑一次
專案 GitHub 位置:
https://github.com/weiawesome/block-chain_go
基本上如何執行在 README.md 也寫得很清晰了
其實還有很多可以去嘗試跟玩的!!!
希望透過這篇能夠理解
必須說 這個區塊鏈程序 我很有成就感
從一開始規劃 到後續實現
真的一度認為這要失敗了
尤其對於 Go 中 Goroutine 與 Channel 應用
也是透過這次我才稍微學會撰寫平行程序
而且也是透過實踐 確切理解
去中心化、共識機制、分支處理、資料庫處理、交易....
結束了整個區塊鏈的製造
想目前對於區塊鏈的模樣 運作細節 網路架構 傳輸方式 都非常孰悉!!!
不過呢? 目前區塊鏈最常見的應用 還沒碰觸到呢? 是時候邁入應用了吧?
那當然就是 "智能合約"
接下來就要趕緊進入 智能合約的撰寫與應用