vendor: Add EVMC 5.2.0

govendor fetch github.com/ethereum/evmc/bindings/go/evmc@=v5.2.0
This commit is contained in:
Paweł Bylica 2018-09-11 14:34:59 +02:00
parent cdf5982cfc
commit 33bf2f9da2
No known key found for this signature in database
GPG key ID: 7A0C037434FE77EF
9 changed files with 2040 additions and 0 deletions

202
vendor/github.com/ethereum/evmc/LICENSE generated vendored Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,279 @@
// EVMC: Ethereum Client-VM Connector API.
// Copyright 2018 The EVMC Authors.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
package evmc
/*
#cgo CFLAGS: -I${SRCDIR}/.. -Wall -Wextra
#cgo !windows LDFLAGS: -ldl
#include <evmc/evmc.h>
#include <evmc/helpers.h>
#include <evmc/loader.h>
#include <stdlib.h>
#include <string.h>
static inline int set_option(struct evmc_instance* instance, char* name, char* value)
{
int ret = evmc_set_option(instance, name, value);
free(name);
free(value);
return ret;
}
struct extended_context
{
struct evmc_context context;
int64_t index;
};
extern const struct evmc_context_fn_table evmc_go_fn_table;
static struct evmc_result execute_wrapper(struct evmc_instance* instance, int64_t context_index, enum evmc_revision rev,
const struct evmc_address* destination, const struct evmc_address* sender, const struct evmc_uint256be* value,
const uint8_t* input_data, size_t input_size, const struct evmc_uint256be* code_hash, int64_t gas,
int32_t depth, enum evmc_call_kind kind, uint32_t flags, const uint8_t* code, size_t code_size)
{
struct evmc_uint256be create2_salt = {};
struct evmc_message msg = {
*destination,
*sender,
*value,
input_data,
input_size,
*code_hash,
create2_salt,
gas,
depth,
kind,
flags,
};
struct extended_context ctx = {{&evmc_go_fn_table}, context_index};
return evmc_execute(instance, &ctx.context, rev, &msg, code, code_size);
}
*/
import "C"
import (
"errors"
"fmt"
"sync"
"unsafe"
"github.com/ethereum/go-ethereum/common"
)
// Static asserts.
const (
_ = uint(common.HashLength - C.sizeof_struct_evmc_uint256be) // The size of evmc_uint256be equals the size of Hash.
_ = uint(C.sizeof_struct_evmc_uint256be - common.HashLength)
_ = uint(common.AddressLength - C.sizeof_struct_evmc_address) // The size of evmc_address equals the size of Address.
_ = uint(C.sizeof_struct_evmc_address - common.AddressLength)
)
type Error int32
func (err Error) IsInternalError() bool {
return err < 0
}
func (err Error) Error() string {
code := C.enum_evmc_status_code(err)
switch code {
case C.EVMC_FAILURE:
return "evmc: failure"
case C.EVMC_REVERT:
return "evmc: revert"
case C.EVMC_OUT_OF_GAS:
return "evmc: out of gas"
case C.EVMC_INVALID_INSTRUCTION:
return "evmc: invalid instruction"
case C.EVMC_UNDEFINED_INSTRUCTION:
return "evmc: undefined instruction"
case C.EVMC_STACK_OVERFLOW:
return "evmc: stack overflow"
case C.EVMC_STACK_UNDERFLOW:
return "evmc: stack underflow"
case C.EVMC_BAD_JUMP_DESTINATION:
return "evmc: bad jump destination"
case C.EVMC_INVALID_MEMORY_ACCESS:
return "evmc: invalid memory access"
case C.EVMC_CALL_DEPTH_EXCEEDED:
return "evmc: call depth exceeded"
case C.EVMC_STATIC_MODE_VIOLATION:
return "evmc: static mode violation"
case C.EVMC_PRECOMPILE_FAILURE:
return "evmc: precompile failure"
case C.EVMC_CONTRACT_VALIDATION_FAILURE:
return "evmc: contract validation failure"
case C.EVMC_ARGUMENT_OUT_OF_RANGE:
return "evmc: argument out of range"
case C.EVMC_WASM_UNREACHABLE_INSTRUCTION:
return "evmc: the WebAssembly unreachable instruction has been hit during execution"
case C.EVMC_WASM_TRAP:
return "evmc: a WebAssembly trap has been hit during execution"
case C.EVMC_REJECTED:
return "evmc: rejected"
}
if code < 0 {
return fmt.Sprintf("evmc: internal error (%d)", int32(code))
}
return fmt.Sprintf("evmc: unknown non-fatal status code %d", int32(code))
}
const (
Failure = Error(C.EVMC_FAILURE)
Revert = Error(C.EVMC_REVERT)
)
type Revision int32
const (
Frontier Revision = C.EVMC_FRONTIER
Homestead Revision = C.EVMC_HOMESTEAD
TangerineWhistle Revision = C.EVMC_TANGERINE_WHISTLE
SpuriousDragon Revision = C.EVMC_SPURIOUS_DRAGON
Byzantium Revision = C.EVMC_BYZANTIUM
Constantinople Revision = C.EVMC_CONSTANTINOPLE
)
type Instance struct {
handle *C.struct_evmc_instance
}
func Load(filename string) (instance *Instance, err error) {
cfilename := C.CString(filename)
var loaderErr C.enum_evmc_loader_error_code
handle := C.evmc_load_and_create(cfilename, &loaderErr)
C.free(unsafe.Pointer(cfilename))
switch loaderErr {
case C.EVMC_LOADER_SUCCESS:
instance = &Instance{handle}
case C.EVMC_LOADER_CANNOT_OPEN:
err = fmt.Errorf("evmc loader: cannot open %s", filename)
case C.EVMC_LOADER_SYMBOL_NOT_FOUND:
err = fmt.Errorf("evmc loader: the EVMC create function not found in %s", filename)
case C.EVMC_LOADER_INVALID_ARGUMENT:
panic("evmc loader: filename argument is invalid")
case C.EVMC_LOADER_INSTANCE_CREATION_FAILURE:
err = errors.New("evmc loader: VM instance creation failure")
case C.EVMC_LOADER_ABI_VERSION_MISMATCH:
err = errors.New("evmc loader: ABI version mismatch")
default:
panic(fmt.Sprintf("evmc loader: unexpected error (%d)", int(loaderErr)))
}
return instance, err
}
func (instance *Instance) Destroy() {
C.evmc_destroy(instance.handle)
}
func (instance *Instance) Name() string {
// TODO: consider using C.evmc_vm_name(instance.handle)
return C.GoString(instance.handle.name)
}
func (instance *Instance) Version() string {
// TODO: consider using C.evmc_vm_version(instance.handle)
return C.GoString(instance.handle.version)
}
func (instance *Instance) SetOption(name string, value string) (err error) {
r := C.set_option(instance.handle, C.CString(name), C.CString(value))
if r != 1 {
err = fmt.Errorf("evmc: option '%s' not accepted", name)
}
return err
}
func (instance *Instance) Execute(ctx HostContext, rev Revision,
destination common.Address, sender common.Address, value common.Hash, input []byte, codeHash common.Hash, gas int64,
depth int, kind CallKind, static bool, code []byte) (output []byte, gasLeft int64, err error) {
flags := C.uint32_t(0)
if static {
flags |= C.EVMC_STATIC
}
ctxId := addHostContext(ctx)
// FIXME: Clarify passing by pointer vs passing by value.
evmcDestination := evmcAddress(destination)
evmcSender := evmcAddress(sender)
evmcValue := evmcUint256be(value)
evmcCodeHash := evmcUint256be(codeHash)
result := C.execute_wrapper(instance.handle, C.int64_t(ctxId), uint32(rev), &evmcDestination, &evmcSender, &evmcValue,
bytesPtr(input), C.size_t(len(input)), &evmcCodeHash, C.int64_t(gas), C.int32_t(depth), C.enum_evmc_call_kind(kind),
flags, bytesPtr(code), C.size_t(len(code)))
removeHostContext(ctxId)
output = C.GoBytes(unsafe.Pointer(result.output_data), C.int(result.output_size))
gasLeft = int64(result.gas_left)
if result.status_code != C.EVMC_SUCCESS {
err = Error(result.status_code)
}
if result.release != nil {
C.evmc_release_result(&result)
}
return output, gasLeft, err
}
var (
hostContextCounter int
hostContextMap = map[int]HostContext{}
hostContextMapMu sync.Mutex
)
func addHostContext(ctx HostContext) int {
hostContextMapMu.Lock()
id := hostContextCounter
hostContextCounter++
hostContextMap[id] = ctx
hostContextMapMu.Unlock()
return id
}
func removeHostContext(id int) {
hostContextMapMu.Lock()
delete(hostContextMap, id)
hostContextMapMu.Unlock()
}
func getHostContext(idx int) HostContext {
hostContextMapMu.Lock()
ctx := hostContextMap[idx]
hostContextMapMu.Unlock()
return ctx
}
func evmcUint256be(in common.Hash) C.struct_evmc_uint256be {
out := C.struct_evmc_uint256be{}
for i := 0; i < len(in); i++ {
out.bytes[i] = C.uint8_t(in[i])
}
return out
}
func evmcAddress(address common.Address) C.struct_evmc_address {
r := C.struct_evmc_address{}
for i := 0; i < len(address); i++ {
r.bytes[i] = C.uint8_t(address[i])
}
return r
}
func bytesPtr(bytes []byte) *C.uint8_t {
if len(bytes) == 0 {
return nil
}
return (*C.uint8_t)(unsafe.Pointer(&bytes[0]))
}

