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
|
||||
|
||||
go build ./bindings/go/evmc
|
||||
go generate ./bindings/go/evmc
|
||||
go test -v ./bindings/go/evmc
|
||||
}
|
||||
|
||||
after_build:
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*.so
|
|
@ -1,6 +1,6 @@
|
|||
// EVMC: Ethereum Client-VM Connector API.
|
||||
// Copyright 2018 The EVMC Authors.
|
||||
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
||||
// Copyright 2019 The EVMC Authors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
||||
|
||||
package evmc
|
||||
|
||||
|
|
|
@ -1,24 +1,49 @@
|
|||
// EVMC: Ethereum Client-VM Connector API.
|
||||
// Copyright 2018 The EVMC Authors.
|
||||
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
||||
// Copyright 2019 The EVMC Authors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
||||
|
||||
//go:generate gcc -shared ../../../examples/example_vm.c -I../../../include -o example_vm.so
|
||||
|
||||
package evmc
|
||||
|
||||
import (
|
||||
"os"
|
||||
"bytes"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
var modulePath = "./example_vm.so"
|
||||
|
||||
func TestLoad(t *testing.T) {
|
||||
i, err := Load(os.Getenv("EVMC_PATH"))
|
||||
i, err := Load(modulePath)
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
defer i.Destroy()
|
||||
if i.Name() != "interpreter" {
|
||||
t.Fatal("name is not 'interpreter'")
|
||||
if i.Name() != "example_vm" {
|
||||
t.Fatalf("name is %s", i.Name())
|
||||
}
|
||||
if i.Version()[0] != '1' {
|
||||
t.Fatalf("version is %s", i.Version())
|
||||
if i.Version()[0] < '0' || i.Version()[0] > '9' {
|
||||
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.
|
||||
// Copyright 2018 The EVMC Authors.
|
||||
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
||||
// Copyright 2019 The EVMC Authors.
|
||||
// Licensed under the Apache License, Version 2.0.
|
||||
|
||||
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]
|
||||
}
|
||||
|
||||
// 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 {
|
||||
AccountExists(addr common.Address) bool
|
||||
GetStorage(addr common.Address, key common.Hash) common.Hash
|
||||
|
@ -78,8 +89,7 @@ type HostContext interface {
|
|||
GetCodeHash(addr common.Address) common.Hash
|
||||
GetCode(addr common.Address) []byte
|
||||
Selfdestruct(addr common.Address, beneficiary common.Address)
|
||||
GetTxContext() (gasPrice common.Hash, origin common.Address, coinbase common.Address, number int64, timestamp int64,
|
||||
gasLimit int64, difficulty common.Hash)
|
||||
GetTxContext() TxContext
|
||||
GetBlockHash(number int64) common.Hash
|
||||
EmitLog(addr common.Address, topics []common.Hash, data []byte)
|
||||
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)
|
||||
ctx := getHostContext(idx)
|
||||
|
||||
gasPrice, origin, coinbase, number, timestamp, gasLimit, difficulty := ctx.GetTxContext()
|
||||
txContext := ctx.GetTxContext()
|
||||
|
||||
return C.struct_evmc_tx_context{
|
||||
evmcBytes32(gasPrice),
|
||||
evmcAddress(origin),
|
||||
evmcAddress(coinbase),
|
||||
C.int64_t(number),
|
||||
C.int64_t(timestamp),
|
||||
C.int64_t(gasLimit),
|
||||
evmcBytes32(difficulty),
|
||||
evmcBytes32(txContext.GasPrice),
|
||||
evmcAddress(txContext.Origin),
|
||||
evmcAddress(txContext.Coinbase),
|
||||
C.int64_t(txContext.Number),
|
||||
C.int64_t(txContext.Timestamp),
|
||||
C.int64_t(txContext.GasLimit),
|
||||
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 build -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:
|
||||
docker:
|
||||
|
|
|
@ -91,6 +91,7 @@ static struct evmc_result execute(struct evmc_instance* instance,
|
|||
ret.output_data = (const uint8_t*)error;
|
||||
ret.output_size = strlen(error);
|
||||
ret.status_code = EVMC_FAILURE;
|
||||
ret.gas_left = msg->gas / 10;
|
||||
ret.release = NULL; // We don't need to release the constant messages.
|
||||
return ret;
|
||||
}
|
||||
|
@ -106,7 +107,10 @@ static struct evmc_result execute(struct evmc_instance* instance,
|
|||
// Assembly: `{ sstore(0, add(sload(0), 1)) }`
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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}};
|
||||
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;
|
||||
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.gas_left = 0;
|
||||
|
|
Loading…
Reference in New Issue