最近非?;鸬?a target="_blank">區(qū)塊鏈技術對于大家來說應該并不陌生。但是很多人只是了解區(qū)塊鏈技術的一些概念,對其底層的一些技術實現(xiàn)原理可能不是很了解。這篇文章會向你介紹區(qū)塊鏈底層采用的通信網(wǎng)絡技術及其網(wǎng)絡中節(jié)點間的通信協(xié)議。
區(qū)塊鏈的底層網(wǎng)絡技術采用的是peer-to-peer網(wǎng)絡,簡稱P2P網(wǎng)絡。這是一種分布式網(wǎng)絡通信技術,又稱 “對等網(wǎng)絡”。與傳統(tǒng)的客戶端/服務器端(client/server, C/S)結構不同的是,在P2P網(wǎng)絡中各個節(jié)點之間沒有主從之分,地位都是對等的,每一個節(jié)點既可以是服務器端也可以是客戶端。
P2P網(wǎng)絡根據(jù)其路由查詢結構可以分為四種類型,分別是集中式、純分布式、混合式和結構化模型。這四種類型也代表著P2P網(wǎng)絡技術的四個發(fā)展階段。
其中,比特幣采用的身世混合式,而現(xiàn)今公鏈大多采用的是結構化類型。在結構化網(wǎng)絡的具體實現(xiàn)上,大都采用DHT(Distributed Hash Table, 分布式哈希表)算法的思想?;贒HT算法思想的具體實現(xiàn)方案有Chord、Pastry、CAN和Kademlia等算法。其中Kademlia算法是以太坊網(wǎng)絡使用的算法,本文中我們將對其進行詳細描述。
比特幣網(wǎng)絡
區(qū)塊鏈技術最早的使用是在比特幣中,前面我們也說到了,比特幣網(wǎng)絡采用的結構是混合式網(wǎng)絡。
比特幣網(wǎng)絡節(jié)點有四個功能,分別是:錢包、挖礦、區(qū)塊鏈數(shù)據(jù)庫、網(wǎng)絡路由。這四大功能并不是比特幣中所有節(jié)點都包含,不同類型的節(jié)點只包含部分功能,只有比特幣核心(Bitcoin Core)節(jié)點才會包含所有的這四個功能。
依據(jù)其所包含的功能不同節(jié)點的類型也不同,但是所有的節(jié)點都會包含路由功能,因為所有的節(jié)點都要參與校驗和廣播(傳播交易和區(qū)塊信息),并且發(fā)現(xiàn)和維持與其他節(jié)點的連接。
除此之外,一些節(jié)點包含完整的區(qū)塊鏈數(shù)據(jù)庫,數(shù)據(jù)庫中包含所有的交易數(shù)據(jù),這類節(jié)點被稱為 “全節(jié)點(Full Block Chain Node)”。全節(jié)點可以獨立自主的校驗所有交易。
還有一些節(jié)點只包含了部分區(qū)塊鏈數(shù)據(jù),一般只包含區(qū)塊頭,這類節(jié)點通過“簡易支付驗證(SPV)”的方式完成對交易的驗證,該類節(jié)點被稱為“SPV節(jié)點”或者“輕量級節(jié)點”。
礦工節(jié)點是通過在特殊的設備上面運行工作量證明(proof-of-work)算法的方式(挖礦)來相互競爭的生成新的區(qū)塊。
礦工節(jié)點中有些節(jié)點是全節(jié)點,被稱為“獨立礦工(Solo Miner)”,另外一些礦工節(jié)點則需要依賴礦池服務器維護的全節(jié)點進行挖礦工作,這類礦工被稱為“礦池礦工(Pool Miner)”,礦池礦工與礦池服務器形成礦池(Mining Pool),這是一個局部的集中式網(wǎng)絡。它們之間通過特殊的礦池協(xié)議進行通信。
目前主流的礦池協(xié)議是Stratum協(xié)議。錢包功能一般是幫助用戶來查看自己的余額、管理公私鑰對以及發(fā)起交易,在比特幣網(wǎng)絡中除了比特幣核心錢包是全節(jié)點之外,大部分的錢包都是輕量級節(jié)點。
一個包含了各種節(jié)點,不同節(jié)點之間運行著比特幣主網(wǎng)絡協(xié)議、Stratum網(wǎng)絡協(xié)議和其他礦池網(wǎng)絡協(xié)議的比特幣擴展網(wǎng)絡如下圖所示:
以太坊網(wǎng)絡
以太坊作為新一代以區(qū)塊鏈作為底層技術的平臺,在很多方面與比特幣很類似,其節(jié)點同樣具有錢包、挖礦、區(qū)塊鏈數(shù)據(jù)庫和路由四大功能、同樣也是由于節(jié)點包含不同的功能而將其分為不同的類型、同樣除了主網(wǎng)絡之外還存在著許多的擴展網(wǎng)絡。但是,與比特幣不同的是其底層網(wǎng)絡結構,比特幣主網(wǎng)的P2P網(wǎng)絡是無結構的,而以太坊使用P2P網(wǎng)絡是有結構的,其P2P網(wǎng)絡通過Kademlia(簡稱Kad)算法來實現(xiàn)。Kad算法作為DHT(分布式哈希表)技術的一種,可以在分布式環(huán)境下實現(xiàn)快速而又準確的路由和定位數(shù)據(jù)的功能。下面我們著重講一下Kad算法的基本內(nèi)容。
Kad算法作為一種分布式數(shù)據(jù)存儲及路由發(fā)現(xiàn)算法,因其具有簡單性、靈活性、安全性的特點,被以太坊用作底層P2P網(wǎng)絡的主要算法。下面我們將通過一個例子來形象的說明Kad算法的主要內(nèi)容及其運行過程。
問題描述與場景假設
我們假設這樣一個場景:有若干圖書供同學們共享,為了公平起見每個人保存其中的幾本,如果你想要看其他的書,就需要向保存這本書的學生來借。那么問題是我們怎么能找到保存著這本書的學生呢?如果一個一個去問的話,效率顯然極低。將這個問題放到P2P網(wǎng)絡中,就是一個節(jié)點如果需要某個資源,它怎么獲取這個資源?怎么快速地找到存儲該資源的節(jié)點?
節(jié)點信息
就像我們在學校中對每一個學生有著唯一的標識一樣,在Kad算法中給每個節(jié)點設置了幾個屬性來唯一標識一個節(jié)點,分別是:節(jié)點ID、IP地址、端口號。對應到我們的例子中就是:節(jié)點ID對應著學生的學號,IP地址和端口號對應著學生的聯(lián)系方式(電話號或者家庭住址)。
每個學生(節(jié)點)手中有以下信息:
· 分配給其的圖書信息(分配到節(jié)點上的資源信息)。這里的信息指的是書名的hash值和書本的內(nèi)容(對于節(jié)點資源中理解為資源的索引和資源的內(nèi)容,將其以《key, value》的形式存儲在節(jié)點上)。
· 一個通訊錄,里面存儲著若干條記錄,每條記錄是某本書的書名hash值和存儲這本書的學生的學號和聯(lián)系方式(一張路由表,每個路由項里面存儲著某個資源的索引和存儲該資源的節(jié)點信息,在Kad算法中,這個路由表稱為“K-bucket”,后面我們將對“K-bucket”進行詳細的介紹)。值得注意的是,這里每個學生存儲的只是一部分同學的聯(lián)系方式(節(jié)點的路由表中只存儲著一部分節(jié)點的信息)。
資源存儲及查找
那么問題來了,我們應該如何將書本分發(fā)給各個同學呢(將資源分配到節(jié)點上)?
在Kad算法中它是這樣做的:將每本書的書名做一個hash計算,將得到書名的hash值作為書本的索引,然后在書本的索引與節(jié)點ID之間建立一個映射。如果一本書的hash值為000110,那么這本書就會被分配給學號為000110的學生。(這就要求hash算法的值域和節(jié)點ID的取值范圍是一致的,在以太坊中,節(jié)點ID的是256位二進制。因為以太坊中采用的hash算法是sha-3,結果長度為256位二進制)
那這里就會有人問了,萬一某一個學生聯(lián)系不上了(節(jié)點下線或者退出網(wǎng)絡)那么豈不是他保存的書(資源)就沒有辦法獲得了?為了解決這個問題,Kad算法采取的方法是將這本書的副本存儲在學號與000110最接近的若干位學生手里,這樣學號為000111、000101等若干學生手里也會有這本書(在節(jié)點中就是將相同的資源存儲在與目標節(jié)點ID最接近的幾個節(jié)點上)。
當你需要找到這本書的時候,你只要對書名進行hash,就可以知道你要找的是哪一(幾)個學生的聯(lián)系方式了(對于節(jié)點中資源來說,我們只需要計算得到資源索引就可以知道要找哪一個或者哪幾個節(jié)點了)。
節(jié)點定位
我們已經(jīng)知道應該找哪一(幾)個學生來獲得圖書,那么接下來的問題就是怎么找到他們的聯(lián)系方式。這里我們對Kad算法中的路由表--“K-bucket”進行介紹,作為一張路由表,K-bucket里面存儲的就是節(jié)點的路由信息,但是和一般的路由表不一樣的是,在K-bucket中是通過距離來對節(jié)點進行分類的,如圖3所示。這里提到了節(jié)點間的距離問題。我們先來看下在kad算法中是如何計算兩節(jié)點間的距離的。
Kad算法中節(jié)點間的距離是邏輯距離,這個邏輯距離是通過對節(jié)點ID進行異或來計算的。目標節(jié)點到本節(jié)點的距離在[2(i-1), 2i)范圍內(nèi)時,該節(jié)點被歸為 “K-bucket i”。比如節(jié)點ID為000111的節(jié)點與節(jié)點ID為000110、000011的節(jié)點之間的距離計算為:000111 ? 000110 = 000001(十進制1)、000111 ? 000011 = 000100(十進制4)。那么按照上述的算法就是,在節(jié)點ID為000111的K-bucket中,節(jié)點ID為000110的節(jié)點被分配到“K-bucket 1”中、節(jié)點ID為000011的節(jié)點被分配到“K-bucket 3”中。
其實這種使用異或來計算距離的方式,相當于將整個網(wǎng)絡拓撲組織成一顆二叉前綴樹如圖4所示。這里所有的節(jié)點都分布在二叉前綴樹的葉子節(jié)點上,這種組織形式相當于按其節(jié)點ID的每一位對節(jié)點距離進行分類。
以圖中的編號為110的節(jié)點為例,因為節(jié)點000、001、010是第三位(從右往左數(shù))與110不同,因此這三個節(jié)點就被分配到110 的“K-bucket 3”中,節(jié)點ID為100、101的節(jié)點因為是第二位(從右往左數(shù))與110不同,因此這兩個節(jié)點就被分配到110 的“K-bucket 2”中,最后節(jié)點ID為111的節(jié)點因為是第一位(從右往左數(shù))與110 不同,因此它就被安排到110的“K-bucket 1”中。
回到以太坊中,在前面已經(jīng)提到了每個節(jié)點ID是256位長,因此在以太坊中的節(jié)點的K-bucket大小分配為256行每行最多存儲16節(jié)點的路由信息。
通過前面的內(nèi)容我們已經(jīng)知道了找到另一個學生聯(lián)系方式(節(jié)點間的距離計算)的方法以及每個學生存儲的通訊錄是怎樣的的結構(節(jié)點中K-bucket的存儲結構)。那我們就來找一本書來看一下在Kad算法中查找某一確定節(jié)點的方式是怎樣的。
學號為000111 的A同學想要找一本名叫《西游記》的書(節(jié)點ID為000111的節(jié)點想要找到某一個特定的資源),他首先通過對書名計算hash值來得到這本書的索引(得到資源的索引),經(jīng)過計算得到《西游記》的hash值為001011,那么他就知道這本書被保存在學號為001011的B學生手里。接著,A同學就計算與這個學生的距離來查找他的通訊錄(節(jié)點計算目標節(jié)點與自己的距離,在K-bucket中查找否有目標節(jié)點),經(jīng)過異或計算:000111 &001011 = 001100(十進制12),經(jīng)過計算發(fā)現(xiàn)這個距離12位于[23, 24)這個區(qū)間中,因此A同學就去他的通訊錄的第4行去找有沒有B同學的聯(lián)系方式:
· 如果有--就直接聯(lián)系B向他借書;
· 如果沒有--就隨便找一個也在第4行的C同學與其取得聯(lián)系,讓C同學在自己的通訊錄中使用同樣的方法找一下是否有B同學的聯(lián)系方式。這里這樣做的原因是C同學學號的第四位(從右往左數(shù))一定與B同學學號的第四位一樣,因此邏輯上C同學距離B同學的距離一定比A同學距離B同學要近。那么就會出現(xiàn)兩種情況:
--如果C同學有B同學聯(lián)系方式,那么他就將B同學的聯(lián)系方式告訴A同學。
--如果沒有,那么C同學就將與B同學在通訊錄的同一行的另一位D同學的聯(lián)系方式告訴A同學,之后A同學在將D同學的聯(lián)系方式存儲起來后與D同學聯(lián)系,進行下一步查找。以此遞歸下去直到找到B同學為止。
這時有人就會問,上面提到一本書不是不僅僅保存在一個同學手里嗎?我們?yōu)槭裁捶且驼疫@一個同學?這是因為上面我們描述的是通過一個確定的節(jié)點ID來查找另一個節(jié)點的過程,對應著Kad算法中的FIND_NODE指令,當然問題中提到的做法是Kad算法中的另一個指令FIND_VALUE。這個指令是通過資源的索引值來搜索指定的資源,其操作過程與FIND_NODE非常類似,最后終止的條件就是有某一個節(jié)點返回了我們要查找的資源數(shù)據(jù)即可。
值得一提的是,K-bucket的這種更新機制是只有老的節(jié)點失效后,才會將新節(jié)點加入到K-bucket中,這樣做會保證在線時間長的節(jié)點會有更大概率被保留,增加了網(wǎng)絡的穩(wěn)定性,避免網(wǎng)絡中節(jié)點因大量新節(jié)點加入更新K-bucket而出現(xiàn)拒絕服務的情況。
總結
以上就是本文分享的所有內(nèi)容,我們先介紹了P2P網(wǎng)絡的基本知識,然后介紹了比特幣網(wǎng)絡的相關內(nèi)容,最后著重介紹了以太坊網(wǎng)絡中Kademlia算法的相關內(nèi)容。
Trias中的goosip協(xié)議與Kad算法比較相關。相對于我們今天講的Kad算法來說,二者對應的層面是不同的,Kad算法更接近底層,而goosip協(xié)議偏高層一點,底層Kad算法在開始將節(jié)點的路由表(K-bucket)創(chuàng)建好為goosip協(xié)議做準備,當goosip協(xié)議挑選a個節(jié)點進行廣播同步信息時,Kad算法可以保證這a個節(jié)點都收到消息并將其存儲下來。
評論