868
vendor/github.com/ethereum/evmc/bindings/go/evmc/evmc.h generated vendored Normal file
View file

@ -0,0 +1,868 @@
/**
* EVMC: Ethereum Client-VM Connector API
*
* @copyright
* Copyright 2018 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*
* @defgroup EVMC EVMC
* @{
*/
#ifndef EVMC_H
#define EVMC_H
#include <stddef.h> /* Definition of size_t. */
#include <stdint.h> /* Definition of int64_t, uint64_t. */
#if __cplusplus
extern "C" {
#endif
/* BEGIN Python CFFI declarations */
enum
{
/** The EVMC ABI version number of the interface declared in this file. */
EVMC_ABI_VERSION = 5
};
/**
* Big-endian 256-bit integer.
*
* 32 bytes of data representing big-endian 256-bit integer. I.e. bytes[0] is
* the most significant byte, bytes[31] is the least significant byte.
* This type is used to transfer to/from the VM values interpreted by the user
* as both 256-bit integers and 256-bit hashes.
*/
struct evmc_uint256be
{
/** The 32 bytes of the big-endian integer or hash. */
uint8_t bytes[32];
};
/** Big-endian 160-bit hash suitable for keeping an Ethereum address. */
struct evmc_address
{
/** The 20 bytes of the hash. */
uint8_t bytes[20];
};
/** The kind of call-like instruction. */
enum evmc_call_kind
{
EVMC_CALL = 0, /**< Request CALL. */
EVMC_DELEGATECALL = 1, /**< Request DELEGATECALL. Valid since Homestead.
The value param ignored. */
EVMC_CALLCODE = 2, /**< Request CALLCODE. */
EVMC_CREATE = 3, /**< Request CREATE. */
EVMC_CREATE2 = 4 /**< Request CREATE2. Valid since Constantinople.*/
};
/** The flags for ::evmc_message. */
enum evmc_flags
{
EVMC_STATIC = 1 /**< Static call mode. */
};
/**
* The message describing an EVM call,
* including a zero-depth calls from a transaction origin.
*/
struct evmc_message
{
/** The destination of the message. */
struct evmc_address destination;
/** The sender of the message. */
struct evmc_address sender;
/**
* The amount of Ether transferred with the message.
*/
struct evmc_uint256be value;
/**
* The message input data.
*
* This MAY be NULL.
*/
const uint8_t* input_data;
/**
* The size of the message input data.
*
* If input_data is NULL this MUST be 0.
*/
size_t input_size;
/**
* The optional hash of the code of the destination account.
* The null hash MUST be used when not specified.
*/
struct evmc_uint256be code_hash;
/**
* The optional value used in new contract address construction.
*
* Ignored unless kind is EVMC_CREATE2.
*/
struct evmc_uint256be create2_salt;
/** The amount of gas for message execution. */
int64_t gas;
/** The call depth. */
int32_t depth;
/** The kind of the call. For zero-depth calls ::EVMC_CALL SHOULD be used. */
enum evmc_call_kind kind;
/**
* Additional flags modifying the call execution behavior.
* In the current version the only valid values are ::EVMC_STATIC or 0.
*/
uint32_t flags;
};
/** The transaction and block data for execution. */
struct evmc_tx_context
{
struct evmc_uint256be tx_gas_price; /**< The transaction gas price. */
struct evmc_address tx_origin; /**< The transaction origin account. */
struct evmc_address block_coinbase; /**< The miner of the block. */
int64_t block_number; /**< The block number. */
int64_t block_timestamp; /**< The block timestamp. */
int64_t block_gas_limit; /**< The block gas limit. */
struct evmc_uint256be block_difficulty; /**< The block difficulty. */
};
struct evmc_context;
/**
* Get transaction context callback function.
*
* This callback function is used by an EVM to retrieve the transaction and
* block context.
*
* @param[out] result The returned transaction context.
* @see ::evmc_tx_context.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
*/
typedef void (*evmc_get_tx_context_fn)(struct evmc_tx_context* result,
struct evmc_context* context);
/**
* Get block hash callback function.
*
* This callback function is used by an EVM to query the block hash of
* a given block.
*
* @param[out] result The returned block hash value.
* @param context The pointer to the Host execution context.
* @param number The block number. Must be a value between
* (and including) 0 and 255.
*/
typedef void (*evmc_get_block_hash_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
int64_t number);
/**
* The execution status code.
*
* Successful execution is represented by ::EVMC_SUCCESS having value 0.
*
* Positive values represent failures defined by VM specifications with generic
* ::EVMC_FAILURE code of value 1.
*
* Status codes with negative values represent VM internal errors
* not provided by EVM specifications. These errors MUST not be passed back
* to the caller. They MAY be handled by the Client in predefined manner
* (see e.g. ::EVMC_REJECTED), otherwise internal errors are not recoverable.
* The generic representant of errors is ::EVMC_INTERNAL_ERROR but
* an EVM implementation MAY return negative status codes that are not defined
* in the EVMC documentation.
*
* @note
* In case new status codes are needed, please create an issue or pull request
* in the EVMC repository (https://github.com/ethereum/evmc).
*/
enum evmc_status_code
{
/** Execution finished with success. */
EVMC_SUCCESS = 0,
/** Generic execution failure. */
EVMC_FAILURE = 1,
/**
* Execution terminated with REVERT opcode.
*
* In this case the amount of gas left MAY be non-zero and additional output
* data MAY be provided in ::evmc_result.
*/
EVMC_REVERT = 2,
/** The execution has run out of gas. */
EVMC_OUT_OF_GAS = 3,
/**
* The designated INVALID instruction has been hit during execution.
*
* The EIP-141 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-141.md)
* defines the instruction 0xfe as INVALID instruction to indicate execution
* abortion coming from high-level languages. This status code is reported
* in case this INVALID instruction has been encountered.
*/
EVMC_INVALID_INSTRUCTION = 4,
/** An undefined instruction has been encountered. */
EVMC_UNDEFINED_INSTRUCTION = 5,
/**
* The execution has attempted to put more items on the EVM stack
* than the specified limit.
*/
EVMC_STACK_OVERFLOW = 6,
/** Execution of an opcode has required more items on the EVM stack. */
EVMC_STACK_UNDERFLOW = 7,
/** Execution has violated the jump destination restrictions. */
EVMC_BAD_JUMP_DESTINATION = 8,
/**
* Tried to read outside memory bounds.
*
* An example is RETURNDATACOPY reading past the available buffer.
*/
EVMC_INVALID_MEMORY_ACCESS = 9,
/** Call depth has exceeded the limit (if any) */
EVMC_CALL_DEPTH_EXCEEDED = 10,
/** Tried to execute an operation which is restricted in static mode. */
EVMC_STATIC_MODE_VIOLATION = 11,
/**
* A call to a precompiled or system contract has ended with a failure.
*
* An example: elliptic curve functions handed invalid EC points.
*/
EVMC_PRECOMPILE_FAILURE = 12,
/**
* Contract validation has failed (e.g. due to EVM 1.5 jump validity,
* Casper's purity checker or ewasm contract rules).
*/
EVMC_CONTRACT_VALIDATION_FAILURE = 13,
/**
* An argument to a state accessing method has a value outside of the
* accepted range of values.
*/
EVMC_ARGUMENT_OUT_OF_RANGE = 14,
/**
* A WebAssembly `unreachable` instruction has been hit during exection.
*/
EVMC_WASM_UNREACHABLE_INSTRUCTION = 15,
/**
* A WebAssembly trap has been hit during execution. This can be for many
* reasons, including division by zero, validation errors, etc.
*/
EVMC_WASM_TRAP = 16,
/** EVM implementation generic internal error. */
EVMC_INTERNAL_ERROR = -1,
/**
* The execution of the given code and/or message has been rejected
* by the EVM implementation.
*
* This error SHOULD be used to signal that the EVM is not able to or
* willing to execute the given code type or message.
* If an EVM returns the ::EVMC_REJECTED status code,
* the Client MAY try to execute it in other EVM implementation.
* For example, the Client tries running a code in the EVM 1.5. If the
* code is not supported there, the execution falls back to the EVM 1.0.
*/
EVMC_REJECTED = -2
};
/* Forward declaration. */
struct evmc_result;
/**
* Releases resources assigned to an execution result.
*
* This function releases memory (and other resources, if any) assigned to the
* specified execution result making the result object invalid.
*
* @param result The execution result which resources are to be released. The
* result itself it not modified by this function, but becomes
* invalid and user MUST discard it as well.
* This MUST NOT be NULL.
*
* @note
* The result is passed by pointer to avoid (shallow) copy of the ::evmc_result
* struct. Think of this as the best possible C language approximation to
* passing objects by reference.
*/
typedef void (*evmc_release_result_fn)(const struct evmc_result* result);
/** The EVM code execution result. */
struct evmc_result
{
/** The execution status code. */
enum evmc_status_code status_code;
/**
* The amount of gas left after the execution.
*
* If evmc_result::code is not ::EVMC_SUCCESS nor ::EVMC_REVERT
* the value MUST be 0.
*/
int64_t gas_left;
/**
* The reference to output data.
*
* The output contains data coming from RETURN opcode (iff evmc_result::code
* field is ::EVMC_SUCCESS) or from REVERT opcode.
*
* The memory containing the output data is owned by EVM and has to be
* freed with evmc_result::release().
*
* This MAY be NULL.
*/
const uint8_t* output_data;
/**
* The size of the output data.
*
* If output_data is NULL this MUST be 0.
*/
size_t output_size;
/**
* The pointer to a function releasing all resources associated with
* the result object.
*
* This function pointer is optional (MAY be NULL) and MAY be set by
* the EVM implementation. If set it MUST be used by the user to
* release memory and other resources associated with the result object.
* After the result resources are released the result object
* MUST NOT be used any more.
*
* The suggested code pattern for releasing EVM results:
* @code
* struct evmc_result result = ...;
* if (result.release)
* result.release(&result);
* @endcode
*
* @note
* It works similarly to C++ virtual destructor. Attaching the release
* function to the result itself allows EVM composition.
*/
evmc_release_result_fn release;
/**
* The address of the contract created by CREATE opcode.
*
* This field has valid value only if the result describes successful
* CREATE (evmc_result::status_code is ::EVMC_SUCCESS).
*/
struct evmc_address create_address;
/**
* Reserved data that MAY be used by a evmc_result object creator.
*
* This reserved 4 bytes together with 20 bytes from create_address form
* 24 bytes of memory called "optional data" within evmc_result struct
* to be optionally used by the evmc_result object creator.
*
* @see evmc_result_optional_data, evmc_get_optional_data().
*
* Also extends the size of the evmc_result to 64 bytes (full cache line).
*/
uint8_t padding[4];
};
/**
* Check account existence callback function
*
* This callback function is used by the EVM to check if
* there exists an account at given address.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address of the account the query is about.
* @return 1 if exists, 0 otherwise.
*/
typedef int (*evmc_account_exists_fn)(struct evmc_context* context,
const struct evmc_address* address);
/**
* Get storage callback function.
*
* This callback function is used by an EVM to query the given contract
* storage entry.
* @param[out] result The returned storage value.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address of the contract.
* @param key The index of the storage entry.
*/
typedef void (*evmc_get_storage_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
const struct evmc_address* address,
const struct evmc_uint256be* key);
/**
* The effect of an attempt to modify a contract storage item.
*
* For the purpose of explaining the meaning of each element, the following
* notation is used:
* - 0 is zero value,
* - X != 0 (X is any value other than 0),
* - Y != X, Y != 0 (Y is any value other than X and 0),
* - the "->" means the change from one value to another.
*/
enum evmc_storage_status
{
/**
* The value of a storage item has been left unchanged: 0 -> 0 and X -> X.
*/
EVMC_STORAGE_UNCHANGED = 0,
/**
* The value of a storage item has been modified: X -> Y.
*/
EVMC_STORAGE_MODIFIED = 1,
/**
* A new storage item has been added: 0 -> X.
*/
EVMC_STORAGE_ADDED = 2,
/**
* A storage item has been deleted: X -> 0.
*/
EVMC_STORAGE_DELETED = 3
};
/**
* Set storage callback function.
*
* This callback function is used by an EVM to update the given contract
* storage entry.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address of the contract.
* @param key The index of the storage entry.
* @param value The value to be stored.
* @return The effect on the storage item, @see ::evmc_storage_status.
*/
typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* context,
const struct evmc_address* address,
const struct evmc_uint256be* key,
const struct evmc_uint256be* value);
/**
* Get balance callback function.
*
* This callback function is used by an EVM to query the balance of the given
* address.
* @param[out] result The returned balance value.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address.
*/
typedef void (*evmc_get_balance_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
const struct evmc_address* address);
/**
* Get code size callback function.
*
* This callback function is used by an EVM to get the size of the code stored
* in the account at the given address. For accounts not having a code, this
* function returns 0.
*/
typedef size_t (*evmc_get_code_size_fn)(struct evmc_context* context,
const struct evmc_address* address);
/**
* Get code size callback function.
*
* This callback function is used by an EVM to get the keccak256 hash of the code stored
* in the account at the given address. For accounts not having a code, this
* function returns keccak256 hash of empty data. For accounts not existing in the state,
* this function returns 0.
*/
typedef void (*evmc_get_code_hash_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
const struct evmc_address* address);
/**
* Copy code callback function.
*
* This callback function is used by an EVM to request a copy of the code
* of the given account to the memory buffer provided by the EVM.
* The Client MUST copy the requested code, starting with the given offset,
* to the provided memory buffer up to the size of the buffer or the size of
* the code, whichever is smaller.
*
* @param context The pointer to the Client execution context.
* @see ::evmc_context.
* @param address The address of the account.
* @param code_offset The offset of the code to copy.
* @param buffer_data The pointer to the memory buffer allocated by the EVM
* to store a copy of the requested code.
* @param buffer_size The size of the memory buffer.
* @return The number of bytes copied to the buffer by the Client.
*/
typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context,
const struct evmc_address* address,
size_t code_offset,
uint8_t* buffer_data,
size_t buffer_size);
/**
* Selfdestruct callback function.
*
* This callback function is used by an EVM to SELFDESTRUCT given contract.
* The execution of the contract will not be stopped, that is up to the EVM.
*
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address of the contract to be selfdestructed.
* @param beneficiary The address where the remaining ETH is going to be
* transferred.
*/
typedef void (*evmc_selfdestruct_fn)(struct evmc_context* context,
const struct evmc_address* address,
const struct evmc_address* beneficiary);
/**
* Log callback function.
*
* This callback function is used by an EVM to inform about a LOG that happened
* during an EVM bytecode execution.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address of the contract that generated the log.
* @param data The pointer to unindexed data attached to the log.
* @param data_size The length of the data.
* @param topics The pointer to the array of topics attached to the log.
* @param topics_count The number of the topics. Valid values are between
* 0 and 4 inclusively.
*/
typedef void (*evmc_emit_log_fn)(struct evmc_context* context,
const struct evmc_address* address,
const uint8_t* data,
size_t data_size,
const struct evmc_uint256be topics[],
size_t topics_count);
/**
* Pointer to the callback function supporting EVM calls.
*
* @param[out] result The result of the call. The result object is not
* initialized by the EVM, the Client MUST correctly
* initialize all expected fields of the structure.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param msg Call parameters. @see ::evmc_message.
*/
typedef void (*evmc_call_fn)(struct evmc_result* result,
struct evmc_context* context,
const struct evmc_message* msg);
/**
* The context interface.
*
* The set of all callback functions expected by EVM instances. This is C
* realisation of vtable for OOP interface (only virtual methods, no data).
* Host implementations SHOULD create constant singletons of this (similarly
* to vtables) to lower the maintenance and memory management cost.
*/
struct evmc_context_fn_table
{
/** Check account existence callback function. */
evmc_account_exists_fn account_exists;
/** Get storage callback function. */
evmc_get_storage_fn get_storage;
/** Set storage callback function. */
evmc_set_storage_fn set_storage;
/** Get balance callback function. */
evmc_get_balance_fn get_balance;
/** Get code size callback function. */
evmc_get_code_size_fn get_code_size;
/** Get code hash callback function. */
evmc_get_code_hash_fn get_code_hash;
/** Copy code callback function. */
evmc_copy_code_fn copy_code;
/** Selfdestruct callback function. */
evmc_selfdestruct_fn selfdestruct;
/** Call callback function. */
evmc_call_fn call;
/** Get transaction context callback function. */
evmc_get_tx_context_fn get_tx_context;
/** Get block hash callback function. */
evmc_get_block_hash_fn get_block_hash;
/** Emit log callback function. */
evmc_emit_log_fn emit_log;
};
/**
* Execution context managed by the Host.
*
* The Host MUST pass the pointer to the execution context to
* ::evmc_execute_fn. The EVM MUST pass the same pointer back to the Host in
* every callback function.
* The context MUST contain at least the function table defining the context
* callback interface.
* Optionally, The Host MAY include in the context additional data.
*/
struct evmc_context
{
/** Function table defining the context interface (vtable). */
const struct evmc_context_fn_table* fn_table;
};
/* Forward declaration. */
struct evmc_instance;
/**
* Destroys the EVM instance.
*
* @param evm The EVM instance to be destroyed.
*/
typedef void (*evmc_destroy_fn)(struct evmc_instance* evm);
/**
* Configures the EVM instance.
*
* Allows modifying options of the EVM instance.
* Options:
* - code cache behavior: on, off, read-only, ...
* - optimizations,
*
* @param evm The EVM instance to be configured.
* @param name The option name. NULL-terminated string. Cannot be NULL.
* @param value The new option value. NULL-terminated string. Cannot be NULL.
* @return 1 if the option set successfully, 0 otherwise.
*/
typedef int (*evmc_set_option_fn)(struct evmc_instance* evm, char const* name, char const* value);
/**
* EVM revision.
*
* The revision of the EVM specification based on the Ethereum
* upgrade / hard fork codenames.
*/
enum evmc_revision
{
EVMC_FRONTIER = 0,
EVMC_HOMESTEAD = 1,
EVMC_TANGERINE_WHISTLE = 2,
EVMC_SPURIOUS_DRAGON = 3,
EVMC_BYZANTIUM = 4,
EVMC_CONSTANTINOPLE = 5,
EVMC_LATEST_REVISION = EVMC_CONSTANTINOPLE
};
/**
* Executes the given EVM bytecode using the input in the message
*
* This function MAY be invoked multiple times for a single EVM instance.
*
* @param instance The EVM instance.
* @param context The pointer to the Client execution context to be passed
* to the callback functions. @see ::evmc_context.
* @param rev Requested EVM specification revision.
* @param msg Call parameters. @see ::evmc_message.
* @param code Reference to the bytecode to be executed.
* @param code_size The length of the bytecode.
* @return All execution results.
*/
typedef struct evmc_result (*evmc_execute_fn)(struct evmc_instance* instance,
struct evmc_context* context,
enum evmc_revision rev,
const struct evmc_message* msg,
uint8_t const* code,
size_t code_size);
/** The opaque type representing a Client-side tracer object. */
struct evmc_tracer_context;
/**
* The callback to trace instructions execution in an EVM.
*
* This function informs the Client what instruction has been executed in the EVM implementation
* and what are the results of executing this particular instruction.
* The message level information (like call depth, destination address, etc.) are not provided here.
* This piece of information can be acquired by inspecting messages being sent to the EVM in
* ::evmc_execute_fn and the results of the messages execution.
*
* @param context The pointer to the Client-side tracing context. This allows to
* implement the tracer in OOP manner.
* @param code_offset The current instruction position in the code.
* @param status_code The status code of the instruction execution.
* @param gas_left The amount of the gas left after the instruction execution.
* @param stack_num_items The current EVM stack height after the instruction execution.
* @param pushed_stack_item The top EVM stack item pushed as the result of the instruction
* execution. This value is null when the instruction does not push
* anything to the stack.
* @param memory_size The size of the EVM memory after the instruction execution.
* @param changed_memory_offset The offset in number of bytes of the beginning of the memory area
* modified as the result of the instruction execution.
* The Client MAY use this information together with
* @p changed_memory_size and @p changed_memory to incrementally
* update the copy of the full VM's memory.
* @param changed_memory_size The size of the memory area modified as the result of
* the instruction execution.
* @param changed_memory The pointer to the memory area modified as the result of
* the instruction execution.
* The Client MAY access the pointed memory area
* (limited by the @p changed_memory_size) only during the current
* execution of the evmc_trace_callback().
* The pointer MUST NOT be stored by the Client.
* The Client MUST NOT assume that
* `changed_memory - changed_memory_offset` is a valid base pointer
* of the VM memory.
*/
typedef void (*evmc_trace_callback)(struct evmc_tracer_context* context,
size_t code_offset,
enum evmc_status_code status_code,
int64_t gas_left,
size_t stack_num_items,
const struct evmc_uint256be* pushed_stack_item,
size_t memory_size,
size_t changed_memory_offset,
size_t changed_memory_size,
const uint8_t* changed_memory);
/**
* Sets the EVM instruction tracer.
*
* When the tracer is set in the EVM instance, the EVM SHOULD call back the tracer with information
* about instructions execution in the EVM.
* @see ::evmc_trace_callback.
*
* This will overwrite the previous settings (the callback and the context).
*
* @param instance The EVM instance.
* @param callback The tracer callback function. This argument MAY be NULL to disable previously
* set tracer.
* @param context The Client-side tracer context. This argument MAY be NULL in case the tracer
* does not require any context. This argument MUST be NULL if the callback
* argument is NULL.
*/
typedef void (*evmc_set_tracer_fn)(struct evmc_instance* instance,
evmc_trace_callback callback,
struct evmc_tracer_context* context);
/**
* The EVM instance.
*
* Defines the base struct of the EVM implementation.
*/
struct evmc_instance
{
/**
* EVMC ABI version implemented by the EVM instance.
*
* Used to detect ABI incompatibilities. The EVMC ABI version
* represented by this file is in ::EVMC_ABI_VERSION.
*/
const int abi_version;
/**
* The name of the EVMC VM implementation.
*
* It MUST be a NULL-terminated not empty string.
*/
const char* name;
/**
* The version of the EVMC VM implementation, e.g. "1.2.3b4".
*
* It MUST be a NULL-terminated not empty string.
*/
const char* version;
/** Pointer to function destroying the EVM instance. */
evmc_destroy_fn destroy;
/** Pointer to function executing a code by the EVM instance. */
evmc_execute_fn execute;
/**
* Optional pointer to function setting the EVM instruction tracer.
*
* If the EVM does not support this feature the pointer can be NULL.
*/
evmc_set_tracer_fn set_tracer;
/**
* Optional pointer to function modifying VM's options.
*
* If the VM does not support this feature the pointer can be NULL.
*/
evmc_set_option_fn set_option;
};
/* END Python CFFI declarations */
#if EVMC_DOCUMENTATION
/**
* Example of a function creating an instance of an example EVM implementation.
*
* Each EVM implementation MUST provide a function returning an EVM instance.
* The function SHOULD be named `evmc_create_<vm-name>(void)`. If the VM name contains hyphens
* replaces them with underscores in the function names.
*
* @par Binaries naming convention
* For VMs distributed as shared libraries, the name of the library SHOULD match the VM name.
* The convetional library filename prefixes and extensions SHOULD be ignored by the Client.
* For example, the shared library with the "beta-interpreter" implementation may be named
* `libbeta-interpreter.so`.
*
* @return EVM instance or NULL indicating instance creation failure.
*/
struct evmc_instance* evmc_create_examplevm(void);
#endif
#if __cplusplus
}
#endif
#endif
/** @} */

