3
3

More than 3 years have passed since last update.

EthermintをforkしてeWASMを追加した

Posted at

最近、(自分の中で)WebAssemblyがきてます。
自分が普段関わってるBlockchainの分野でもWebAssemblyの導入が多く議論されています。
その一つにEthereum上でwasmを動かすeWASM VMがあります。

開発が止まっているみたいですが、testnetも用意されています。

これには、heraというeWASM VMが使われていますが、こちらもかなり前から開発が止まっているようでした...

さらに調査してみるとSecond StateというプロジェクトでWebAssemblyを使ったVMが開発されていることが分かりました。

スクリーンショット 2020-06-08 23.58.36.png

Official: https://www.secondstate.io/
Github: https://github.com/second-state/SSVM

ということで、今回はeWASMとそれに関連したSecond Stateのプロジェクトについて調べてみました。
そして、最新のgo-ethereumをimportしてeWASMが使えるようにEthermintを改造してみました。

eWASMについて

Ewasm 1.0

  • wasmのサブセット
  • 各命令の前にuseGASを挿入して、GASのコストを計算する
  • eWASM Contract
  • 不動小数点を使わない
  • Ethereum Environment Interfaceのモジュール のみをimportし、他のモジュール はimportしていない
  • mainとmemoryという2つのシンボルをexportする
    • main: VMが実行する関数
    • memory: EEIのモジュール が書き込むメモリスペース
  • Ethereum Environment Interface(EEI)

    • eWASM ContractがEthereumにアクセスするためのAPI
    • WebAssemblyのModuleとして実装され、eWASMの中でimportして使う
    • 例えば、Ethereumの特定のAccountの残高を取得するgetBalance, Accountにメッセージを送るcallなど 元々、EVM1の命令として実装されていたが、WASMではこのような命令はないので、モジュール としてimportして使う仕様となっている
  • System Contract

    • eWASM VMが利用するContract
    • Contractとして定義されたインターフェース
    • 仮想マシンの外で実装したいロジックをContractの形で定義しておき、仮想マシンがcallして使う仕組み
    • EVM1のPrecompiled Contractに相当
    • Sentinel Contract
      • ContractをdeployするときにVMが呼び出し、
        1. コードがeWASMの仕様にあっている確認
        2. gas計算ロジックを追加
        3. deploy準備OKの印として、preambleをつける
    • EVM Transcompiler
      • EVM1のbytecodeをeWASMにtranscompileする処理を実行
      • EVM1をサポートしていない場合VMを呼び出す

Ewasm 2.0

  • Ewasm 2.0のSmart contractはExecution Environments (EE)と呼ばれる
  • EEは全てWASMによって作成される
  • クロスシャードをサポートするため、各EEはシャードで実行される
  • EEはstate rootのみを取得できる
  • EEはstateless
  • scout: Ethereum 2.0 Phase 2 execution prototyping engine

  • 詳細は今後調査したい。特にstate shardingの環境下でどうやってcontractを実行するのか...など

Second stateのプロジェクトを使ったeWASMの構造

  • eWASMが使えるVMは現在Second stateによって開発が進められている。

ssvm-eth.png

ewasmint

調べたことを参考にEthermintをwasmで実行できるように改造してみました。

go-ethereum

  • 最新版のgo-ethereumはewasmのinterpreterに対応していないので、forkしてvm moduleを修正しました。

  • EVMのinstanceを作るときにchainconfigを確認して、wasmのflagが立っていれば、ewasmのinterpreterを使うように分岐しています。

  • &EVMC{...}でewasm用のinstanceを用意します。

evm.go
func NewEVM(ctx Context, statedb StateDB, chainConfig *params.ChainConfig, vmConfig Config) *EVM {
    evm := &EVM{
        Context:      ctx,
        StateDB:      statedb,
        vmConfig:     vmConfig,
        chainConfig:  chainConfig,
        chainRules:   chainConfig.Rules(ctx.BlockNumber),
        interpreters: make([]Interpreter, 0, 1),
    }

    if chainConfig.IsEWASM(ctx.BlockNumber) {
        evm.interpreters = append(evm.interpreters, &EVMC{ewasmModule, evm, evmc.CapabilityEWASM, false})
    }

    if vmConfig.EVMInterpreter != "" {
        evm.interpreters = append(evm.interpreters, &EVMC{evmModule, evm, evmc.CapabilityEVM1, false})
    } else {
        // vmConfig.EVMInterpreter will be used by EVM-C, it won't be checked here
        // as we always want to have the built-in EVM as the failover option.
        evm.interpreters = append(evm.interpreters, NewEVMInterpreter(evm, vmConfig))
    }

    evm.interpreter = evm.interpreters[0]

    return evm
}

Ethermint

  • emintdをstartするときにssvm-evmcをbuildして生成されたbinaryを指定します。
emintd start --vm-wasm <your/build/folder>/tools/ssvm-evmc/libssvm-evmc.dylib
  • このflagを利用してEVMのinstanceを作るときにwasmを選択するようにしています。
  • go-ethereumでもwasmを使うときのflagが用意されています。それを指定するとvm.InitEVMCEwasmが呼ばれて、pathが設定されますが、Ethermintでは外部からvmのinstanceを作るようにしなければならないので、NewEVMの直前でvm.InitEVMCEwasmを読んでいます。
state_transition.go
func (st StateTransition) newEVM(ctx sdk.Context, csdb *CommitStateDB, gasLimit uint64, gasPrice *big.Int) *vm.EVM {
    // Create context for evm
    context := vm.Context{
        CanTransfer: core.CanTransfer,
        Transfer:    core.Transfer,
        Origin:      st.Sender,
        Coinbase:    common.Address{}, // there's no benefitiary since we're not mining
        BlockNumber: big.NewInt(ctx.BlockHeight()),
        Time:        big.NewInt(ctx.BlockHeader().Time.Unix()),
        Difficulty:  big.NewInt(0), // unused. Only required in PoW context
        GasLimit:    gasLimit,
        GasPrice:    gasPrice,
    }

    if emint.VM != "" {
        vm.InitEVMCEwasm(emint.VM)
        return vm.NewEVM(context, csdb, GenerateWASMChainConfig(st.ChainID), vm.Config{})
    }
    return vm.NewEVM(context, csdb, GenerateEVM1ChainConfig(st.ChainID), vm.Config{})

}

あとは、READMEにしたがって進めるとEthermint上でwasm contractが実行できます。
SolidityからwasmへのcompilerはSOLLを使います。

コードは以下にあります。
Github: https://github.com/shiki-tak/ewasmint

まとめ

  • eWASMにも1.0と2.0がある。
  • 1.0はEVMをwasmで実現した感じ?
  • 2.0になるとShard chainに対応したVMになるみたい。
  • Blockchain + WebAssemblyはまじ楽しい!
  • 調べれば調べるほど、色々なプロジェクトが出てくるので今後も継続して調査したい
3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3