1.5 比特幣架構詳解
• 比特幣前端
○ 錢包:錢包儲存使用者私鑰,管理使用者餘額,提供比特幣交易(支付,轉賬)功能
§ 分類
□ 決定性錢包:決定性指私鑰是否由種子生成
□ 非決定性錢包:直接儲存私鑰,私鑰都儲存在DB上面
® 非決定性錢包不夠安全
® 管理不方便
□ 決定性錢包:所有私鑰都由一個私鑰種子通過單向的雜湊演算法生成
® 備份方便,只要備份私鑰種子,就可以一次性恢復所有的私鑰
® 分類
◊ 普通決定性錢包:由私鑰種子直接生成所有的私鑰
◊ 層級決定性錢包:由私鑰種子生成父私鑰,父私鑰生成子私鑰
§ 部署場景分類
□ 移動錢包:執行在手機,移動終端的輕量級錢包。移動錢包不會下載整條區塊鏈,採用“簡化支付驗證(SPV)”方法驗證交易,也叫SPV錢包。
® SPV驗證:依靠網路上的可信任節點 查詢所有區塊的區塊頭,以及按照交易的確認數,再有就是能否在相應的區塊中找到該筆交易來驗證支付的真偽。
□ 桌面錢包
® 分類
◊ 厚錢包:下載整條區塊鏈,進行完整交易
} bitcoinCore:提供完整錢包功能,包括簽名,錢包加密,備份,金鑰匯入,匯出等
} 厚錢包主要優勢是安全,但有交易驗證的開銷,適合於安全性要求很高的場景
◊ 薄錢包:不會下載整條區塊鏈,而是採用SPV等方式來驗證與使用者相關支付交易
} 薄錢包主要優勢是靈活性高,但是安全性相對較差,適合於小額支付場景
□ 網際網路錢包
® 網際網路錢包也不下載整條區塊鏈,它依託於第三方的平臺為使用者提供隱私保護
◊ 其優勢是可以在任何地方,任何裝置上管理錢包,但安全性不高
◊ 產品:coinCorner,Blockchain.info等
□ 紙錢包
® 將私鑰進行冷備份,可以用於防範電腦或者USB介質損壞所造成的私鑰丟失,而且由於其離線存在,可以有效防範黑客通過網路攻擊盜竊私鑰。需要防止物理偷竊
§ HTTP/JSON RPC API
□ 比特幣提供的介面,供外部通過介面控制比特幣節點。
□ 比特幣提供了一個HTTP/JSON RPC的服務端,外部程式可以通過JSON RPC API來訪問比特幣節點。
§ 命令列工具 bitcoin-cli
□ 控制比特幣的節點。通過JSON RPC API介面訪問比特幣後臺bitcoind。使用者可以通過發命令來守完成比特幣的各項操作,比如查詢餘額,支付,轉賬等
§ 比特幣瀏覽器
□ 比特幣提供一個跨平臺的C++ Libbitcoin庫,該庫支援比特幣全節點服務端和瀏覽器作為客戶端命令列工具。比特幣瀏覽器命令提供與bitcoin-cli基本一樣的功能。
□ 額外功能:金鑰管理功能,處理工具。
§ 圖形開發工具(QT)
□ 比特幣核心是比特幣使用最廣泛的客戶端,採用QT開發完成
• 節點後臺
○ 功能:負責參與比特幣網路的通訊互聯,維護區塊鏈,驗證區塊,交易,廣播,轉播傳遞區塊交易資訊。
○ 比特幣的後臺程式主要由bitcoind與挖礦節點程式構成。
○ 區塊鏈管理:涉及初始區塊鏈下載,連線區塊,斷開區塊,校驗區塊和儲存區塊,以及發現最長鏈條的區塊。
§ 下載區塊鏈
□ 在比特幣全節點第一次加入網路執行時,先要下載並驗證整條區塊鏈。當區塊鏈容量不斷增大時,要花費時間就越來越長。所以在新版本中,比特幣釋出了新的初始區塊的下載方式。叫“區塊報頭等待”。該方式可以大大提高初始區塊的下載速度。在此模式下,新的節點 先從鄰節點下載所有的區塊報頭(一個報頭佔80個位元組,而一個區塊有1M,因此,只下載報頭可以極大的提速)。當所有報頭完成下載之後,節點就可以並行的從多個鄰節點下載不同區間的區塊,從而大大提高整條區塊鏈的下載速度。
§ 接收區塊鏈
□ 在現有的節點 開戶時,會先將整個區塊的索引從LevelDB調進記憶體。需要注意的問題在於該區塊鏈的索引不是單條的鏈,而可能是一個樹,也就是說每個區塊只有一個父區塊,但可能有多個子區塊,因此可能會導致分叉,這就需要逐漸發現哪個子區塊屬於最長的區塊鏈。
□ 當一個節點接收到到一個新的區塊,如果該區塊包含的指向前區塊的區塊頭雜湊值與節點當前頂端雜湊值相同時,該節點就會嘗試接收新的區塊,並將其作為當前鏈條的最頂端的區塊,從而 延伸節點所擁有的區塊鏈。
§ 區塊鏈的驗證
□ 在區塊鏈管理中,連線區塊函式是一個檢測雙花交易的關鍵。原理:該函式對新接收的區塊中所有交易進行檢測,驗證是否每個交易的比特幣來都能在當前的“尚未花費比特幣”(Unspend Transaction Output-UTXO)記錄中找到匹配。如果遇到網路延遲的情況,節點接收的區塊可能 不按順序到達,在這種情況下,有些交易的比特幣來源可能在UTXO記錄中暫時找不到,但當後面收到延遲到來的區塊後,UTXO記錄會被更新,區塊鏈就能連線起來。
§ 重組區塊鏈
□ 當節點發現網路中有一條不基於它當前區塊鏈的一條更長的區塊鏈時,它需要斷開現有區塊並對區塊鏈進行重組。這種情況主要發生在不同礦工幾乎同時挖到合法的區塊時,就會產生分叉。
□ 斷開區塊,重組區塊鏈,這些涉及到UTXO更改,被斷開的區塊中交易會回退到交易記憶體池,此時“回滾”記錄就可以用來 回滾斷開區塊中的交易。
○ 區塊驗證(驗證內容)
§ 交易的格式必須正確
§ 交易的輸入和輸出不能為空
§ 交易大小不能超過定義的區塊最大值MAX_BLOCK_SIZE
§ 每個交易的輸出以及所有輸出的合計必須在一定範圍內:0~2100萬比特幣
§ 輸入的雜湊值不能為零,不應該轉播挖礦交易
§ nLockTime不能大於INT_MAX
§ 交易的位元組大小必須要大於等於100
§ 交易的簽名運算元不能超過簽名操作的上限
§ 解鎖指令碼只能把數字放入堆疊,鎖定指令碼必須是標準格式
§ 和收到的交易相匹配的交易必須能在當前交易池或者主鏈上的某個區塊中找到
§ 對交易的每個輸入,如果其對應的UTXO輸出能在當前的交易池中找到,該交易必須拒絕(雙花交易)。因為當前交易池是未經記錄在區塊鏈中的交易,而交易的每個輸入應該來自於確認的UTXO,如果在當前交易池中找到,就是雙花交易。
§ 對交易的每個輸入,如果其對應的UTXO輸出不能在主鏈或當前交易池中找到,則其是一個孤兒交易,應該放入孤兒交易池中
§ 對交易中的每個輸入,如果其對應的UTXO輸出是一個挖礦初始交易,該初始應該獲得100個確認區塊的確認
§ 對交易中的每個輸入,其對應的輸出必須是UTXO
§ 用對應的輸出交易來獲得輸入值,檢查每個輸入的值及其合計,應該在允許的區間(0~2100W比特幣)
§ 如果一個交易的輸入合計小於輸出總計,則必須拒絕該交易
§ 如果交易的費用太低,則拒絕該交易
§ 每個輸入的解鎖指令碼必須和相應的輸出的鎖定指令碼共同驗證交易的合規性
○ 記憶體池管理
§ 記憶體池的管理就是交易池管理
§ 節點將通過驗證的交易放在一個交易池中,準備放到一個挖到的區塊中。
§ 當礦工挖到一個合格的區塊後,他將按照一定的優先順序次序中交易池中選出交易放到區塊中。
§ 優先順序是按照交易中的輸入 對應的UTXO的“鏈齡”和交易額的大小來劃分的。越老UTXO交易以及交易額越大的交易優先順序越高。
§ 優先順序計算公式:Priority = Sum(Value Of input * Input Age) / Transaction Size
□ UTXO鏈齡:按已在鏈上記錄該交易的區塊為起點,按後面有多少個區塊來計算,也就是計量該區塊在區塊鏈上的“深度”。
□ 交易的大小以位元組為單位。
□ 要成為高優先順序,一般來說高優先順序的值高於57600000,這個優先順序相當於1個比特幣交易額的優先順序,已經有了一天的“鏈齡”(相當於已經有144個區塊的確認),交易長度是250位元組。比特幣區塊中的前50K位元組都會保留給高優先順序的交易。
§ 當區塊被填滿後,剩下的交易都會留在記憶體池,等待下一個區塊的到來。隨著等待時間越長,“鏈齡”會逐漸增加,它們以後被選中的機率會越來越大。記憶體池中的交易不會過期,但是需要注意,記憶體池的交易不會被儲存在硬碟上,一旦挖礦節點重啟,記憶體池的交易會被清空。
○ 鄰節點管理
§ 當一個新比特幣節點做初始啟動的時候,它需要發現網路中的其它節點,並至少與一個節點相連。
§ 一般情況 下是與一個已知節點在8333商品建立 TCP連線。
§ 新節點是如何發現鄰節點的?
□ 方法一:用一些"DNS種子"查詢DNS,"DNS種子"是提供比特幣節點地址的DNS伺服器。比特幣核心帶有5個不同的"DNS種子",可以提供穩定的比特幣節點地址。
□ 方法二:直接把一個已知的鄰節點作為種子節點,通過它發現更多的鄰節點。當發現新的鄰節點後,新節點一般會斷開和種子節點的連線。將節點將其資訊傳送給鄰節點,鄰節點會繼續將新節點的地址轉發給它們的鄰節點,這樣新的節點就能夠被網路上其它節點知道,並保持其在網路上連線的暢通。新的節點一般會維持與8個鄰節點的連結。新節點啟動結束後,它會記住最近連上的鄰節點的地址。當它重新啟動的時候,它能夠很快完成和已知鄰節點的連線。如果以前的節點都連不上,就會重新開始初始啟動流程。
□ 節點維護
® 如果一個連線在一段時間內沒有互動,節點就會定期發一些資訊去維護連線,如果一個節點和鄰節點的連線在超過90分鐘裡沒有聯絡,該鄰節點會被認為已經下線,節點會尋找一個新的鄰節點來進行連線。
® 這麼做的好處在於無需中心控制,網路節點可以自由加入或者離開網路,即比特幣網路能動態的調節節點連線,以保證比特幣網路的正常執行。
○ 共識管理
§ 比特幣裡主要的共識管理包括挖礦,區塊驗證,交易驗證規則
§ 比特幣的關鍵是在陌生的P2P環境建立共識機制,因此共識管理至關重要。
§ 比特幣的共識管理必須支援前身相容,即使過去的版本有缺陷也要保持,否則會導致比特幣網路出現分叉
○ 規則管理
§ 比特幣的共識規則是所有節點都必須遵守的規則。而每個節點都可以採用一些共識規則以外的修改化規則,這部分規則由規則管理模組實現。
§ 例項:交易存放記憶體池的規則。比如一個節點可以拒絕儲存、中轉大於200KB的交易。
○ 密碼模組
§ 密碼模組主要是處理比特幣的地址,採用RIPEMD和SHA-256演算法以及Base-58編碼來生成比特幣地址。
§ 比特幣的公鑰是通過私鑰產生的,然後通過SHA演算法SHA256和RIPEMD演算法RIPEMD160對公鑰進行處理,最後通過Base58編碼形成比特幣地址
§ Base58類似於Base64,就是過濾了一些容易混淆的字元,比如 數字“0”,O(大寫o),l(小寫L),I(大寫i),“+”,“/"
§ Base58Check的校驗碼對地址資訊進行雙重SHA256雜湊處理,並取前4位做校驗碼,加在比特幣地址後面,因此,比特幣地址帶有校驗資訊,可以防止人為錯誤
○ 簽名模組
§ 比特幣採用橢圓曲線數字簽名演算法(ECDSA)來實現數字簽名以及生成公鑰。
○ 指令碼引擎
§ 比特幣的指令碼語言是一種專門設計的,與”Forth“類似的,基於堆疊的程式設計指令碼語言。
§ 基於堆疊的語言的指令只按順序執行一次,也就是說,沒有迴圈或者跳轉指令。
§ 指令碼指令數會給一個程式執行時間的上限和所需記憶體的上限。
§ 設計原因:防止礦工提交可能有死迴圈的指令碼。
§ 作為一個虛擬貨幣系統,比特幣的這種設計足以滿足需求,還有很大的空間去擴充套件
§ 比特幣的指令碼語言非常小,只能有256個指令,每個指令是一個位元組長。
§ 256個指令中,有75個是保留指令,15個已經廢棄。
§ 很多指令在比特幣網路上不能執行,因為每個節點可以自己的指令碼白名單,只允許執行白名單上的指令。
§ 常見指令如下:
OP_DUP 將堆疊頭上的內容複製一份,並且壓入堆疊
OP_HASH160 彈出堆疊頭內容,先用SHA256對其做雜湊處理,再用RIPEMD-160對結果做第二次雜湊處理,結果壓入堆疊
OP_EQUALVERIFY 彈出堆疊頭上的兩項內容,如果兩個內容一樣,返回”真“值,否則返回”假“值
OP_CHECKSIG 用輸入的公鑰檢查輸入的簽名,如果簽名符合,返回真,否則返回假
OP_CHECKMULTISIG 用提供的多個公鑰檢查多重簽名的正確性
○ 挖礦
§ 比特幣核心不帶挖礦功能
§ 裝置進化史:CPU-->GPU-->FPGA-->ASIC
§ 挖礦進化史:個人礦機-->礦池
§ 挖礦演算法 SHA256演算法
§ 挖礦原理:不斷對區塊報頭進行雜湊處理,每次嘗試改變一個隨機數,直到區塊的報頭的雜湊值符合指定的條件:比如起始必須有多少個零,才算挖到一個合格的區塊。
§ 由於雜湊處理不可逆,也就是不能通過雜湊值反推出輸入值,因此不能預測輸入的引數,只能隨機測試。
§ 比特幣挖礦的難度目標決定網路大約多長時間能夠挖出一個區塊。
§ 平均10分鐘左右能挖出一個區塊,可調整
§ 位元通過調整挖礦難度來調整出塊速度。具體而言,每隔2016個區塊,所有節點都要重新更新比特幣的挖礦難度目標,所以其到2016個區塊所需要的時間應該是20160分鐘,如果實際時間小於20160,說明難度太低,需要加大難度,如果實際時間大於20160,說明難度高,需要降低難度
○ HTTP/JSON RPC伺服器
§ 對外提供HTTP和JSON RPC的介面,外部程式可以通過JSON RPC介面來呼叫比特幣的API,從而達到控制比特幣節點的功能。
○ Berkeley DB和LevelDB資料庫
§ Berkeley DB
□ 比特幣使用Berkeley DB作為錢包資料庫,這是一個開源的檔案資料庫,這是一個輕巧而又效能高的嵌入式資料庫。
□ Berkeley DB可以儲存任意型別的鍵值對,而且可以一個鍵儲存多個數據。
□ Berkeley DB可以支援數千個併發執行緒同時操作資料庫,支援最大256TB資料
□ 比特幣的區塊原始資料不是存放在資料庫中,而只是作為檔案型別儲存在硬碟 上。
§ Level DB
□ Level DB主要用於儲存區塊的索引和UTXO記錄
□ 它是一個非常高效的鍵值資料庫
□ Level DB的資料是冗餘資料,可以用原始區塊資料來重建。但如果沒有Level DB的資料,比特幣的校驗和其它操作都會變得很慢。
○ P2P網路管理
§ 功能:在P2P網路上實現和其他鄰節點的通訊功能。
§ 通訊功能包括:發現鄰節點,連線並管理與鄰節點的Socket連線,與鄰節點交換不同的P2P訊息(區塊和交易),還可以在特殊情況下禁止異常行為的鄰節點連線。
§ 比特幣的預設配置是主動連線8個鄰節點,同時允許最多125個其它鄰節點發起連線請求
§ 防止DoS攻擊:禁止異常行為的鄰節點連線
§ 比特幣節點分類
□ 全功能節點
® 全功能節點帶有錢包,RPC服務端,具有挖礦功能和進行節點校驗區塊和交易,並把區塊和交易跳轉給與之相連線的鄰接點。
□ 基礎全節點
® 基礎全節點也做區塊和交易的交易和中轉,但不挖礦,不帶有錢包和RPC服務端
□ SPV節點
® 校驗過程
◊ SPV節點一般會在與鄰節點的連線中設定過濾器,該過濾器只接收包含錢包裡的公鑰地址的交易。
◊ 當一個鄰節點看到一個交易與SPV節點的過濾器設定的條件符合,它就會用merkelblock訊息來給該SPV節點發送一個區塊。該訊息包含了一個區塊頭和一個連線該交易到Merkle樹根的一個merkle路徑。
◊ SPV節點可以利用該merkle路徑把交易和包含交易的區塊聯絡起來,並驗證交易包含在區塊中。
◊ SPV節點還可以用區塊頭來驗證包含交易的區塊和區塊鏈中的其它區塊能連上。
◊ 通過以上兩個驗證,可以證明交易記錄在區塊連上。
§ ZMO佇列管理
□ 比特幣採用ZMQ作為訊息佇列管理和訊息分發工具。
□ ZMQ是一個比較簡單而且易用的傳輸層,提供一個像框架一樣的socket庫,使得Socket程式設計更加簡單、簡潔,效能更高。
§ ZMQ類似於一個底層的網路通訊庫,在Socket API之上做了一層封裝,將網路通訊、程序通訊和執行緒通訊抽象為統一的API介面。