View file

@ -0,0 +1,155 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
/**
* EVMC Helpers
*
* A collection of helper functions for invoking a VM instance methods.
* These are convenient for languages where invoking function pointers
* is "ugly" or impossible (such as Go).
*
* @defgroup helpers EVMC Helpers
* @{
*/
#pragma once
#include <evmc/evmc.h>
/**
* Returns true if the VM instance has a compatible ABI version.
*/
static inline int evmc_is_abi_compatible(struct evmc_instance* instance)
{
return instance->abi_version == EVMC_ABI_VERSION;
}
/**
* Returns the name of the VM instance.
*/
static inline const char* evmc_vm_name(struct evmc_instance* instance)
{
return instance->name;
}
/**
* Returns the version of the VM instance.
*/
static inline const char* evmc_vm_version(struct evmc_instance* instance)
{
return instance->version;
}
/**
* Destroys the VM instance.
*
* @see evmc_destroy_fn
*/
static inline void evmc_destroy(struct evmc_instance* instance)
{
instance->destroy(instance);
}
/**
* Sets the option for the VM instance, if the feature is supported by the VM.
*
* @see evmc_set_option_fn
*/
static inline int evmc_set_option(struct evmc_instance* instance,
char const* name,
char const* value)
{
if (instance->set_option)
return instance->set_option(instance, name, value);
return 0;
}
/**
* Sets the tracer callback for the VM instance, if the feature is supported by the VM.
*
* @see evmc_set_tracer_fn
*/
static inline void evmc_set_tracer(struct evmc_instance* instance,
evmc_trace_callback callback,
struct evmc_tracer_context* context)
{
if (instance->set_tracer)
instance->set_tracer(instance, callback, context);
}
/**
* Executes code in the VM instance.
*
* @see evmc_execute_fn.
*/
static inline struct evmc_result evmc_execute(struct evmc_instance* instance,
struct evmc_context* context,
enum evmc_revision rev,
const struct evmc_message* msg,
uint8_t const* code,
size_t code_size)
{
return instance->execute(instance, context, rev, msg, code, code_size);
}
/**
* Releases the resources allocated to the execution result.
*
* @see evmc_release_result_fn
*/
static inline void evmc_release_result(struct evmc_result* result)
{
result->release(result);
}
/**
* Helpers for optional storage of evmc_result.
*
* In some contexts (i.e. evmc_result::create_address is unused) objects of
* type evmc_result contains a memory storage that MAY be used by the object
* owner. This group defines helper types and functions for accessing
* the optional storage.
*
* @defgroup result_optional_storage Result Optional Storage
* @{
*/
/**
* The union representing evmc_result "optional storage".
*
* The evmc_result struct contains 24 bytes of optional storage that can be
* reused by the object creator if the object does not contain
* evmc_result::create_address.
*
* A VM implementation MAY use this memory to keep additional data
* when returning result from evmc_execute_fn().
* The host application MAY use this memory to keep additional data
* when returning result of performed calls from evmc_call_fn().
*
* @see evmc_get_optional_storage(), evmc_get_const_optional_storage().
*/
union evmc_result_optional_storage
{
uint8_t bytes[24]; /**< 24 bytes of optional storage. */
void* pointer; /**< Optional pointer. */
};
/** Provides read-write access to evmc_result "optional storage". */
static inline union evmc_result_optional_storage* evmc_get_optional_storage(
struct evmc_result* result)
{
return (union evmc_result_optional_storage*)&result->create_address;
}
/** Provides read-only access to evmc_result "optional storage". */
static inline const union evmc_result_optional_storage* evmc_get_const_optional_storage(
const struct evmc_result* result)
{
return (const union evmc_result_optional_storage*)&result->create_address;
}
/** @} */
/** @} */

