比特幣是一種基于P2P網(wǎng)絡(luò)的加密數(shù)字貨幣银还,本文將從P2P技術(shù)的角度來講解比特幣的架構(gòu)和實(shí)現(xiàn)蟋恬,通過跟傳統(tǒng)P2P應(yīng)用的對比,分析比特幣的不同之處年缎,以及這些差異點(diǎn)如何影響比特幣的設(shè)計。
P2P技術(shù)
Peer-to-Peer技術(shù)可以在客戶端節(jié)點(diǎn)之間直接建立聯(lián)系矾睦,進(jìn)行數(shù)據(jù)的分發(fā)晦款,從而減少Client-Server模式下的服務(wù)器和帶寬的消耗。這樣不僅可以用更少的服務(wù)器資源為更大規(guī)模的用戶提供服務(wù)枚冗,甚至還可以完全不用服務(wù)器的介入缓溅,純粹通過用戶節(jié)點(diǎn)的互聯(lián)來進(jìn)行資源的發(fā)布和分享,進(jìn)而衍生出各種有趣的應(yīng)用赁温。
傳統(tǒng)的P2P應(yīng)用最常見的有三個領(lǐng)域:文件下載坛怪、視頻播放、VoIP通信股囊。文件下載領(lǐng)域有BitTorrent袜匿、eMule、迅雷等稚疹,視頻播放領(lǐng)域有pplive居灯、ppstream等,VoIP領(lǐng)域有Skype内狗、YY語音等怪嫌。
P2P應(yīng)用主要包含兩個層面,一是P2P網(wǎng)絡(luò)的建立和維護(hù)柳沙,二是在P2P網(wǎng)絡(luò)上分發(fā)數(shù)據(jù)岩灭。前者包括peer的發(fā)現(xiàn)、peer地址池管理赂鲤、peer連接的建立和管理噪径、peer之間的通信機(jī)制。后者包括數(shù)據(jù)的性質(zhì)(用途数初、來源找爱、格式等)、索引方式泡孩、校驗(yàn)缴允、數(shù)據(jù)在內(nèi)存、磁盤上的存儲和在網(wǎng)絡(luò)上的傳輸?shù)取H绻f前者是P2P應(yīng)用的基礎(chǔ)练般,那么后者就是P2P應(yīng)用的核心。對不同的應(yīng)用來說锈候,P2P網(wǎng)絡(luò)部分的架構(gòu)差別較小薄料,只在實(shí)現(xiàn)細(xì)節(jié)上會有一些不同的選擇,而數(shù)據(jù)上的差別則往往決定著架構(gòu)設(shè)計和實(shí)現(xiàn)方案上的不同泵琳。
因?yàn)槲覍oIP了解有限摄职,下面就以文件下載和視頻播放為例來做對比分析。
P2P網(wǎng)絡(luò)的搭建和維護(hù)
1 peer發(fā)現(xiàn)
文件下載和視頻播放應(yīng)用一般都是通過tracker之類的服務(wù)器來獲取初始的peer地址列表获列,比特幣也是類似谷市,通過查詢dns seeds來獲取初始節(jié)點(diǎn)地址。另外击孩,由于比特幣的很多節(jié)點(diǎn)會長時間不間斷運(yùn)行迫悠,所以還會把這些節(jié)點(diǎn)地址保存在本地,下次啟動時直接嘗試連接巩梢。
2 peer連接建立和管理
P2P應(yīng)用都會監(jiān)聽網(wǎng)絡(luò)端口创泄,接收其它peer的連接請求,同時也會向其它peer發(fā)起連接括蝠。連接建立后鞠抑,會交換peer信息,進(jìn)入P2P協(xié)議層的握手階段忌警。握手成功后搁拙,就可以跟這個peer正常通信,包括分發(fā)數(shù)據(jù)等法绵。
對正在握手的peer和已經(jīng)握手成功的peer箕速,需要進(jìn)行監(jiān)控管理,檢查通信超時和各種狀態(tài)異常礼烈,踢掉一些狀態(tài)較差的節(jié)點(diǎn)弧满,嘗試連接一些新的節(jié)點(diǎn),從而保持足夠數(shù)量的狀態(tài)較好的peer連接此熬,以進(jìn)行高效的數(shù)據(jù)分發(fā)庭呜。
3 地址交換
握手成功的peer之間可以交換peer地址信息,以獲取更多可連接的peer犀忱。
4 地址池
從tracker或dns seeds查詢到的和通過地址交換得到的peer地址都會加入地址池來管理募谎。peer連接管理模塊會不斷從地址池選擇peer發(fā)起連接。地址池還會記錄peer的通信歷史阴汇,對狀態(tài)較差或有問題的peer数冬,降低其重連的優(yōu)先級。
數(shù)據(jù)分發(fā)
前面的網(wǎng)絡(luò)部分是P2P應(yīng)用的共同之處,這一節(jié)的數(shù)據(jù)部分則是它們的差異之所在拐纱,也是這篇文章講述的重點(diǎn)铜异。
數(shù)據(jù)的用途和來源
比特幣特殊之處在于數(shù)據(jù)的用途和來源。比特幣的數(shù)據(jù)是交易信息秸架,因?yàn)樯婕暗截泿藕唾Y產(chǎn)揍庄,所以對數(shù)據(jù)的安全性要求很高,需要做比較強(qiáng)的校驗(yàn)东抹。而交易數(shù)據(jù)由各個節(jié)點(diǎn)自行生成蚂子,是完全去中心化的,這導(dǎo)致交易數(shù)據(jù)無法保持順序性缭黔,使得數(shù)據(jù)的索引方式變得更復(fù)雜食茎,后面會進(jìn)一步分析這一點(diǎn)。
文件下載和視頻播放等應(yīng)用對安全性的要求就沒那么高馏谨,而且它們的數(shù)據(jù)要么事先生成好别渔,并通過可信渠道發(fā)布(例如BT中torrent文件的生成和發(fā)布),要么由單個特殊的節(jié)點(diǎn)來生成和發(fā)布(例如視頻播放里的發(fā)布節(jié)點(diǎn)或源節(jié)點(diǎn))田巴,這樣更容易保證數(shù)據(jù)的權(quán)威性和順序性钠糊,所以對數(shù)據(jù)進(jìn)行簽名校驗(yàn)和順序編號就可以使系統(tǒng)正常運(yùn)轉(zhuǎn)。
數(shù)據(jù)格式
對BT文件下載來說壹哺,數(shù)據(jù)就是一個文件或目錄抄伍,目錄也會被視為由各個子目錄和文件拼接成的單個虛擬文件,所以BT的數(shù)據(jù)可以被抽象成單個的有限長度的字節(jié)數(shù)組管宵。對于單個文件的視頻點(diǎn)播來說截珍,數(shù)據(jù)性質(zhì)跟文件下載一樣;對于某些格式的直播和HLS的點(diǎn)播來說箩朴,情況要復(fù)雜一些岗喉,因?yàn)槭芟抻诿襟w格式的幀劃分的邊界,一般可以抽象成順序的不定長的小文件列表炸庞。
比特幣的數(shù)據(jù)格式比較不一樣钱床,它既不像BT里純粹的字節(jié)數(shù)組,也不像視頻點(diǎn)播和直播里附帶媒體信息的字節(jié)數(shù)組和字節(jié)流埠居,而是結(jié)構(gòu)化的交易數(shù)據(jù)查牌。
數(shù)據(jù)標(biāo)識和索引方式
就像網(wǎng)頁需要以URL(Uniform Resource Locator)為指引才能訪問一樣,P2P里的數(shù)據(jù)也需要先被標(biāo)識和索引滥壕,然后才能進(jìn)行分發(fā)纸颜。
文件下載和視頻播放采用的是3個級別的索引。首先绎橘,一個文件下載任務(wù)和一個視頻節(jié)目都是一個獨(dú)立的資源胁孙,分發(fā)這個資源的peer獨(dú)立成網(wǎng),跟其它資源的peer一般不需要發(fā)生關(guān)聯(lián)。其次涮较,資源內(nèi)部再進(jìn)一步做切片和索引稠鼻,例如BT里的文件會被切分成定長的piece,從0開始順序編號狂票,作為傳輸和存儲的基本單位枷餐。最后piece內(nèi)部還會進(jìn)一步劃分成更小的block,作為下載調(diào)度的單位苫亦。視頻播放里的單文件點(diǎn)播也跟BT一樣,直播(包括HLS直播)和HLS點(diǎn)播里則可以把每個不定長的小文件視為一個piece怨咪,進(jìn)行順序編號屋剑,piece內(nèi)部一樣做定長切片,作為下載調(diào)度的單位诗眨。有了這3級索引唉匾,就可以唯一的標(biāo)識P2P網(wǎng)絡(luò)上傳輸?shù)囊粋€數(shù)據(jù)片。
比特幣里采用的是2級索引匠楚。比特幣不像前面那樣按任務(wù)和節(jié)目劃分網(wǎng)絡(luò)巍膘,而是所有的peer都屬于同一個網(wǎng)絡(luò)。在這個網(wǎng)絡(luò)里分發(fā)的數(shù)據(jù)有第一級的Block和第二級的Transaction芋簿。
由于比特幣交易數(shù)據(jù)的生成是完全去中心化的峡懈,所以無法像文件下載和視頻播放應(yīng)用里那樣對切片數(shù)據(jù)做順序的編號和順序的存儲,只能以數(shù)據(jù)的hash作為唯一標(biāo)識与斤,并以鏈表而非數(shù)組的方式建立順序的關(guān)聯(lián)肪康。這樣就得到了區(qū)塊鏈這種特殊的數(shù)據(jù)結(jié)構(gòu)。
區(qū)塊鏈并不是簡單的把索引方式從數(shù)值變?yōu)閔ash撩穿,把數(shù)據(jù)結(jié)構(gòu)從數(shù)組/字典變成鏈表磷支,而是由于鏈表分叉的存在,導(dǎo)致區(qū)塊鏈實(shí)際上變成了區(qū)塊“樹”食寡,所以比特幣的實(shí)現(xiàn)變得更復(fù)雜雾狈,例如在數(shù)據(jù)儲方面,不僅要以hash為key存儲所有的BlockIndex抵皱,還需要選擇和記錄最長(累積工作量最大)的已驗(yàn)證區(qū)塊鏈表善榛,并按區(qū)塊高度做順序存儲;還有叨叙,下載Header時锭弊,需要提供已有Header的區(qū)塊鏈路徑采樣做參考,也就是代碼里的BlockLocator擂错。但另一方面味滞,基于分叉和側(cè)鏈,也可以產(chǎn)生很多新的應(yīng)用。
數(shù)據(jù)同步
在P2P網(wǎng)絡(luò)中剑鞍,peer一般需要廣播自己有哪些(新)數(shù)據(jù)昨凡,以方便別的peer來下載。例如BT里會發(fā)送bitfield和have報文蚁署,視頻播放應(yīng)用里一般也有類似報文便脊。比特幣由于有大量的歷史數(shù)據(jù),所以歷史數(shù)據(jù)不用廣播光戈,通過直接先下載BlockHeader數(shù)據(jù)的方式來探測哪痰,對最新的交易數(shù)據(jù),用inv報文來廣播久妆。
知道別的peer有哪些數(shù)據(jù)后晌杰,就可以開始下載。BT一般采用分散化的下載調(diào)度筷弦,以促進(jìn)全網(wǎng)數(shù)據(jù)分布的健康度肋演。視頻播放在采取順序下載調(diào)度,從用戶觀看位置點(diǎn)開始做預(yù)下載烂琴。
比特幣的數(shù)據(jù)下載過程就要麻煩一些爹殊,因?yàn)樗臄?shù)據(jù)格式更復(fù)雜,既有Block又有Transaction奸绷。而且由于Block尺寸大梗夸,數(shù)量多,不適合放在內(nèi)存中做處理健盒,所以引入了BlockHeader和BlockIndex這些索引數(shù)據(jù)绒瘦。在較新版bitcoin core中,一般先下載所有的BlockHeader扣癣,然后再開始下載Block惰帽,這個過程被稱為Initial Block Download。
BlockHeader是區(qū)塊的頭信息父虑,包括前向區(qū)塊的哈希该酗、merkle根哈希、時間戳和其它驗(yàn)證PoW需要用到的數(shù)據(jù)士嚎。BlockIndex是在BlockHeader基礎(chǔ)上呜魄,根據(jù)區(qū)塊鏈狀態(tài)計算出的區(qū)塊索引信息,包括區(qū)塊的高度和前向BlockIndex的指針等莱衩。BlockHeader用于在P2P網(wǎng)絡(luò)中傳播爵嗅,BlockIndex則用于節(jié)點(diǎn)內(nèi)部做索引和各種處理。因?yàn)锽lockIndex比較小笨蚁,可以全部放在內(nèi)存里睹晒,同時趟庄,它還會被寫到磁盤的block/index數(shù)據(jù)庫中,供程序下次啟動后加載使用伪很。
BlockHeader下載完后戚啥,就可以開始下載Block。根據(jù)已有的BlockIndex信息锉试,尋找合適的幾個peer猫十,以Block的哈希值為索引來下載Block數(shù)據(jù)。對下載到的Block數(shù)據(jù)進(jìn)行各種校驗(yàn)呆盖,包括驗(yàn)證Double-Spending和交易腳本簽名等拖云,校驗(yàn)通過的Block可以從中提取Coin(UTXO)信息,記錄到chainstate數(shù)據(jù)庫中应又,供以后校驗(yàn)新的交易江兢。
沒有被納入Block的交易也可以通過廣播后被下載,然后一邊在通過驗(yàn)證后繼續(xù)轉(zhuǎn)發(fā)丁频,一邊存入交易池中等待做其它處理。
總結(jié)
比特幣和其它P2P應(yīng)用相比邑贴,在P2P網(wǎng)絡(luò)方面并沒有明顯的差別席里,但由于比特幣交易數(shù)據(jù)的生成是完全去中心化的和無序的,所以不能像文件下載和視頻播放應(yīng)用里那樣做順序的編號處理拢驾,只能簡單的以鏈表的形式關(guān)聯(lián)起來奖磁,這樣就形成了區(qū)塊鏈這種數(shù)據(jù)結(jié)構(gòu)。