01.11 技術分析:以太坊、比特幣和比特幣現金上的智能合約有什麼差異?

編者注:原標題為《技術分析 :以太坊、比特幣和比特幣現金上的智能合約》

儘管以太坊是第一個擁有圖靈完備智能合約的平臺,但已經有可能使用一種稱為「比特幣腳本」(Script)的語言在比特幣上創建基本合約。而比特幣現金最近一直在改善其智能合約功能。儘管不如以太坊先進,但它們都以自己獨特的方式和優勢支持鏈上智能合約的存在。

本文重點介紹這三個平臺上智能合約之間的突出區別。由於關注的重點是智能合約和腳本功能,因此在此不會討論平臺或區塊鏈的基礎知識。本文還特此介紹了鏈上智能合約,以及存在幾種第二層智能合約解決方案,例如 RSK。這些解決方案絕對值得討論,礙於篇幅不做非常深入的研究。

以太坊:自有狀態且圖靈完備

以太坊是迄今為止最大的智能合約平臺,其智能合約使用以太坊虛擬機(EVM)實現,這是一個圖靈完備的虛擬機。這意味著只要有足夠的資源,EVM 就可以計算任何東西。從概念上講,這與許多其他通用平臺(例如 Java 虛擬機 JVM)相似,該平臺用於執行 Java 程序。

解釋 EVM

不過那些通用平臺與以太坊的 EVM 之間的最大區別在於,以太坊的智能合約代碼由所有以太坊節點執行,以驗證交易的有效性。為了獎勵節點執行此代碼,所有 EVM 操作碼均具有相關的燃氣成本,如下圖所示。

圖:EVM 費用結構

每筆交易都會花費大量的 Gas,具體取決於所使用的操作碼。用以太坊的原生加密貨幣 ETH 支付 Gas 費用。為了限制這些節點每個區塊必須執行的計算量,單個區塊中可以使用的 Gas 量有一個限制,稱為「區塊 Gas 限制」。

在執行智能合約功能期間,合約可以存儲和訪問必要的數據。根據其用途,這些數據可以存儲於不同的位置,即位於不同的數據位置。首先是「堆棧」(stack),其中包含計算中使用的值。只能輕鬆訪問堆棧中的前 16 個項目,因此不適合長期存儲。下面顯示了使用堆棧進行計算。

圖:基於堆棧的計算

其次,為了補充堆棧,「contract memory」可用於在當前合約執行過程中存儲、檢索和傳遞數據。可以從內存中檢索這些值,以將其用於堆棧上進行計算,並將結果存儲回內存中。這些值僅在當前執行期間持續存在。在合約執行結束時,將擦除 contract memory 內存和堆棧。

最終,數據所在的位置是

「 contract storage」,用於在合同執行期間持久保存數據。持久性變量(如 token 餘額)存儲在合約存儲中。為了實現數據持久性,contract memory 存儲在每個以太坊節點上。因此,其內存類似於 RAM,而存儲類似於硬盤驅動器或持久數據庫。

更多以太坊虛擬機如何工作的細節可參見 MyCrypto 的文章。

編寫智能合約

儘管所有智能合約都使用 EVM,但大多數智能合約不是使用 EVM 字節碼手工編寫的,就像大多數 JVM 字節碼不是手工編寫的一樣。相反,有幾種高級語言可用於在以太坊中編寫智能合約,最受歡迎的語言是 Solidity,除此之外還出現了 Vyper,也是一種面向 EVM 的編程語言。下圖包含一個非常簡單的 Solidity 智能合約的示例。

與智能合約互動

以太坊中的智能合約作為字節碼存在於以太坊網絡上。這意味著將 Solidity 代碼編譯為字節碼,然後通過發送部署交易(deployment transaction)將其部署到網絡。這是一種特殊的交易,沒有任何接收者,但以字節碼作為交易數據。

這些部署的合約僅以 EVM 字節碼的「碎片」形式存在於網絡中,幾乎無法單獨使用。為了與它們進行「接頭」,需要提供一個應用程序二進制接口(ABI),其中包括所有公共功能及其參數的列表。為了使用戶對這些合約有更多瞭解,Etherscan之類的服務幫助可以驗證合約源代碼,以便用戶可以在使用合同之前檢查代碼。

