SPV是什麼?SPV節點和SPV錢包詳情介紹

買賣虛擬貨幣

SPV是什麼?SPV是“Simplified Payment Verification”(簡單支付驗證)的縮寫。中本聰論文簡要地提及了這一概念,指出:不執行完全節點也可驗證支付,使用者只需要儲存所有的block header就可以了。使用者雖然不能自己驗證交易,但如果能夠從區塊鏈的某處找到相符的交易,他就可以知道網路已經認可了這筆交易,而且得到了網路的多少個確認。

按照中本聰的原文,這裡有個細節需要注意,SPV指的是“支付驗證“,而不是“交易驗證”。這兩種驗證有很大區別。

“交易驗證”非常複雜,涉及到驗證是否有足夠餘額可供支出、是否存在雙花、指令碼能否透過等等,通常由執行完全節點的礦工來完成。

“支付驗證”則比較簡單,只判斷用於“支付”的那筆交易是否已經被驗證過,並得到了多少的算力保護(多少確認數)。

考慮這樣一種情況,A收到來自B的一個通知,B聲稱他已經從某某賬戶中匯款一定數額的錢給了A。去中心方式下,沒有任何人能證明B的可靠。接到這一通知,A如何能判斷B所說的是真的呢?

在比特幣系統中,這一通知是以一個固定格式的“交易”來實現的,該交易中包含B的匯款賬戶支票、B的簽名、匯給A的金額以及A的地址。

如果A想本人親自驗證這筆交易,首先,A要遍歷區塊鏈賬本,定位到B的賬戶上,這樣才能檢視B所給的賬戶支票上是否曾經有足夠的金額;接下來,A要遍歷後續的所有賬本,看B是否已經支出了這個賬戶支票上的錢給別人(是否存在雙花欺騙);然後還要驗證指令碼來判斷B是否擁有該賬戶的支配權。這一過程要求A必須得到完整的區塊鏈才行。

但是,如果A只想知道這筆支付是否已經得到了驗證(如果驗證了就發貨),他可以依賴比特幣系統來快速驗證。即,檢查發生此項支付的那筆交易是否已經收錄於區塊鏈中,並得到了多少個確認。

原理:block header中有三個關鍵欄位,一是prev_block_hash(前一區塊的hash值,確保了區塊鏈所記錄的交易次序);二是bits(當前區塊的計算難度), 三是merkle_root_hash(藉助merkle tree演算法,確保收錄與區塊中所有交易的真實性)。

驗證某個交易是否真實存在時,理論上,使用者可以透過以下方式進行驗證:

(為了簡化模型,我們假設用tx_hash來定位block。這種方法有被“交易可鍛性”攻擊的風險,實際應用中可以根據output_point來定位。)

0. 從網路上獲取並儲存最長鏈的所有block header至本地;

1. 計算該交易的hash值tx_hash;

2. 定位到包含該tx_hash所在的區塊,驗證block header是否包含在已知的最長鏈中;

3. 從區塊中獲取構建merkle tree所需的hash值;

4. 根據這些hash值計算merkle_root_hash;

5. 若計算結果與block header中的merkle_root_hash相等,則交易真實存在。

6. 根據該block header所處的位置,確定該交易已經得到多少個確認。

優點:極大地節省儲存空間。減輕終端使用者的負擔。無論未來的交易量有多大,block header的大小始終不變,只有80位元組。按照每小時6個的出塊速度,每年產出52560個區塊。當只儲存block header時,每年新增的儲存需求約為4兆位元組,100年後累計的儲存需求僅為400兆,即使使用者使用的是最低端的裝置,正常情況下也完全能夠負載。

問題:如何才能透過tx_hash定位到該交易所在的區塊? 以往的比特幣協議中缺少對此的支援。

比特幣錢包

在進一步討論SPV的實現之前,先要說明一下比特幣錢包存放的是什麼,錢包和私鑰之間是什麼關係?

既然用到“錢包”一詞,那麼應該與我們日常生活中使用的錢包有一定的相似之處。為了更直觀說明,我們與日常生活中所使用的錢包做一下對比。

