mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
core/vm: Add support for AoT compilation of WASM precompiles
This commit is contained in:
parent
94db4dc329
commit
cc5bed4b21
6 changed files with 504 additions and 8 deletions
233
core/vm/aot.go
Normal file
233
core/vm/aot.go
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
// Copyright (c) 2018 Timo Savola. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package vm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/vm/aot"
|
||||
|
||||
"github.com/tsavola/wag"
|
||||
"github.com/tsavola/wag/buffer"
|
||||
"github.com/tsavola/wag/compile"
|
||||
"github.com/tsavola/wag/object/debug/dump"
|
||||
"github.com/tsavola/wag/wa"
|
||||
)
|
||||
|
||||
const linearMemoryAddressSpace = 8 * 1024 * 1024 * 1024
|
||||
const signalStackReserve = 8192
|
||||
const goStackVectorOffset = -4 * 8
|
||||
|
||||
type importFunc struct {
|
||||
index int
|
||||
params int
|
||||
}
|
||||
|
||||
func makeMem(size int, prot, extraFlags int) (mem []byte, err error) {
|
||||
if size > 0 {
|
||||
mem, err = syscall.Mmap(-1, 0, size, prot, syscall.MAP_PRIVATE|syscall.MAP_ANONYMOUS|extraFlags)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func memAddr(mem []byte) uintptr {
|
||||
return (*reflect.SliceHeader)(unsafe.Pointer(&mem)).Data
|
||||
}
|
||||
|
||||
func alignSize(size, alignment int) int {
|
||||
return (size + (alignment - 1)) &^ (alignment - 1)
|
||||
}
|
||||
|
||||
func GrowMemory(size int32) {
|
||||
|
||||
}
|
||||
|
||||
// AoTContract
|
||||
type AoTContract struct {
|
||||
Code []byte
|
||||
Num int
|
||||
ImportVector []byte
|
||||
ImportFuncs map[string]importFunc
|
||||
}
|
||||
|
||||
func NewAoTContract(code []byte, num int) *AoTContract {
|
||||
ret := &AoTContract{Code: code, Num: num}
|
||||
ret.ImportFuncs = make(map[string]importFunc)
|
||||
ret.ImportVector = make([]byte, (5+4)*8)
|
||||
|
||||
binary.LittleEndian.PutUint64(ret.ImportVector[0:], aot.ImportUseGas())
|
||||
binary.LittleEndian.PutUint64(ret.ImportVector[8:], aot.ImportCallDataCopy())
|
||||
binary.LittleEndian.PutUint64(ret.ImportVector[16:], aot.ImportGetCallDataSize())
|
||||
binary.LittleEndian.PutUint64(ret.ImportVector[24:], aot.ImportFinish())
|
||||
binary.LittleEndian.PutUint64(ret.ImportVector[32:], aot.ImportRevert())
|
||||
ret.ImportFuncs["useGas"] = importFunc{-9, 1}
|
||||
ret.ImportFuncs["callDataCopy"] = importFunc{-8, 3}
|
||||
ret.ImportFuncs["getCallDataSize"] = importFunc{-7, 0}
|
||||
ret.ImportFuncs["finish"] = importFunc{-6, 2}
|
||||
ret.ImportFuncs["revert"] = importFunc{-5, 2}
|
||||
|
||||
binary.LittleEndian.PutUint64(ret.ImportVector[56:], aot.ImportGrowMemoryHandler())
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ac *AoTContract) ResolveFunc(module, field string, sig wa.FuncType) (index int, err error) {
|
||||
if module != "ethereum" {
|
||||
err = fmt.Errorf("import function's module is unknown: %s %s", module, field)
|
||||
return
|
||||
}
|
||||
|
||||
i := ac.ImportFuncs[field]
|
||||
if i.index == 0 {
|
||||
err = fmt.Errorf("import function not supported: %s", field)
|
||||
return
|
||||
}
|
||||
if len(sig.Params) != i.params {
|
||||
err = fmt.Errorf("%s: import function has wrong number of parameters: import signature has %d, syscall wrapper has %d", field, len(sig.Params), i.params)
|
||||
return
|
||||
}
|
||||
|
||||
index = i.index
|
||||
return
|
||||
}
|
||||
|
||||
func (ac *AoTContract) ResolveGlobal(module, field string, t wa.Type) (init uint64, err error) {
|
||||
err = fmt.Errorf("imported global not supported: %s %s", module, field)
|
||||
return
|
||||
}
|
||||
|
||||
func (ac *AoTContract) RequiredGas(code []byte) uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (ac *AoTContract) Run(input []byte, contract *Contract) ([]byte, error) {
|
||||
var (
|
||||
textSize = compile.DefaultMaxTextSize
|
||||
stackSize = wa.PageSize
|
||||
entry = "main"
|
||||
dumpText = false
|
||||
)
|
||||
|
||||
progReader := bytes.NewReader(input)
|
||||
|
||||
vecSize := alignSize(len(ac.ImportVector), os.Getpagesize())
|
||||
|
||||
vecTextMem, err := makeMem(vecSize+textSize, syscall.PROT_READ|syscall.PROT_WRITE, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
vecMem := vecTextMem[:vecSize]
|
||||
copy(vecMem[vecSize-len(ac.ImportVector):], ac.ImportVector)
|
||||
|
||||
contractData := make([]byte, 8+8+8+len(input) /* original rsp + gas + size + data */)
|
||||
binary.LittleEndian.PutUint64(contractData[8:], contract.Gas)
|
||||
binary.LittleEndian.PutUint64(contractData[16:], uint64(len(input)))
|
||||
copy(contractData[24:], input)
|
||||
cdAddr := uint64(memAddr(contractData))
|
||||
binary.LittleEndian.PutUint64(vecTextMem[vecSize-4*8:], cdAddr)
|
||||
|
||||
textMem := vecTextMem[vecSize:]
|
||||
textAddr := memAddr(textMem)
|
||||
textBuf := buffer.NewStatic(textMem[:0], len(textMem))
|
||||
|
||||
config := &wag.Config{
|
||||
Text: textBuf,
|
||||
MemoryAlignment: os.Getpagesize(),
|
||||
Entry: entry,
|
||||
}
|
||||
obj, err := wag.Compile(config, progReader, ac)
|
||||
if dumpText && len(obj.Text) > 0 {
|
||||
e := dump.Text(os.Stdout, obj.Text, textAddr, obj.FuncAddrs, &obj.Names)
|
||||
if err == nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
binary.LittleEndian.PutUint64(ac.ImportVector[40:], uint64(obj.InitialMemorySize))
|
||||
|
||||
globalsMemory, err := makeMem(obj.MemoryOffset+linearMemoryAddressSpace, syscall.PROT_NONE, 0)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
err = syscall.Mprotect(globalsMemory[:obj.MemoryOffset+obj.InitialMemorySize], syscall.PROT_READ|syscall.PROT_WRITE)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
copy(globalsMemory, obj.GlobalsMemory)
|
||||
|
||||
memoryAddr := memAddr(globalsMemory) + uintptr(obj.MemoryOffset)
|
||||
|
||||
if err := syscall.Mprotect(vecMem, syscall.PROT_READ); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
if err := syscall.Mprotect(textMem, syscall.PROT_READ|syscall.PROT_EXEC); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
stackMem, err := makeMem(stackSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_STACK)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
stackOffset := stackSize - len(obj.StackFrame)
|
||||
copy(stackMem[stackOffset:], obj.StackFrame)
|
||||
|
||||
stackAddr := memAddr(stackMem)
|
||||
stackLimit := stackAddr + signalStackReserve
|
||||
stackPtr := stackAddr + uintptr(stackOffset)
|
||||
|
||||
if stackLimit >= stackPtr {
|
||||
log.Fatal("stack is too small for starting program")
|
||||
}
|
||||
|
||||
retaddr, retsize := aot.Exec(textAddr, stackLimit, memoryAddr, stackPtr)
|
||||
|
||||
gasLeft := binary.LittleEndian.Uint64(contractData[8:])
|
||||
if gasLeft == 0xffffffffffffffff {
|
||||
fmt.Println("Out of gas")
|
||||
return nil, ErrOutOfGas
|
||||
} else {
|
||||
fmt.Println("gas left: ", gasLeft, "result: ", globalsMemory[retaddr+obj.MemoryOffset:retaddr+obj.MemoryOffset+retsize])
|
||||
contract.Gas = gasLeft
|
||||
if retsize == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
retData := make([]byte, retsize)
|
||||
copy(retData, globalsMemory[retaddr+obj.MemoryOffset:retaddr+obj.MemoryOffset+retsize])
|
||||
return retData, nil
|
||||
}
|
||||
|
||||
// TODO cleanup all protected memory areas
|
||||
}
|
||||
24
core/vm/aot/eei.go
Normal file
24
core/vm/aot/eei.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package aot
|
||||
|
||||
func ImportGetCallDataSize() uint64
|
||||
func ImportUseGas() uint64
|
||||
func ImportCallDataCopy() uint64
|
||||
func ImportFinish() uint64
|
||||
func ImportRevert() uint64
|
||||
func ImportGrowMemoryHandler() uint64
|
||||
153
core/vm/aot/eei_amd64.s
Normal file
153
core/vm/aot/eei_amd64.s
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
TEXT ·ImportGetCallDataSize(SB),$0-8
|
||||
LEAQ ethereumGetCallDataSize<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT ethereumGetCallDataSize<>(SB),NOSPLIT,$0
|
||||
// Get pointer to the contract info area into r13
|
||||
MOVQ -0x20(R15), R13
|
||||
MOVQ 0x10(R13), AX
|
||||
RET
|
||||
|
||||
TEXT ·ImportUseGas(SB),$0-8
|
||||
LEAQ ethereumUseGas<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT ethereumUseGas<>(SB),NOSPLIT,$0
|
||||
// Get pointer to the contract info area into r13
|
||||
MOVQ -0x20(R15), R13
|
||||
|
||||
MOVQ 8(SP), AX // Gas required
|
||||
MOVQ 0x8(R13), CX // Gas left
|
||||
CMPQ AX, CX
|
||||
JA oog
|
||||
|
||||
SUBQ AX, CX
|
||||
MOVQ CX, 0x8(R13)
|
||||
XORQ AX, AX
|
||||
XORQ CX, CX
|
||||
RET
|
||||
|
||||
oog:
|
||||
// Set gas value to -1
|
||||
XORQ AX, AX
|
||||
NOTQ AX
|
||||
MOVQ AX, 0x8(R13)
|
||||
// Recover the saved value of the stack
|
||||
MOVQ -0x20(R15), SI
|
||||
MOVQ (SI), SP
|
||||
RET
|
||||
|
||||
TEXT ·ImportCallDataCopy(SB),$0-8
|
||||
LEAQ ethereumCallDataCopy<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT ethereumCallDataCopy<>(SB),NOSPLIT,$0
|
||||
// Get pointer to the contract info area into r13
|
||||
MOVQ -0x20(R15), R13
|
||||
|
||||
// Get pointer to input data
|
||||
MOVQ R13, SI
|
||||
ADDQ $0x18, SI // start of input buffer
|
||||
MOVQ 0x10(SP), AX // rax = input data offset
|
||||
ADDQ AX, SI
|
||||
|
||||
// Load and check the size of data to be
|
||||
// copied to the destination buffer
|
||||
MOVQ 0x8(SP), CX // rcx = number of bytes
|
||||
ADDQ CX, AX // rax = input buffer + nbytes
|
||||
MOVQ 0x10(R13), R12 // r12 = max size
|
||||
CMPQ AX, R12
|
||||
JA eei_error
|
||||
|
||||
// Load address of the destination buffer
|
||||
MOVQ 0x18(SP), DI
|
||||
ADDQ R14, DI
|
||||
|
||||
copy:
|
||||
MOVB (SI), AX
|
||||
MOVB AX, (DI)
|
||||
ADDQ $1, SI
|
||||
ADDQ $1, DI
|
||||
LOOP copy
|
||||
RET
|
||||
|
||||
eei_error:
|
||||
// Recover the saved value of the stack
|
||||
MOVQ -0x20(R15), SI
|
||||
MOVQ (SI), SP
|
||||
RET
|
||||
|
||||
TEXT ·ImportFinish(SB),$0-8
|
||||
LEAQ ethereumFinish<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
// Voir si je peux mettre $0-16 et ret+0(FP), ret+8(FP)
|
||||
TEXT ethereumFinish<>(SB),NOSPLIT,$0
|
||||
// Get both arguments from the stack, before it
|
||||
// is changed back to its previous value
|
||||
MOVQ 8(SP), AX
|
||||
MOVQ 16(SP), CX
|
||||
|
||||
// Recover the saved value of the stack
|
||||
MOVQ -0x20(R15), SI
|
||||
MOVQ (SI), SP
|
||||
|
||||
// Store the buffer addresses and size at
|
||||
// the location where go expects both parameters
|
||||
// to be stored, on the initial stack.
|
||||
MOVQ CX, 0x28(SP)
|
||||
MOVQ AX, 0x30(SP)
|
||||
RET
|
||||
|
||||
TEXT ·ImportRevert(SB),$0-8
|
||||
LEAQ ethereumRevert<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT ethereumRevert<>(SB),NOSPLIT,$0
|
||||
// Get both arguments from the stack, before it
|
||||
// is changed back to its previous value
|
||||
MOVQ 8(SP), AX
|
||||
MOVQ 16(SP), CX
|
||||
|
||||
// Recover the saved value of the stack
|
||||
MOVQ -0x20(R15), SI
|
||||
MOVQ (SI), SP
|
||||
|
||||
// Store the buffer addresses and size at
|
||||
// the location where go expects both parameters
|
||||
// to be stored, on the initial stack.
|
||||
MOVQ CX, 0x28(SP)
|
||||
MOVQ AX, 0x30(SP)
|
||||
RET
|
||||
|
||||
TEXT ·ImportGrowMemoryHandler(SB),$0-8
|
||||
LEAQ growMemoryHandler<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT growMemoryHandler<>(SB),NOSPLIT,$0-8
|
||||
//CALL main·GrowMemory+0(FP)
|
||||
RET
|
||||
9
core/vm/aot/exec.go
Normal file
9
core/vm/aot/exec.go
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// Copyright (c) 2018 Timo Savola. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package aot
|
||||
|
||||
func Exec(textBase, stackLimit, memoryBase, stackPtr uintptr) (int, int)
|
||||
func ImportTrapHandler() uint64
|
||||
func ImportGrowMemory() uint64
|
||||
77
core/vm/aot/exec_amd64.s
Normal file
77
core/vm/aot/exec_amd64.s
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) 2018 Timo Savola. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Copyright 2019 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func exec(textBase, stackLimit, memoryBase, stackPtr uintptr)
|
||||
TEXT ·Exec(SB),NOSPLIT,$0-48
|
||||
MOVQ textBase+0(FP), R15
|
||||
MOVQ stackLimit+8(FP), BX
|
||||
MOVQ memoryBase+16(FP), R14
|
||||
MOVQ stackPtr+24(FP), CX
|
||||
|
||||
MOVQ -0x20(R15), DI
|
||||
MOVQ SP, (DI)
|
||||
|
||||
MOVQ CX, SP // stack ptr
|
||||
|
||||
XORL AX, AX
|
||||
XORL CX, CX
|
||||
XORL BP, BP
|
||||
XORL SI, SI
|
||||
XORL DI, DI
|
||||
XORL R8, R8
|
||||
XORL R9, R9
|
||||
XORL R10, R10
|
||||
XORL R11, R11
|
||||
XORL R12, R12
|
||||
XORL R13, R13
|
||||
|
||||
MOVQ R15, DX
|
||||
ADDQ $32, DX // init routine
|
||||
JMP DX
|
||||
|
||||
// func importTrapHandler() uint64
|
||||
TEXT ·ImportTrapHandler(SB),$0-8
|
||||
LEAQ trapHandler<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT trapHandler<>(SB),NOSPLIT,$0
|
||||
CMPL AX, $0 // exit trap (lower 32 bits)
|
||||
JE exittrap
|
||||
ADDL $100, AX // 100 + trap id
|
||||
JMP sysexit
|
||||
|
||||
exittrap:
|
||||
SHRQ $32, AX // exit code (higher 32 bits)
|
||||
sysexit:
|
||||
MOVL AX, DI
|
||||
MOVL $231, AX // exit_group syscall
|
||||
SYSCALL
|
||||
|
||||
// func importGrowMemory() uint64
|
||||
TEXT ·ImportGrowMemory(SB),$0-8
|
||||
LEAQ growMemory<>(SB), AX
|
||||
MOVQ AX, ret+0(FP)
|
||||
RET
|
||||
|
||||
TEXT growMemory<>(SB),NOSPLIT,$0
|
||||
HLT // TODO: implementation
|
||||
|
|
@ -67,14 +67,14 @@ var PrecompiledContractsByzantium = map[common.Address]PrecompiledContract{
|
|||
// PrecompiledContractsEWASM contains the default set of pre-compiled Ethereum
|
||||
// contracts used for Ethereum 1.x release.
|
||||
var PrecompiledContractsEWASM = map[common.Address]PrecompiledContract{
|
||||
common.BytesToAddress([]byte{1}): newEWASMPrecompile(ewasmEcrecoverCode, 1),
|
||||
common.BytesToAddress([]byte{2}): newEWASMPrecompile(ewasmSha256HashCode, 2),
|
||||
common.BytesToAddress([]byte{3}): newEWASMPrecompile(ewasmRipemd160hashCode, 3),
|
||||
common.BytesToAddress([]byte{4}): newEWASMPrecompile(ewasmIdentityCode, 4),
|
||||
common.BytesToAddress([]byte{5}): newEWASMPrecompile(ewasmExpmodCode, 5),
|
||||
common.BytesToAddress([]byte{6}): newEWASMPrecompile(ewasmEcaddCode, 6),
|
||||
common.BytesToAddress([]byte{7}): newEWASMPrecompile(ewasmEcmulCode, 7),
|
||||
common.BytesToAddress([]byte{8}): newEWASMPrecompile(ewasmEcpairingCode, 8),
|
||||
common.BytesToAddress([]byte{1}): NewAoTContract(ewasmEcrecoverCode, 1),
|
||||
common.BytesToAddress([]byte{2}): NewAoTContract(ewasmSha256HashCode, 2),
|
||||
common.BytesToAddress([]byte{3}): NewAoTContract(ewasmRipemd160hashCode, 3),
|
||||
common.BytesToAddress([]byte{4}): NewAoTContract(ewasmIdentityCode, 4),
|
||||
common.BytesToAddress([]byte{5}): NewAoTContract(ewasmExpmodCode, 5),
|
||||
common.BytesToAddress([]byte{6}): NewAoTContract(ewasmEcaddCode, 6),
|
||||
common.BytesToAddress([]byte{7}): NewAoTContract(ewasmEcmulCode, 7),
|
||||
common.BytesToAddress([]byte{8}): NewAoTContract(ewasmEcpairingCode, 8),
|
||||
}
|
||||
|
||||
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
|
||||
|
|
|
|||
Loading…
Reference in a new issue