通過連接到以太坊節點並使用其JSON-RPC 接口,可以直接訪問所有智能合約。但是,許多智能合約卻是通過連接到節點並管理 ABI 的前端應用程序訪問的。這可以通過眾多不同的以太坊 SDK (例如 web3.js 或 ethers.js)之一來完成,它們可以在後臺調用 JSON-RPC。這為合約用戶提供了更好的體驗,相當於最困難的部分被形象化了。

可以通過兩種不同的方式與智能合約進行交互:調用(Calls)和交易(Transactions)。調用是合約功能的本地調用,它不會向區塊鏈廣播任何內容。因此,調用過程是「只讀」的,不能對合約狀態進行任何更改,也不會產生任何費用。而交易是實打實的「寫入操作」,確實會廣播到網絡,幷包含在區塊鏈中,並且會產生礦工費用。以 ERC20 令牌為例,通過調用檢索 token 餘額,同時通過發動交易轉移令牌。

智能合約間互操作

以太坊的這些屬性(具有圖靈完備的 EVM 和持久性存儲)允許創建在鏈上運行的任何類型的去中心化應用程序。一個很好的例子就是 DeFi 生態系統,其中包括 Maker,Uniswap 和 Compound 等應用程序,以及 ERC20 和 ERC721 令牌標準。這些應用程序允許具有無限數量的動態參與者的複雜功能。

圖:rDai 中的 DeFi 互操作性

最重要的是,智能合約本身可以成為其他智能合約的「參與者」,從而實現這些合約之間的強大集成和組合。比如,持有代幣餘額並將其借給 Compound 或與 Uniswap 交易所的智能合約,或者是使用 rDai 自動投資 DAI 並將應計利息貢獻給慈善機構。

儘管智能合約可以彼此交互,但是鏈上的每個交易都必須來自外部帳戶。因此,以太坊智能合約間的交互仍然必須由用戶通過初始交易來觸發。在此初始觸發之後,合約間的交互類似於直接訪問。

換句話說,某個智能合約可以調用其他智能合約的「只讀功能」或觸發「寫入操作」(交易)。由於只有外部帳戶才能觸發交易,因此智能合約之間的交易稱為內部交易或消息調用,以與用戶啟動的交易區分開

比特幣:無狀態且簡單

所有比特幣交易(包括定期轉賬)均由基於堆棧的、被稱為「比特幣腳本」(Script)的編程語言支持。上文提到以太坊的 EVM 是為圖靈完備且可互操作的智能合約而設計的,而比特幣腳本卻有意添加各種限制,並且以根本不同的方式工作。

解釋比特幣腳本

就想 EVM,比特幣腳本使用堆棧(Stack)來保存值(Value)並在這些值上執行計算。但與 EVM 不同的是,堆棧是比特幣腳本中唯一可用的數據位置。這意味著,很難存儲多個值以便在以後的合約執行中使用。更重要的是,這意味著不可能存儲或修改那些在合約執行期間仍存在的值(但 EVM 可以)。

這是以太坊的智能合約和比特幣的最大區別。以太坊的模型是有狀態的,而比特幣是無狀態的。通俗理解就是,以太坊可以被認為類似於普通的命令式可變數據編程範例,而比特幣則類似於功能不變的數據範例。

比特幣的模型允許獨立且高效得多地驗證交易,這使得並行化和分片交易更加容易。但是,如果沒有任何可變的數據存儲,在比特幣上創建像以太坊那樣的複雜智能合約就更加困難,比如,ERC20 合約必須跟蹤代幣餘額並進行更改。

除了這些狀態差異之外,還有其他一些因素限制了比特幣智能合約的複雜性。值得注意的是,比特幣腳本缺乏對某些算術函數以及任何形式的循環或遞歸的支持。其合約還具有 520 個字節的有效大小限制,並且最多隻能包含 201 個操作碼。

比特幣上的大多數智能合約都屬於幾類簡單合約。例如,可以由多個參與者使用的多重簽名合約,或哈希時間鎖定合約(HTLC)。

頭等倉小知識:關於哈希鎖定,可以舉一個簡單的例子,比如你從我這兒買一段視頻,這個視頻通過密碼訪問,那麼在交易合約中,我把視頻的訪問密碼也變成其中的一個 key,如果要達成交易,這個 key 必須讓你知道;而一旦你知道(你拿到視頻),錢就支付給我了,並且整個交易過程一定要在設定好的時間內完成,超出時間則合約也將自動觸發。