日常生活中裡面存放的可能是紙幣、支票、印鑑等等(為了簡化說明,我們把銀行卡排除在外,使用銀行卡涉及到很多中間環節,增加表述上的複雜度)。

用紙幣購物時,

1. 從錢包中湊足若干張不同面值的紙幣,計算總面值是否大於所需金額以及應找回多少零錢;

2. 將這些紙幣直接交給賣方;

3. 賣方驗證這些紙幣的真偽;

4. 賣方計算這些紙幣的面值是否大於或等於商品價格,並找回相應的零錢。

5. 將收到的零錢放回錢包。

比特幣的錢包裡存放的相當於是一張張標有面值的“一次性支票”和對應的“印鑑”。支付時,

1. 使用者從錢包中取出若干張“一次性支票”,自己計算總面值是否大於所需金額以及應找回多少零錢,注意要扣除比特幣系統所收取的手續費;

2. 給賣方開一張支票,註明賣方地址和支付金額;如果需要找零,給自己開一張找零支票(寫上自己的地址和找零金額);

3. 在每張從錢包中取出的支票上加蓋對應的印鑑,確認支付權;

4. 將這些票據提交給比特幣系統,比特幣系統驗證支票的真偽和支付是否有效。

5. 若比特幣系統驗證透過,收款方將收到的支票放入錢包。使用者則將自己錢包中的已支付的支票丟棄(這些支票已經被比特幣系統視為無效了,無法繼續使用),

即使是剛接觸比特幣的人,估計也能猜出“印鑑”指的是“私鑰”。但“一次性支票”是什麼?

比特幣系統中,這種“一次性支票”的術語是UTXO,全稱是Unspent Transaction Outputs(未花費的交易輸出)。區塊鏈是一個收錄所有歷史交易(Transaction)的總帳,每個區塊(block)中包含若干筆交易記錄。

每個交易記錄由兩部分構成:資金來源(可以有多個來源)和資金去向(可以有多個去向),術語為Tx_in(交易輸入)和Tx_out(交易輸出)。也就是說,每筆交易TX包含有若干個Tx_in和若干個Tx_out。

除創世區塊中的交易(genesis block)外,每筆交易必須要有資金來源。資金來源有兩種,一種是挖礦獎勵(依照固定演算法實現的貨幣發行),出現在每個block的第一筆交易中;另一種是先前的交易中未曾使用的某個Tx_out(交易輸出),即UTXO。支出方要出示證據來證明自己對該Tx_out擁有所有權,而比特幣系統則要驗證該Tx_out是否真的未被花費(是否是UTXO)以及支出方是否有權將其花費。

資金去向(TX_out)包含兩個部分,一是傳遞的金額,二是支配權(誰可以動用)。取款權透過比特幣的指令碼系統來實現。若收款方地址是以1開頭的普通地址,則指令碼中會包含地址所對應公鑰的hash值(hash260),動用款項時一般需要用對應的私鑰進行簽名;若收款方地址是以3開頭的多重簽名地址,則指令碼中會包含某個特定指令碼的hash值(hash260),動用款項時,一般需要依照特定的指令碼,用多個私鑰來簽名。

使用者錢包中的比特幣實際上是使用者擁有支配權的、且尚未花費的Tx_out中記錄的金額總和,即使用者可支配的所有UTXO金額之和。

完整的錢包中應存有若干個UTXO和支配每個UTXO時所對應的私鑰。當然,有時從安全形度出發,可能會把錢包劃分為兩個部分,線上錢包中只有UTXO,而離線錢包只存私鑰。

但是,使用者怎麼才能把自己的所有UTXO都放到錢包中呢?

使用者如何收錄自己的UTXO

(一)去中心化方式:

實現方法:

1. 在本地建立一個用於儲存UTXO的資料庫;

2. 設定區塊掃描起始點(區塊鏈上的掃描起始高度),從該點開始,依次下載該點之後所有區塊(block)的完整資料。

3. 解析每個block的所有TX資料,依次讀取每個Tx_in的prev_Tx_out([tx hash] + [tx_out的序號]),檢索UTXO資料庫中是否存在這個Tx_out,如果有,則從UTXO資料庫中刪除(或標記刪除)。