View file

@ -0,0 +1,28 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#include "_cgo_export.h"
#include <stdlib.h>
const struct evmc_context_fn_table evmc_go_fn_table = {
(evmc_account_exists_fn)accountExists,
(evmc_get_storage_fn)getStorage,
(evmc_set_storage_fn)setStorage,
(evmc_get_balance_fn)getBalance,
(evmc_get_code_size_fn)getCodeSize,
(evmc_get_code_hash_fn)getCodeHash,
(evmc_copy_code_fn)copyCode,
(evmc_selfdestruct_fn)selfdestruct,
(evmc_call_fn)call,
(evmc_get_tx_context_fn)getTxContext,
(evmc_get_block_hash_fn)getBlockHash,
(evmc_emit_log_fn)emitLog,
};
void evmc_go_free_result_output(const struct evmc_result* result)
{
free((void*)result->output_data);
}

View file

@ -0,0 +1,238 @@
// EVMC: Ethereum Client-VM Connector API.
// Copyright 2018 The EVMC Authors.
// Licensed under the Apache License, Version 2.0. See the LICENSE file.
package evmc
/*
#cgo CFLAGS: -I${SRCDIR}/.. -Wall -Wextra -Wno-unused-parameter
#include <evmc/evmc.h>
struct extended_context
{
struct evmc_context context;
int64_t index;
};
void evmc_go_free_result_output(const struct evmc_result* result);
*/
import "C"
import (
"math/big"
"unsafe"
"github.com/ethereum/go-ethereum/common"
)
type CallKind int
const (
Call CallKind = C.EVMC_CALL
DelegateCall CallKind = C.EVMC_DELEGATECALL
CallCode CallKind = C.EVMC_CALLCODE
Create CallKind = C.EVMC_CREATE
Create2 CallKind = C.EVMC_CREATE2
)
type StorageStatus int
const (
StorageUnchanged StorageStatus = C.EVMC_STORAGE_UNCHANGED
StorageModified StorageStatus = C.EVMC_STORAGE_MODIFIED
StorageAdded StorageStatus = C.EVMC_STORAGE_ADDED
StorageDeleted StorageStatus = C.EVMC_STORAGE_DELETED
)
func goAddress(in C.struct_evmc_address) common.Address {
out := common.Address{}
for i := 0; i < len(out); i++ {
out[i] = byte(in.bytes[i])
}
return out
}
func goHash(in C.struct_evmc_uint256be) common.Hash {
out := common.Hash{}
for i := 0; i < len(out); i++ {
out[i] = byte(in.bytes[i])
}
return out
}
func goByteSlice(data *C.uint8_t, size C.size_t) []byte {
if size == 0 {
return []byte{}
}
return (*[1 << 30]byte)(unsafe.Pointer(data))[:size:size]
}
type HostContext interface {
AccountExists(addr common.Address) bool
GetStorage(addr common.Address, key common.Hash) common.Hash
SetStorage(addr common.Address, key common.Hash, value common.Hash) StorageStatus
GetBalance(addr common.Address) common.Hash
GetCodeSize(addr common.Address) int
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)
GetBlockHash(number int64) common.Hash
EmitLog(addr common.Address, topics []common.Hash, data []byte)
Call(kind CallKind,
destination common.Address, sender common.Address, value *big.Int, input []byte, gas int64, depth int,
static bool) (output []byte, gasLeft int64, createAddr common.Address, err error)
}
//export accountExists
func accountExists(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) C.int {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
exists := ctx.AccountExists(goAddress(*pAddr))
r := C.int(0)
if exists {
r = 1
}
return r
}
//export getStorage
func getStorage(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.struct_evmc_uint256be) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
value := ctx.GetStorage(goAddress(*pAddr), goHash(*pKey))
*pResult = evmcUint256be(value)
}
//export setStorage
func setStorage(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.struct_evmc_uint256be, pVal *C.struct_evmc_uint256be) C.enum_evmc_storage_status {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
return C.enum_evmc_storage_status(ctx.SetStorage(goAddress(*pAddr), goHash(*pKey), goHash(*pVal)))
}
//export getBalance
func getBalance(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
balance := ctx.GetBalance(goAddress(*pAddr))
*pResult = evmcUint256be(balance)
}
//export getCodeSize
func getCodeSize(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) C.size_t {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
return C.size_t(ctx.GetCodeSize(goAddress(*pAddr)))
}
//export getCodeHash
func getCodeHash(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
*pResult = evmcUint256be(ctx.GetCodeHash(goAddress(*pAddr)))
}
//export copyCode
func copyCode(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, offset C.size_t, p *C.uint8_t, size C.size_t) C.size_t {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
code := ctx.GetCode(goAddress(*pAddr))
length := C.size_t(len(code))
if offset >= length {
return 0
}
toCopy := length - offset
if toCopy > size {
toCopy = size
}
out := goByteSlice(p, size)
copy(out, code[offset:])
return toCopy
}
//export selfdestruct
func selfdestruct(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pBeneficiary *C.struct_evmc_address) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
ctx.Selfdestruct(goAddress(*pAddr), goAddress(*pBeneficiary))
}
//export getTxContext
func getTxContext(pResult unsafe.Pointer, pCtx unsafe.Pointer) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
gasPrice, origin, coinbase, number, timestamp, gasLimit, difficulty := ctx.GetTxContext()
*(*C.struct_evmc_tx_context)(pResult) = C.struct_evmc_tx_context{
evmcUint256be(gasPrice),
evmcAddress(origin),
evmcAddress(coinbase),
C.int64_t(number),
C.int64_t(timestamp),
C.int64_t(gasLimit),
evmcUint256be(difficulty),
}
}
//export getBlockHash
func getBlockHash(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, number int64) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
*pResult = evmcUint256be(ctx.GetBlockHash(number))
}
//export emitLog
func emitLog(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pData unsafe.Pointer, dataSize C.size_t, pTopics unsafe.Pointer, topicsCount C.size_t) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
// FIXME: Optimize memory copy
data := C.GoBytes(pData, C.int(dataSize))
tData := C.GoBytes(pTopics, C.int(topicsCount*32))
nTopics := int(topicsCount)
topics := make([]common.Hash, nTopics)
for i := 0; i < nTopics; i++ {
copy(topics[i][:], tData[i*32:(i+1)*32])
}
ctx.EmitLog(goAddress(*pAddr), topics, data)
}
//export call
func call(pResult *C.struct_evmc_result, pCtx unsafe.Pointer, msg *C.struct_evmc_message) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
kind := CallKind(msg.kind)
output, gasLeft, createAddr, err := ctx.Call(kind, goAddress(msg.destination), goAddress(msg.sender), goHash(msg.value).Big(),
goByteSlice(msg.input_data, msg.input_size), int64(msg.gas), int(msg.depth), msg.flags != 0)
statusCode := C.enum_evmc_status_code(0)
if err != nil {
statusCode = C.enum_evmc_status_code(err.(Error))
}
result := C.struct_evmc_result{}
result.status_code = statusCode
result.gas_left = C.int64_t(gasLeft)
result.create_address = evmcAddress(createAddr)
if len(output) > 0 {
// TODO: We could pass it directly to the caller without a copy. The caller should release it. Check depth.
cOutput := C.CBytes(output)
result.output_data = (*C.uint8_t)(cOutput)
result.output_size = C.size_t(len(output))
result.release = (C.evmc_release_result_fn)(C.evmc_go_free_result_output)
}
*pResult = result
}

