源碼地址:https://github.com/corgi-kx/blockchain_golang.git
????本程序是模仿比特幣的功能所編寫的區(qū)塊鏈公鏈demo,主要應用到了密碼學,共識算法,對等網(wǎng)絡,區(qū)塊鏈防篡改結(jié)構(gòu)等相關知識,并把各個知識點結(jié)合到一起,編寫成了簡單完善的可運行公鏈demo
程序特點:
- 基于工作量證明共識算法桨螺,數(shù)據(jù)以區(qū)塊鏈的結(jié)構(gòu)進行存儲
- 去中心化白嘁,運用P2P技術(shù)各個節(jié)點之間相對獨立
- 主動尋找網(wǎng)絡中的對等節(jié)點第献,自動連接并存入本地節(jié)點池
- 節(jié)點退出時會向全網(wǎng)廣播赔嚎,其余節(jié)點動態(tài)更新當前可連接節(jié)點池
- 挖礦成功節(jié)點獲得記賬權(quán)换可,并向全網(wǎng)廣播同步最新區(qū)塊,其余節(jié)點驗證通過后存入本地區(qū)塊鏈中
- 交易轉(zhuǎn)帳使用UTXO交易模型,支持一次交易存在多筆轉(zhuǎn)賬
- 支持中文助記詞導入讨勤,由助記詞生成公私鑰密鑰對(使用的橢圓曲線算法)
- 交易轉(zhuǎn)賬使用私鑰進行數(shù)字簽名购裙,公鑰驗證,并因為UTXO的結(jié)構(gòu)避免了簽名的重復使用問題
- 為未花費UTXO單獨建立數(shù)據(jù)表,優(yōu)化轉(zhuǎn)賬交易速度
- 使用默克爾樹生成交易的根hash(當前demo并沒有區(qū)分區(qū)塊頭與區(qū)塊體萌狂,僅僅是想使用此數(shù)據(jù)結(jié)構(gòu)練練手)
- 持久化區(qū)塊鏈與公私鑰信息档玻,存入節(jié)點本地數(shù)據(jù)庫中(每個節(jié)點擁有自己的獨立數(shù)據(jù)庫)
- 自定義挖礦難度值、曠工挖礦獎勵值
- 自定義交易池大小茫藏,滿足指定筆數(shù)的交易后才會開始挖礦
主要模塊:
- 命令調(diào)度模塊
- UTXO交易生成模塊
- 密碼學加解密模塊
- 區(qū)塊生成误趴、驗證模塊
- 數(shù)據(jù)持久化模塊
- P2P網(wǎng)絡通訊模塊
- 日志輸出模塊
命令調(diào)度模塊
??? 啟動程序后,控制臺捕捉用戶輸入信息务傲,通過對用戶的輸入解析出命令以及跟隨在命令后的值凉当。根據(jù)不同命令對程序進行相關操作
UTXO交易生成模塊
??? 交易轉(zhuǎn)賬模塊基于UTXO模型,但并沒有引入比特幣腳本售葡,腳本處直接使用數(shù)字簽名的字節(jié)數(shù)組進行替代看杭。當用戶A轉(zhuǎn)賬給用戶B時,需要用戶A使用私鑰對"輸入" (包含了用戶A所擁有的"輸出"交易hash天通、索引等信息)進行數(shù)字簽名泊窘,生成交易后發(fā)送給其他節(jié)點,其他節(jié)點則使用用戶A的公鑰對其進行簽名驗證。
??? 由于UTXO的特殊結(jié)構(gòu)烘豹,天然的避免了重放攻擊瓜贾,并不需要像以太坊賬戶系統(tǒng)一樣添加nonce值,但是為了避免UTXO的重復計算問題携悯,在上一筆轉(zhuǎn)賬未打包進區(qū)塊之前暫不支持同一地址的再次轉(zhuǎn)賬
??? 支持一筆交易多筆轉(zhuǎn)賬祭芦,并為了優(yōu)化轉(zhuǎn)賬查詢速度創(chuàng)建了UTXO數(shù)據(jù)表專門用于存儲所有區(qū)塊鏈中未花費的輸出。
??? 想要了解更多關于UTXO相關憔鬼,建議參考這篇文章
密碼學加解密模塊
- 單向散列函數(shù):sha256 ripemd-160
主要用于將整體區(qū)塊通過計算轉(zhuǎn)換為固定長度的字符串,方便進行數(shù)據(jù)校驗 - 編解碼算法:base58
由于私鑰原始長度過長不利于記憶龟劲,使用base58編碼對私鑰、地址進行可視化編碼 - 非對稱加密:橢圓曲線算法(crypto/elliptic p256)
通過助記詞文本提取7對中文詞語作為種子轴或,通過使用橢圓曲線算法生成公私鑰密鑰對昌跌,私鑰用于對交易數(shù)據(jù)進行數(shù)字簽名,公鑰對簽名進行驗證來確保發(fā)起人身份照雁。
公鑰通過一系列運算生成地址蚕愤,地址用于查詢余額,以及接收轉(zhuǎn)賬Token
???地址生成規(guī)則如下:
- 通過橢圓曲線算法生成公鑰
- 對公鑰進行sha256散列和ripemd160散列,獲得publickeyHash
- 在publickeyHash前面加上version(版本)字節(jié)數(shù)組獲得versionPublickeyHash
- 對versionPublickeyHash進行兩次sha256散列并取前4位字節(jié)饺蚊,獲得tailfHash
- 將tailfHash拼接到versionPublickeyHash后面萍诱,獲得公鑰的最終Hash即finalHash
- 最后將finalHash進行Base58編碼得到比特幣地址
曾經(jīng)有個疑問,為何比特幣生成地址要這么麻煩污呼,既然非對稱加密只擁有公鑰是無法倒推出私鑰的裕坊,為何不直接使用公鑰當?shù)刂罚菍€進行hash多次來取得地址燕酷,直到最近看了篇文章才明白咧虎,該文章提到量子計算機是可以破解橢圓曲線加密的焙糟,其可以通過公鑰快速尋找到私鑰信息。但是量子計算機很難逆轉(zhuǎn)Hash算法(或者說需要2的80次方個步驟來破解Hash),所以你的比特幣放在一個未支付過的地址中(根據(jù)UTXO交易模型厌殉,輸出存的是公鑰Hash而不是公鑰,這同樣解釋了為何UTXO輸入存的是公鑰而輸出存的是公鑰Hash)是相當安全的塔沃。也就是說已有花費的地址在面對量子計算機面前是不安全的阵翎,沒有花費的地址有較強的抗量子性院领。
區(qū)塊生成、驗證
??? 基于POW共識算法生成區(qū)塊浴麻,首先根據(jù)難度值(可在配置文件里定義)來定義挖礦難度(一串大數(shù))得问,通過調(diào)用go自身的隨機數(shù)包crypto/rand來不斷的變換隨機數(shù)nonce(上個版本用的nonce值自身累加的方法,但是分叉的概率太大),不斷哈希區(qū)塊自身來使最終計算出來的區(qū)塊自身hash值小于當前定義的挖礦難度則獲得出塊權(quán)利软免。
??? 出塊節(jié)點可獲得獎勵代幣并擁有記賬權(quán)宫纬,出塊后像全網(wǎng)進行廣播。其余P2P節(jié)點收到區(qū)塊后首先對區(qū)塊自身hash進行驗證膏萧,其次檢驗區(qū)塊里的prehash與本地的前區(qū)塊hash是否一致漓骚,最后存入本地數(shù)據(jù)庫中蝌衔。
數(shù)據(jù)持久化模塊
??? 持久化層基于KV型數(shù)據(jù)庫blot多封裝了一層,主要接口為put、view蝌蹂、delete噩斟。每次調(diào)用接口會單獨打開、關閉數(shù)據(jù)庫的句柄孤个,所以不會出現(xiàn)被其他線程占用的情況剃允。數(shù)據(jù)庫分別建立了三個表 BlockBucket(用于存放區(qū)塊的詳細信息)、AddrBucket(用于存放本地錢包數(shù)據(jù))齐鲤、UTXOBucket(用于存放未消費UTXO數(shù)據(jù))
P2P網(wǎng)絡通訊模塊
??? 使用適合局域網(wǎng)尋址的mdns技術(shù)斥废,由于所使用的包在windows下存在找不到網(wǎng)絡的bug,所以本程序建議在linux/mac下運行给郊。
??? 節(jié)點啟動后會自動在局域網(wǎng)中尋找其他對等節(jié)點牡肉,發(fā)現(xiàn)后會存放在節(jié)點池中(存于內(nèi)存),節(jié)點之間相互通訊的數(shù)據(jù)前十二個字節(jié)默認為命令淆九,根據(jù)命令不同來對本地的區(qū)塊鏈相關信息進行反饋
??? 主要運行原理為分發(fā)區(qū)塊與收到交易后的挖礦:
??獲取區(qū)塊流程:
- 互相對比區(qū)塊高度
- 獲取缺失的區(qū)塊hash
- 通過區(qū)塊hash來接收缺失的整個區(qū)塊
- 區(qū)塊驗證荚板,存入數(shù)據(jù)庫
??挖礦流程:
- 通過某個節(jié)點發(fā)送交易數(shù)據(jù)到全網(wǎng)節(jié)點
- 節(jié)點接收到交易,對交易進行簽名驗證,余額驗證
- 驗證通過后存入交易池吩屹,滿足交易池大小后開始挖礦
- 挖礦成功,全網(wǎng)廣播區(qū)塊高度
- 發(fā)送區(qū)塊到其他節(jié)點
- 其他節(jié)點進行區(qū)塊驗證拧抖,存入數(shù)據(jù)庫
日志輸出模塊
??? 使用自制的log包煤搜,程序啟動后會默認在當前目錄下(可在配置文件設置)生成log+端口號的日志文件,所有程序產(chǎn)生的debug信息都會打印到此日志文件中唧席,建議開啟一個窗口進行實時監(jiān)聽以方便觀察節(jié)點之間的交互擦盾,以及區(qū)塊生成的詳細步驟
【日志包特點】:
- 支持定向輸出日志到指定文件
- 支持一鍵隱藏調(diào)試信息
- 支持彩色打印(windows/linux/mac均支持)
- 顯示輸出日志的類名淌哟、函數(shù)/方法名
主要使用的工具包
包 | 作用 |
---|---|
github.com/boltdb/bolt | k,v型數(shù)據(jù)庫 |
github.com/spf13/viper | 配置文件讀取工具 |
github.com/golang/crypto | 密碼學相關工具 |
github.com/libp2p/go-libp2p | ipfs旗下的p2p通訊工具 |
github.com/corgi-kx/logcustom | 日志輸出工具 |
程序運行教程:
1.下載后編譯
本demo建議在linux/mac下運行迹卢,否則會出現(xiàn)助記詞亂碼,找不到對等網(wǎng)絡的問題
git clone https://github.com/corgi-kx/blockchain_golang.git
go build -mod=vendor -o chain main.go
2.打開多個窗口
為了簡化操作徒仓,在同一臺電腦中啟動不同端口來模擬P2P節(jié)點(三個窗口用于啟動程序腐碱,三個窗口用于實時查看日志)
實機操作時,如果出現(xiàn)找不到其他節(jié)點情況可能是防火墻問題掉弛,請關閉防火墻后在試
3.修改配置文件
主要修改本地監(jiān)聽ip症见,本地監(jiān)聽端口。其他的默認即可
不建議調(diào)小難度閥值殃饿,避免產(chǎn)生區(qū)塊分叉情況谋作,demo暫未對區(qū)塊分叉做處理
vi config.yaml
blockchain:
#挖礦難度值,越大越難挖
mine_difficulty_value: 24
#挖礦獎勵代幣數(shù)量
token_reward_num: 25
#交易池大小(滿足多少條交易才開始進行挖礦)
trade_pool_length: 2
#日志存放路徑
log_path: "./"
#中文助記詞種子路徑
chinese_mnemonic_path: "./chinese_mnemonic_world.txt"
network:
#本地監(jiān)聽IP
listen_host: "192.168.0.164"
#本地監(jiān)聽端口
listen_port: "9000"
#節(jié)點組唯一標識名稱(如果節(jié)點間名稱不同會找不到網(wǎng)絡)
rendezvous_string: "meetme"
#網(wǎng)絡傳輸流的協(xié)議id(如果節(jié)點間id不同發(fā)送不了數(shù)據(jù))
protocol_id: "/chain/1.1.0"
4.啟動節(jié)點,創(chuàng)建錢包,生成創(chuàng)世區(qū)塊
啟動節(jié)點1
./chain
通過命令,先生成三個錢包地址
> generateWallet
助記詞: ["肺段","生地","齒槽","幾維","中葡","芒魚","光華"]
私鑰: 6HrLjHE4Qm31dZFGjemwNLZM3iqnxoSUqKb5VtEKbWzh
地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
> generateWallet
助記詞: ["扭傷","剪創(chuàng)","肌病","下陷","廣發(fā)","濁音","斜疝"]
私鑰: 7yBRSB46q8ZeEiYbwZDSvKzzsh1MYAygeo2i689uEMAf
地址: 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS
> generateWallet
助記詞: ["心室","缺缸","瓣胃","黑茶","份額","張銅","回游"]
私鑰: 872CCeLS8bDrC7bdSoFrgUSWm57eqTdypEhKbErYC9xi
地址: 1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD
生成創(chuàng)世區(qū)塊(賦予第一個地址100Tokens)
> genesis -a 12BwtcVWimms9rrKxxoCev68woGyMYS4sk -v 100
已成生成創(chuàng)世區(qū)塊
日志1實時查看日志(可以看到挖礦過程)
tail -f log9000.txt
節(jié)點2,節(jié)點3依次修改配置文件的端口號為9001,9002,啟動這兩個節(jié)點來同步創(chuàng)世區(qū)塊
這時節(jié)點1的日志監(jiān)測到網(wǎng)絡中存在的其他節(jié)點
每個節(jié)點設置挖礦獎勵地址(也可以不設置,不設置的情況下,節(jié)點挖到礦后不會產(chǎn)生獎勵)
節(jié)點1設置挖礦獎勵地址:
> setRewardAddr -a 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
已設置地址12BwtcVWimms9rrKxxoCev68woGyMYS4sk為挖礦獎勵地址!
節(jié)點2設置挖礦獎勵地址:
> setRewardAddr -a 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS
已設置地址1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS為挖礦獎勵地址乎芳!
節(jié)點3設置挖礦獎勵地址:
> setRewardAddr -a 1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD
已設置地址1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD為挖礦獎勵地址遵蚜!
節(jié)點1進行轉(zhuǎn)帳操作(創(chuàng)世地址像其他兩個地址每個轉(zhuǎn)帳10Tokens)
> transfer -from ["12BwtcVWimms9rrKxxoCev68woGyMYS4sk","12BwtcVWimms9rrKxxoCev68woGyMYS4sk"] -to ["1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS","1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD"] -amount [10,10]
已執(zhí)行轉(zhuǎn)帳命令
三個節(jié)點中,由節(jié)點2挖到區(qū)塊,里所應當節(jié)點2獲得挖礦獎勵25Tokens
getBalance
查看余額命令,可以查看三個地址的余額信息
> getBalance -a 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
地址:12BwtcVWimms9rrKxxoCev68woGyMYS4sk的余額為:80
> getBalance -a 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS
地址:1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS的余額為:35
> getBalance -a 1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD
地址:1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD的余額為:10
8.查看區(qū)塊詳細信息
任意節(jié)點輸入printAllBlock
命令查看區(qū)塊信息
區(qū)塊1為創(chuàng)世區(qū)塊,只有賦予12BwtcVWimms9rrKxxoCev68woGyMYS4sk
的100UTXO輸出
可以看到區(qū)塊2:
第一筆交易,地址12BwtcVWimms9rrKxxoCev68woGyMYS4sk
先花掉創(chuàng)世區(qū)塊額度為100的UTXO,給自身生成一個90UTXO,給地址1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS
生成10UTXO .
第二筆交易地址12BwtcVWimms9rrKxxoCev68woGyMYS4sk
使用第一筆交易輸出的90額度的UTXO,給自身生成一個80UTXO 以及給地址1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD
生成10UTXO
第三筆交易為挖礦獎勵交易,所以只有輸出,沒有輸入,給地址1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS
生成25UTXO(在配置文件中設置的25獎勵額度)
> printAllBlock
========================================================================================================
本塊hash 00000008acfb9a8dcf3bb923f4eb6f2ddfc27dcaff861ea6848a9074ca46d85b
------------------------------交易數(shù)據(jù)------------------------------
本次交易id: 988ecbe7f374855aa94addb873f22960cf43646bdaeb562533f3e683478270db
tx_input:
交易id: bb717bd6717c8cae3829875187b97f256859277ad4a52ac57cdbc132895ca154
索引: 0
簽名信息: 8c8b0628ceadebbc9e97b490a40a23494d3f8286f1af045f1e1f18d529c49a90afa194799182c264ee15871b5dd35c773e5dd46427fc8e2c268356ce09f6b60b
公鑰: 8e0f1fe7d6177f11027818663048392cee8952cefcf1ceeec8edc84e176f46cedd338575f709b412eeab904d7027056354038f8aef7a1940f45264f7116ba793
地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
tx_output:
金額: 90
公鑰Hash: 0d0a1aeb1baf838828a54ac97b09524f0b0c3210
地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
---------------
金額: 10
公鑰Hash: 6eb2d1846217aa089dfa26e3147b767e1de0b08d
地址: 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS
本次交易id: 443b4a4f04204bd8ed2bdfcc096642a27457c27aa47c2ee81486d7440b059521
tx_input:
交易id: 988ecbe7f374855aa94addb873f22960cf43646bdaeb562533f3e683478270db
索引: 0
簽名信息: 2a064297227ba07c7ea92eebb1d43f3fe4dfbd6c7e78be8ec2d1d30e20fa51500c8bdb591c11908a877aeef61b4c64f9a851cc44af441cbe6893e1b80e42032c
公鑰: 8e0f1fe7d6177f11027818663048392cee8952cefcf1ceeec8edc84e176f46cedd338575f709b412eeab904d7027056354038f8aef7a1940f45264f7116ba793
地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
tx_output:
金額: 80
公鑰Hash: 0d0a1aeb1baf838828a54ac97b09524f0b0c3210
地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
---------------
金額: 10
公鑰Hash: 8fa79c32a067830be3b16ade637d370e1d1e6e0d
地址: 1E6aRBxfncAsypUnjGxPJYbR4JQ3gZ6hHD
本次交易id: 2420c67272ab7832d6148a36a6b38166862d12e265f184439e6ab2e606b01245
tx_input:
tx_output:
金額: 25
公鑰Hash: 6eb2d1846217aa089dfa26e3147b767e1de0b08d
地址: 1B6KYdABXZDwq8xGTbdDknpHBo11CkihxS
--------------------------------------------------------------------
時間戳 2019-11-18 03:23:57 PM
區(qū)塊高度 2
隨機數(shù) 2808567053068705071
上一個塊hash 0000007d7b7c7b540d9d1b0d1d06b6936e1bc613f6ab7de1ae0275cdaef4e4a4
========================================================================================================
本塊hash 0000007d7b7c7b540d9d1b0d1d06b6936e1bc613f6ab7de1ae0275cdaef4e4a4
------------------------------交易數(shù)據(jù)------------------------------
本次交易id: bb717bd6717c8cae3829875187b97f256859277ad4a52ac57cdbc132895ca154
tx_input:
交易id:
索引: -1
簽名信息:
公鑰:
地址:
tx_output:
金額: 100
公鑰Hash: 0d0a1aeb1baf838828a54ac97b09524f0b0c3210
地址: 12BwtcVWimms9rrKxxoCev68woGyMYS4sk
--------------------------------------------------------------------
時間戳 2019-11-18 10:43:41 AM
區(qū)塊高度 1
隨機數(shù) 8604076799988393002
上一個塊hash 0000000000000000000000000000000000000000000000000000000000000000
========================================================================================================
9.其他
你也可以在節(jié)點2,節(jié)點3發(fā)起轉(zhuǎn)帳,不過首先需要通過助記詞導入錢包信息,例子如下:
importMnword -m ["扭傷","剪創(chuàng)","肌病","下陷","廣發(fā)","濁音","斜疝"]
更多功能請自行發(fā)掘 :)
???建了個QQ群:722124200 有問題可以加群互相討論 :)
???郵箱:mikesen1994@gmail.com ?????? ?? ???? ? vx:965952482