而且由於比特幣上的這些合約非常簡單,大多數價值是通過將不同的合約與其他脫鏈應用程序邏輯相結合而捕獲的。這樣,可以將簡單的合同組合起來以創建複雜的解決方案,例如閃電網絡或跨鏈拍賣等等。

解釋比特幣交易

比特幣每一筆交易都是通過所謂的「交易輸出」實現的。當這些交易輸出在某個賬戶中可用,它們就被稱為未用交易輸出(UTXOs)
。這些 UTXOs 被鎖定腳本(或>與 EVM 一樣,所有比特幣節點都執行這些腳本來驗證交易,但是比特幣區塊鏈並沒有 Gas 成本的概念,因此,按交易數據的每個字節向礦工支付費用。為了限制節點必須完成的工作量,在一些更密集的腳本操作上也加入了一些限制。

與智能合約互動

比特幣中的智能合約的編寫使用P2SH 模式(頭等倉注:有翻譯為「向腳本哈希支付」)。P2SH 模式中的鎖定腳本包含腳本哈希,並且需要提供完整腳本(稱為贖回腳本)以及該贖回腳本的解鎖腳本的解鎖腳本。下圖顯示了這種模式。

圖:P2SH 模式

頭等倉小知識:P2SH 模式是為了簡化複雜腳本的運用而被引入的(傳統機制是 P2PKH),將複雜的鎖定腳本編譯成一個含有 20 個字節哈希的簡單腳本,就想比特幣地址是基於 Base58 編碼的一個含有 20 個字節的公鑰。P2SH 跟傳統 P2PKH 方式的最大區別是把設置轉出條件的人從發送者變成接收者。通過在贖回腳本中添加各種轉出條件可以來實現形式多樣的交易,例如多重簽名交易。

比特幣節點分兩個階段驗證這些智能合約交易。首先,對「贖回腳本」進行哈希處理,並對照「鎖定腳本」中的哈希值進行檢查。如果它們匹配,則用「鎖定腳本」去解鎖「贖回腳本」,就好像「贖回腳本」才是初始的鎖定腳本一樣。

因為只有字節碼的哈希值存儲在比特幣鏈上,所以完整的字節碼必須存儲在鏈外,幷包含在任何合同執行的解鎖腳本中。因此,比特幣智能合約的「部署」是免費的,但以後執行合約的成本更高。相反,以太坊的初始部署相對昂貴,而後來的合約執行則便宜。

這些部署上的差異鼓勵綜合使用這兩種智能合約。一個很好的例子是 LocalCryptos,它支持以太坊和比特幣的非託管本地交易。

對於以太坊,它使用一個大的智能合約來跟蹤所有交易,而對於比特幣,它為每筆交易創建單獨的合約

編寫智能合約

雖然以太坊有多種高級語言可以編譯為 EVM 字節碼,但比特幣對此的關注較少。儘管可以用比特幣腳本構建的系統很複雜,但是合約本身通常很簡單。因此,幾乎沒有必要抽象出底層系統。而且由於比特幣合約有大小限制且每增加一個字節的高昂成本,因此保證合約「儘可能小」很重要

儘管這些高級語言在比特幣中不太重要,但它們確實存在。Ivy 是比特幣中「最精緻」的高級語言,該語言由 Dan Robinson 於 2017 年創建。下圖給出了一個用 Ivy 編寫的智能合約示例。如果接收者未及時使用該合同,則該合約可用於發送可以由發送者收回的款項。

最近,Blockstream 的幾位研究人員發佈了 Miniscript,該語言專注於智能合約的分析和可組合性,而不是抽象底層系統。考慮到比特幣合約往往缺乏抽象的複雜性,這似乎是正確的道路。

比特幣現金:可組合功能

上文一方面是以太坊,它能夠創建許多功能強大且有用的智能合約,這些合約完全存在於以太坊鏈上,同時,由於其有狀態(Stateful)的性質,它還提出了擴展性問題。另一方面,比特幣的智能合約無狀態(Stateless)模型允許對智能合約交易進行獨立,簡單的驗證,但是其腳本系統限制了合同的實用性。

在分叉之前,比特幣現金(Bitcoin Cash)和比特幣擁有相同的歷史,因此它們的底層腳本系統在功能上是相同的,比特幣現金也受益於這些相同的方面。從那時起,比特幣現金社區的很大一部分就認識到了對「更有用的智能合約」的需求。比特幣現金啟用了新功能,使其智能合約更有用,同時保留了允許比特幣進行無狀態驗證的基本屬性。

BCH 的功能升級

要了解比特幣現金智能合約的可能性,我們需要查看其半年兩次的網絡升級。自 2017 年最初的硬分叉以來,每年 5 月和 11 月都將執行這些網絡升級。我們特別討論了對比特幣腳本引擎的更改,儘管已進行了其他一些改進,例如 Schnorr 簽名。

在比特幣的早期,由於一些操作碼不安全使用而被禁用。在比特幣現金分叉之後的第一年內,比特幣-ABC 節點的開發人員解決了這些問題,並重新引入了經過稍微修改的功能的操作碼,如下圖所示。最重要的是,該升級使在比特幣腳本中對結構化數據進行編碼和解碼成為可能。

圖:2018 年 5 月 BCH 啟用了新的操作碼

此後半年,在 2018 年 11 月的比特幣現金網絡升級中發佈了另一個新的操作碼。其中包括該更新 OP_CHECKDATASIG,它使用戶可以驗證比特幣腳本中任何消息的簽名。如果我們結合 2018 年推出的腳本更新,這些更新可用於將新穎有用的智能合約功能引入比特幣現金。

編寫智能合約

相對於原始比特幣腳本,比特幣現金的新功能為其智能合約增加了很多額外的複雜性。這使得擁有一個通過高級語言、SDK 和工具提供更高級別抽象層的生態系統變得更加重要。

目前正在處理此問題的兩個大項目是 Spedn (由筆名 Tendo Pein 創建)和 CashScript (由本文作者 Rosco Kalis 創建,受以太坊的 Solidity 語言的啟發)。儘管它們仍在積極開發中,但這些工具使處理比特幣現金中的智能合約變得更加容易。下文將使用 CashScript 代碼片段來闡述一些功能。

預言機(Oracles)

當過去的比特幣腳本更新組合在一起時,它們使您可以通過受信任的預言機將外部數據帶入比特幣現金的智能合約中。可以將結構化數據編碼為字節數組,並由 oracle 提供程序簽名。然後,智能合約可以驗證簽名並解碼結構化數據。

可以在下面的 HODLVault 示例合同中查看此示例。該合同強制執行 HODLing,直到達到一定的 BCH / USD 價格為止。所需的 BCH / USD 價格供稿由 oracle 提供程序發佈,並由用戶傳遞到合同中。為了增加分散性,可以將智能合約設置為使用多個數據源,而不是信任單個集中式服務。

保證合同(Covenants)

第二個大用例是稱為「保證合同」(Covenants)的技術,該技術的名稱來自物權法中用來限制對象使用的術語。就比特幣現金而言,它限制了智能合約中貨幣的使用。因此,儘管比特幣中的智能合約只能授權一般的貨幣支出,但比特幣現金合約能夠對可支出的金額或收款人的身份施加限制。

轉讓比特幣時,發送者必須提供簽名以授權交易。為了生成此簽名,發送方對交易的哈希表示進行簽名。此哈希稱為Sighash,而實際的交易數據包含在Sighash 原像中。

通過使用_OP_CHECKSIG_和_OP_CHECKDATASIG_具有相同的簽名,我們可以訪問 Sighash 數據。數據格式可以在規範中進行檢查,幷包含在下面的圖像中。一個重要字段是>

圖:比特幣現金 Sighash 數據格式

知道保證合同在技術層面上是如何工作的,這很不錯,但是 CashScript 已經抽象出了與契約有關的大多數複雜性。使用 CashScript 編寫智能合約時,這些字段很容易獲得,而無需執行手動驗證和解碼 Sighash 原圖的步驟。

第一個使用保證合同技術的智能合約是 Licho 的 Last Will (最後的遺囑),這是一個智能合約,可讓用戶將死者的財產轉移到自己的財產上。合同定義了三個不同的功能。第一種允許繼承者在 180 天后索取資金。第二個允許所有者的冷密鑰(ColdKey)以任何方式花錢。第三個允許所有者的熱密鑰(Hot Key)通過強制將全部合約餘額發送回合約來刷新 180 天的期限。

下面包含 CashScript 版本的 Last Will,但是原始版本是由 Spedn 編寫的,可以在此處進行查看。

這是有用的保證合同的簡單示例之一,但是保證合同可實現甚至更復雜的功能。在《Last Will》合約簽訂後,其創建者 Karol Trzeszczkowski 繼續創建了 Mecenas,該公司可強制執行 Patreon 等定期付款。

保證合同最初是在題為《 Bitcoin Covenants》的論文中提出的,該論文需要一個新的操作碼_OP_CHECKOUTPUTVERIFY_。隨後提出了其他建議,例如_OP_CHECKTEMPLATEVERIFY_或_OP_CHECKSIGFROMSTACK_。後者與比特幣現金的盟約實施非常相似。可在 Tendo Pein 的文章中學習到保證合同的更多信息。

模擬狀態(Simulated state)

查看「最後的遺囑」合約,當合同到位時更改繼承者可能很有價值。由於我們可以通過查看當前合約的字節碼來強制發送到當前合約,因此我們可以通過稍微更改此字節碼來強制發送到稍微不同的合約。可以創建了一個函數,該函數將整個合同的餘額發送到具有完全相同的字節碼但具有不同的繼承者的合約。

我們只能使用已知大小(例如 20 字節)的構造函數參數來執行此操作。構造函數參數始終是合同字節碼的第一個數據,這就是我們能夠輕鬆地用新數據替換舊數據的方式。該 inheritor 是第一個構造函數的參數,它的大小為 20 個字節,因此我們能夠應用該技術,如可以看到下面。

通過使用該技術,可以在保留合約相同規則的同時更改合約中的某些變量。我們將其稱為「模擬狀態」,因為它提供了合約狀態的某些好處,並且不存在像以太坊那樣有狀態(Stateful)的系統的可拓展性問題。由於必須在某處進行權衡,因此此方法還有其他缺點。

主要問題是我們實際上並未更改原始合同中的任何變量,因為由於比特幣現金的無狀態性,這是不可能的。而是創建一個新合同(具有新地址),並將全部餘額轉移到該新合約中。由於新地址,這會導致 UX 問題,但是可以通過在這些智能合約上具有良好的應用程序層抽象來緩解這些問題。

在字節碼內部替換這些變量可能會感到很麻煩,尤其是在嘗試替換字節碼內部更深的變量時。應該以高級語言抽象該功能,以便通過提供新參數自動生成新的字節碼。這種抽象可能看起來像這樣:

許多抽象性是以更大的合約為代價的,從而導致更高的費用。 但比特幣現金的交易費用通常很低,因此可謂集二者之大成。但是比特幣現金具有與比特幣相同的大小限制,因此這些抽象確實使保持在限制內變得更加困難。這導致許多開發人員不得不手動優化已編譯的字節碼。

結論

每種加密貨幣都在其智能合約系統中進行權衡。以太坊是功能最廣泛的最常用的智能合約平臺。比特幣通過其無狀態腳本系統提供了更基本的智能合約版本,此無狀態系統驗證效率更高,但功能較少。比特幣現金與比特幣具有相同的基礎,但是增加了新功能,試圖在有效驗證和有用的智能合約之間折衷。最後,所有人都朝著相似的目標邁進。

展望未來

本文寫於 2019 年第四季度,反映了平臺的當前狀態。加密貨幣是一個快節奏的領域,因此涉及這些平臺的人們始終在努力進行改進,這可能會改變生態系統的前景。

以太坊正在開發主要的以太坊 2.0 版本,其第 0 階段計劃於 2020 年第一季度上線。以太坊 2.0 旨在通過轉移到權益證明,實施分片和其他改進來解決以太坊 1.x 的性能問題。ETH2.0 的完整路線圖尚未確定,可能要花費數年時間才能推出。但是,如果此重大更新能夠實現其目標,則可以為以太坊提供強有力的支持。

比特幣中的智能合約研究致力於進一步提高智能合約的效率和隱私性,這包括 Taproot 和無腳本腳本之類的解決方案。而比特幣現金則繼續致力於啟用其他智能合約功能,並致力於使這些更改更易於訪問。