链上兼容EVM、Wasm虚拟机的实现思路

2022-09-26 17:00:43 浏览数 (1)

概述

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.

代码语言:javascript复制
// cesi.ts
export declare function getCallDataSize(): u32
export declare function callDataCopy(bufOut: Uint8Array, offset: u32, length: u32): void
export declare function getCodeSize(): u32

// lib_contract.ts
export namespace contract {
    export function getCodeSize(): u32 {
    return cesi.getCodeSize();
  }
  ....
}

// index_test.ts
export function testCoreAPI(): void {
    var codeSize = contract.getCodeSize(); 
}  

在smart chain链的客户端中,实现了这些Host函数

代码语言:javascript复制
//export cesiGetCallDataSize
func cesiGetCallDataSize(context unsafe.Pointer) int32 {
    return convertContext(context).getCallDataSize()
}
//export cesiCallDataCopy
func cesiCallDataCopy(context unsafe.Pointer, resultOffset int32, dataOffset, length int32) {
    convertContext(context).callDataCopy(resultOffset, dataOffset, length)
}
//export cesiGetCodeSize
func cesiGetCodeSize(context unsafe.Pointer) int32 {
    return convertContext(context).getCodeSize()
}

将用高级语言(Rust/AssemblyScript)编写的Wasm合约编译为字节码(WebAssembly ByteCode),上传至链,创建Wasm虚拟机后,进行运行,并由Host函数提供EEI语义的支持.

代码语言:javascript复制
  --------------                 ---------------                 --------------- 
 |              |   create VM   |               |       run     |               |
 |  Wasm        | ------------> |      VM       | ------------->|   host func   |
 |  ByteCode    |               |               |               |               | 
  --------------                 ---------------                 --------------- 

EVM虚拟机集成

在coinex smart chain中,使用了[ethereum/evmone]作为以太坊虚拟机的实现,该项目内部实现了以太坊的所有指令;同时,提供了一个接口HostContext,负责与区块链进行数据交互;在smart chain 客户端中通过实现该接口,为evm虚拟机提供数据支持;

通过调用evmc提供的接口,从evmone的动态库中创建evm虚拟机;然后通过虚拟机提供的接口Execute,传入合约code,用户输入等一系列参数信息,运行合约。

代码语言:javascript复制
  --------------                 ---------------                 --------------- 
 |              |   params      | contract code |       run     |               |
 |  Load EMV    | ------------> |     input     | ------------->|  HostContext  |
 |              |               |     ...       |               |               | 
  --------------                 ---------------                 --------------- 

虚拟机间的兼容

为了使smart chain在执行合约时,不用关注虚拟机的实现细节,增加了中间层,来兼容两种虚拟机的创建、执行;

  1. 在合约的元信息中增加标识,来表明合约字节码类型;
  2. 依据标识来创建指定类型的虚拟机;
  3. 通过引入中间层接口ContractExecutor,来屏蔽smart chain 在链上执行合约时,对两种虚拟机实现细节的关注.
  4. 在虚拟机执行时,通过使用ABI编码后的参数,来做到虚拟机之间的互相调用
代码语言:javascript复制
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)
}
代码语言:javascript复制
  --------------                 ---------------                 --------------- 
 |              |  create vm    |               |    run        |               |
 |  Contract    | ------------> |   Contract    | ------------->|    Execute    |
 |  Info        |               |   Executor    |               |               | 
  --------------                 ---------------                 --------------- 

总结

至此,我们完整介绍了方案三(提供两种虚拟机)的实现思路;通过在链上支持两种虚拟机,来使以太坊APP的开发者可以几乎无成本的进行生态迁移。

smart-architecture.jpg

0 人点赞