概述
Coinex Smart Chain是一條基於Cosmos-SDK實現的Ethereum Semantic的智慧合約鏈,底層提供了EVM、Wasm兩種虛擬機器來執行智慧合約。開發者可以使用傳統的Solidity語言編寫合約、或其它可以編譯為WebAssembly高階語言(如:Rust/C++/AssemblyScript)編寫合約,將編譯後的合約位元組碼上傳至Coinex Smart Chain上執行;並且兩種型別的位元組碼合約之間可以互相進行呼叫。
基於上述這種開發理念,引申出一個問題:如何在Wasm上實現實現Ethereum Semantic. 對此初步提供了三種方案:
1.將Solidity合約編譯為Wasm位元組碼
使用類似於SOLL的方案,將Solidity合約編譯為等價的WebAssembly位元組碼,底層提供Wasm虛擬機器來執行合約。
2.在Wasm上提供系統合約,來執行Solidity位元組碼的合約
在Wasm虛擬機器上構建EVM位元組碼器,來執行編譯後的Solidity位元組碼。
3.提供兩種虛擬機器的實現,不同的位元組碼合約在不同的虛擬機器上執行
使用兩種虛擬機器,分別執行EVM位元組碼合約和WebAseembly位元組碼合約,同時在Wasm虛擬機器上透過Host函式,提供Ethereum Semantic的實現,以便做到兩種虛擬機器合約之間的互相呼叫。
基於技術實現難度、執行效能等方面的考慮,採用了第三種方案。下面將詳細介紹該方案的實現思路
Wasm虛擬機器實現Ethereum Semantic在Wasm虛擬機器中執行合約時,除了虛擬機器自身之外,還需要依賴一些外部Host函式的支援,透過在Host中,提供EEI實現,以便在Wasm虛擬機器中提供 Ethereum Semantic.
Coinex Smart Chain提供了便於合約匯入的SDK,以便在用高階語言(Rust/AssemblyScript/)寫Wasm合約時,可以呼叫這些外部Host函式;將合約編譯為Wasm位元組碼時,SDK中宣告的所有export函式,都將由Coinex Smart Chain客戶端提供實現。
示例如下:
在smart-sdk-as專案中,提供了as專案使用的sdk.
// cesi.tsexport declare function getCallDataSize(): u32export declare function callDataCopy(bufOut: Uint8Array, offset: u32, length: u32): voidexport declare function getCodeSize(): u32// lib_contract.tsexport namespace contract {export function getCodeSize(): u32 {return cesi.getCodeSize(); } ....}// index_test.tsexport function testCoreAPI(): void {var codeSize = contract.getCodeSize(); }
在smart chain鏈的客戶端中,實現了這些Host函式
//export cesiGetCallDataSizefunc cesiGetCallDataSize(context unsafe.Pointer) int32 {return convertContext(context).getCallDataSize()}//export cesiCallDataCopyfunc cesiCallDataCopy(context unsafe.Pointer, resultOffset int32, dataOffset, length int32) { convertContext(context).callDataCopy(resultOffset, dataOffset, length)}//export cesiGetCodeSizefunc cesiGetCodeSize(context unsafe.Pointer) int32 {return convertContext(context).getCodeSize()}
將用高階語言(Rust/AssemblyScript)編寫的Wasm合約編譯為位元組碼(WebAssembly ByteCode),上傳至鏈,建立Wasm虛擬機器後,進行執行,並由Host函式提供EEI語義的支援.
+--------------+ +---------------+ +---------------+| | create VM | | run | || Wasm | ------------> | VM | ------------->| host func || ByteCode | | | | | +--------------+ +---------------+ +---------------+
EVM虛擬機器整合
在coinex smart chain中,使用了[ethereum/evmone]作為以太坊虛擬機器的實現,該專案內部實現了以太坊的所有指令;同時,提供了一個介面HostContext,負責與區塊鏈進行資料互動;在smart chain 客戶端中透過實現該介面,為evm虛擬機器提供資料支援;
透過呼叫evmc提供的介面,從evmone的動態庫中建立evm虛擬機器;然後透過虛擬機器提供的介面Execute,傳入合約code,使用者輸入等一系列引數資訊,執行合約。
+---------------+ +---------------+ +---------------+ | | params | contract code | run | || Load EVM | ---------> | input | ----------> | HostContext || | | ... | | |+---------------++---------------++---------------+
虛擬機器間的相容
為了使smart chain在執行合約時,不用關注虛擬機器的實現細節,增加了中間層,來相容兩種虛擬機器的建立、執行;
1.在合約的元資訊中增加標識,來表明合約位元組碼型別;
2.依據標識來建立指定型別的虛擬機器;
3.透過引入中間層介面ContractExecutor,來遮蔽smart chain 在鏈上執行合約時,對兩種虛擬機器實現細節的關注.
4.在虛擬機器執行時,透過使用ABI編碼後的引數,來做到虛擬機器之間的互相呼叫
type ContractInfo struct { ContractType uint8}func CreateVM(cfg Config) (ContractExecutor, error) {switch cfg.Flag {case EVM:return evm.NewVmEvmc()case Wasm:return wasm.NewWasmer(cfg.Ctx, cfg.Keeper, cfg.ContractAddr, cfg.Code, cfg.CodeHash, cfg.Ims) }return nil, types.ErrVMUnsupported}type ContractExecutor interface { Execute(ctx interface{}, rev evm.Revision, kind evm.CallKind, static bool, depth int, gas int64, destination sdk.AccAddress, sender sdk.AccAddress, input []byte, value int64, code []byte, create2Salt []byte) (output []byte, gasLeft int64, err error)}
+---------------+ +---------------+ +---------------+| | create vm | | run | || Contract |------------> | Contract |-------------> | Execute || Info | | Executor | | |+---------------+ +---------------+ +---------------+
總結
至此,我們完整介紹了方案三(提供兩種虛擬機器)的實現思路;透過在鏈上支援兩種虛擬機器,來使以太坊APP的開發者可以幾乎無成本的進行生態遷移。
本文由CoinEx Chain開發團隊成員撰寫。CoinEx Chain是全球首條基於Tendermint共識協議和Cosmos SDK開發的DEX專用公鏈,藉助IBC來實現DEX公鏈、智慧合約鏈、隱私鏈三條鏈合一的方式去解決可擴充套件性(Scalability)、去中心化(Decentralization)、安全性(security)區塊鏈不可能三角的問題,能夠高效能的支援數字資產的交易以及基於智慧合約的Defi應用。