mirror of https://github.com/status-im/evmc.git
Merge pull request #197 from ethereum/go-txcontext
go: Combine tx context into TxContext struct
This commit is contained in:
commit
f6b10594ce
|
@ -47,6 +47,8 @@ build_script:
|
||||||
copy lib/loader/loader.c bindings/go/evmc
|
copy lib/loader/loader.c bindings/go/evmc
|
||||||
|
|
||||||
go build ./bindings/go/evmc
|
go build ./bindings/go/evmc
|
||||||
|
go generate ./bindings/go/evmc
|
||||||
|
go test -v ./bindings/go/evmc
|
||||||
}
|
}
|
||||||
|
|
||||||
after_build:
|
after_build:
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
*.so
|
|
@ -1,6 +1,6 @@
|
||||||
// EVMC: Ethereum Client-VM Connector API.
|
// EVMC: Ethereum Client-VM Connector API.
|
||||||
// Copyright 2018 The EVMC Authors.
|
// Copyright 2019 The EVMC Authors.
|
||||||
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
// Licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
package evmc
|
package evmc
|
||||||
|
|
||||||
|
|
|
@ -1,24 +1,49 @@
|
||||||
// EVMC: Ethereum Client-VM Connector API.
|
// EVMC: Ethereum Client-VM Connector API.
|
||||||
// Copyright 2018 The EVMC Authors.
|
// Copyright 2019 The EVMC Authors.
|
||||||
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
// Licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
|
//go:generate gcc -shared ../../../examples/example_vm.c -I../../../include -o example_vm.so
|
||||||
|
|
||||||
package evmc
|
package evmc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"bytes"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var modulePath = "./example_vm.so"
|
||||||
|
|
||||||
func TestLoad(t *testing.T) {
|
func TestLoad(t *testing.T) {
|
||||||
i, err := Load(os.Getenv("EVMC_PATH"))
|
i, err := Load(modulePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
defer i.Destroy()
|
defer i.Destroy()
|
||||||
if i.Name() != "interpreter" {
|
if i.Name() != "example_vm" {
|
||||||
t.Fatal("name is not 'interpreter'")
|
t.Fatalf("name is %s", i.Name())
|
||||||
}
|
}
|
||||||
if i.Version()[0] != '1' {
|
if i.Version()[0] < '0' || i.Version()[0] > '9' {
|
||||||
t.Fatalf("version is %s", i.Version())
|
t.Fatalf("version number is weird: %s", i.Version())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecute(t *testing.T) {
|
||||||
|
vm, _ := Load(modulePath)
|
||||||
|
defer vm.Destroy()
|
||||||
|
|
||||||
|
addr := common.Address{}
|
||||||
|
h := common.Hash{}
|
||||||
|
output, gasLeft, err := vm.Execute(nil, Byzantium, Call, false, 1, 999, addr, addr, nil, h, nil, h)
|
||||||
|
|
||||||
|
if bytes.Compare(output, []byte("Welcome to Byzantium!")) != 0 {
|
||||||
|
t.Errorf("execution unexpected output: %s", output)
|
||||||
|
}
|
||||||
|
if gasLeft != 99 {
|
||||||
|
t.Error("execution gas left is incorrect")
|
||||||
|
}
|
||||||
|
if err != Failure {
|
||||||
|
t.Error("execution returned unexpected error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// EVMC: Ethereum Client-VM Connector API.
|
// EVMC: Ethereum Client-VM Connector API.
|
||||||
// Copyright 2018 The EVMC Authors.
|
// Copyright 2019 The EVMC Authors.
|
||||||
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
// Licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
package evmc
|
package evmc
|
||||||
|
|
||||||
|
@ -69,6 +69,17 @@ func goByteSlice(data *C.uint8_t, size C.size_t) []byte {
|
||||||
return (*[1 << 30]byte)(unsafe.Pointer(data))[:size:size]
|
return (*[1 << 30]byte)(unsafe.Pointer(data))[:size:size]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TxContext contains information about current transaction and block.
|
||||||
|
type TxContext struct {
|
||||||
|
GasPrice common.Hash
|
||||||
|
Origin common.Address
|
||||||
|
Coinbase common.Address
|
||||||
|
Number int64
|
||||||
|
Timestamp int64
|
||||||
|
GasLimit int64
|
||||||
|
Difficulty common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
type HostContext interface {
|
type HostContext interface {
|
||||||
AccountExists(addr common.Address) bool
|
AccountExists(addr common.Address) bool
|
||||||
GetStorage(addr common.Address, key common.Hash) common.Hash
|
GetStorage(addr common.Address, key common.Hash) common.Hash
|
||||||
|
@ -78,8 +89,7 @@ type HostContext interface {
|
||||||
GetCodeHash(addr common.Address) common.Hash
|
GetCodeHash(addr common.Address) common.Hash
|
||||||
GetCode(addr common.Address) []byte
|
GetCode(addr common.Address) []byte
|
||||||
Selfdestruct(addr common.Address, beneficiary common.Address)
|
Selfdestruct(addr common.Address, beneficiary common.Address)
|
||||||
GetTxContext() (gasPrice common.Hash, origin common.Address, coinbase common.Address, number int64, timestamp int64,
|
GetTxContext() TxContext
|
||||||
gasLimit int64, difficulty common.Hash)
|
|
||||||
GetBlockHash(number int64) common.Hash
|
GetBlockHash(number int64) common.Hash
|
||||||
EmitLog(addr common.Address, topics []common.Hash, data []byte)
|
EmitLog(addr common.Address, topics []common.Hash, data []byte)
|
||||||
Call(kind CallKind,
|
Call(kind CallKind,
|
||||||
|
@ -162,16 +172,16 @@ func getTxContext(pCtx unsafe.Pointer) C.struct_evmc_tx_context {
|
||||||
idx := int((*C.struct_extended_context)(pCtx).index)
|
idx := int((*C.struct_extended_context)(pCtx).index)
|
||||||
ctx := getHostContext(idx)
|
ctx := getHostContext(idx)
|
||||||
|
|
||||||
gasPrice, origin, coinbase, number, timestamp, gasLimit, difficulty := ctx.GetTxContext()
|
txContext := ctx.GetTxContext()
|
||||||
|
|
||||||
return C.struct_evmc_tx_context{
|
return C.struct_evmc_tx_context{
|
||||||
evmcBytes32(gasPrice),
|
evmcBytes32(txContext.GasPrice),
|
||||||
evmcAddress(origin),
|
evmcAddress(txContext.Origin),
|
||||||
evmcAddress(coinbase),
|
evmcAddress(txContext.Coinbase),
|
||||||
C.int64_t(number),
|
C.int64_t(txContext.Number),
|
||||||
C.int64_t(timestamp),
|
C.int64_t(txContext.Timestamp),
|
||||||
C.int64_t(gasLimit),
|
C.int64_t(txContext.GasLimit),
|
||||||
evmcBytes32(difficulty),
|
evmcBytes32(txContext.Difficulty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
// EVMC: Ethereum Client-VM Connector API.
|
||||||
|
// Copyright 2019 The EVMC Authors.
|
||||||
|
// Licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
|
package evmc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testHostContext struct{}
|
||||||
|
|
||||||
|
func (host *testHostContext) AccountExists(addr common.Address) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) GetStorage(addr common.Address, key common.Hash) common.Hash {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) SetStorage(addr common.Address, key common.Hash, value common.Hash) (status StorageStatus) {
|
||||||
|
return StorageUnchanged
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) GetBalance(addr common.Address) common.Hash {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) GetCodeSize(addr common.Address) int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) GetCodeHash(addr common.Address) common.Hash {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) GetCode(addr common.Address) []byte {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) Selfdestruct(addr common.Address, beneficiary common.Address) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) GetTxContext() TxContext {
|
||||||
|
txContext := TxContext{}
|
||||||
|
txContext.Number = 42
|
||||||
|
return txContext
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) GetBlockHash(number int64) common.Hash {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) EmitLog(addr common.Address, topics []common.Hash, data []byte) {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (host *testHostContext) Call(kind CallKind,
|
||||||
|
destination common.Address, sender common.Address, value *big.Int, input []byte, gas int64, depth int,
|
||||||
|
static bool, salt *big.Int) (output []byte, gasLeft int64, createAddr common.Address, err error) {
|
||||||
|
return nil, gas, common.Address{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTxContext(t *testing.T) {
|
||||||
|
vm, _ := Load(modulePath)
|
||||||
|
defer vm.Destroy()
|
||||||
|
|
||||||
|
host := &testHostContext{}
|
||||||
|
code := []byte("\x43\x60\x00\x52\x59\x60\x00\xf3")
|
||||||
|
|
||||||
|
addr := common.Address{}
|
||||||
|
h := common.Hash{}
|
||||||
|
output, gasLeft, err := vm.Execute(host, Byzantium, Call, false, 1, 100, addr, addr, nil, h, code, h)
|
||||||
|
|
||||||
|
if len(output) != 20 {
|
||||||
|
t.Errorf("unexpected output size: %d", len(output))
|
||||||
|
}
|
||||||
|
if bytes.Compare(output[0:3], []byte("42\x00")) != 0 {
|
||||||
|
t.Errorf("execution unexpected output: %s", output)
|
||||||
|
}
|
||||||
|
if gasLeft != 50 {
|
||||||
|
t.Errorf("execution gas left is incorrect: %x", gasLeft)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Error("execution returned unexpected error")
|
||||||
|
}
|
||||||
|
}
|
|
@ -147,6 +147,8 @@ jobs:
|
||||||
go get -v github.com/ethereum/go-ethereum/common
|
go get -v github.com/ethereum/go-ethereum/common
|
||||||
go build -v ./bindings/go/evmc
|
go build -v ./bindings/go/evmc
|
||||||
go vet -v ./bindings/go/evmc
|
go vet -v ./bindings/go/evmc
|
||||||
|
go generate -v ./bindings/go/evmc
|
||||||
|
go test -v ./bindings/go/evmc
|
||||||
|
|
||||||
bindings-go-1.9:
|
bindings-go-1.9:
|
||||||
docker:
|
docker:
|
||||||
|
|
|
@ -91,6 +91,7 @@ static struct evmc_result execute(struct evmc_instance* instance,
|
||||||
ret.output_data = (const uint8_t*)error;
|
ret.output_data = (const uint8_t*)error;
|
||||||
ret.output_size = strlen(error);
|
ret.output_size = strlen(error);
|
||||||
ret.status_code = EVMC_FAILURE;
|
ret.status_code = EVMC_FAILURE;
|
||||||
|
ret.gas_left = msg->gas / 10;
|
||||||
ret.release = NULL; // We don't need to release the constant messages.
|
ret.release = NULL; // We don't need to release the constant messages.
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -106,7 +107,10 @@ static struct evmc_result execute(struct evmc_instance* instance,
|
||||||
// Assembly: `{ sstore(0, add(sload(0), 1)) }`
|
// Assembly: `{ sstore(0, add(sload(0), 1)) }`
|
||||||
const char counter[] = "\x60\x01\x60\x00\x54\x01\x60\x00\x55";
|
const char counter[] = "\x60\x01\x60\x00\x54\x01\x60\x00\x55";
|
||||||
|
|
||||||
if (code_size == strlen(return_address) &&
|
// Assembly: `{ mstore(0, number()) return(0, msize()) }`
|
||||||
|
const char return_block_number[] = "\x43\x60\x00\x52\x59\x60\x00\xf3";
|
||||||
|
|
||||||
|
if (code_size == (sizeof(return_address) - 1) &&
|
||||||
strncmp((const char*)code, return_address, code_size) == 0)
|
strncmp((const char*)code, return_address, code_size) == 0)
|
||||||
{
|
{
|
||||||
static const size_t address_size = sizeof(msg->destination);
|
static const size_t address_size = sizeof(msg->destination);
|
||||||
|
@ -124,7 +128,8 @@ static struct evmc_result execute(struct evmc_instance* instance,
|
||||||
ret.release = &free_result_output_data;
|
ret.release = &free_result_output_data;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
else if (code_size == strlen(counter) && strncmp((const char*)code, counter, code_size) == 0)
|
else if (code_size == (sizeof(counter) - 1) &&
|
||||||
|
strncmp((const char*)code, counter, code_size) == 0)
|
||||||
{
|
{
|
||||||
const evmc_bytes32 key = {{0}};
|
const evmc_bytes32 key = {{0}};
|
||||||
evmc_bytes32 value = context->host->get_storage(context, &msg->destination, &key);
|
evmc_bytes32 value = context->host->get_storage(context, &msg->destination, &key);
|
||||||
|
@ -133,6 +138,21 @@ static struct evmc_result execute(struct evmc_instance* instance,
|
||||||
ret.status_code = EVMC_SUCCESS;
|
ret.status_code = EVMC_SUCCESS;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
else if (code_size == (sizeof(return_block_number) - 1) &&
|
||||||
|
strncmp((const char*)code, return_block_number, code_size) == 0)
|
||||||
|
{
|
||||||
|
const struct evmc_tx_context tx_context = context->host->get_tx_context(context);
|
||||||
|
const size_t output_size = 20;
|
||||||
|
|
||||||
|
uint8_t* output_data = (uint8_t*)calloc(1, output_size);
|
||||||
|
snprintf((char*)output_data, output_size, "%u", (unsigned)tx_context.block_number);
|
||||||
|
ret.status_code = EVMC_SUCCESS;
|
||||||
|
ret.gas_left = msg->gas / 2;
|
||||||
|
ret.output_data = output_data;
|
||||||
|
ret.output_size = output_size;
|
||||||
|
ret.release = &free_result_output_data;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret.status_code = EVMC_FAILURE;
|
ret.status_code = EVMC_FAILURE;
|
||||||
ret.gas_left = 0;
|
ret.gas_left = 0;
|
||||||
|
|
Loading…
Reference in New Issue