4. 依次解析每個Tx_out的指令碼,若與使用者相關,則將[tx hash] + [Tx_out的序號]以及整個tx_out的內容記錄到UTXO資料庫;

備註:如果錢包中只有新建立的私鑰,可以從最新的區塊開始掃描(由於私鑰發生碰撞的可能性可以視為0.在你告知他人比特幣地址之前,該私鑰對應的地址上不會有任何收入)

優點:不依賴於信任;資料準確。

缺點:速度慢,需要從比特幣網路下載大量資料,對網路造成的壓力大。

(二)中心化方式:

1. 某個中心化機構(或個人)執行完整的比特幣節點,建立一個收錄所有UTXO的資料庫。

2. 使用者用中心化機構提供的api來請求與自己有關的UTXO資料。

優點:速度快,不拖累比特幣網路;

缺點:依賴於信任;資料不一定準確(有可能中心化伺服器出現故障,或是與中心伺服器的會話被劫持,資料遭篡改)

四、瘦客戶端、SPV輕錢包和SPV節點是什麼?

瘦客戶端:參考了SPV的機制,在監聽收款地址時,客戶端在本地只需儲存與使用者可支配交易相關的資料。因為本地沒有完整的區塊鏈,缺少傳送方的相關資料,客戶端無法親自驗證交易是否合法,只能判斷交易是否是被收錄,並且得到了幾個確認。這與SPV有很多相似之處,因而很多場合下這種瘦客戶端也常被成為是“SPV客戶端”,不過,與SPV的區別是,在去中心化方式下,這些客戶端仍需下載每個新區塊的全部資料並進行解析,只是無需在本地儲存全部資料而已。

“輕錢包”是用瘦客戶端模式實現的錢包,因為不儲存完整區塊鏈,就涉及到如何獲取UTXO的問題。不同的開發者可能有各自的實現方法,但從效率上考慮,往往多用中心化的方式來實現。

SPV節點:支援使用布隆過濾器(Bloom filter)在快速檢索並返回相關資料的節點。

SPV在實現上涉及到一個問題,如何才能透過交易特徵值(比如tx_hash)來定位到該支付交易所在的區塊?用中心化方式來實現很好解決,但用去中心化就不那麼簡單了,因為以往的比特幣系統協議中缺少對SPV的支援。去中心方式下獲取資料必須做到以下兩點:1. 客戶端和節點間採用公認的協議通訊;2. 資料真實性的自驗證——客戶端無需信任節點是否是誠實節點,返回的資料本身可以證明 該資料的真實性。

原有協議中,可以透過getheaders命令來獲取block headers,可以透過getdata命令支援獲取指定的block, 但不支援透過tx_hash反向查詢所在的block。為了定位block,客戶端往往不得不下載整個區塊鏈。

新的比特幣協議中增加了Bloom filter的功能,Bloom filter解決了客戶端檢索的問題,原理是Bloom filter可以快速判斷出某檢索值一定不存在於某個指定的集合,從而可以過濾掉大量無關資料,減少客戶端不必要的下載量。這樣的節點可以為去中心化方式SPV查詢提供必要的支援。

前文提到,SPV的用途是驗證某個支付是否確實存在,並得到多少個確認。而錢包的用途則是用於管理自己的資產以及進行支付。簡言之,SPV的應用場合往往是為發貨做準備(知道錢到帳了),“輕錢包”的應用場合往往是數錢或花錢。雖然“輕錢包”中部分借鑑了SPV的機制,但和SPV是完全不用的應用方向,直接把這兩個詞連起略顯牽強。這種錢包要麼採用中心化的方式——提高了效率,但引入了信任的風險;要麼採用去中心化方式——無需信任,但效率低,且增加網路的負擔。

SPV節點的出現使以去中心化方式來實現高效、低負荷的“輕錢包”成為了可能。筆者認為將基於SPV節點來實現的”輕錢包”簡稱為“SPV輕錢包”可能會更為合適些。

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;