diff --git a/.gitmodules b/.gitmodules
index aa1fc4065..0ddb5c183 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,9 +5,6 @@
[submodule "test/tests"]
path = test/jsontests
url = https://github.com/ethereum/tests.git
-[submodule "hera"]
- path = hera
- url = https://github.com/ewasm/hera
[submodule "cpp-ethereum"]
path = cpp-ethereum
url = https://github.com/ethereum/cpp-ethereum.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 120000
index c0a44c6bc..000000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1 +0,0 @@
-cpp-ethereum/CMakeLists.txt
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 000000000..646a1cb39
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,173 @@
+#------------------------------------------------------------------------------
+# Top-level CMake file for cpp-ethereum.
+#
+# The documentation for cpp-ethereum is hosted at http://cpp-ethereum.org
+#
+# ------------------------------------------------------------------------------
+# This file is part of cpp-ethereum.
+#
+# cpp-ethereum is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# cpp-ethereum is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with cpp-ethereum. If not, see
+#
+# (c) 2014-2016 cpp-ethereum contributors.
+#------------------------------------------------------------------------------
+
+cmake_minimum_required(VERSION 3.5.1)
+
+if (NOT DEFINED CMAKE_TOOLCHAIN_FILE)
+ # The default toolchain file configures compilers and build environment.
+ # This configuration is also used by hunter to build dependencies.
+ # CMake will cache this value, not need to explictly specify CACHE param.
+ set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/toolchain.cmake)
+endif()
+
+set(ETH_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "The path to the cmake directory")
+list(APPEND CMAKE_MODULE_PATH ${ETH_CMAKE_DIR})
+
+set(CPP_ETHEREUM_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "Path to the root directory for cpp-ethereum")
+
+# set cmake_policies
+include(EthPolicy)
+eth_policy()
+
+if(CMAKE_CONFIGURATION_TYPES)
+ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo" CACHE STRING "" FORCE)
+endif()
+
+# Map current configuration to configurations of imported targets.
+set(CMAKE_MAP_IMPORTED_CONFIG_DEBUG Release)
+set(CMAKE_MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release)
+
+set(HUNTER_CONFIGURATION_TYPES Release)
+set(HUNTER_JOBS_NUMBER 4)
+set(HUNTER_CACHE_SERVERS "https://github.com/ethereum/hunter-cache")
+include(HunterGate)
+HunterGate(
+ URL "https://github.com/ruslo/hunter/archive/v0.19.232.tar.gz"
+ SHA1 "a412c45fe4c5a72fed386f62dd8d753bd4fd3d11"
+ LOCAL
+)
+
+if(HUNTER_ENABLED)
+ # Find Python executable,
+ # prefer version 3 that has requests module included.
+ set(Python_ADDITIONAL_VERSIONS 3)
+ find_package(PythonInterp)
+ if(PYTHONINTERP_FOUND)
+ hunter_gate_self(
+ "${HUNTER_CACHED_ROOT}"
+ "${HUNTER_VERSION}"
+ "${HUNTER_SHA1}"
+ hunter_dir
+ )
+ set(hunter_upload_script "${hunter_dir}/maintenance/upload-cache-to-github.py")
+ set(hunter_cache_dir "${HUNTER_GATE_ROOT}/_Base/Cache")
+ set(hunter_tmp_dir "${HUNTER_GATE_ROOT}/tmp")
+ add_custom_target(
+ hunter_upload_cache
+ ${PYTHON_EXECUTABLE} ${hunter_upload_script}
+ --username hunter-cache-bot
+ --repo-owner ethereum
+ --repo hunter-cache
+ --cache-dir ${hunter_cache_dir}
+ --temp-dir ${hunter_tmp_dir}
+ )
+ endif()
+endif()
+
+# project name and version should be set after cmake_policy CMP0048
+project(cpp-ethereum VERSION "1.3.0")
+
+if (NOT EXISTS ${CMAKE_SOURCE_DIR}/evmjit/.git)
+ message(FATAL_ERROR "Git submodules not initialized, execute:\n git submodule update --init")
+endif()
+
+set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY On)
+
+include(EthCcache)
+include(EthOptions)
+include(EthCompilerSettings)
+include(EthExecutableHelper)
+include(EthDependencies)
+include(EthUtils)
+
+set(Boost_USE_STATIC_LIBS ON)
+set(Boost_USE_MULTITHREADED ON)
+hunter_add_package(Boost COMPONENTS program_options filesystem system thread context fiber)
+find_package(Boost CONFIG REQUIRED program_options filesystem system thread context fiber)
+
+hunter_add_package(jsoncpp)
+find_package(jsoncpp CONFIG REQUIRED)
+
+hunter_add_package(Snappy)
+find_package(Snappy CONFIG REQUIRED)
+
+hunter_add_package(cryptopp)
+find_package(cryptopp CONFIG REQUIRED)
+
+hunter_add_package(libjson-rpc-cpp)
+find_package(libjson-rpc-cpp CONFIG REQUIRED)
+
+include(ProjectSecp256k1)
+include(ProjectLibFF)
+
+find_package(Threads)
+
+if(MINIUPNPC)
+ find_package(Miniupnpc 1.8.2013 REQUIRED)
+endif()
+
+set(UTILS_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/utils")
+
+configure_project()
+
+if (HERA)
+ add_subdirectory(hera)
+endif()
+
+#Global include path for all libs.
+include_directories("${CMAKE_SOURCE_DIR}")
+
+add_subdirectory(libdevcore)
+add_subdirectory(libdevcrypto)
+add_subdirectory(libp2p)
+
+add_subdirectory(libethash)
+
+add_subdirectory(libethcore)
+add_subdirectory(libevm)
+add_subdirectory(libethereum)
+add_subdirectory(libethashseal)
+
+add_subdirectory(libwebthree)
+add_subdirectory(libweb3jsonrpc)
+
+if (EVMJIT)
+ add_subdirectory(evmjit)
+endif()
+
+add_subdirectory(eth)
+
+if (TOOLS)
+ add_subdirectory(ethkey)
+ add_subdirectory(ethvm)
+ add_subdirectory(rlp)
+endif()
+
+if (TESTS)
+ enable_testing()
+ add_subdirectory(test)
+endif()
+
+# TODO: Split out json_spirit, libscrypt and sec256k1.
+add_subdirectory(utils)
diff --git a/hera b/hera
deleted file mode 160000
index 2645bd4d1..000000000
--- a/hera
+++ /dev/null
@@ -1 +0,0 @@
-Subproject commit 2645bd4d189fb5bc24faea2183ea335506949b3e
diff --git a/libevm b/libevm
deleted file mode 120000
index 6db25189a..000000000
--- a/libevm
+++ /dev/null
@@ -1 +0,0 @@
-cpp-ethereum/libevm/
\ No newline at end of file
diff --git a/libevm/CMakeLists.txt b/libevm/CMakeLists.txt
new file mode 100644
index 000000000..9f93b03e0
--- /dev/null
+++ b/libevm/CMakeLists.txt
@@ -0,0 +1,35 @@
+
+set(sources
+ ExtVMFace.cpp ExtVMFace.h
+ Instruction.cpp Instruction.h
+ VMFace.h
+ VMConfig.h
+ VM.cpp VM.h
+ VMCalls.cpp
+ VMOpt.cpp
+ VMSIMD.cpp
+ VMValidate.cpp
+ VMFactory.cpp VMFactory.h
+)
+
+if(EVMJIT OR HERA)
+ list(APPEND sources
+ EVMC.cpp EVMC.h
+ )
+endif()
+
+add_library(evm ${sources})
+
+target_link_libraries(evm PUBLIC ethcore devcore PRIVATE jsoncpp_lib_static Boost::program_options)
+target_include_directories(evm PUBLIC ${CMAKE_SOURCE_DIR}/evmjit/include)
+target_include_directories(evm PUBLIC ${CMAKE_SOURCE_DIR}/hera/src)
+
+if(EVMJIT)
+ target_link_libraries(evm PRIVATE evmjit)
+ target_compile_definitions(evm PRIVATE ETH_EVMJIT)
+endif()
+
+if(HERA)
+ target_link_libraries(evm PRIVATE hera)
+ target_compile_definitions(evm PRIVATE ETH_HERA)
+endif()
diff --git a/libevm/EVMC.cpp b/libevm/EVMC.cpp
new file mode 100644
index 000000000..ea4dba38b
--- /dev/null
+++ b/libevm/EVMC.cpp
@@ -0,0 +1,78 @@
+// Copyright 2018 cpp-ethereum Authors.
+// Licensed under the GNU General Public License v3. See the LICENSE file.
+
+#include "EVMC.h"
+
+#include
+#include
+#include
+
+namespace dev
+{
+namespace eth
+{
+EVM::EVM(evm_instance* _instance) noexcept : m_instance(_instance)
+{
+ assert(m_instance != nullptr);
+ assert(m_instance->abi_version == EVM_ABI_VERSION);
+
+ // Set the options.
+ for (auto& pair : evmcOptions())
+ m_instance->set_option(m_instance, pair.first.c_str(), pair.second.c_str());
+}
+
+owning_bytes_ref EVMC::exec(u256& io_gas, ExtVMFace& _ext, const OnOpFunc& _onOp)
+{
+ assert(_ext.envInfo().number() >= 0);
+ assert(_ext.envInfo().timestamp() >= 0);
+
+ constexpr int64_t int64max = std::numeric_limits::max();
+
+ // TODO: The following checks should be removed by changing the types
+ // used for gas, block number and timestamp.
+ (void)int64max;
+ assert(io_gas <= int64max);
+ assert(_ext.envInfo().gasLimit() <= int64max);
+ assert(_ext.depth <= std::numeric_limits::max());
+
+ auto gas = static_cast(io_gas);
+ EVM::Result r = execute(_ext, gas);
+
+ if (r.status() == EVM_REJECTED)
+ {
+ cwarn << "Execution rejected by EVM-C, executing with interpreter";
+ return VMFactory::create(VMKind::Interpreter)->exec(io_gas, _ext, _onOp);
+ }
+
+ // TODO: Add EVM-C result codes mapping with exception types.
+ if (r.status() == EVM_FAILURE)
+ BOOST_THROW_EXCEPTION(OutOfGas());
+
+ io_gas = r.gasLeft();
+
+ // FIXME: Copy the output for now, but copyless version possible.
+ owning_bytes_ref output{r.output().toVector(), 0, r.output().size()};
+
+ if (r.status() == EVM_REVERT)
+ throw RevertInstruction(std::move(output));
+
+ return output;
+}
+
+evm_revision toRevision(EVMSchedule const& _schedule)
+{
+ if (_schedule.haveCreate2)
+ return EVM_CONSTANTINOPLE;
+ if (_schedule.haveRevert)
+ return EVM_BYZANTIUM;
+ if (_schedule.eip158Mode)
+ return EVM_SPURIOUS_DRAGON;
+ if (_schedule.eip150Mode)
+ return EVM_TANGERINE_WHISTLE;
+ if (_schedule.haveDelegateCall)
+ return EVM_HOMESTEAD;
+ return EVM_FRONTIER;
+}
+
+}
+}
diff --git a/libevm/EVMC.h b/libevm/EVMC.h
new file mode 100644
index 000000000..0e727db1b
--- /dev/null
+++ b/libevm/EVMC.h
@@ -0,0 +1,98 @@
+// Copyright 2018 cpp-ethereum Authors.
+// Licensed under the GNU General Public License v3. See the LICENSE file.
+
+#pragma once
+
+#include
+#include
+
+namespace dev
+{
+namespace eth
+{
+/// Translate the EVMSchedule to EVM-C revision.
+evm_revision toRevision(EVMSchedule const& _schedule);
+
+/// The RAII wrapper for an EVM-C instance.
+class EVM
+{
+public:
+ explicit EVM(evm_instance* _instance) noexcept;
+
+ ~EVM() { m_instance->destroy(m_instance); }
+
+ EVM(EVM const&) = delete;
+ EVM& operator=(EVM) = delete;
+
+ class Result
+ {
+ public:
+ explicit Result(evm_result const& _result):
+ m_result(_result)
+ {}
+
+ ~Result()
+ {
+ if (m_result.release)
+ m_result.release(&m_result);
+ }
+
+ Result(Result&& _other) noexcept:
+ m_result(_other.m_result)
+ {
+ // Disable releaser of the rvalue object.
+ _other.m_result.release = nullptr;
+ }
+
+ Result(Result const&) = delete;
+ Result& operator=(Result const&) = delete;
+
+ evm_status_code status() const
+ {
+ return m_result.status_code;
+ }
+
+ int64_t gasLeft() const
+ {
+ return m_result.gas_left;
+ }
+
+ bytesConstRef output() const
+ {
+ return {m_result.output_data, m_result.output_size};
+ }
+
+ private:
+ evm_result m_result;
+ };
+
+ /// Handy wrapper for evm_execute().
+ Result execute(ExtVMFace& _ext, int64_t gas)
+ {
+ auto mode = toRevision(_ext.evmSchedule());
+ uint32_t flags = _ext.staticCall ? EVM_STATIC : 0;
+ evm_message msg = {toEvmC(_ext.myAddress), toEvmC(_ext.caller),
+ toEvmC(_ext.value), _ext.data.data(),
+ _ext.data.size(), toEvmC(_ext.codeHash), gas,
+ static_cast(_ext.depth), EVM_CALL, flags};
+ return Result{m_instance->execute(
+ m_instance, &_ext, mode, &msg, _ext.code.data(), _ext.code.size()
+ )};
+ }
+
+private:
+ /// The VM instance created with EVM-C _create() function.
+ evm_instance* m_instance = nullptr;
+};
+
+
+/// The wrapper implementing the VMFace interface with a EVM-C VM as a backend.
+class EVMC : public EVM, public VMFace
+{
+public:
+ explicit EVMC(evm_instance* _instance) : EVM(_instance) {}
+
+ owning_bytes_ref exec(u256& io_gas, ExtVMFace& _ext, OnOpFunc const& _onOp) final;
+};
+}
+}
diff --git a/libevm/ExtVMFace.cpp b/libevm/ExtVMFace.cpp
new file mode 100644
index 000000000..80c675b51
--- /dev/null
+++ b/libevm/ExtVMFace.cpp
@@ -0,0 +1,301 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see .
+*/
+
+#include "ExtVMFace.h"
+
+namespace dev
+{
+namespace eth
+{
+namespace
+{
+
+static_assert(sizeof(Address) == sizeof(evm_address), "Address types size mismatch");
+static_assert(alignof(Address) == alignof(evm_address), "Address types alignment mismatch");
+
+inline Address fromEvmC(evm_address const& _addr)
+{
+ return reinterpret_cast(_addr);
+}
+
+static_assert(sizeof(h256) == sizeof(evm_uint256be), "Hash types size mismatch");
+static_assert(alignof(h256) == alignof(evm_uint256be), "Hash types alignment mismatch");
+
+inline u256 fromEvmC(evm_uint256be const& _n)
+{
+ return fromBigEndian(_n.bytes);
+}
+
+int accountExists(evm_context* _context, evm_address const* _addr) noexcept
+{
+ auto& env = static_cast(*_context);
+ Address addr = fromEvmC(*_addr);
+ return env.exists(addr) ? 1 : 0;
+}
+
+void getStorage(
+ evm_uint256be* o_result,
+ evm_context* _context,
+ evm_address const* _addr,
+ evm_uint256be const* _key
+) noexcept
+{
+ (void) _addr;
+ auto& env = static_cast(*_context);
+ assert(fromEvmC(*_addr) == env.myAddress);
+ u256 key = fromEvmC(*_key);
+ *o_result = toEvmC(env.store(key));
+}
+
+void setStorage(
+ evm_context* _context,
+ evm_address const* _addr,
+ evm_uint256be const* _key,
+ evm_uint256be const* _value
+) noexcept
+{
+ (void) _addr;
+ auto& env = static_cast(*_context);
+ assert(fromEvmC(*_addr) == env.myAddress);
+ u256 index = fromEvmC(*_key);
+ u256 value = fromEvmC(*_value);
+ if (value == 0 && env.store(index) != 0) // If delete
+ env.sub.refunds += env.evmSchedule().sstoreRefundGas; // Increase refund counter
+
+ env.setStore(index, value); // Interface uses native endianness
+}
+
+void getBalance(
+ evm_uint256be* o_result,
+ evm_context* _context,
+ evm_address const* _addr
+) noexcept
+{
+ auto& env = static_cast(*_context);
+ *o_result = toEvmC(env.balance(fromEvmC(*_addr)));
+}
+
+size_t getCode(byte const** o_code, evm_context* _context, evm_address const* _addr)
+{
+ auto& env = static_cast(*_context);
+ Address addr = fromEvmC(*_addr);
+ if (o_code != nullptr)
+ {
+ auto& code = env.codeAt(addr);
+ *o_code = code.data();
+ return code.size();
+ }
+ return env.codeSizeAt(addr);
+}
+
+void selfdestruct(
+ evm_context* _context,
+ evm_address const* _addr,
+ evm_address const* _beneficiary
+) noexcept
+{
+ (void) _addr;
+ auto& env = static_cast(*_context);
+ assert(fromEvmC(*_addr) == env.myAddress);
+ env.suicide(fromEvmC(*_beneficiary));
+}
+
+
+void log(
+ evm_context* _context,
+ evm_address const* _addr,
+ uint8_t const* _data,
+ size_t _dataSize,
+ evm_uint256be const _topics[],
+ size_t _numTopics
+) noexcept
+{
+ (void) _addr;
+ auto& env = static_cast(*_context);
+ assert(fromEvmC(*_addr) == env.myAddress);
+ h256 const* pTopics = reinterpret_cast(_topics);
+ env.log(h256s{pTopics, pTopics + _numTopics},
+ bytesConstRef{_data, _dataSize});
+}
+
+void getTxContext(evm_tx_context* result, evm_context* _context) noexcept
+{
+ auto& env = static_cast(*_context);
+ result->tx_gas_price = toEvmC(env.gasPrice);
+ result->tx_origin = toEvmC(env.origin);
+ result->block_coinbase = toEvmC(env.envInfo().author());
+ result->block_number = static_cast(env.envInfo().number());
+ result->block_timestamp = static_cast(env.envInfo().timestamp());
+ result->block_gas_limit = static_cast(env.envInfo().gasLimit());
+ result->block_difficulty = toEvmC(env.envInfo().difficulty());
+}
+
+void getBlockHash(evm_uint256be* o_hash, evm_context* _envPtr, int64_t _number)
+{
+ auto& env = static_cast(*_envPtr);
+ *o_hash = toEvmC(env.blockHash(_number));
+}
+
+void create(evm_result* o_result, ExtVMFace& _env, evm_message const* _msg) noexcept
+{
+ u256 gas = _msg->gas;
+ u256 value = fromEvmC(_msg->value);
+ bytesConstRef init = {_msg->input_data, _msg->input_size};
+ // ExtVM::create takes the sender address from .myAddress.
+ assert(fromEvmC(_msg->sender) == _env.myAddress);
+
+ h160 addr;
+ owning_bytes_ref output;
+ std::tie(addr, output) = _env.create(
+ value, gas, init, Instruction::CREATE, u256(0), {}
+ );
+ o_result->gas_left = static_cast(gas);
+ o_result->release = nullptr;
+ if (addr)
+ {
+ o_result->status_code = EVM_SUCCESS;
+ o_result->create_address = toEvmC(addr);
+ o_result->output_data = nullptr;
+ o_result->output_size = 0;
+ }
+ else
+ {
+ o_result->status_code = EVM_REVERT;
+
+ // Pass the output to the EVM without a copy. The EVM will delete it
+ // when finished with it.
+
+ // First assign reference. References are not invalidated when vector
+ // of bytes is moved. See `.takeBytes()` below.
+ o_result->output_data = output.data();
+ o_result->output_size = output.size();
+
+ // Place a new vector of bytes containing output in result's reserved memory.
+ auto* data = evm_get_optional_data(o_result);
+ static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big");
+ new(data) bytes(output.takeBytes());
+ // Set the destructor to delete the vector.
+ o_result->release = [](evm_result const* _result)
+ {
+ auto* data = evm_get_const_optional_data(_result);
+ auto& output = reinterpret_cast(*data);
+ // Explicitly call vector's destructor to release its data.
+ // This is normal pattern when placement new operator is used.
+ output.~bytes();
+ };
+ }
+}
+
+void call(evm_result* o_result, evm_context* _context, evm_message const* _msg) noexcept
+{
+ assert(_msg->gas >= 0 && "Invalid gas value");
+ auto& env = static_cast(*_context);
+
+ // Handle CREATE separately.
+ if (_msg->kind == EVM_CREATE)
+ return create(o_result, env, _msg);
+
+ CallParameters params;
+ params.gas = _msg->gas;
+ params.apparentValue = fromEvmC(_msg->value);
+ params.valueTransfer =
+ _msg->kind == EVM_DELEGATECALL ? 0 : params.apparentValue;
+ params.senderAddress = fromEvmC(_msg->sender);
+ params.codeAddress = fromEvmC(_msg->destination);
+ params.receiveAddress =
+ _msg->kind == EVM_CALL ? params.codeAddress : env.myAddress;
+ params.data = {_msg->input_data, _msg->input_size};
+ params.staticCall = (_msg->flags & EVM_STATIC) != 0;
+ params.onOp = {};
+
+ bool success = false;
+ owning_bytes_ref output;
+ std::tie(success, output) = env.call(params);
+ // FIXME: We have a mess here. It is hard to distinguish reverts from failures.
+ // In first case we want to keep the output, in the second one the output
+ // is optional and should not be passed to the contract, but can be useful
+ // for EVM in general.
+ o_result->status_code = success ? EVM_SUCCESS : EVM_REVERT;
+ o_result->gas_left = static_cast(params.gas);
+
+ // Pass the output to the EVM without a copy. The EVM will delete it
+ // when finished with it.
+
+ // First assign reference. References are not invalidated when vector
+ // of bytes is moved. See `.takeBytes()` below.
+ o_result->output_data = output.data();
+ o_result->output_size = output.size();
+
+ // Place a new vector of bytes containing output in result's reserved memory.
+ auto* data = evm_get_optional_data(o_result);
+ static_assert(sizeof(bytes) <= sizeof(*data), "Vector is too big");
+ new(data) bytes(output.takeBytes());
+ // Set the destructor to delete the vector.
+ o_result->release = [](evm_result const* _result)
+ {
+ auto* data = evm_get_const_optional_data(_result);
+ auto& output = reinterpret_cast(*data);
+ // Explicitly call vector's destructor to release its data.
+ // This is normal pattern when placement new operator is used.
+ output.~bytes();
+ };
+}
+
+evm_context_fn_table const fnTable = {
+ accountExists,
+ getStorage,
+ setStorage,
+ getBalance,
+ getCode,
+ selfdestruct,
+ eth::call,
+ getTxContext,
+ getBlockHash,
+ eth::log
+};
+
+}
+
+ExtVMFace::ExtVMFace(
+ EnvInfo const& _envInfo,
+ Address _myAddress,
+ Address _caller,
+ Address _origin,
+ u256 _value,
+ u256 _gasPrice,
+ bytesConstRef _data,
+ bytes _code,
+ h256 const& _codeHash,
+ unsigned _depth,
+ bool _staticCall
+):
+ evm_context{&fnTable},
+ m_envInfo(_envInfo),
+ myAddress(_myAddress),
+ caller(_caller),
+ origin(_origin),
+ value(_value),
+ gasPrice(_gasPrice),
+ data(_data),
+ code(std::move(_code)),
+ codeHash(_codeHash),
+ depth(_depth),
+ staticCall(_staticCall)
+{}
+
+}
+}
diff --git a/libevm/ExtVMFace.h b/libevm/ExtVMFace.h
new file mode 100644
index 000000000..b36f100e5
--- /dev/null
+++ b/libevm/ExtVMFace.h
@@ -0,0 +1,257 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see .
+*/
+
+#pragma once
+
+#include "Instruction.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+namespace dev
+{
+namespace eth
+{
+
+/// Reference to a slice of buffer that also owns the buffer.
+///
+/// This is extension to the concept C++ STL library names as array_view
+/// (also known as gsl::span, array_ref, here vector_ref) -- reference to
+/// continuous non-modifiable memory. The extension makes the object also owning
+/// the referenced buffer.
+///
+/// This type is used by VMs to return output coming from RETURN instruction.
+/// To avoid memory copy, a VM returns its whole memory + the information what
+/// part of this memory is actually the output. This simplifies the VM design,
+/// because there are multiple options how the output will be used (can be
+/// ignored, part of it copied, or all of it copied). The decision what to do
+/// with it was moved out of VM interface making VMs "stateless".
+///
+/// The type is movable, but not copyable. Default constructor available.
+class owning_bytes_ref: public vector_ref
+{
+public:
+ owning_bytes_ref() = default;
+
+ /// @param _bytes The buffer.
+ /// @param _begin The index of the first referenced byte.
+ /// @param _size The number of referenced bytes.
+ owning_bytes_ref(bytes&& _bytes, size_t _begin, size_t _size):
+ m_bytes(std::move(_bytes))
+ {
+ // Set the reference *after* the buffer is moved to avoid
+ // pointer invalidation.
+ retarget(&m_bytes[_begin], _size);
+ }
+
+ owning_bytes_ref(owning_bytes_ref const&) = delete;
+ owning_bytes_ref(owning_bytes_ref&&) = default;
+ owning_bytes_ref& operator=(owning_bytes_ref const&) = delete;
+ owning_bytes_ref& operator=(owning_bytes_ref&&) = default;
+
+ /// Moves the bytes vector out of here. The object cannot be used any more.
+ bytes&& takeBytes()
+ {
+ reset(); // Reset reference just in case.
+ return std::move(m_bytes);
+ }
+
+private:
+ bytes m_bytes;
+};
+
+struct SubState
+{
+ std::set suicides; ///< Any accounts that have suicided.
+ LogEntries logs; ///< Any logs.
+ u256 refunds; ///< Refund counter of SSTORE nonzero->zero.
+
+ SubState& operator+=(SubState const& _s)
+ {
+ suicides += _s.suicides;
+ refunds += _s.refunds;
+ logs += _s.logs;
+ return *this;
+ }
+
+ void clear()
+ {
+ suicides.clear();
+ logs.clear();
+ refunds = 0;
+ }
+};
+
+class ExtVMFace;
+class LastBlockHashesFace;
+class VM;
+
+using OnOpFunc = std::function;
+
+struct CallParameters
+{
+ CallParameters() = default;
+ CallParameters(
+ Address _senderAddress,
+ Address _codeAddress,
+ Address _receiveAddress,
+ u256 _valueTransfer,
+ u256 _apparentValue,
+ u256 _gas,
+ bytesConstRef _data,
+ OnOpFunc _onOpFunc
+ ): senderAddress(_senderAddress), codeAddress(_codeAddress), receiveAddress(_receiveAddress),
+ valueTransfer(_valueTransfer), apparentValue(_apparentValue), gas(_gas), data(_data), onOp(_onOpFunc) {}
+ Address senderAddress;
+ Address codeAddress;
+ Address receiveAddress;
+ u256 valueTransfer;
+ u256 apparentValue;
+ u256 gas;
+ bytesConstRef data;
+ bool staticCall = false;
+ OnOpFunc onOp;
+};
+
+class EnvInfo
+{
+public:
+ EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed):
+ m_headerInfo(_current),
+ m_lastHashes(_lh),
+ m_gasUsed(_gasUsed)
+ {}
+ // Constructor with custom gasLimit - used in some synthetic scenarios like eth_estimateGas RPC method
+ EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, u256 const& _gasLimit):
+ EnvInfo(_current, _lh, _gasUsed)
+ {
+ m_headerInfo.setGasLimit(_gasLimit);
+ }
+
+ BlockHeader const& header() const { return m_headerInfo; }
+
+ int64_t number() const { return m_headerInfo.number(); }
+ Address const& author() const { return m_headerInfo.author(); }
+ int64_t timestamp() const { return m_headerInfo.timestamp(); }
+ u256 const& difficulty() const { return m_headerInfo.difficulty(); }
+ u256 const& gasLimit() const { return m_headerInfo.gasLimit(); }
+ LastBlockHashesFace const& lastHashes() const { return m_lastHashes; }
+ u256 const& gasUsed() const { return m_gasUsed; }
+
+private:
+ BlockHeader m_headerInfo;
+ LastBlockHashesFace const& m_lastHashes;
+ u256 m_gasUsed;
+};
+
+/**
+ * @brief Interface and null implementation of the class for specifying VM externalities.
+ */
+class ExtVMFace: public evm_context
+{
+public:
+ /// Null constructor.
+ ExtVMFace() = default;
+
+ /// Full constructor.
+ ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth, bool _staticCall);
+
+ virtual ~ExtVMFace() = default;
+
+ ExtVMFace(ExtVMFace const&) = delete;
+ ExtVMFace& operator=(ExtVMFace const&) = delete;
+
+ /// Read storage location.
+ virtual u256 store(u256) { return 0; }
+
+ /// Write a value in storage.
+ virtual void setStore(u256, u256) {}
+
+ /// Read address's balance.
+ virtual u256 balance(Address) { return 0; }
+
+ /// Read address's code.
+ virtual bytes const& codeAt(Address) { return NullBytes; }
+
+ /// @returns the size of the code in bytes at the given address.
+ virtual size_t codeSizeAt(Address) { return 0; }
+
+ /// Does the account exist?
+ virtual bool exists(Address) { return false; }
+
+ /// Suicide the associated contract and give proceeds to the given address.
+ virtual void suicide(Address) { sub.suicides.insert(myAddress); }
+
+ /// Create a new (contract) account.
+ virtual std::pair create(u256, u256&, bytesConstRef, Instruction, u256, OnOpFunc const&) = 0;
+
+ /// Make a new message call.
+ /// @returns success flag and output data, if any.
+ virtual std::pair call(CallParameters&) = 0;
+
+ /// Revert any changes made (by any of the other calls).
+ virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(myAddress, std::move(_topics), _data.toBytes())); }
+
+ /// Hash of a block if within the last 256 blocks, or h256() otherwise.
+ virtual h256 blockHash(u256 _number) = 0;
+
+ /// Get the execution environment information.
+ EnvInfo const& envInfo() const { return m_envInfo; }
+
+ /// Return the EVM gas-price schedule for this execution context.
+ virtual EVMSchedule const& evmSchedule() const { return DefaultSchedule; }
+
+private:
+ EnvInfo const& m_envInfo;
+
+public:
+ // TODO: make private
+ Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be).
+ Address caller; ///< Address which sent the message (either equal to origin or a contract).
+ Address origin; ///< Original transactor.
+ u256 value; ///< Value (in Wei) that was passed to this address.
+ u256 gasPrice; ///< Price of gas (that we already paid).
+ bytesConstRef data; ///< Current input data.
+ bytes code; ///< Current code that is executing.
+ h256 codeHash; ///< SHA3 hash of the executing code
+ SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
+ unsigned depth = 0; ///< Depth of the present call.
+ bool staticCall = false; ///< Throw on state changing.
+};
+
+inline evm_address toEvmC(Address const& _addr)
+{
+ return reinterpret_cast(_addr);
+}
+
+inline evm_uint256be toEvmC(h256 const& _h)
+{
+ return reinterpret_cast(_h);
+}
+
+}
+}
diff --git a/libevm/Instruction.cpp b/libevm/Instruction.cpp
new file mode 100644
index 000000000..d3c3e2685
--- /dev/null
+++ b/libevm/Instruction.cpp
@@ -0,0 +1,229 @@
+/*
+ This file is part of cpp-ethereum.
+
+ cpp-ethereum is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ cpp-ethereum is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with cpp-ethereum. If not, see .
+*/
+
+#include "Instruction.h"
+#include