物數鏈狀態轉換函式:APPLY(S,TX) -> S’,可以定義如下:
1 檢查交易的格式是否正確(即有正確數值)、簽名是否有效和隨機數是否與傳送者賬戶的隨機數匹配。如否,返回錯誤。
2 計算交易費用:fee=STARTGAS * GASPRICE,並從簽名中確定傳送者的地址。從傳送者的賬戶中減去交易費用和增加傳送者的隨機數。如果賬戶餘額不足,返回錯誤。
3 設定初值 GAS = STARTGAS,並根據交易中的位元組數減去一定量的燃料值。
4 從傳送者的賬戶轉移價值到接收者賬戶。如果接收賬戶還不存在,建立此賬戶。如果接收賬戶是一個合約,執行合約的程式碼,直到程式碼執行結束或者燃料用完。
5 如果因為傳送者賬戶沒有足夠的錢或者程式碼執行耗盡燃料導致價值轉移失敗,恢復原來的狀態,但是還需要支付交易費用,交易費用加至礦工賬戶。
6 否則,將所有剩餘的燃料歸還給傳送者,消耗掉的燃料作為交易費用傳送給礦工。
例如,假設合約的程式碼如下:
if !contract.storage[msg.data[0]]:
contract.storage[msg.data[0]] = msg.data[1]
需要注意的是,在現實中合約程式碼是用底層虛擬機器程式碼寫成的。假設合約儲存器開始時是空的,一個值為 10 個幣,燃料為 2000,燃料價格為 0.001 個幣並且兩個資料欄位值為[ 2, ‘CHARLIE’ ] [3]的交易傳送後,狀態轉換函式的處理過程如下:
1 檢查交易是否有效、格式是否正確。
2 檢查交易傳送者至少有 2000*0.001=2 個幣。如果有,從傳送者賬戶中減去 2個幣。
3 初始設定 gas=2000,假設交易長為 170 位元組,每位元組的費用是 5,減去 850,所以還剩 1150。
4 從傳送者賬戶減去 10 個幣,為合約賬戶增加 10 個幣。
5 執行程式碼。在這個合約中,執行程式碼很簡單:它檢查合約儲存器索引為 2 處是否已使用,注意到它未被使用,然後將其值置為 CHARLIE。假設這消耗了 187 單位的燃料,於是剩餘的燃料為 1150 – 187 = 963。
6. 向傳送者的賬戶增加 963*0.001=0.963 個幣,返回最終狀態。
如果沒有合約接收交易,那麼所有的交易費用就等於 GASPRICE 乘以交易的位元組長度,交易的資料就與交易費用無關了。另外,需要注意的是,合約發起的訊息可以對它們產生的計算分配燃料限額,如果子計算的燃料用完了,它只恢復到訊息發出時的狀態。因此,就像交易一樣,合約也可以透過對它產生的子計算設定嚴格的限制,保護它們的計算資源。
5 程式碼執行
物數鏈合約的程式碼使用低階的基於堆疊的位元組碼的語言寫成的,被稱為“物數鏈虛擬機器程式碼”。程式碼由一系列位元組構成,每一個位元組代表一種操作。一般而言,程式碼執行是無限迴圈,程式計數器每增加一(初始值為零)就執行一次操作,直到程式碼執行完畢或者遇到錯誤,STOP 或者 RETURN 指令。操作可以訪問三種儲存資料的空間:
●堆疊,一種後進先出的資料儲存,32 位元組的數值可以入棧,出棧。
●記憶體,可無限擴充套件的位元組佇列。
●合約的長期儲存,一個秘鑰/數值的儲存,其中秘鑰和數值都是 32 位元組大小,與計算結束即重置的堆疊和記憶體不同,儲存內容將長期保持。
程式碼可以象訪問區塊頭資料一樣訪問數值,傳送者和接受到的訊息中的資料,程式碼還可以返回資料的位元組佇列作為輸出。
虛擬機器程式碼的正式執行模型令人驚訝地簡單。當物數鏈虛擬機器執行時,它的完整的計算狀態可以由元組(block_state, transaction, message, code, memory, stack, pc, gas)來定義,這裡 block_state 是包含所有賬戶餘額和儲存的全域性狀態。每輪執行時,透過調出程式碼的第 pc(程式計數器)個位元組,當前指令被找到,每個指令都有定義自己如何影響元組。例如,ADD 將兩個元素出棧並將它們的和入棧,將 gas(燃料)減一併將 pc 加一,SSTORE 將頂部的兩個元素出棧並將第二個元素插入到由第一個元素定義的合約儲存位置,同樣減少最多 200 的 gas 值並將 pc 加一,雖然有許多方法透過即時編譯去最佳化,但物數鏈的基礎性的實施可以用幾百行程式碼實現。
6 區塊鏈和挖礦
雖然有一些不同,但物數鏈的區塊鏈在很多方面類似於比特幣區塊鏈。它們的區塊鏈架構的不同在於,物數鏈區塊不僅包含交易記錄和最近的狀態,還包含區塊序號和難度值。物數鏈中的區塊確認演算法如下:
1 檢查區塊引用的上一個區塊是否存在和有效。
2 檢查區塊的時間戳是否比引用的上一個區塊大,而且小於 2 分鐘。
3 檢查區塊序號、難度值、 交易根,叔根和燃料限額(許多以太坊特有的底層概念)是否有效。
4 檢查區塊的工作量證明是否有效。
5 將 S[0]賦值為上一個區塊的 STATE_ROOT。
6 將 TX 賦值為區塊的交易列表,一共有 n 筆交易。對於屬於 0……n-1 的 i,進行狀態轉換 S[i+1] = APPLY(S[i],TX[i])。如果任何一個轉換髮生錯誤,或者程式執行到此處所花費的燃料(gas)超過了 GASLIMIT,返回錯誤。
7 用 S[n]給 S_FINAL 賦值, 向礦工支付區塊獎勵。
8 檢查 S-FINAL 是否與 STATE_ROOT 相同。如果相同,區塊是有效的。否則,區塊是無效的。
物數鏈確認效率遠超比特幣相提並論。原因是狀態儲存在樹結構中(tree structure),每增加一個區塊只需要改變樹結構的一小部分。因此,一般而言,兩個相鄰的區塊的樹結構的大部分應該是相同的,因此儲存一次資料,可以利用指標(即子樹雜湊)引用兩次。一種被稱為“帕特里夏樹”(“Patricia Tree”)的樹結構可以實現這一點,其中包括了對默克爾樹概念的修改,不僅允許改變節點,而且還可以插入和刪除節點。
應用一般來講,物數鏈之上一個完美的例子是為解決物流資訊共享問題而設的自我強制懸賞。透過獨創的環形計算(annular calculate)將資料分享做成一個標準化共識,改進區塊鏈的識別和共識獎勵。
7 改進版幽靈協議
幽靈協議提出的動機是當前快速確認的塊鏈因為區塊的高作廢率而受到低安全性困擾;因為區塊需要花一定時間(設為 t)擴散至全網,如果礦工 A 挖出了一個區塊然後礦工 B 碰巧在 A 的區塊擴散至 B 之前挖出了另外一個區塊,礦工 B 的區塊就會作廢並且沒有對網路安全作出貢獻。此外,這裡還有中心化問題:如果 A 是一個擁有全網 30%算力的礦池而 B 擁有 10%的算力,A 將面臨 70%的時間都在產生作廢區塊的風險而 B 在 90%的時間裡都在產生作廢區塊。因此,如果作廢率高,A 將簡單地因為更高的算力份額而更有效率,綜合這兩個因素,區塊產生速度快的塊鏈很可能導致一個礦池擁有實際上能夠控制挖礦過程的算力份額。透過在計算哪條鏈“最長”的時候把廢區塊也包含進來,幽靈協議解決了降低網路安全性的第一個問題;這就是說,不僅一個區塊的父區塊和更早的祖先塊,祖先塊的作廢的後代區塊也被加進來以計算哪一個區塊擁有支援其的最大工作量證明。物數鏈付給以“叔區塊”身份為新塊確認作出貢獻的廢區塊 87.5%的獎勵,把它們納入計算的“侄子區塊” 將獲得獎勵的 12.5%,不過,交易費用不獎勵給叔區塊。
物數鏈實施了一個只下探到第五層的簡化版本的幽靈協議。其特點是,廢區塊只能以叔區塊的身份被其父母的第二代至第五代後輩區塊,而不是更遠關係的後輩區塊(例如父母區塊的第六代後輩區塊,或祖父區塊的第三代後輩區塊)納入計算。這樣做有幾個原因。首先,無條件的幽靈協議將給計算給定區塊的哪一個叔區塊合法帶來過多的複雜性。其次,帶有物數鏈所使用的補償的無條件的幽靈協議剝奪了礦工在主鏈而不是一個公開攻擊者的鏈上挖礦的激勵。最後,計算表明帶有激勵的五層幽靈協議即使在出塊時間為 15s 的情況下也實現了了 95%以上的效率,而擁有 25%算力的礦工從中心化得到的益處小於 3%。
費用因為每個釋出到區塊鏈的交易都佔用了下載和驗證的成本,需要有一個包括交易費的規範機制來防範濫發交易。比特幣使用的預設方法是純自願的交易費用,依靠礦工擔當守門人並設定動態的最低費用。因為這種方法是“基於市場的”,使得礦工和交易傳送者能夠按供需來決定價格,所以這種方法在比特幣社羣被很順利地接受了。然而,這個邏輯的問題在於,交易處理並非一個市場;雖然根據直覺把交易處理解釋成礦工給傳送者提供的服務是很有吸引力的,但事實上一個礦工收錄的交易是需要網路中每個節點處理的,所以交易處理中最大部分的成本是由第三方而不是決定是否收錄交易的礦工承擔的。於是,非常有可能發生公地悲劇。
然而,當給出一個特殊的不夠精確的簡化假設時,這個基於市場的機制的漏洞很神奇地消除了自己的影響。論證如下。假設:
1 一個交易帶來 k 步操作, 提供獎勵 kR 給任何收錄該交易的礦工,這裡 R 由交易釋出者設定, k 和 R 對於礦工都是事先(大致上)可見的。
2 每個節點處理每步操作的成本都是 C (即所有節點的效率一致)。
3 有 N 個挖礦節點,每個算力一致(即全網算力的 1/N)。
4 沒有不挖礦的全節點。
當預期獎勵大於成本時,礦工願意挖礦。這樣,因為礦工有 1/N 的機會處理下一個區塊,所以預期的收益是 kR/N , 礦工的處理成本簡單為 kC. 這樣當 kR/N >kC,即 R > NC 時。礦工願意收錄交易。注意 R 是由交易傳送者提供的每步費用,是礦工從處理交易中獲益的下限。 NC 是全網處理一個操作的成本。所以,礦工僅有動機去收錄那些收益大於成本的交易。
然而,這些假設與實際情況有幾點重要的偏離:
1.因為額外的驗證時間延遲了塊的廣播因而增加了塊成為廢塊的機會,處理交易的礦工比其它的驗證節點付出了更高的成本。
2.不挖礦的全節點是存在的。
3.實踐中算力分佈可能最後是極端不平均的。
4.以破壞網路為己任的投機者,政敵和瘋子確實存在,並且他們能夠聰明地設定合同使得他們的成本比其它驗證節點低得多。
上面第 1 點驅使礦工收錄更少的交易,第 2 點增加了 NC; 因此這兩點的影響至少部分互相抵消了. 第 3 點和第 4 點是主要問題;作為解決方案我們簡單地建立了一個浮動的上限:沒有區塊能夠包含比 BLK_LIMIT_FACTOR 倍長期指數移動平均值更多的運算元。具體地:
blk.oplimit = floor((blk.parent.oplimit * (EMAFACTOR – 1) + floor(parent.opcount* BLK_LIMIT_FACTOR)) /EMA_FACTOR) BLK_LIMIT_FACTOR 和 EMA_FACTOR 是暫且被設為 65536 和 1.5 的常數,但可能會在更深入的分析後調整。
8 計算和圖靈完備
需要強調的是物數鏈虛擬機器是圖靈完備的; 這意味著虛擬機器程式碼可以實現任何可以想象的計算,包括無限迴圈。物數鏈虛擬機器程式碼有兩種方式實現迴圈。首先,JUMP 指令可以讓程式跳回至程式碼前面某處,還有允許如 while x < 27: x = x * 2 一樣的條件語句的 JUMPI 指令實現條件跳轉。其次,合約可以呼叫其它合約,有透過遞迴實現迴圈的潛力。這很自然地導致了一個問題:惡意使用者能夠透過迫使礦工和全節點進入無限迴圈而不得不關機嗎? 這問題出現是因為電腦科學中一個叫停機問題的問題:一般意義上沒有辦法知道,一個給定的程式是否能在有限的時間內結束執行。
我們的方案透過為每一個交易設定執行執行的最大計算步數來解決問題,如果超過則計算被恢復原狀但依然要支付費用。訊息以同樣的方式工作。為顯示這一方案背後的動機,請考慮下面的例子:
一個攻擊者建立了一個執行無限迴圈的合約,然後傳送了一個啟用迴圈的交易給礦工,礦工將處理交易,執行無限迴圈直到燃料耗盡。即使燃料耗盡交易半途停止,交易依然正確(回到原處)並且礦工依然從攻擊者哪裡掙到了每一步計算的費用。
一個攻擊者建立一個非常長的無限迴圈意圖迫使礦工長時間內一直計算致使在計算結束前若干區塊已經產生於是礦工無法收錄交易以賺取費用。然而,攻擊者需要釋出一個 STARTGAS 值以限制可執行步數,因而礦工將提前知道計算將耗費過多的步數。
一個攻擊者看到一個包含諸如 send(A,contract.storage[A]); contract.storage[A] = 0格式的合約然後傳送帶有隻夠執行第一步的費用的而不夠執行第二步的交易(即提現但不減少賬戶餘額)。合約作者無需擔心防衛類似攻擊,因為如果執行中途停止則所有變更都被回覆。
一個金融合約靠提取九個專用資料釋出器的中值來工作以最小化風險,一個攻擊者接管了其中一個資料提供器,然後把這個可變地址呼叫機制設計成可更改的資料提供器轉為執行一個無限迴圈,以求嘗試逼迫任何從此合約索要資金的嘗試都會因燃料耗盡而中止。然而,該合約可以在訊息裡設定燃料限制以防範此類問題。
圖靈完備的替代是圖靈不完備,這裡 JUMP 和 JUMPI 指令不存在並且在某個給定時間每個合約只允許有一個複製存在於呼叫堆疊內。在這樣的系統裡,上述的費用系統和圍繞我們的方案的效率的不確定性可能都是不需要的,因為執行一個合約的成本將被它的大小決定。此外,圖靈不完備甚至不是一個大的限制,在我們內部設想的所有合約例子中,至今只有一個需要迴圈,而且即使這迴圈也可以被 26 個單行程式碼段的重複所代替。考慮到圖靈完備帶來的嚴重的麻煩和有限的益處,為什麼不簡單地使用一種圖靈不完備語言呢?事實上圖靈不完備遠非一個簡潔的解決方
案。為什麼?請考慮下面的合約:
C0: call(C1); call(C1);
C1: call(C2); call(C2);
C2: call(C3); call(C3); …
C49: call(C50); call(C50);
C50: (run one step of a program and record the change in storage)
現在,傳送一個這樣的交易給 A,這樣,在 51 個交易中,我們有了一個需要花費 250 步計算的合約,礦工可能嘗試透過為每一個合約維護一個最高可執行步數並且對於遞迴呼叫其它合約的合約計算可能執行步數從而預先檢測這樣的邏輯炸彈,但是這會使礦工禁止建立其它合約的合約(因為上面 26 個合約的建立和執行可以很容易地放入一個單獨合約內)。另外一個問題點是一個訊息的地址欄位是一個變數,所以通常來講可能甚至無法預先知道一個合約將要呼叫的另外一個合約是哪一個。於是,最終我們有了一個驚人的結論:圖靈完備的管理驚人地容易,而在缺乏同樣的控制時圖靈不完備的管理驚人地困難- 那為什麼不讓協議圖靈完備呢?
9 挖礦的去中心化
物數鏈現在的目的是使用一個基於為每 1000 個隨機數隨機產生唯一雜湊的函式的挖礦演算法,用足夠寬的計算域,去除專用硬體的優勢。注意每單個使用者使用他們的私人膝上型電腦或桌上型電腦就可以幾乎免費地完成一定量的挖礦活動,但當到了100%的 CPU 使用率之後更多地挖礦就會需要他們支付電力和硬體成本。ASIC 挖礦公司需要從第一個雜湊開始就為電力和硬體支付成本。所以,如果中心化收益能夠保持在(E + H) /E 以下,那麼即使 ASICs 被製造出來普通礦工依然有生存空間。另外,我們計劃將挖礦演算法設計成挖礦需要訪問整個區塊鏈,迫使礦工儲存完成的區塊鏈或者至少能夠驗證每筆交易。這去除了對中心化礦池的需要;雖然礦池依然可以扮演平滑收益分配的隨機性的角色,但這功能可以被沒有中心化控制的 P2P 礦池完成地同樣好。這樣即使大部分普通使用者依然傾向選擇輕客戶端,透過增加網路中的全節點數量也有助於抵禦中心化。
10 擴充套件性
擴充套件性問題是常被關注的地方,與比特幣一樣,物數鏈也遭受著每個交易都需要網路中的每個節點處理這一困境的折磨。比特幣的當前區塊鏈大小約為 20GB,以每小時 1MB 的速度增長。如果比特幣網路處理 Visa 級的 2000tps 的交易,它將以每三秒 1MB 的速度增長(1GB 每小時,8TB 每年)。物數鏈可能也會經歷相似的甚至更糟的增長模式,因為在物數鏈之上還會有很多應用,而不是像比特幣只是簡單的貨幣,但物數鏈全節點只需儲存狀態而不是完整的區塊鏈歷史這一事實讓情況得到了改善。
大區塊鏈的問題是中心化風險。如果塊鏈大小增加至比如 100TB,可能的場景將是隻有非常小數目的大商家會執行全節點,而常規使用者使用輕的 SPV 節點。這會增加對全節點合夥欺詐牟利(例如更改區塊獎勵,給他們自己 BTC)的風險的擔憂。輕節點將沒有辦法立刻檢測到這種欺詐。當然,至少可能存在一個誠實的全節點,並且幾個小時之後有關詐騙的資訊會透過 Reddit 這樣的渠道洩露,但這時已經太晚:任憑普通使用者做出怎樣的努力去廢除已經產生的區塊,他們都會遇到與發動一次成功的 51%攻擊同等規模的巨大的不可行的協調問題。物數鏈會使用兩個附加的策略以應對此問題。首先,因為基於區塊鏈的挖礦演算法,至少每個礦工會被迫成為一個全節點,這保證了一定數量的全節點。其次,更重要的是,處理完每筆交易後,我們會把一箇中間狀態樹的根包含進區塊鏈。即使區塊驗證是中心化的,只要有一個誠實的驗證節點存在,中心化的問題就可以透過一個驗證協議避免。如果一個礦工釋出了一個不正確的區塊,這區塊要麼是格式錯,要麼狀態 S[n]是錯的。因為 S[0]是正確的,必然有第一個錯誤狀態 S[i]但 S[i-1]是正確的,驗證節點將提供索引 i,一起提供的還有處理 APPLY(S[i-1],TX[i]) -> S[i]所需的帕特里夏樹節點的子集。這些節點將受命進行這部分計算,看產生的 S[i]與先前提供的值是否一致。另外,更復雜的是惡意礦工釋出不完整區塊進行攻擊,造成沒有足夠的資訊去確定區塊是否正確。解決方案是質疑-迴應協議:驗證節點對目標交易索引發起質疑,接受到質疑資訊的輕節點會對相應的區塊取消信任,直到另外一個礦工或者驗證者提供一個帕特里夏節點子集作為正確的證據。
11 綜述
去中心化應用上述合約機制使得任何一個人能夠在一個虛擬機器上建立透過全網共識來執行命令列應用(從根本上來說是),它能夠更改一個全網可訪問的狀態作為它的“硬碟”。然而,對於多數人來說,用作交易傳送機制的命令列介面缺乏足夠的使用者友好使得去中心化成為有吸引力的替代方案。最後,一個完整的“去中心化應用”應該包括底層的商業邏輯元件和上層的圖形使用者介面元件。物數鏈客戶端被設計成一個網路瀏覽器,但包括對“LDBC” Javascript API 物件的支援,可被客戶端裡看到的特定的網頁用來與物數鏈互動。從“傳統”網頁的角度看來,這些網頁是完全靜態的內容,因為區塊鏈和其它去中心化協議將完全代替伺服器來處理使用者發起的請求。最後,去中心化協議有希望自己利用某種方式使用 LDBC 來儲存網頁。
12 結論
物數鏈協議圍繞去物流資料分享去中心化儲存,去中心化計算以及數十個類似概念建立的協議和去中心化應用,有潛力從根本上提升物流行業的效率,並透過首次新增經濟層為其它的 P2P 協議提供有力支撐,最終,同樣會有大批與金錢毫無關係的應用出現。
物數鏈協議實現的任意狀態轉換概念提供了一個具有獨特潛力的平臺;與封閉式的,為諸如資料儲存,或金融等單一目的設計的協議不同,從設計上是開放式的,並且我們相信它極其適合作為基礎層服務於在將來的年份裡出現的極其大量的物流行業和非行業協議。
更多區塊鏈資訊:http://www.qukuaiwang.com.cn/news