View file

@ -0,0 +1,153 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
#include <evmc/loader.h>
#include <evmc/evmc.h>
#include <evmc/helpers.h>
#include <stdint.h>
#include <string.h>
#if _WIN32
#include <Windows.h>
#define DLL_HANDLE HMODULE
#define DLL_OPEN(filename) LoadLibrary(filename)
#define DLL_CLOSE(handle) FreeLibrary(handle)
#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn) GetProcAddress(handle, name)
#define HAVE_STRCPY_S 1
#else
#include <dlfcn.h>
#define DLL_HANDLE void*
#define DLL_OPEN(filename) dlopen(filename, RTLD_LAZY)
#define DLL_CLOSE(handle) dlclose(handle)
#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn)(uintptr_t) dlsym(handle, name)
#define HAVE_STRCPY_S 0
#endif
#define PATH_MAX_LENGTH 4096
#if !HAVE_STRCPY_S
static void strcpy_s(char* dest, size_t destsz, const char* src)
{
size_t len = strlen(src);
if (len > destsz - 1)
len = destsz - 1;
memcpy(dest, src, len);
dest[len] = 0;
}
#endif
evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* error_code)
{
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
evmc_create_fn create_fn = NULL;
if (!filename)
{
ec = EVMC_LOADER_INVALID_ARGUMENT;
goto exit;
}
const size_t length = strlen(filename);
if (length == 0 || length > PATH_MAX_LENGTH)
{
ec = EVMC_LOADER_INVALID_ARGUMENT;
goto exit;
}
DLL_HANDLE handle = DLL_OPEN(filename);
if (!handle)
{
ec = EVMC_LOADER_CANNOT_OPEN;
goto exit;
}
// Create name buffer with the prefix.
const char prefix[] = "evmc_create_";
const size_t prefix_length = strlen(prefix);
char name[sizeof(prefix) + PATH_MAX_LENGTH];
strcpy_s(name, sizeof(name), prefix);
// Find filename in the path.
const char* sep_pos = strrchr(filename, '/');
#if _WIN32
// On Windows check also Windows classic path separator.
const char* sep_pos_windows = strrchr(filename, '\\');
sep_pos = sep_pos_windows > sep_pos ? sep_pos_windows : sep_pos;
#endif
const char* name_pos = sep_pos ? sep_pos + 1 : filename;
// Skip "lib" prefix if present.
const char lib_prefix[] = "lib";
const size_t lib_prefix_length = strlen(lib_prefix);
if (strncmp(name_pos, lib_prefix, lib_prefix_length) == 0)
name_pos += lib_prefix_length;
strcpy_s(name + prefix_length, PATH_MAX_LENGTH, name_pos);
// Trim the file extension.
char* ext_pos = strrchr(name, '.');
if (ext_pos)
*ext_pos = 0;
// Replace all "-" with "_".
char* dash_pos = name;
while ((dash_pos = strchr(dash_pos, '-')) != NULL)
*dash_pos++ = '_';
// Search for the "full name" based function name.
create_fn = DLL_GET_CREATE_FN(handle, name);
if (!create_fn)
{
// Try the "short name" based function name.
const char* short_name_pos = strrchr(name, '_');
if (short_name_pos)
{
short_name_pos += 1;
memmove(name + prefix_length, short_name_pos, strlen(short_name_pos) + 1);
create_fn = DLL_GET_CREATE_FN(handle, name);
}
}
if (!create_fn)
create_fn = DLL_GET_CREATE_FN(handle, "evmc_create");
if (!create_fn)
{
DLL_CLOSE(handle);
ec = EVMC_LOADER_SYMBOL_NOT_FOUND;
}
exit:
if (error_code)
*error_code = ec;
return create_fn;
}
struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code)
{
evmc_create_fn create_fn = evmc_load(filename, error_code);
if (!create_fn)
return NULL;
struct evmc_instance* instance = create_fn();
if (!instance)
{
*error_code = EVMC_LOADER_INSTANCE_CREATION_FAILURE;
return NULL;
}
if (!evmc_is_abi_compatible(instance))
{
*error_code = EVMC_LOADER_ABI_VERSION_MISMATCH;
return NULL;
}
return instance;
}

