Merge pull request #42 from ethereum/extensions

Extensions
This commit is contained in:
Alex Beregszaszi 2018-07-13 15:52:41 +01:00 committed by GitHub
commit 97221d2db7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 169 additions and 9 deletions

54
include/evmc/helpers.h Normal file
View File

@ -0,0 +1,54 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018 Pawel Bylica.
* Licensed under the MIT License. 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>
/**
* 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;
}
/**
* 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);
}
/** @} */

View File

@ -3,13 +3,19 @@
* Licensed under the MIT License. See the LICENSE file. * Licensed under the MIT License. See the LICENSE file.
*/ */
/**
* EVM Instruction Tables
*
* A collection of metrics for EVM1 instruction set.
*
* @defgroup instructions EVM Instructions
* @{
*/
#pragma once #pragma once
#include <evmc/evmc.h> #include <evmc/evmc.h>
#include <evmc/utils.h> #include <evmc/utils.h>
#include <stdint.h>
#if __cplusplus #if __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -209,3 +215,5 @@ EVMC_EXPORT const char* const* evmc_get_instruction_names_table(enum evmc_revisi
#if __cplusplus #if __cplusplus
} }
#endif #endif
/** @} */

View File

@ -3,6 +3,15 @@
* Licensed under the MIT License. See the LICENSE file. * Licensed under the MIT License. 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 #pragma once
#if __cplusplus #if __cplusplus
@ -15,10 +24,23 @@ typedef struct evmc_instance* (*evmc_create_fn)(void);
/** Error codes for the EVMC loader. */ /** Error codes for the EVMC loader. */
enum evmc_loader_error_code enum evmc_loader_error_code
{ {
/** The loader succeeded. */
EVMC_LOADER_SUCCESS = 0, EVMC_LOADER_SUCCESS = 0,
EVMC_LOADER_CANNOT_OPEN,
EVMC_LOADER_SYMBOL_NOT_FOUND, /** The loader cannot open the given file name. */
EVMC_LOADER_INVALID_ARGUMENT, 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,
}; };
/** /**
@ -27,7 +49,7 @@ enum evmc_loader_error_code
* This function tries to open a DLL at the given `filename`. On UNIX-like systems dlopen() function * 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. * is used. On Windows LoadLibrary() function is used.
* *
* If the file does not exist or is not a valid shared library the ::EVMC_ERRC_CANNOT_OPEN error * 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. * code is signaled and NULL is returned.
* *
* After the DLL is successfully loaded the function tries to find the EVM create function in the * After the DLL is successfully loaded the function tries to find the EVM create function in the
@ -48,18 +70,38 @@ enum evmc_loader_error_code
* "evmc_create_interpreter". * "evmc_create_interpreter".
* *
* If the create function is found in the library, the pointer to the function is returned. * If the create function is found in the library, the pointer to the function is returned.
* Otherwise, the ::EVMC_ERRC_SYMBOL_NOT_FOUND error code is signaled and NULL 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 * @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 * containing the EVM implementation. If the value is NULL, an empty C-string
* or longer than the path maximum length the ::EVMC_ERRC_INVALID_ARGUMENT is * or longer than the path maximum length the ::EVMC_LOADER_INVALID_ARGUMENT is
* signaled. * signaled.
* @param error_code The pointer to the error code. If not NULL the value is set to * @param error_code The pointer to the error code. If not NULL the value is set to
* ::EVMC_ERRC_SUCCESS on success or any other error code as described above. * ::EVMC_LOADER_SUCCESS on success or any other error code as described above.
* @return The pointer to the EVM create function or NULL. * @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); 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 #if __cplusplus
} }
#endif #endif
/** @} */

View File

@ -4,6 +4,7 @@
*/ */
#include <evmc/loader.h> #include <evmc/loader.h>
#include <evmc/evmc.h>
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@ -121,3 +122,26 @@ exit:
*error_code = ec; *error_code = ec;
return create_fn; 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 (instance->abi_version != EVMC_ABI_VERSION)
{
*error_code = EVMC_LOADER_ABI_VERSION_MISMATCH;
return NULL;
}
return instance;
}

View File

@ -24,6 +24,8 @@ add_custom_command(
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> _ COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> _
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> lib_.so COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> lib_.so
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> ../aaa.evm COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> ../aaa.evm
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> failure.vm
COMMAND ${CMAKE_COMMAND} -E ${cmd} $<TARGET_FILE:vm-mock> abi42.vm
COMMAND ${CMAKE_COMMAND} -E touch empty.file COMMAND ${CMAKE_COMMAND} -E touch empty.file
) )

View File

@ -244,3 +244,19 @@ TEST(loader, lib_)
x = evmc_load(path, nullptr); x = evmc_load(path, nullptr);
EXPECT_EQ(x, nullptr); EXPECT_EQ(x, nullptr);
} }
TEST(loader, load_and_create_failure)
{
evmc_loader_error_code ec;
auto vm = evmc_load_and_create("unittests/failure.vm", &ec);
EXPECT_EQ(vm, nullptr);
EXPECT_EQ(ec, EVMC_LOADER_INSTANCE_CREATION_FAILURE);
}
TEST(loader, load_and_create_abi_mismatch)
{
evmc_loader_error_code ec;
auto vm = evmc_load_and_create("unittests/abi42.vm", &ec);
EXPECT_EQ(vm, nullptr);
EXPECT_EQ(ec, EVMC_LOADER_ABI_VERSION_MISMATCH);
}

View File

@ -3,6 +3,7 @@
* Licensed under the MIT License. See the LICENSE file. * Licensed under the MIT License. See the LICENSE file.
*/ */
#include <evmc/evmc.h>
#include <evmc/utils.h> #include <evmc/utils.h>
EVMC_EXPORT void* evmc_create_aaa() EVMC_EXPORT void* evmc_create_aaa()
@ -14,3 +15,16 @@ EVMC_EXPORT void* evmc_create_eee_bbb()
{ {
return (void*)0xeeebbb; return (void*)0xeeebbb;
} }
EVMC_EXPORT void* evmc_create_failure()
{
return NULL;
}
EVMC_EXPORT struct evmc_instance* evmc_create_abi42()
{
static struct evmc_instance instance = {
.abi_version = 42,
};
return &instance;
}