View file

@ -0,0 +1,109 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
*/
/**
* EVMC Loader Library
*
* The EVMC Loader Library supports loading VMs implemented as Dynamically Loaded Libraries
* (DLLs, shared objects).
*
* @defgroup loader EVMC Loader
* @{
*/
#pragma once
#if __cplusplus
extern "C" {
#endif
/** The function pointer type for EVMC create functions. */
typedef struct evmc_instance* (*evmc_create_fn)(void);
/** Error codes for the EVMC loader. */
enum evmc_loader_error_code
{
/** The loader succeeded. */
EVMC_LOADER_SUCCESS = 0,
/** The loader cannot open the given file name. */
EVMC_LOADER_CANNOT_OPEN = 1,
/** The VM create function not found. */
EVMC_LOADER_SYMBOL_NOT_FOUND = 2,
/** The invalid argument value provided. */
EVMC_LOADER_INVALID_ARGUMENT = 3,
/** The creation of a VM instance has failed. */
EVMC_LOADER_INSTANCE_CREATION_FAILURE = 4,
/** The ABI version of the VM instance has mismatched. */
EVMC_LOADER_ABI_VERSION_MISMATCH = 5,
};
/**
* Dynamically loads the shared object (DLL) with an EVM implementation.
*
* This function tries to open a DLL at the given `filename`. On UNIX-like systems dlopen() function
* is used. On Windows LoadLibrary() function is used.
*
* If the file does not exist or is not a valid shared library the ::EVMC_LOADER_CANNOT_OPEN error
* code is signaled and NULL is returned.
*
* After the DLL is successfully loaded the function tries to find the EVM create function in the
* library. The `filename` is used to guess the EVM name and the name of the create function.
* The create function name is constructed by the following rules. Consider example path:
* "/ethereum/libexample-interpreter.so".
* - the filename is taken from the path:
* "libexample-interpreter.so",
* - the "lib" prefix and file extension are stripped from the name:
* "example-interpreter"
* - all "-" are replaced with "_" to construct _full name_:
* "example_interpreter",
* - the _full name_ is split by "_" char and the last item is taken to form the _short name_:
* "interpreter",
* - the name "evmc_create_" + _full name_ is checked in the library:
* "evmc_create_example_interpreter",
* - then, the name "evmc_create_" + _short name_ is checked in the library:
* "evmc_create_interpreter".
* - lastly, the name "evmc_create" is checked in the library
*
* If the create function is found in the library, the pointer to the function is returned.
* Otherwise, the ::EVMC_LOADER_SYMBOL_NOT_FOUND error code is signaled and NULL is returned.
*
* It is safe to call this function with the same filename argument multiple times
* (the DLL is not going to be loaded multiple times).
*
* @param filename The null terminated path (absolute or relative) to the shared library
* containing the EVM implementation. If the value is NULL, an empty C-string
* or longer than the path maximum length the ::EVMC_LOADER_INVALID_ARGUMENT is
* signaled.
* @param error_code The pointer to the error code. If not NULL the value is set to
* ::EVMC_LOADER_SUCCESS on success or any other error code as described above.
* @return The pointer to the EVM create function or NULL.
*/
evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* error_code);
/**
* Dynamically loads the VM DLL and creates the VM instance.
*
* This is a macro for creating the VM instance with the function returned from evmc_load().
* The function signals the same errors as evmc_load() and additionally:
* - ::EVMC_LOADER_INSTANCE_CREATION_FAILURE when the create function returns NULL,
* - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different
* from the ABI version of this library (::EVMC_ABI_VERSION).
*
* It is safe to call this function with the same filename argument multiple times:
* the DLL is not going to be loaded multiple times, but the function will return new VM instance
* each time.
*/
struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code);
#if __cplusplus
}
#endif
/** @} */

8
vendor/vendor.json vendored
View file

@ -104,6 +104,14 @@
"revision": "a3814ce5008e612a0c6d027608b54e1d0d9a5613", "revision": "a3814ce5008e612a0c6d027608b54e1d0d9a5613",
"revisionTime": "2018-01-22T22:25:45Z" "revisionTime": "2018-01-22T22:25:45Z"
}, },
{
"checksumSHA1": "gvcZHEaRD0J5Y6QrFTo0GrR2TkE=",
"path": "github.com/ethereum/evmc/bindings/go/evmc",
"revision": "224080ef8c8d99f5cfe59067a3bd995be23349bf",
"revisionTime": "2018-08-28T21:11:56Z",
"version": "=v5.2.0",
"versionExact": "v5.2.0"
},
{ {
"checksumSHA1": "7oFpbmDfGobwKsFLIf6wMUvVoKw=", "checksumSHA1": "7oFpbmDfGobwKsFLIf6wMUvVoKw=",
"path": "github.com/fatih/color", "path": "github.com/fatih/color",