Merge pull request #7010 from ethereum/useevmone

Use evmone for testing.
This commit is contained in:
chriseth 2019-08-08 18:35:47 +02:00 committed by GitHub
commit 18ffe3b3ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 1083 additions and 1239 deletions

View File

@ -282,7 +282,7 @@ jobs:
at: build at: build
- run: - run:
name: "soltest: Syntax Tests" name: "soltest: Syntax Tests"
command: build/test/soltest -t 'syntaxTest*' -- --no-ipc --testpath test command: build/test/soltest -t 'syntaxTest*' -- --testpath test
- run: - run:
name: "Code Coverage: Syntax Tests" name: "Code Coverage: Syntax Tests"
command: codecov --flags syntax --gcov-root build command: codecov --flags syntax --gcov-root build
@ -478,7 +478,6 @@ jobs:
environment: environment:
EVM: constantinople EVM: constantinople
OPTIMIZE: 0 OPTIMIZE: 0
SOLTEST_IPC: 0
ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2
t_ubu_homestead: t_ubu_homestead:

View File

@ -46,15 +46,6 @@ RUN set -ex; \
FROM base AS libraries FROM base AS libraries
# Aleth for end-to-end tests
ARG ALETH_VERSION="1.6.0"
ARG ALETH_HASH="7f7004e1563299bc57882e32b32e4a195747dfb6"
ARG ALETH_URL="https://github.com/ethereum/aleth/releases/download/v${ALETH_VERSION}/aleth-${ALETH_VERSION}-linux-x86_64.tar.gz"
RUN set -ex; \
wget -q -O /tmp/aleth.tar.gz "${ALETH_URL}"; \
test "$(shasum /tmp/aleth.tar.gz)" = "$ALETH_HASH /tmp/aleth.tar.gz"; \
tar -xf /tmp/aleth.tar.gz -C /usr
# Z3 # Z3
RUN set -ex; \ RUN set -ex; \
git clone --depth=1 --branch="Z3-4.8.5" https://github.com/Z3Prover/z3.git /usr/src/z3; \ git clone --depth=1 --branch="Z3-4.8.5" https://github.com/Z3Prover/z3.git /usr/src/z3; \

View File

@ -36,27 +36,17 @@ set -e
OPTIMIZE=${OPTIMIZE:-"0"} OPTIMIZE=${OPTIMIZE:-"0"}
EVM=${EVM:-"invalid"} EVM=${EVM:-"invalid"}
WORKDIR=${CIRCLE_WORKING_DIRECTORY:-.} WORKDIR=${CIRCLE_WORKING_DIRECTORY:-.}
SOLTEST_IPC=${SOLTEST_IPC:-1}
REPODIR="$(realpath $(dirname $0)/..)" REPODIR="$(realpath $(dirname $0)/..)"
ALETH_PATH="/usr/bin/aleth"
source "${REPODIR}/scripts/common.sh" source "${REPODIR}/scripts/common.sh"
# Test result output directory (CircleCI is reading test results from here) # Test result output directory (CircleCI is reading test results from here)
mkdir -p test_results mkdir -p test_results
ALETH_PID=$(run_aleth)
function cleanup() {
safe_kill $ALETH_PID $ALETH_PATH
}
trap cleanup INT TERM
# in case we run with ASAN enabled, we must increase stck size. # in case we run with ASAN enabled, we must increase stck size.
ulimit -s 16384 ulimit -s 16384
BOOST_TEST_ARGS="--color_output=no --show_progress=yes --logger=JUNIT,error,test_results/$EVM.xml" BOOST_TEST_ARGS="--color_output=no --show_progress=yes --logger=JUNIT,error,test_results/$EVM.xml"
SOLTEST_ARGS="--evm-version=$EVM --ipcpath "${WORKDIR}/geth.ipc" $flags" SOLTEST_ARGS="--evm-version=$EVM --evmonepath /usr/lib/libevmone.so $flags"
test "${SOLTEST_IPC}" = "1" || SOLTEST_ARGS="$SOLTEST_ARGS --no-ipc"
test "${OPTIMIZE}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --optimize" test "${OPTIMIZE}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --optimize"
test "${ABI_ENCODER_V2}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --abiencoderv2 --optimize-yul" test "${ABI_ENCODER_V2}" = "1" && SOLTEST_ARGS="${SOLTEST_ARGS} --abiencoderv2 --optimize-yul"

View File

@ -5,9 +5,6 @@
# #
# http://solidity.readthedocs.org # http://solidity.readthedocs.org
# #
# TODO - Tests currently disabled, because Tests-over-IPC code is using UNIX
# sockets unconditionally at the time of writing.
#
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# This file is part of solidity. # This file is part of solidity.
# #
@ -71,7 +68,7 @@ build_script:
test_script: test_script:
- cd %APPVEYOR_BUILD_FOLDER%\build\test\%CONFIGURATION% - cd %APPVEYOR_BUILD_FOLDER%\build\test\%CONFIGURATION%
- soltest.exe --show-progress -- --testpath %APPVEYOR_BUILD_FOLDER%\test --no-ipc --no-smt - soltest.exe --show-progress -- --testpath %APPVEYOR_BUILD_FOLDER%\test --no-smt
# Skip bytecode compare if private key is not available # Skip bytecode compare if private key is not available
- cd %APPVEYOR_BUILD_FOLDER% - cd %APPVEYOR_BUILD_FOLDER%
- ps: if ($env:priv_key) { - ps: if ($env:priv_key) {

View File

@ -81,15 +81,23 @@ Thank you for your help!
Running the compiler tests Running the compiler tests
========================== ==========================
The ``./scripts/tests.sh`` script executes most Solidity tests and The ``./scripts/tests.sh`` script executes most Solidity tests automatically,
runs ``aleth`` automatically if it is in the path. The script does not download it, but for quicker feedback, you might want to run specific tests.
so you need to install it first. Please read on for the details.
Solidity includes different types of tests, most of them bundled into the `Boost C++ Test Framework <https://www.boost.org/doc/libs/1_69_0/libs/test/doc/html/index.html>`_ application ``soltest``. Solidity includes different types of tests, most of them bundled into the
Some of them require the ``aleth`` client in testing mode, others require ``libz3``. `Boost C++ Test Framework <https://www.boost.org/doc/libs/1_69_0/libs/test/doc/html/index.html>`_ application ``soltest``.
Running ``build/test/soltest` or its wrapper ``scripts/soltest.sh`` is sufficient for most changes.
To run a basic set of tests that require neither ``aleth`` nor ``libz3``, run Some tests require the ``libevmone.so`` library, others require ``libz3``.
``./scripts/soltest.sh --no-ipc --no-smt``.
The test system will automatically try to discover the location of ``libevmone.so``
starting from the current directory. If it does not find it, the relevant tests
are skipped. To run all tests, download the library from
`Github <https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz>`_
and either place it in the project root path or inside the ``deps`` folder.
If you do not have libz3 installed on your system, you should disable the SMT tests:
``./scripts/soltest.sh --no-smt``.
``./build/test/soltest --help`` has extensive help on all of the options available. ``./build/test/soltest --help`` has extensive help on all of the options available.
See especially: See especially:
@ -100,27 +108,19 @@ See especially:
.. note :: .. note ::
Those working in a Windows environment wanting to run the above basic sets without aleth or libz3 in Git Bash, you would have to do: ``./build/test/Release/soltest.exe -- --no-ipc --no-smt``. Those working in a Windows environment wanting to run the above basic sets without libz3 in Git Bash, you would have to do: ``./build/test/Release/soltest.exe -- --no-smt``.
If you're running this in plain Command Prompt, use ``.\build\test\Release\soltest.exe -- --no-ipc --no-smt``. If you are running this in plain Command Prompt, use ``.\build\test\Release\soltest.exe -- --no-smt``.
The option ``--no-smt`` disables the tests that require ``libz3`` and
``--no-ipc`` disables those that require ``aleth``.
If you want to run the ipc tests (that test the semantics of the generated code),
you need to install `aleth <https://github.com/ethereum/aleth/releases/download/v1.6.0/aleth-1.6.0-linux-x86_64.tar.gz>`_ and run it in testing mode: ``aleth --db memorydb --test -d /tmp/testeth``.
To run the actual tests, use: ``./scripts/soltest.sh --ipcpath /tmp/testeth/geth.ipc``.
To run a subset of tests, you can use filters: To run a subset of tests, you can use filters:
``./scripts/soltest.sh -t TestSuite/TestName --ipcpath /tmp/testeth/geth.ipc``, ``./scripts/soltest.sh -t TestSuite/TestName,
where ``TestName`` can be a wildcard ``*``. where ``TestName`` can be a wildcard ``*``.
For example, here's an example test you might run; For example, here is an example test you might run;
``./scripts/soltest.sh -t "yulOptimizerTests/disambiguator/*" --no-ipc --no-smt``. ``./scripts/soltest.sh -t "yulOptimizerTests/disambiguator/*" --no-smt``.
This will test all the tests for the disambiguator. This will test all the tests for the disambiguator.
To get a list of all tests, use To get a list of all tests, use
``./build/test/soltest --list_content=HRF -- --ipcpath /tmp/irrelevant``. ``./build/test/soltest --list_content=HRF``.
If you want to debug using GDB, make sure you build differently than the "usual". If you want to debug using GDB, make sure you build differently than the "usual".
For example, you could run the following command in your ``build`` folder: For example, you could run the following command in your ``build`` folder:
@ -137,11 +137,6 @@ in addition to those found in ``soltest``.
The CI runs additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target. The CI runs additional tests (including ``solc-js`` and testing third party Solidity frameworks) that require compiling the Emscripten target.
.. note ::
Some versions of ``aleth`` can not be used for testing. We suggest using
the same version that the Solidity continuous integration tests use.
Currently the CI uses version ``1.6.0`` of ``aleth``.
Writing and running syntax tests Writing and running syntax tests
-------------------------------- --------------------------------

View File

@ -33,6 +33,7 @@
#include <string> #include <string>
#include <set> #include <set>
#include <functional> #include <functional>
#include <utility>
/// Operators need to stay in the global namespace. /// Operators need to stay in the global namespace.

View File

@ -1,21 +0,0 @@
#!/usr/bin/env bash
ALETH_PATH=$1
ALETH_TMP_OUT=$2
shift
shift
$ALETH_PATH $@ &> >(tail -n 100000 &> "$ALETH_TMP_OUT") &
PID=$!
function cleanup()
{
kill $PID
}
trap cleanup INT TERM
wait $PID

View File

@ -55,42 +55,3 @@ safe_kill()
kill -9 $PID kill -9 $PID
fi fi
} }
# Ensures aleth executable and exposes the following information:
#
# - env var ALETH_PATH: to point to the aleth executable.
# - directory /tmp/test if needed. No cleanup is done on this directory
function download_aleth()
{
if which aleth &>/dev/null; then
ALETH_PATH=`which aleth`
elif [[ "$OSTYPE" == "darwin"* ]]; then
ALETH_PATH="$(realpath $(dirname "$0")/..)/aleth"
elif [ "$CIRCLECI" ] || [ -z $CI ]; then
ALETH_PATH="aleth"
else
ALETH_PATH="/tmp/test/bin/aleth"
mkdir -p /tmp/test
# Any time the hash is updated here, the "Running the compiler tests" section in contributing.rst should also be updated.
local ALETH_HASH="7f7004e1563299bc57882e32b32e4a195747dfb6"
local ALETH_VERSION="1.6.0"
wget -q -O /tmp/test/aleth.tar.gz https://github.com/ethereum/aleth/releases/download/v${ALETH_VERSION}/aleth-${ALETH_VERSION}-linux-x86_64.tar.gz
test "$(shasum /tmp/test/aleth.tar.gz)" = "$ALETH_HASH /tmp/test/aleth.tar.gz"
tar -xf /tmp/test/aleth.tar.gz -C /tmp/test
sync
chmod +x $ALETH_PATH
sync # Otherwise we might get a "text file busy" error
fi
}
# Executes aleth in the background and echos its PID.
function run_aleth()
{
$ALETH_PATH --db memorydb --test -d "${WORKDIR}" &> /dev/null &
echo $!
# Wait until the IPC endpoint is available.
while [ ! -S "${WORKDIR}/geth.ipc" ] ; do sleep 1; done
sleep 2
}

View File

@ -1,17 +0,0 @@
#!/usr/bin/env sh
# Script to build the eth binary from latest develop
# for ubuntu trusty and ubuntu artful.
# Requires docker.
set -e
REPO_ROOT="$(dirname "$0")"/../..
for rel in artful trusty
do
docker build -t eth_$rel -f "$REPO_ROOT"/scripts/cpp-ethereum/eth_$rel.docker .
tmp_container=$(docker create eth_$rel sh)
echo "Built eth ($rel) at $REPO_ROOT/build/eth_$rel"
docker cp ${tmp_container}:/build/eth/eth "$REPO_ROOT"/build/eth_$rel
done

View File

@ -1,7 +0,0 @@
FROM ubuntu:artful
RUN apt update
RUN apt -y install libleveldb-dev cmake g++ git
RUN git clone --recursive https://github.com/ethereum/cpp-ethereum --branch develop --single-branch --depth 1
RUN mkdir /build && cd /build && cmake /cpp-ethereum -DCMAKE_BUILD_TYPE=RelWithDebInfo -DTOOLS=Off -DTESTS=Off
RUN cd /build && make eth

View File

@ -1,13 +0,0 @@
FROM ubuntu:trusty
RUN apt-get update
RUN apt-get -y install software-properties-common python-software-properties
RUN add-apt-repository ppa:ubuntu-toolchain-r/test
RUN apt-get update
RUN apt-get -y install gcc libleveldb-dev git curl make gcc-7 g++-7
RUN ln -sf /usr/bin/gcc-7 /usr/bin/gcc
RUN ln -sf /usr/bin/g++-7 /usr/bin/g++
RUN git clone --recursive https://github.com/ethereum/cpp-ethereum --branch develop --single-branch --depth 1
RUN ./cpp-ethereum/scripts/install_cmake.sh
RUN mkdir /build && cd /build && ~/.local/bin/cmake /cpp-ethereum -DCMAKE_BUILD_TYPE=RelWithDebInfo -DTOOLS=Off -DTESTS=Off
RUN cd /build && make eth

View File

@ -104,9 +104,6 @@ case $(uname -s) in
brew install cmake brew install cmake
if [ "$CI" = true ]; then if [ "$CI" = true ]; then
brew upgrade cmake brew upgrade cmake
brew tap ethereum/ethereum
brew install cpp-ethereum
brew linkapps cpp-ethereum
else else
brew upgrade brew upgrade
fi fi
@ -337,13 +334,6 @@ case $(uname -s) in
sudo apt-get -y update sudo apt-get -y update
sudo apt-get -y install libz3-dev sudo apt-get -y install libz3-dev
fi fi
# Install 'eth', for use in the Solidity Tests-over-IPC.
# We will not use this 'eth', but its dependencies
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo add-apt-repository -y ppa:ethereum/ethereum-dev
sudo apt-get -y update
sudo apt-get -y install eth
fi fi
;; ;;

View File

@ -33,10 +33,6 @@ REPO_ROOT="$(dirname "$0")/.."
source "${REPO_ROOT}/scripts/common.sh" source "${REPO_ROOT}/scripts/common.sh"
WORKDIR=`mktemp -d` WORKDIR=`mktemp -d`
# Will be printed in case of a test failure
ALETH_TMP_OUT=`mktemp`
IPC_ENABLED=true
ALETH_PID=
CMDLINE_PID= CMDLINE_PID=
if [[ "$OSTYPE" == "darwin"* ]] if [[ "$OSTYPE" == "darwin"* ]]
@ -48,10 +44,6 @@ cleanup() {
# ensure failing commands don't cause termination during cleanup (especially within safe_kill) # ensure failing commands don't cause termination during cleanup (especially within safe_kill)
set +e set +e
if [[ "$IPC_ENABLED" = true ]] && [[ -n "${ALETH_PID}" ]]
then
safe_kill $ALETH_PID $ALETH_PATH
fi
if [[ -n "$CMDLINE_PID" ]] if [[ -n "$CMDLINE_PID" ]]
then then
safe_kill $CMDLINE_PID "Commandline tests" safe_kill $CMDLINE_PID "Commandline tests"
@ -59,7 +51,6 @@ cleanup() {
echo "Cleaning up working directory ${WORKDIR} ..." echo "Cleaning up working directory ${WORKDIR} ..."
rm -rf "$WORKDIR" || true rm -rf "$WORKDIR" || true
rm $ALETH_TMP_OUT
} }
trap cleanup INT TERM trap cleanup INT TERM
@ -89,20 +80,6 @@ else
fi fi
fi fi
function check_aleth() {
printTask "Running IPC tests with $ALETH_PATH..."
if ! hash $ALETH_PATH 2>/dev/null; then
printError "$ALETH_PATH not found"
exit 1
fi
}
if [ "$IPC_ENABLED" = true ];
then
download_aleth
check_aleth
ALETH_PID=$(run_aleth)
fi
EVM_VERSIONS="homestead byzantium" EVM_VERSIONS="homestead byzantium"
@ -112,7 +89,7 @@ then
fi fi
# And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer # And then run the Solidity unit-tests in the matrix combination of optimizer / no optimizer
# and homestead / byzantium VM, # pointing to that IPC endpoint. # and homestead / byzantium VM
for optimize in "" "--optimize" for optimize in "" "--optimize"
do do
for vm in $EVM_VERSIONS for vm in $EVM_VERSIONS
@ -143,16 +120,9 @@ do
fi fi
set +e set +e
"$REPO_ROOT"/build/test/soltest --show-progress $log -- --testpath "$REPO_ROOT"/test "$optimize" --evm-version "$vm" $SMT_FLAGS $IPC_FLAGS $force_abiv2_flag --ipcpath "${WORKDIR}/geth.ipc" "$REPO_ROOT"/build/test/soltest --show-progress $log -- --testpath "$REPO_ROOT"/test "$optimize" --evm-version "$vm" $SMT_FLAGS $force_abiv2_flag
if test "0" -ne "$?"; then if test "0" -ne "$?"; then
if [ -n "$log_directory" ]
then
# Need to kill aleth first so the log is written
safe_kill $ALETH_PID $ALETH_PATH
cp $ALETH_TMP_OUT $log_directory/aleth.log
printError "Some test failed, wrote aleth.log"
fi
exit 1 exit 1
fi fi
set -e set -e

View File

@ -57,15 +57,30 @@ boost::filesystem::path testPath()
return {}; return {};
} }
std::string IPCEnvOrDefaultPath() std::string EVMOneEnvOrDefaultPath()
{ {
if (auto path = getenv("ETH_TEST_IPC")) if (auto path = getenv("ETH_EVMONE"))
return path; return path;
if (auto home = getenv("HOME")) auto const searchPath =
return std::string(home) + "/.ethereum/geth.ipc"; {
fs::path("/usr/local/lib"),
return std::string{}; fs::path("/usr/lib"),
fs::current_path() / "deps",
fs::current_path() / "deps" / "lib",
fs::current_path() / ".." / "deps",
fs::current_path() / ".." / "deps" / "lib",
fs::current_path() / ".." / ".." / "deps",
fs::current_path() / ".." / ".." / "deps" / "lib",
fs::current_path()
};
for (auto const& basePath: searchPath)
{
fs::path p = basePath / "libevmone.so";
if (fs::exists(p))
return p.string();
}
return {};
} }
CommonOptions::CommonOptions(std::string _caption): CommonOptions::CommonOptions(std::string _caption):
@ -77,8 +92,7 @@ CommonOptions::CommonOptions(std::string _caption):
options.add_options() options.add_options()
("evm-version", po::value(&evmVersionString), "which evm version to use") ("evm-version", po::value(&evmVersionString), "which evm version to use")
("testpath", po::value<fs::path>(&this->testPath)->default_value(dev::test::testPath()), "path to test files") ("testpath", po::value<fs::path>(&this->testPath)->default_value(dev::test::testPath()), "path to test files")
("ipcpath", po::value<fs::path>(&ipcPath)->default_value(IPCEnvOrDefaultPath()), "path to ipc socket") ("evmonepath", po::value<fs::path>(&evmonePath)->default_value(EVMOneEnvOrDefaultPath()), "path to libevmone.so")
("no-ipc", po::bool_switch(&disableIPC), "disable semantic tests")
("no-smt", po::bool_switch(&disableSMT), "disable SMT checker"); ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker");
} }
@ -95,19 +109,6 @@ void CommonOptions::validate() const
"Invalid test path specified." "Invalid test path specified."
); );
if (!disableIPC)
{
assertThrow(
!ipcPath.empty(),
ConfigException,
"No ipc path specified. The --ipcpath argument must not be empty when given."
);
assertThrow(
fs::exists(ipcPath),
ConfigException,
"Invalid ipc path specified."
);
}
} }
bool CommonOptions::parse(int argc, char const* const* argv) bool CommonOptions::parse(int argc, char const* const* argv)

View File

@ -34,11 +34,10 @@ struct ConfigException : public Exception {};
struct CommonOptions: boost::noncopyable struct CommonOptions: boost::noncopyable
{ {
boost::filesystem::path ipcPath; boost::filesystem::path evmonePath;
boost::filesystem::path testPath; boost::filesystem::path testPath;
bool optimize = false; bool optimize = false;
bool optimizeYul = false; bool optimizeYul = false;
bool disableIPC = false;
bool disableSMT = false; bool disableSMT = false;
langutil::EVMVersion evmVersion() const; langutil::EVMVersion evmVersion() const;

View File

@ -24,6 +24,8 @@
#include <test/evmc/helpers.hpp> #include <test/evmc/helpers.hpp>
#include <test/evmc/loader.h> #include <test/evmc/loader.h>
#include <libevmasm/GasMeter.h>
#include <libdevcore/Exceptions.h> #include <libdevcore/Exceptions.h>
#include <libdevcore/Assertions.h> #include <libdevcore/Assertions.h>
#include <libdevcore/Keccak256.h> #include <libdevcore/Keccak256.h>
@ -33,9 +35,36 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::test; using namespace dev::test;
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::vm& _vmInstance):
m_vm(_vmInstance) evmc::vm* EVMHost::getVM(string const& _path)
{ {
static unique_ptr<evmc::vm> theVM;
if (!theVM && !_path.empty())
{
evmc_loader_error_code errorCode = {};
evmc_instance* vm = evmc_load_and_create(_path.c_str(), &errorCode);
if (vm && errorCode == EVMC_LOADER_SUCCESS)
theVM = make_unique<evmc::vm>(vm);
else
{
cerr << "Error loading VM from " << _path;
if (char const* errorMsg = evmc_last_error_msg())
cerr << ":" << endl << errorMsg;
cerr << endl;
}
}
return theVM.get();
}
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm):
m_vm(_vm)
{
if (!m_vm)
{
cerr << "Unable to find library libevmone.so" << endl;
assertThrow(false, Exception, "");
}
if (_evmVersion == langutil::EVMVersion::homestead()) if (_evmVersion == langutil::EVMVersion::homestead())
m_evmVersion = EVMC_HOMESTEAD; m_evmVersion = EVMC_HOMESTEAD;
else if (_evmVersion == langutil::EVMVersion::tangerineWhistle()) else if (_evmVersion == langutil::EVMVersion::tangerineWhistle())
@ -77,8 +106,22 @@ void EVMHost::selfdestruct(const evmc_address& _addr, const evmc_address& _benef
evmc::result EVMHost::call(evmc_message const& _message) noexcept evmc::result EVMHost::call(evmc_message const& _message) noexcept
{ {
if (_message.destination == convertToEVMC(Address(2))) if (_message.destination == convertToEVMC(Address(1)))
return precompileECRecover(_message);
else if (_message.destination == convertToEVMC(Address(2)))
return precompileSha256(_message); return precompileSha256(_message);
else if (_message.destination == convertToEVMC(Address(3)))
return precompileRipeMD160(_message);
else if (_message.destination == convertToEVMC(Address(4)))
return precompileIdentity(_message);
else if (_message.destination == convertToEVMC(Address(5)))
return precompileModExp(_message);
else if (_message.destination == convertToEVMC(Address(6)))
return precompileALTBN128G1Add(_message);
else if (_message.destination == convertToEVMC(Address(7)))
return precompileALTBN128G1Mul(_message);
else if (_message.destination == convertToEVMC(Address(8)))
return precompileALTBN128PairingProduct(_message);
State stateBackup = m_state; State stateBackup = m_state;
@ -88,6 +131,20 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
bytes code; bytes code;
evmc_message message = _message; evmc_message message = _message;
if (message.depth == 0)
{
message.gas -= message.kind == EVMC_CREATE ? eth::GasCosts::txCreateGas : eth::GasCosts::txGas;
for (size_t i = 0; i < message.input_size; ++i)
message.gas -= message.input_data[i] == 0 ? eth::GasCosts::txDataZeroGas : eth::GasCosts::txDataNonZeroGas;
if (message.gas < 0)
{
evmc::result result({});
result.status_code = EVMC_OUT_OF_GAS;
m_state = stateBackup;
return result;
}
}
if (message.kind == EVMC_CREATE) if (message.kind == EVMC_CREATE)
{ {
// TODO this is not the right formula // TODO this is not the right formula
@ -123,17 +180,28 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
evmc_address currentAddress = m_currentAddress; evmc_address currentAddress = m_currentAddress;
m_currentAddress = message.destination; m_currentAddress = message.destination;
evmc::result result = m_vm.execute(*this, m_evmVersion, message, code.data(), code.size()); evmc::result result = m_vm->execute(*this, m_evmVersion, message, code.data(), code.size());
m_currentAddress = currentAddress; m_currentAddress = currentAddress;
if (result.status_code != EVMC_SUCCESS) if (message.kind == EVMC_CREATE)
m_state = stateBackup; {
else if (message.kind == EVMC_CREATE) result.gas_left -= eth::GasCosts::createDataGas * result.output_size;
if (result.gas_left < 0)
{
result.gas_left = 0;
result.status_code = EVMC_OUT_OF_GAS;
// TODO clear some fields?
}
else
{ {
result.create_address = message.destination; result.create_address = message.destination;
destination.code = bytes(result.output_data, result.output_data + result.output_size); destination.code = bytes(result.output_data, result.output_data + result.output_size);
destination.codeHash = convertToEVMC(keccak256(destination.code)); destination.codeHash = convertToEVMC(keccak256(destination.code));
} }
}
if (result.status_code != EVMC_SUCCESS)
m_state = stateBackup;
return result; return result;
} }
@ -199,6 +267,35 @@ evmc_bytes32 EVMHost::convertToEVMC(h256 const& _data)
return d; return d;
} }
evmc::result EVMHost::precompileECRecover(evmc_message const& _message) noexcept
{
// NOTE this is a partial implementation for some inputs.
static map<bytes, bytes> const inputOutput{
{
fromHex(
"18c547e4f7b0f325ad1e56f57e26c745b09a3e503d86e00e5255ff7f715d3d1c"
"000000000000000000000000000000000000000000000000000000000000001c"
"73b1693892219d736caba55bdb67216e485557ea6b6af75f37096c9aa6a5a75f"
"eeb940b1d03b21e36b0e47e79769f095fe2ab855bd91e3a38756b7d75a9c4549"
),
fromHex("000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b")
},
{
fromHex(
"47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad"
"000000000000000000000000000000000000000000000000000000000000001c"
"debaaa0cddb321b2dcaaf846d39605de7b97e77ba6106587855b9106cb104215"
"61a22d94fa8b8a687ff9c911c844d1c016d1a685a9166858f9c7c1bc85128aca"
),
fromHex("0000000000000000000000008743523d96a1b2cbe0c6909653a56da18ed484af")
}
};
evmc::result result = precompileGeneric(_message, inputOutput);
result.status_code = EVMC_SUCCESS;
result.gas_left = _message.gas;
return result;
}
evmc::result EVMHost::precompileSha256(evmc_message const& _message) noexcept evmc::result EVMHost::precompileSha256(evmc_message const& _message) noexcept
{ {
// static data so that we do not need a release routine... // static data so that we do not need a release routine...
@ -209,7 +306,400 @@ evmc::result EVMHost::precompileSha256(evmc_message const& _message) noexcept
)); ));
evmc::result result({}); evmc::result result({});
result.gas_left = _message.gas;
result.output_data = hash.data(); result.output_data = hash.data();
result.output_size = hash.size(); result.output_size = hash.size();
return result; return result;
} }
evmc::result EVMHost::precompileRipeMD160(evmc_message const& _message) noexcept
{
// NOTE this is a partial implementation for some inputs.
static map<bytes, bytes> const inputOutput{
{
bytes{},
fromHex("0000000000000000000000009c1185a5c5e9fc54612808977ee8f548b2258d31")
},
{
fromHex("0000000000000000000000000000000000000000000000000000000000000004"),
fromHex("0000000000000000000000001b0f3c404d12075c68c938f9f60ebea4f74941a0")
},
{
fromHex("0000000000000000000000000000000000000000000000000000000000000005"),
fromHex("000000000000000000000000ee54aa84fc32d8fed5a5fe160442ae84626829d9")
},
{
fromHex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"),
fromHex("0000000000000000000000001cf4e77f5966e13e109703cd8a0df7ceda7f3dc3")
},
{
fromHex("0000000000000000000000000000000000000000000000000000000000000000"),
fromHex("000000000000000000000000f93175303eba2a7b372174fc9330237f5ad202fc")
},
{
fromHex(
"0800000000000000000000000000000000000000000000000000000000000000"
"0401000000000000000000000000000000000000000000000000000000000000"
"0000000400000000000000000000000000000000000000000000000000000000"
"00000100"
),
fromHex("000000000000000000000000f93175303eba2a7b372174fc9330237f5ad202fc")
},
{
fromHex(
"0800000000000000000000000000000000000000000000000000000000000000"
"0501000000000000000000000000000000000000000000000000000000000000"
"0000000500000000000000000000000000000000000000000000000000000000"
"00000100"
),
fromHex("0000000000000000000000004f4fc112e2bfbe0d38f896a46629e08e2fcfad5")
},
{
fromHex(
"08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ff010000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
"ffffffff00000000000000000000000000000000000000000000000000000000"
"00000100"
),
fromHex("000000000000000000000000c0a2e4b1f3ff766a9a0089e7a410391730872495")
},
{
fromHex(
"6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546"
"4748494a4b4c4d4e4f505152535455565758595a303132333435363738393f21"
),
fromHex("00000000000000000000000036c6b90a49e17d4c1e1b0e634ec74124d9b207da")
},
{
fromHex("6162636465666768696a6b6c6d6e6f707172737475767778797a414243444546"),
fromHex("000000000000000000000000ac5ab22e07b0fb80c69b6207902f725e2507e546")
}
};
return precompileGeneric(_message, inputOutput);
}
evmc::result EVMHost::precompileIdentity(evmc_message const& _message) noexcept
{
// static data so that we do not need a release routine...
bytes static data;
data = bytes(_message.input_data, _message.input_data + _message.input_size);
evmc::result result({});
result.gas_left = _message.gas;
result.output_data = data.data();
result.output_size = data.size();
return result;
}
evmc::result EVMHost::precompileModExp(evmc_message const&) noexcept
{
// TODO implement
evmc::result result({});
result.status_code = EVMC_FAILURE;
return result;
}
evmc::result EVMHost::precompileALTBN128G1Add(evmc_message const& _message) noexcept
{
// NOTE this is a partial implementation for some inputs.
static map<bytes, bytes> const inputOutput{
{
fromHex(
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
"1385281136ff5b2c326807ff0a824b6ca4f21fcc7c8764e9801bc4ad497d5012"
"02254594be8473dcf018a2aa66ea301e38fc865823acf75a9901721d1fc6bf4c"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"1385281136ff5b2c326807ff0a824b6ca4f21fcc7c8764e9801bc4ad497d5012"
"02254594be8473dcf018a2aa66ea301e38fc865823acf75a9901721d1fc6bf4c"
)
},
{
fromHex(
"0000000000000000000000000000000000000000000000000000000000000001"
"0000000000000000000000000000000000000000000000000000000000000002"
"0000000000000000000000000000000000000000000000000000000000000001"
"0000000000000000000000000000000000000000000000000000000000000002"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd3"
"15ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4"
)
},
{
fromHex(
"0000000000000000000000000000000000000000000000000000000000000001"
"0000000000000000000000000000000000000000000000000000000000000002"
"0000000000000000000000000000000000000000000000000000000000000001"
"30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd45"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
)
},
{
fromHex(
"10b4876441e14a6be92a7fe66550848c01c676a12ac31d7cc13b21f49c4307c8"
"09f5528bdb0ef9354837a0f4b4c9da973bd5b805d359976f719ab0b74e0a7368"
"28d3c57516712e7843a5b3cfa7d7274a037943f5bd57c227620ad207728e4283"
"2795fa9df21d4b8b329a45bae120f1fd9df9049ecacaa9dd1eca18bc6a55cd2f"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"16aed5ed486df6b2fb38015ded41400009ed4f34bef65b87b1f90f47052f8d94"
"16dabf21b3f25b9665269d98dc17b1da6118251dc0b403ae50e96dfe91239375"
)
},
{
fromHex(
"1385281136ff5b2c326807ff0a824b6ca4f21fcc7c8764e9801bc4ad497d5012"
"02254594be8473dcf018a2aa66ea301e38fc865823acf75a9901721d1fc6bf4c"
"1644e84fef7b7fdc98254f0654580173307a3bc44db990581e7ab55a22446dcf"
"28c2916b7e875692b195831945805438fcd30d2693d8a80cf8c88ec6ef4c315d"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"1e018816fc9bbd91313301ae9c254bb7d64d6cd54f3b49b92925e43e256b5faa"
"1d1f2259c715327bedb42c095af6c0267e4e1be836b4e04b3f0502552f93cca9"
)
},
{
fromHex(
"16aed5ed486df6b2fb38015ded41400009ed4f34bef65b87b1f90f47052f8d94"
"16dabf21b3f25b9665269d98dc17b1da6118251dc0b403ae50e96dfe91239375"
"25ff95a3abccf32adc6a4c3c8caddca67723d8ada802e9b9f612e3ddb40b2005"
"0d82b09bb4ec927bbf182bdc402790429322b7e2f285f2aad8ea135cbf7143d8"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"29d160febeef9770d47a32ee3b763850eb0594844fa57dd31b8ed02c78fdb797"
"2c7cdf62c2498486fd52646e577a06723ce97737b3c958262d78c4a413661e8a"
),
},
{
fromHex(
"18014701594179c6b9ccae848e3d15c1f76f8a68b8092578296520e46c9bae0c"
"1b5ed0e9e8f3ff35589ea81a45cf63887d4a92c099a3be1d97b26f0db96323dd"
"16a1d378d1a98cf5383cdc512011234287ca43b6a078d1842d5c58c5b1f475cc"
"1309377a7026d08ca1529eab74381a7e0d3a4b79d80bacec207cd52fc8e3769c"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"2583ed10e418133e44619c336f1be5ddae9e20d634a7683d9661401c750d7df4"
"0185fbba22de9e698262925665735dbc4d6e8288bc3fc39fae10ca58e16e77f7"
)
},
{
fromHex(
"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59"
"3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41"
"0f25929bcb43d5a57391564615c9e70a992b10eafa4db109709649cf48c50dd2"
"16da2f5cb6be7a0aa72c440c53c9bbdfec6c36c7d515536431b3a865468acbba"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"1496064626ba8bffeb7805f0d16143a65649bb0850333ea512c03fcdaf31e254"
"07b4f210ab542533f1ee5633ae4406cd16c63494b537ce3f1cf4afff6f76a48f"
),
},
{
fromHex(
"1e018816fc9bbd91313301ae9c254bb7d64d6cd54f3b49b92925e43e256b5faa"
"1d1f2259c715327bedb42c095af6c0267e4e1be836b4e04b3f0502552f93cca9"
"2364294faf6b89fedeede9986aa777c4f6c2f5c4a4559ee93dfec9b7b94ef80b"
"05aeae62655ea23865ae6661ae371a55c12098703d0f2301f4223e708c92efc6"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"2801b21090cbc48409e352647f3857134d373f81741f9d5e3d432f336d76f517"
"13cf106acf943c2a331de21c7d5e3351354e7412f2dba2918483a6593a6828d4"
)
},
{
fromHex(
"2583ed10e418133e44619c336f1be5ddae9e20d634a7683d9661401c750d7df4"
"0185fbba22de9e698262925665735dbc4d6e8288bc3fc39fae10ca58e16e77f7"
"258f1faa356e470cca19c928afa5ceed6215c756912af5725b8db5777cc8f3b6"
"175ced8a58d0c132c2b95ba14c16dde93e7f7789214116ff69da6f44daa966e6"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"10b4876441e14a6be92a7fe66550848c01c676a12ac31d7cc13b21f49c4307c8"
"09f5528bdb0ef9354837a0f4b4c9da973bd5b805d359976f719ab0b74e0a7368"
)
},
{
fromHex(
"26dcfbc2e0bc9d82efb4acd73cb3e99730e27e10177fcfb78b6399a4bfcdf391"
"27c440dbd5053253a3a692f9bf89b9b6e9612127cf97db1e11ffa9679acc933b"
"1496064626ba8bffeb7805f0d16143a65649bb0850333ea512c03fcdaf31e254"
"07b4f210ab542533f1ee5633ae4406cd16c63494b537ce3f1cf4afff6f76a48f"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"186bac5188a98c45e6016873d107f5cd131f3a3e339d0375e58bd6219347b008"
"1e396bc242de0214898b0f68035f53ad5a6f96c6c8390ac56ed6ec9561d23159"
)
},
{
fromHex(
"26dcfbc2e0bc9d82efb4acd73cb3e99730e27e10177fcfb78b6399a4bfcdf391"
"27c440dbd5053253a3a692f9bf89b9b6e9612127cf97db1e11ffa9679acc933b"
"1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59"
"3034dd2920f673e204fee2811c678745fc819b55d3e9d294e45c9b03a76aef41"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"20a754d2071d4d53903e3b31a7e98ad6882d58aec240ef981fdf0a9d22c5926a"
"29c853fcea789887315916bbeb89ca37edb355b4f980c9a12a94f30deeed3021"
)
},
{
fromHex(
"27231d5cdd0011259ff75678cf5a8f7840c22cb71d52b25e21e071205e8d9bc4"
"26dd3d225c9a71476db0cf834232eba84020f3073c6d20c519963e0b98f235e1"
"2174f0221490cd9c15b0387f3251ec3d49517a51c37a8076eac12afb4a95a707"
"1d1c3fcd3161e2a417b4df0955f02db1fffa9005210fb30c5aa3755307e9d1f5"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"18014701594179c6b9ccae848e3d15c1f76f8a68b8092578296520e46c9bae0c"
"1b5ed0e9e8f3ff35589ea81a45cf63887d4a92c099a3be1d97b26f0db96323dd"
),
},
{
fromHex(
"2801b21090cbc48409e352647f3857134d373f81741f9d5e3d432f336d76f517"
"13cf106acf943c2a331de21c7d5e3351354e7412f2dba2918483a6593a6828d4"
"2a49621e12910cd90f3e731083d454255bf1c533d6e15b8699156778d0f27f5d"
"2590ee31824548d159aa2d22296bf149d564c0872f41b89b7dc5c6e6e3cd1c4d"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"27231d5cdd0011259ff75678cf5a8f7840c22cb71d52b25e21e071205e8d9bc4"
"26dd3d225c9a71476db0cf834232eba84020f3073c6d20c519963e0b98f235e1"
)
},
{
fromHex(
"29d160febeef9770d47a32ee3b763850eb0594844fa57dd31b8ed02c78fdb797"
"2c7cdf62c2498486fd52646e577a06723ce97737b3c958262d78c4a413661e8a"
"0aee46a7ea6e80a3675026dfa84019deee2a2dedb1bbe11d7fe124cb3efb4b5a"
"044747b6e9176e13ede3a4dfd0d33ccca6321b9acd23bf3683a60adc0366ebaf"
"0000000000000000000000000000000000000000000000000000000000000000"
"0000000000000000000000000000000000000000000000000000000000000000"
),
fromHex(
"26dcfbc2e0bc9d82efb4acd73cb3e99730e27e10177fcfb78b6399a4bfcdf391"
"27c440dbd5053253a3a692f9bf89b9b6e9612127cf97db1e11ffa9679acc933b"
)
}
};
return precompileGeneric(_message, inputOutput);
}
evmc::result EVMHost::precompileALTBN128G1Mul(evmc_message const& _message) noexcept
{
// NOTE this is a partial implementation for some inputs.
static map<bytes, bytes> const inputOutput{
{
fromHex("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000"),
fromHex("030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4")
},
{
fromHex("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000"),
fromHex("17c139df0efee0f766bc0204762b774362e4ded88953a39ce849a8a7fa163fa901e0559bacb160664764a357af8a9fe70baa9258e0b959273ffc5718c6d4cc7c")
},
{
fromHex("09b54f111d3b2d1b2fe1ae9669b3db3d7bf93b70f00647e65c849275de6dc7fe18b2e77c63a3e400d6d1f1fbc6e1a1167bbca603d34d03edea231eb0ab7b14b4030f7b0c405c888aff922307ea2cd1c70f64664bab76899500341f4260a209290000000000000000000000000000000000000000000000000000000000000000"),
fromHex("16a1d378d1a98cf5383cdc512011234287ca43b6a078d1842d5c58c5b1f475cc1309377a7026d08ca1529eab74381a7e0d3a4b79d80bacec207cd52fc8e3769c")
},
{
fromHex("0a6de0e2240aa253f46ce0da883b61976e3588146e01c9d8976548c145fe6e4a04fbaa3a4aed4bb77f30ebb07a3ec1c7d77a7f2edd75636babfeff97b1ea686e1551dcd4965285ef049512d2d30cbfc1a91acd5baad4a6e19e22e93176197f170000000000000000000000000000000000000000000000000000000000000000"),
fromHex("28d3c57516712e7843a5b3cfa7d7274a037943f5bd57c227620ad207728e42832795fa9df21d4b8b329a45bae120f1fd9df9049ecacaa9dd1eca18bc6a55cd2f")
},
{
fromHex("0c54b42137b67cc268cbb53ac62b00ecead23984092b494a88befe58445a244a18e3723d37fae9262d58b548a0575f59d9c3266db7afb4d5739555837f6b8b3e0c692b41f1acc961f6ea83bae2c3a1a55c54f766c63ba76989f52c149c17b5e70000000000000000000000000000000000000000000000000000000000000000"),
fromHex("258f1faa356e470cca19c928afa5ceed6215c756912af5725b8db5777cc8f3b6175ced8a58d0c132c2b95ba14c16dde93e7f7789214116ff69da6f44daa966e6")
},
{
fromHex("0f103f14a584d4203c27c26155b2c955f8dfa816980b24ba824e1972d6486a5d0c4165133b9f5be17c804203af781bcf168da7386620479f9b885ecbcd27b17b0ea71d0abb524cac7cfff5323e1d0b14ab705842426c978f96753ccce258ed930000000000000000000000000000000000000000000000000000000000000000"),
fromHex("2a49621e12910cd90f3e731083d454255bf1c533d6e15b8699156778d0f27f5d2590ee31824548d159aa2d22296bf149d564c0872f41b89b7dc5c6e6e3cd1c4d")
},
{
fromHex("111e2e2a5f8828f80ddad08f9f74db56dac1cc16c1cb278036f79a84cf7a116f1d7d62e192b219b9808faa906c5ced871788f6339e8d91b83ac1343e20a16b3000000000000000000000000000000000000000e40800000000000000008cdcbc0000000000000000000000000000000000000000000000000000000000000000"),
fromHex("25ff95a3abccf32adc6a4c3c8caddca67723d8ada802e9b9f612e3ddb40b20050d82b09bb4ec927bbf182bdc402790429322b7e2f285f2aad8ea135cbf7143d8")
},
{
fromHex("17d5d09b4146424bff7e6fb01487c477bbfcd0cdbbc92d5d6457aae0b6717cc502b5636903efbf46db9235bbe74045d21c138897fda32e079040db1a16c1a7a11887420878c0c8e37605291c626585eabbec8d8b97a848fe8d58a37b004583510000000000000000000000000000000000000000000000000000000000000000"),
fromHex("2364294faf6b89fedeede9986aa777c4f6c2f5c4a4559ee93dfec9b7b94ef80b05aeae62655ea23865ae6661ae371a55c12098703d0f2301f4223e708c92efc6")
},
{
fromHex("1c36e713d4d54e3a9644dffca1fc524be4868f66572516025a61ca542539d43f042dcc4525b82dfb242b09cb21909d5c22643dcdbe98c4d082cc2877e96b24db016086cc934d5cab679c6991a4efcedbab26d7e4fb23b6a1ad4e6b5c2fb59ce50000000000000000000000000000000000000000000000000000000000000000"),
fromHex("1644e84fef7b7fdc98254f0654580173307a3bc44db990581e7ab55a22446dcf28c2916b7e875692b195831945805438fcd30d2693d8a80cf8c88ec6ef4c315d")
},
{
fromHex("1e39e9f0f91fa7ff8047ffd90de08785777fe61c0e3434e728fce4cf35047ddc2e0b64d75ebfa86d7f8f8e08abbe2e7ae6e0a1c0b34d028f19fa56e9450527cb1eec35a0e955cad4bee5846ae0f1d0b742d8636b278450c534e38e06a60509f90000000000000000000000000000000000000000000000000000000000000000"),
fromHex("1385281136ff5b2c326807ff0a824b6ca4f21fcc7c8764e9801bc4ad497d501202254594be8473dcf018a2aa66ea301e38fc865823acf75a9901721d1fc6bf4c")
},
{
fromHex("232063b584fb76c8d07995bee3a38fa7565405f3549c6a918ddaa90ab971e7f82ac9b135a81d96425c92d02296322ad56ffb16299633233e4880f95aafa7fda70689c3dc4311426ee11707866b2cbdf9751dacd07245bf99d2113d3f5a8cac470000000000000000000000000000000000000000000000000000000000000000"),
fromHex("2174f0221490cd9c15b0387f3251ec3d49517a51c37a8076eac12afb4a95a7071d1c3fcd3161e2a417b4df0955f02db1fffa9005210fb30c5aa3755307e9d1f5")
}
};
return precompileGeneric(_message, inputOutput);
}
evmc::result EVMHost::precompileALTBN128PairingProduct(evmc_message const& _message) noexcept
{
// This is a partial implementation - it always returns "success"
bytes static data = fromHex("0000000000000000000000000000000000000000000000000000000000000001");
return resultWithGas(_message, data);
}
evmc::result EVMHost::precompileGeneric(
evmc_message const& _message,
map<bytes, bytes> const& _inOut) noexcept
{
bytes input(_message.input_data, _message.input_data + _message.input_size);
if (_inOut.count(input))
return resultWithGas(_message, _inOut.at(input));
else
{
evmc::result result({});
result.status_code = EVMC_FAILURE;
return result;
}
}
evmc::result EVMHost::resultWithGas(
evmc_message const& _message,
bytes const& _data
) noexcept
{
evmc::result result({});
result.status_code = EVMC_SUCCESS;
result.gas_left = _message.gas;
result.output_data = _data.data();
result.output_size = _data.size();
return result;
}

View File

@ -38,7 +38,12 @@ using Address = h160;
class EVMHost: public evmc::Host class EVMHost: public evmc::Host
{ {
public: public:
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::vm& _vmInstance); /// Tries to dynamically load libevmone. @returns nullptr on failure.
/// The path has to be provided for the first successful run and will be ignored
/// afterwards.
static evmc::vm* getVM(std::string const& _path = {});
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm = getVM());
struct Account struct Account
{ {
@ -66,6 +71,10 @@ public:
Account* account(evmc_address const& _address) Account* account(evmc_address const& _address)
{ {
// Make all precompiled contracts exist.
// Be future-proof and consider everything below 1024 as precompiled contract.
if (u160(convertFromEVMC(_address)) < 1024)
m_state.accounts[_address];
auto it = m_state.accounts.find(_address); auto it = m_state.accounts.find(_address);
return it == m_state.accounts.end() ? nullptr : &it->second; return it == m_state.accounts.end() ? nullptr : &it->second;
} }
@ -147,11 +156,6 @@ public:
size_t _topicsCount size_t _topicsCount
) noexcept; ) noexcept;
evmc_revision getRevision()
{
return m_evmVersion;
}
static Address convertFromEVMC(evmc_address const& _addr); static Address convertFromEVMC(evmc_address const& _addr);
static evmc_address convertToEVMC(Address const& _addr); static evmc_address convertToEVMC(Address const& _addr);
static h256 convertFromEVMC(evmc_bytes32 const& _data); static h256 convertFromEVMC(evmc_bytes32 const& _data);
@ -163,9 +167,20 @@ public:
evmc_address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878")); evmc_address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878"));
private: private:
evmc::result precompileECRecover(evmc_message const& _message) noexcept;
evmc::result precompileSha256(evmc_message const& _message) noexcept; evmc::result precompileSha256(evmc_message const& _message) noexcept;
evmc::result precompileRipeMD160(evmc_message const& _message) noexcept;
evmc::result precompileIdentity(evmc_message const& _message) noexcept;
evmc::result precompileModExp(evmc_message const& _message) noexcept;
evmc::result precompileALTBN128G1Add(evmc_message const& _message) noexcept;
evmc::result precompileALTBN128G1Mul(evmc_message const& _message) noexcept;
evmc::result precompileALTBN128PairingProduct(evmc_message const& _message) noexcept;
evmc::result precompileGeneric(evmc_message const& _message, std::map<bytes, bytes> const& _inOut) noexcept;
/// @returns a result object with no gas usage and result data taken from @a _data.
/// @note The return value is only valid as long as @a _data is alive!
static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept;
evmc::vm& m_vm; evmc::vm* m_vm = nullptr;
evmc_revision m_evmVersion; evmc_revision m_evmVersion;
}; };

View File

@ -22,6 +22,12 @@
#include <test/ExecutionFramework.h> #include <test/ExecutionFramework.h>
#include <test/EVMHost.h>
#include <test/evmc/evmc.hpp>
#include <test/evmc/loader.h>
#include <test/evmc/helpers.hpp>
#include <libdevcore/CommonIO.h> #include <libdevcore/CommonIO.h>
#include <boost/test/framework.hpp> #include <boost/test/framework.hpp>
@ -29,46 +35,31 @@
#include <cstdlib> #include <cstdlib>
#include <chrono>
#include <thread>
using namespace std; using namespace std;
using namespace dev; using namespace dev;
using namespace dev::test; using namespace dev::test;
namespace // anonymous
{
h256 const EmptyTrie("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421");
string getIPCSocketPath()
{
string ipcPath = dev::test::Options::get().ipcPath.string();
if (ipcPath.empty())
BOOST_FAIL("ERROR: ipcPath not set! (use --ipcpath <path> or the environment variable ETH_TEST_IPC)");
return ipcPath;
}
}
ExecutionFramework::ExecutionFramework(): ExecutionFramework::ExecutionFramework():
ExecutionFramework(getIPCSocketPath(), dev::test::Options::get().evmVersion()) ExecutionFramework(dev::test::Options::get().evmVersion())
{ {
} }
ExecutionFramework::ExecutionFramework(string const& _ipcPath, langutil::EVMVersion _evmVersion): ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion):
m_rpc(RPCSession::instance(_ipcPath)),
m_evmVersion(_evmVersion), m_evmVersion(_evmVersion),
m_optimiserSettings(solidity::OptimiserSettings::minimal()), m_optimiserSettings(solidity::OptimiserSettings::minimal()),
m_showMessages(dev::test::Options::get().showMessages), m_showMessages(dev::test::Options::get().showMessages),
m_sender(m_rpc.account(0)) m_evmHost(make_shared<EVMHost>(m_evmVersion))
{ {
if (dev::test::Options::get().optimizeYul) if (dev::test::Options::get().optimizeYul)
m_optimiserSettings = solidity::OptimiserSettings::full(); m_optimiserSettings = solidity::OptimiserSettings::full();
else if (dev::test::Options::get().optimize) else if (dev::test::Options::get().optimize)
m_optimiserSettings = solidity::OptimiserSettings::standard(); m_optimiserSettings = solidity::OptimiserSettings::standard();
m_rpc.test_rewindToBlock(0); m_evmHost->reset();
for (size_t i = 0; i < 10; i++)
m_evmHost->m_state.accounts[EVMHost::convertToEVMC(account(i))].balance =
EVMHost::convertToEVMC(u256(1) << 100);
} }
std::pair<bool, string> ExecutionFramework::compareAndCreateMessage( std::pair<bool, string> ExecutionFramework::compareAndCreateMessage(
@ -99,22 +90,28 @@ std::pair<bool, string> ExecutionFramework::compareAndCreateMessage(
u256 ExecutionFramework::gasLimit() const u256 ExecutionFramework::gasLimit() const
{ {
auto latestBlock = m_rpc.eth_getBlockByNumber("latest", false); return {m_evmHost->get_tx_context().block_gas_limit};
return u256(latestBlock["gasLimit"].asString());
} }
u256 ExecutionFramework::gasPrice() const u256 ExecutionFramework::gasPrice() const
{ {
return u256(m_rpc.eth_gasPrice()); return {EVMHost::convertFromEVMC(m_evmHost->get_tx_context().tx_gas_price)};
} }
u256 ExecutionFramework::blockHash(u256 const& _blockNumber) const u256 ExecutionFramework::blockHash(u256 const& _number) const
{ {
return u256(m_rpc.eth_getBlockByNumber(toHex(_blockNumber, HexPrefix::Add), false)["hash"].asString()); return {EVMHost::convertFromEVMC(m_evmHost->get_block_hash(uint64_t(_number & numeric_limits<uint64_t>::max())))};
}
u256 ExecutionFramework::blockNumber() const
{
return m_evmHost->m_state.blockNumber;
} }
void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 const& _value) void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 const& _value)
{ {
m_evmHost->newBlock();
if (m_showMessages) if (m_showMessages)
{ {
if (_isCreation) if (_isCreation)
@ -125,104 +122,121 @@ void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256
cout << " value: " << _value << endl; cout << " value: " << _value << endl;
cout << " in: " << toHex(_data) << endl; cout << " in: " << toHex(_data) << endl;
} }
RPCSession::TransactionData d; evmc_message message = {};
d.data = "0x" + toHex(_data); message.input_data = _data.data();
d.from = "0x" + toString(m_sender); message.input_size = _data.size();
d.gas = toHex(m_gas, HexPrefix::Add); message.sender = EVMHost::convertToEVMC(m_sender);
d.gasPrice = toHex(m_gasPrice, HexPrefix::Add); message.value = EVMHost::convertToEVMC(_value);
d.value = toHex(_value, HexPrefix::Add);
if (!_isCreation)
{
d.to = dev::toString(m_contractAddress);
BOOST_REQUIRE(m_rpc.eth_getCode(d.to, "pending").size() > 2);
// Use eth_call to get the output
m_output = fromHex(m_rpc.eth_call(d, "pending"), WhenError::Throw);
}
string txHash = m_rpc.eth_sendTransaction(d);
m_rpc.rpcCall("eth_flush");
m_rpc.test_mineBlocks(1);
RPCSession::TransactionReceipt receipt(m_rpc.eth_getTransactionReceipt(txHash));
m_blockNumber = u256(receipt.blockNumber);
if (_isCreation) if (_isCreation)
{ {
m_contractAddress = Address(receipt.contractAddress); message.kind = EVMC_CREATE;
BOOST_REQUIRE(m_contractAddress); message.destination = EVMHost::convertToEVMC(Address{});
string code = m_rpc.eth_getCode(receipt.contractAddress, "latest");
m_output = fromHex(code, WhenError::Throw);
} }
else
{
message.kind = EVMC_CALL;
message.destination = EVMHost::convertToEVMC(m_contractAddress);
}
message.gas = m_gas.convert_to<int64_t>();
evmc::result result = m_evmHost->call(message);
m_output = bytes(result.output_data, result.output_data + result.output_size);
if (_isCreation)
m_contractAddress = EVMHost::convertFromEVMC(result.create_address);
m_gasUsed = m_gas - result.gas_left;
m_transactionSuccessful = (result.status_code == EVMC_SUCCESS);
if (m_showMessages) if (m_showMessages)
{ {
cout << " out: " << toHex(m_output) << endl; cout << " out: " << toHex(m_output) << endl;
cout << " tx hash: " << txHash << endl; cout << " result: " << size_t(result.status_code) << endl;
cout << " gas used: " << m_gasUsed.str() << endl;
}
} }
m_gasUsed = u256(receipt.gasUsed); void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount)
m_logs.clear();
for (auto const& log: receipt.logEntries)
{ {
LogEntry entry; m_evmHost->newBlock();
entry.address = Address(log.address);
for (auto const& topic: log.topics)
entry.topics.push_back(h256(topic));
entry.data = fromHex(log.data, WhenError::Throw);
m_logs.push_back(entry);
}
if (!receipt.status.empty()) if (m_showMessages)
m_transactionSuccessful = (receipt.status == "1");
else
m_transactionSuccessful = (m_gas != m_gasUsed);
}
void ExecutionFramework::sendEther(Address const& _to, u256 const& _value)
{ {
RPCSession::TransactionData d; cout << "SEND_ETHER " << m_sender.hex() << " -> " << _addr.hex() << ":" << endl;
d.data = "0x"; if (_amount > 0)
d.from = "0x" + toString(m_sender); cout << " value: " << _amount << endl;
d.gas = toHex(m_gas, HexPrefix::Add); }
d.gasPrice = toHex(m_gasPrice, HexPrefix::Add); evmc_message message = {};
d.value = toHex(_value, HexPrefix::Add); message.sender = EVMHost::convertToEVMC(m_sender);
d.to = dev::toString(_to); message.value = EVMHost::convertToEVMC(_amount);
message.kind = EVMC_CALL;
message.destination = EVMHost::convertToEVMC(_addr);
message.gas = m_gas.convert_to<int64_t>();
string txHash = m_rpc.eth_sendTransaction(d); m_evmHost->call(message);
m_rpc.test_mineBlocks(1);
} }
size_t ExecutionFramework::currentTimestamp() size_t ExecutionFramework::currentTimestamp()
{ {
auto latestBlock = m_rpc.eth_getBlockByNumber("latest", false); return m_evmHost->get_tx_context().block_timestamp;
return size_t(u256(latestBlock.get("timestamp", "invalid").asString()));
} }
size_t ExecutionFramework::blockTimestamp(u256 _number) size_t ExecutionFramework::blockTimestamp(u256 _block)
{ {
auto latestBlock = m_rpc.eth_getBlockByNumber(toString(_number), false); if (_block > blockNumber())
return size_t(u256(latestBlock.get("timestamp", "invalid").asString())); return 0;
else
return size_t((currentTimestamp() / blockNumber()) * _block);
} }
Address ExecutionFramework::account(size_t _i) Address ExecutionFramework::account(size_t _idx)
{ {
return Address(m_rpc.accountCreateIfNotExists(_i)); return Address(h256(u256{"0x1212121212121212121212121212120000000012"} + _idx * 0x1000), Address::AlignRight);
} }
bool ExecutionFramework::addressHasCode(Address const& _addr) bool ExecutionFramework::addressHasCode(Address const& _addr)
{ {
string code = m_rpc.eth_getCode(toString(_addr), "latest"); return m_evmHost->get_code_size(EVMHost::convertToEVMC(_addr)) != 0;
return !code.empty() && code != "0x"; }
size_t ExecutionFramework::numLogs() const
{
return m_evmHost->m_state.logs.size();
}
size_t ExecutionFramework::numLogTopics(size_t _logIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).topics.size();
}
h256 ExecutionFramework::logTopic(size_t _logIdx, size_t _topicIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).topics.at(_topicIdx);
}
Address ExecutionFramework::logAddress(size_t _logIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).address;
}
bytes const& ExecutionFramework::logData(size_t _logIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).data;
} }
u256 ExecutionFramework::balanceAt(Address const& _addr) u256 ExecutionFramework::balanceAt(Address const& _addr)
{ {
return u256(m_rpc.eth_getBalance(toString(_addr), "latest")); return u256(EVMHost::convertFromEVMC(m_evmHost->get_balance(EVMHost::convertToEVMC(_addr))));
} }
bool ExecutionFramework::storageEmpty(Address const& _addr) bool ExecutionFramework::storageEmpty(Address const& _addr)
{ {
h256 root(m_rpc.eth_getStorageRoot(toString(_addr), "latest")); if (EVMHost::Account const* acc = m_evmHost->account(EVMHost::convertToEVMC(_addr)))
BOOST_CHECK(root); {
return root == EmptyTrie; for (auto const& entry: acc->storage)
if (!(entry.second == evmc_bytes32{}))
return false;
}
return true;
} }

View File

@ -23,7 +23,6 @@
#pragma once #pragma once
#include <test/Options.h> #include <test/Options.h>
#include <test/RPCSession.h>
#include <libsolidity/interface/OptimiserSettings.h> #include <libsolidity/interface/OptimiserSettings.h>
@ -38,6 +37,8 @@ namespace dev
{ {
namespace test namespace test
{ {
class EVMHost;
using rational = boost::rational<dev::bigint>; using rational = boost::rational<dev::bigint>;
/// An Ethereum address: 20 bytes. /// An Ethereum address: 20 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes. /// @NOTE This is not endian-specific; it's just a bunch of bytes.
@ -55,7 +56,7 @@ class ExecutionFramework
public: public:
ExecutionFramework(); ExecutionFramework();
explicit ExecutionFramework(std::string const& _ipcPath, langutil::EVMVersion _evmVersion); explicit ExecutionFramework(langutil::EVMVersion _evmVersion);
virtual ~ExecutionFramework() = default; virtual ~ExecutionFramework() = default;
virtual bytes const& compileAndRunWithoutCheck( virtual bytes const& compileAndRunWithoutCheck(
@ -200,9 +201,7 @@ public:
u256 gasLimit() const; u256 gasLimit() const;
u256 gasPrice() const; u256 gasPrice() const;
u256 blockHash(u256 const& _blockNumber) const; u256 blockHash(u256 const& _blockNumber) const;
u256 const& blockNumber() const { u256 blockNumber() const;
return m_blockNumber;
}
template<typename Range> template<typename Range>
static bytes encodeArray(bool _dynamicallySized, bool _dynamicallyEncoded, Range const& _elements) static bytes encodeArray(bool _dynamicallySized, bool _dynamicallyEncoded, Range const& _elements)
@ -257,26 +256,23 @@ protected:
bool storageEmpty(Address const& _addr); bool storageEmpty(Address const& _addr);
bool addressHasCode(Address const& _addr); bool addressHasCode(Address const& _addr);
RPCSession& m_rpc; size_t numLogs() const;
size_t numLogTopics(size_t _logIdx) const;
struct LogEntry h256 logTopic(size_t _logIdx, size_t _topicIdx) const;
{ Address logAddress(size_t _logIdx) const;
Address address; bytes const& logData(size_t _logIdx) const;
std::vector<h256> topics;
bytes data;
};
langutil::EVMVersion m_evmVersion; langutil::EVMVersion m_evmVersion;
solidity::OptimiserSettings m_optimiserSettings = solidity::OptimiserSettings::minimal(); solidity::OptimiserSettings m_optimiserSettings = solidity::OptimiserSettings::minimal();
bool m_showMessages = false; bool m_showMessages = false;
std::shared_ptr<EVMHost> m_evmHost;
bool m_transactionSuccessful = true; bool m_transactionSuccessful = true;
Address m_sender; Address m_sender = account(0);
Address m_contractAddress; Address m_contractAddress;
u256 m_blockNumber;
u256 const m_gasPrice = 100 * szabo; u256 const m_gasPrice = 100 * szabo;
u256 const m_gas = 100000000; u256 const m_gas = 100000000;
bytes m_output; bytes m_output;
std::vector<LogEntry> m_logs;
u256 m_gasUsed; u256 m_gasUsed;
}; };

View File

@ -44,7 +44,7 @@ struct Testsuite
boost::filesystem::path const path; boost::filesystem::path const path;
boost::filesystem::path const subpath; boost::filesystem::path const subpath;
bool smt; bool smt;
bool ipc; bool needsVM;
TestCase::TestCaseCreator testCaseCreator; TestCase::TestCaseCreator testCaseCreator;
}; };
@ -52,7 +52,7 @@ struct Testsuite
/// Array of testsuits that can be run interactively as well as automatically /// Array of testsuits that can be run interactively as well as automatically
Testsuite const g_interactiveTestsuites[] = { Testsuite const g_interactiveTestsuites[] = {
/* /*
Title Path Subpath SMT IPC Creator function */ Title Path Subpath SMT NeedsVM Creator function */
{"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create}, {"Yul Optimizer", "libyul", "yulOptimizerTests", false, false, &yul::test::YulOptimizerTest::create},
{"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create}, {"Yul Interpreter", "libyul", "yulInterpreterTests", false, false, &yul::test::YulInterpreterTest::create},
{"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create}, {"Yul Object Compiler", "libyul", "objectCompiler", false, false, &yul::test::ObjectCompilerTest::create},

View File

@ -1,396 +0,0 @@
/*
This file is part of solidity.
solidity 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.
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
The Implementation originally from https://msdn.microsoft.com/en-us/library/windows/desktop/aa365592(v=vs.85).aspx
*/
/// @file RPCSession.cpp
/// Low-level IPC communication between the test framework and the Ethereum node.
#include <test/RPCSession.h>
#include <test/Options.h>
#include <liblangutil/EVMVersion.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/JSON.h>
#include <string>
#include <stdio.h>
#include <thread>
#include <chrono>
using namespace std;
using namespace dev;
IPCSocket::IPCSocket(string const& _path): m_path(_path)
{
#if defined(_WIN32)
m_socket = CreateFile(
m_path.c_str(), // pipe name
GENERIC_READ | // read and write access
GENERIC_WRITE,
0, // no sharing
NULL, // default security attribute
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (m_socket == INVALID_HANDLE_VALUE)
BOOST_FAIL("Error creating IPC socket object!");
#else
if (_path.length() >= sizeof(sockaddr_un::sun_path))
BOOST_FAIL("Error opening IPC: socket path is too long!");
struct sockaddr_un saun;
memset(&saun, 0, sizeof(sockaddr_un));
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, _path.c_str());
// http://idletechnology.blogspot.ca/2011/12/unix-domain-sockets-on-osx.html
//
// SUN_LEN() might be optimal, but it seemingly affects the portability,
// with at least Android missing this macro. Just using the sizeof() for
// structure seemingly works, and would only have the side-effect of
// sending larger-than-required packets over the socket. Given that this
// code is only used for unit-tests, that approach seems simpler.
#if defined(__APPLE__)
saun.sun_len = sizeof(struct sockaddr_un);
#endif // defined(__APPLE__)
if ((m_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
BOOST_FAIL("Error creating IPC socket object");
if (connect(m_socket, reinterpret_cast<struct sockaddr const*>(&saun), sizeof(struct sockaddr_un)) < 0)
{
close(m_socket);
BOOST_FAIL("Error connecting to IPC socket: " << _path);
}
#endif
}
string IPCSocket::sendRequest(string const& _req)
{
#if defined(_WIN32)
// Write to the pipe.
DWORD cbWritten;
BOOL fSuccess = WriteFile(
m_socket, // pipe handle
_req.c_str(), // message
_req.size(), // message length
&cbWritten, // bytes written
NULL); // not overlapped
if (!fSuccess || (_req.size() != cbWritten))
BOOST_FAIL("WriteFile to pipe failed");
// Read from the pipe.
DWORD cbRead;
fSuccess = ReadFile(
m_socket, // pipe handle
m_readBuf, // buffer to receive reply
sizeof(m_readBuf), // size of buffer
&cbRead, // number of bytes read
NULL); // not overlapped
if (!fSuccess)
BOOST_FAIL("ReadFile from pipe failed");
return string(m_readBuf, m_readBuf + cbRead);
#else
if (send(m_socket, _req.c_str(), _req.length(), 0) != (ssize_t)_req.length())
BOOST_FAIL("Writing on IPC failed.");
auto start = chrono::steady_clock::now();
ssize_t ret;
do
{
ret = recv(m_socket, m_readBuf, sizeof(m_readBuf), 0);
// Also consider closed socket an error.
if (ret < 0)
BOOST_FAIL("Reading on IPC failed.");
}
while (
ret == 0 &&
chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - start).count() < m_readTimeOutMS
);
if (ret == 0)
BOOST_FAIL("Timeout reading on IPC.");
return string(m_readBuf, m_readBuf + ret);
#endif
}
RPCSession& RPCSession::instance(string const& _path)
{
try
{
static RPCSession session(_path);
BOOST_REQUIRE_EQUAL(session.m_ipcSocket.path(), _path);
return session;
}
catch (std::exception const&)
{
BOOST_THROW_EXCEPTION(std::runtime_error("Error creating RPC session for socket: " + _path));
}
}
string RPCSession::eth_getCode(string const& _address, string const& _blockNumber)
{
return rpcCall("eth_getCode", { quote(_address), quote(_blockNumber) }).asString();
}
Json::Value RPCSession::eth_getBlockByNumber(string const& _blockNumber, bool _fullObjects)
{
// NOTE: to_string() converts bool to 0 or 1
return rpcCall("eth_getBlockByNumber", { quote(_blockNumber), _fullObjects ? "true" : "false" });
}
RPCSession::TransactionReceipt RPCSession::eth_getTransactionReceipt(string const& _transactionHash)
{
TransactionReceipt receipt;
Json::Value const result = rpcCall("eth_getTransactionReceipt", { quote(_transactionHash) });
receipt.gasUsed = result["gasUsed"].asString();
receipt.contractAddress = result["contractAddress"].asString();
receipt.blockNumber = result["blockNumber"].asString();
if (m_receiptHasStatusField)
{
BOOST_REQUIRE(!result["status"].isNull());
receipt.status = result["status"].asString();
}
for (auto const& log: result["logs"])
{
LogEntry entry;
entry.address = log["address"].asString();
entry.data = log["data"].asString();
for (auto const& topic: log["topics"])
entry.topics.push_back(topic.asString());
receipt.logEntries.push_back(entry);
}
return receipt;
}
string RPCSession::eth_sendTransaction(TransactionData const& _td)
{
return rpcCall("eth_sendTransaction", { _td.toJson() }).asString();
}
string RPCSession::eth_call(TransactionData const& _td, string const& _blockNumber)
{
return rpcCall("eth_call", { _td.toJson(), quote(_blockNumber) }).asString();
}
string RPCSession::eth_sendTransaction(string const& _transaction)
{
return rpcCall("eth_sendTransaction", { _transaction }).asString();
}
string RPCSession::eth_getBalance(string const& _address, string const& _blockNumber)
{
string address = (_address.length() == 20) ? "0x" + _address : _address;
return rpcCall("eth_getBalance", { quote(address), quote(_blockNumber) }).asString();
}
string RPCSession::eth_getStorageRoot(string const& _address, string const& _blockNumber)
{
string address = (_address.length() == 20) ? "0x" + _address : _address;
return rpcCall("eth_getStorageRoot", { quote(address), quote(_blockNumber) }).asString();
}
string RPCSession::eth_gasPrice()
{
return rpcCall("eth_gasPrice").asString();
}
void RPCSession::personal_unlockAccount(string const& _address, string const& _password, int _duration)
{
BOOST_REQUIRE_MESSAGE(
rpcCall("personal_unlockAccount", { quote(_address), quote(_password), to_string(_duration) }),
"Error unlocking account " + _address
);
}
string RPCSession::personal_newAccount(string const& _password)
{
string addr = rpcCall("personal_newAccount", { quote(_password) }).asString();
BOOST_TEST_MESSAGE("Created account " + addr);
return addr;
}
void RPCSession::test_setChainParams(vector<string> const& _accounts)
{
string forks;
if (test::Options::get().evmVersion() >= langutil::EVMVersion::tangerineWhistle())
forks += "\"EIP150ForkBlock\": \"0x00\",\n";
if (test::Options::get().evmVersion() >= langutil::EVMVersion::spuriousDragon())
forks += "\"EIP158ForkBlock\": \"0x00\",\n";
if (test::Options::get().evmVersion() >= langutil::EVMVersion::byzantium())
{
forks += "\"byzantiumForkBlock\": \"0x00\",\n";
m_receiptHasStatusField = true;
}
if (test::Options::get().evmVersion() >= langutil::EVMVersion::constantinople())
forks += "\"constantinopleForkBlock\": \"0x00\",\n";
if (test::Options::get().evmVersion() >= langutil::EVMVersion::petersburg())
forks += "\"constantinopleFixForkBlock\": \"0x00\",\n";
static string const c_configString = R"(
{
"sealEngine": "NoProof",
"params": {
"accountStartNonce": "0x00",
"maximumExtraDataSize": "0x1000000",
"blockReward": "0x",
"allowFutureBlocks": true,
)" + forks + R"(
"homesteadForkBlock": "0x00"
},
"genesis": {
"author": "0000000000000010000000000000000000000000",
"timestamp": "0x00",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x",
"gasLimit": "0x1000000000000",
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"nonce": "0x0000000000000042",
"difficulty": "131072"
},
"accounts": {
"0000000000000000000000000000000000000001": { "wei": "1", "precompiled": { "name": "ecrecover", "linear": { "base": 3000, "word": 0 } } },
"0000000000000000000000000000000000000002": { "wei": "1", "precompiled": { "name": "sha256", "linear": { "base": 60, "word": 12 } } },
"0000000000000000000000000000000000000003": { "wei": "1", "precompiled": { "name": "ripemd160", "linear": { "base": 600, "word": 120 } } },
"0000000000000000000000000000000000000004": { "wei": "1", "precompiled": { "name": "identity", "linear": { "base": 15, "word": 3 } } },
"0000000000000000000000000000000000000005": { "wei": "1", "precompiled": { "name": "modexp" } },
"0000000000000000000000000000000000000006": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_add", "linear": { "base": 500, "word": 0 } } },
"0000000000000000000000000000000000000007": { "wei": "1", "precompiled": { "name": "alt_bn128_G1_mul", "linear": { "base": 40000, "word": 0 } } },
"0000000000000000000000000000000000000008": { "wei": "1", "precompiled": { "name": "alt_bn128_pairing_product" } }
}
}
)";
Json::Value config;
BOOST_REQUIRE(jsonParseStrict(c_configString, config));
for (auto const& account: _accounts)
config["accounts"][account]["wei"] = "0x100000000000000000000000000000000000000000";
test_setChainParams(jsonCompactPrint(config));
}
void RPCSession::test_setChainParams(string const& _config)
{
BOOST_REQUIRE(rpcCall("test_setChainParams", { _config }) == true);
}
void RPCSession::test_rewindToBlock(size_t _blockNr)
{
BOOST_REQUIRE(rpcCall("test_rewindToBlock", { to_string(_blockNr) }) == true);
}
void RPCSession::test_mineBlocks(int _number)
{
u256 startBlock = fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString()));
BOOST_REQUIRE(rpcCall("test_mineBlocks", { to_string(_number) }, true) == true);
BOOST_REQUIRE(fromBigEndian<u256>(fromHex(rpcCall("eth_blockNumber").asString())) == startBlock + _number);
}
void RPCSession::test_modifyTimestamp(size_t _timestamp)
{
BOOST_REQUIRE(rpcCall("test_modifyTimestamp", { to_string(_timestamp) }) == true);
}
Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const& _args, bool _canFail)
{
string request = "{\"jsonrpc\":\"2.0\",\"method\":\"" + _methodName + "\",\"params\":[";
for (size_t i = 0; i < _args.size(); ++i)
{
request += _args[i];
if (i + 1 != _args.size())
request += ", ";
}
request += "],\"id\":" + to_string(m_rpcSequence) + "}";
++m_rpcSequence;
BOOST_TEST_MESSAGE("Request: " + request);
string reply = m_ipcSocket.sendRequest(request);
BOOST_TEST_MESSAGE("Reply: " + reply);
Json::Value result;
string errorMsg;
if (!jsonParseStrict(reply, result, &errorMsg))
BOOST_FAIL("Failed to parse JSON-RPC response: " + errorMsg);
if (!result.isMember("id") || !result["id"].isUInt())
BOOST_FAIL("Badly formatted JSON-RPC response (missing or non-integer \"id\")");
if (result["id"].asUInt() != (m_rpcSequence - 1))
BOOST_FAIL(
"Response identifier mismatch. "
"Expected " + to_string(m_rpcSequence - 1) + " but got " + to_string(result["id"].asUInt()) + "."
);
if (result.isMember("error"))
{
if (_canFail)
return Json::Value();
BOOST_FAIL("Error on JSON-RPC call: " + result["error"]["message"].asString());
}
if (!result.isMember("result") || result["result"].isNull())
BOOST_FAIL(
"Missing result for JSON-RPC call: " +
result.toStyledString() +
"\nRequest was " +
request
);
return result["result"];
}
string const& RPCSession::accountCreate()
{
m_accounts.push_back(personal_newAccount(""));
personal_unlockAccount(m_accounts.back(), "", 100000);
return m_accounts.back();
}
string const& RPCSession::accountCreateIfNotExists(size_t _id)
{
while ((_id + 1) > m_accounts.size())
accountCreate();
return m_accounts[_id];
}
RPCSession::RPCSession(string const& _path):
m_ipcSocket(_path)
{
accountCreate();
// This will pre-fund the accounts create prior.
test_setChainParams(m_accounts);
}
string RPCSession::TransactionData::toJson() const
{
Json::Value json;
json["from"] = (from.length() == 20) ? "0x" + from : from;
json["to"] = (to.length() == 20 || to == "") ? "0x" + to : to;
json["gas"] = gas;
json["gasprice"] = gasPrice;
json["value"] = value;
json["data"] = data;
return jsonCompactPrint(json);
}

View File

@ -1,146 +0,0 @@
/*
This file is part of solidity.
solidity 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.
solidity 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 solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file RPCSession.h
* @author Dimtiry Khokhlov <dimitry@ethdev.com>
* @date 2016
*/
#if defined(_WIN32)
#include <windows.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include <json/value.h>
#include <boost/noncopyable.hpp>
#include <boost/test/unit_test.hpp>
#include <string>
#include <stdio.h>
#include <map>
#if defined(_WIN32)
class IPCSocket : public boost::noncopyable
{
public:
explicit IPCSocket(std::string const& _path);
std::string sendRequest(std::string const& _req);
~IPCSocket() { CloseHandle(m_socket); }
std::string const& path() const { return m_path; }
private:
std::string m_path;
HANDLE m_socket;
TCHAR m_readBuf[512000];
};
#else
class IPCSocket: public boost::noncopyable
{
public:
explicit IPCSocket(std::string const& _path);
std::string sendRequest(std::string const& _req);
~IPCSocket() {
shutdown(m_socket, SHUT_RDWR);
close(m_socket);
}
std::string const& path() const { return m_path; }
private:
std::string m_path;
int m_socket;
/// Socket read timeout in milliseconds. Needs to be large because the key generation routine
/// might take long.
unsigned static constexpr m_readTimeOutMS = 300000;
char m_readBuf[512000];
};
#endif
class RPCSession: public boost::noncopyable
{
public:
struct TransactionData
{
std::string from;
std::string to;
std::string gas;
std::string gasPrice;
std::string value;
std::string data;
std::string toJson() const;
};
struct LogEntry {
std::string address;
std::vector<std::string> topics;
std::string data;
};
struct TransactionReceipt
{
std::string gasUsed;
std::string contractAddress;
std::vector<LogEntry> logEntries;
std::string blockNumber;
/// note: pre-byzantium the status field will be empty
std::string status;
};
static RPCSession& instance(std::string const& _path);
std::string eth_getCode(std::string const& _address, std::string const& _blockNumber);
Json::Value eth_getBlockByNumber(std::string const& _blockNumber, bool _fullObjects);
std::string eth_call(TransactionData const& _td, std::string const& _blockNumber);
TransactionReceipt eth_getTransactionReceipt(std::string const& _transactionHash);
std::string eth_sendTransaction(TransactionData const& _td);
std::string eth_sendTransaction(std::string const& _transaction);
std::string eth_getBalance(std::string const& _address, std::string const& _blockNumber);
std::string eth_getStorageRoot(std::string const& _address, std::string const& _blockNumber);
std::string eth_gasPrice();
std::string personal_newAccount(std::string const& _password);
void personal_unlockAccount(std::string const& _address, std::string const& _password, int _duration);
void test_setChainParams(std::vector<std::string> const& _accounts);
void test_setChainParams(std::string const& _config);
void test_rewindToBlock(size_t _blockNr);
void test_modifyTimestamp(size_t _timestamp);
void test_mineBlocks(int _number);
Json::Value rpcCall(std::string const& _methodName, std::vector<std::string> const& _args = std::vector<std::string>(), bool _canFail = false);
std::string const& account(size_t _id) const { return m_accounts.at(_id); }
std::string const& accountCreate();
std::string const& accountCreateIfNotExists(size_t _id);
private:
explicit RPCSession(std::string const& _path);
inline std::string quote(std::string const& _arg) { return "\"" + _arg + "\""; }
/// Parse std::string replacing keywords to values
void parseString(std::string& _string, std::map<std::string, std::string> const& _varMap);
IPCSocket m_ipcSocket;
size_t m_rpcSequence = 1;
bool m_receiptHasStatusField = false;
std::vector<std::string> m_accounts;
};

View File

@ -44,7 +44,6 @@ public:
struct Config struct Config
{ {
std::string filename; std::string filename;
std::string ipcPath;
langutil::EVMVersion evmVersion; langutil::EVMVersion evmVersion;
}; };

View File

@ -37,6 +37,7 @@
#include <test/InteractiveTests.h> #include <test/InteractiveTests.h>
#include <test/Options.h> #include <test/Options.h>
#include <test/EVMHost.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
@ -74,13 +75,12 @@ int registerTests(
boost::unit_test::test_suite& _suite, boost::unit_test::test_suite& _suite,
boost::filesystem::path const& _basepath, boost::filesystem::path const& _basepath,
boost::filesystem::path const& _path, boost::filesystem::path const& _path,
std::string const& _ipcPath,
TestCase::TestCaseCreator _testCaseCreator TestCase::TestCaseCreator _testCaseCreator
) )
{ {
int numTestsAdded = 0; int numTestsAdded = 0;
fs::path fullpath = _basepath / _path; fs::path fullpath = _basepath / _path;
TestCase::Config config{fullpath.string(), _ipcPath, dev::test::Options::get().evmVersion()}; TestCase::Config config{fullpath.string(), dev::test::Options::get().evmVersion()};
if (fs::is_directory(fullpath)) if (fs::is_directory(fullpath))
{ {
test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string()); test_suite* sub_suite = BOOST_TEST_SUITE(_path.filename().string());
@ -89,7 +89,7 @@ int registerTests(
fs::directory_iterator() fs::directory_iterator()
)) ))
if (fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename())) if (fs::is_directory(entry.path()) || TestCase::isTestFilename(entry.path().filename()))
numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename(), _ipcPath, _testCaseCreator); numTestsAdded += registerTests(*sub_suite, _basepath, _path / entry.path().filename(), _testCaseCreator);
_suite.add(sub_suite); _suite.add(sub_suite);
} }
else else
@ -140,6 +140,14 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
master.p_name.value = "SolidityTests"; master.p_name.value = "SolidityTests";
dev::test::Options::get().validate(); dev::test::Options::get().validate();
bool disableSemantics = !dev::test::EVMHost::getVM(dev::test::Options::get().evmonePath.string());
if (disableSemantics)
{
cout << "Unable to find libevmone.so. Please provide the path using -- --evmonepath <path>." << endl;
cout << "You can download it at" << endl;
cout << "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz" << endl;
cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl;
}
// Include the interactive tests in the automatic tests as well // Include the interactive tests in the automatic tests as well
for (auto const& ts: g_interactiveTestsuites) for (auto const& ts: g_interactiveTestsuites)
{ {
@ -148,19 +156,18 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] )
if (ts.smt && options.disableSMT) if (ts.smt && options.disableSMT)
continue; continue;
if (ts.ipc && options.disableIPC) if (ts.needsVM && disableSemantics)
continue; continue;
solAssert(registerTests( solAssert(registerTests(
master, master,
options.testPath / ts.path, options.testPath / ts.path,
ts.subpath, ts.subpath,
options.ipcPath.string(),
ts.testCaseCreator ts.testCaseCreator
) > 0, std::string("no ") + ts.title + " tests found"); ) > 0, std::string("no ") + ts.title + " tests found");
} }
if (dev::test::Options::get().disableIPC) if (disableSemantics)
{ {
for (auto suite: { for (auto suite: {
"ABIDecoderTest", "ABIDecoderTest",

View File

@ -20,11 +20,14 @@
* Tests for a fixed fee registrar contract. * Tests for a fixed fee registrar contract.
*/ */
#include <string>
#include <tuple>
#include <boost/test/unit_test.hpp>
#include <test/libsolidity/SolidityExecutionFramework.h> #include <test/libsolidity/SolidityExecutionFramework.h>
#include <test/contracts/ContractInterface.h> #include <test/contracts/ContractInterface.h>
#include <test/EVMHost.h>
#include <boost/test/unit_test.hpp>
#include <string>
#include <tuple>
using namespace std; using namespace std;
using namespace dev::test; using namespace dev::test;
@ -413,7 +416,8 @@ BOOST_AUTO_TEST_CASE(auction_simple)
registrar.reserve(name); registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0); BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// "wait" until auction end // "wait" until auction end
m_rpc.test_modifyTimestamp(currentTimestamp() + m_biddingTime + 10);
m_evmHost->m_state.timestamp += m_biddingTime + 10;
// trigger auction again // trigger auction again
registrar.reserve(name); registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), m_sender); BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
@ -425,7 +429,7 @@ BOOST_AUTO_TEST_CASE(auction_bidding)
string name = "x"; string name = "x";
unsigned startTime = 0x776347e2; unsigned startTime = 0x776347e2;
m_rpc.test_modifyTimestamp(startTime); m_evmHost->m_state.timestamp = startTime;
RegistrarInterface registrar(*this); RegistrarInterface registrar(*this);
// initiate auction // initiate auction
@ -433,55 +437,24 @@ BOOST_AUTO_TEST_CASE(auction_bidding)
registrar.reserve(name); registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0); BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// overbid self // overbid self
m_rpc.test_modifyTimestamp(startTime + m_biddingTime - 10); m_evmHost->m_state.timestamp = startTime + m_biddingTime - 10;
registrar.setNextValue(12); registrar.setNextValue(12);
registrar.reserve(name); registrar.reserve(name);
// another bid by someone else // another bid by someone else
sendEther(account(1), 10 * ether); sendEther(account(1), 10 * ether);
m_sender = account(1); m_sender = account(1);
m_rpc.test_modifyTimestamp(startTime + 2 * m_biddingTime - 50); m_evmHost->m_state.timestamp = startTime + 2 * m_biddingTime - 50;
registrar.setNextValue(13); registrar.setNextValue(13);
registrar.reserve(name); registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0); BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// end auction by first bidder (which is not highest) trying to overbid again (too late) // end auction by first bidder (which is not highest) trying to overbid again (too late)
m_sender = account(0); m_sender = account(0);
m_rpc.test_modifyTimestamp(startTime + 4 * m_biddingTime); m_evmHost->m_state.timestamp = startTime + 4 * m_biddingTime;
registrar.setNextValue(20); registrar.setNextValue(20);
registrar.reserve(name); registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), account(1)); BOOST_CHECK_EQUAL(registrar.owner(name), account(1));
} }
BOOST_AUTO_TEST_CASE(auction_renewal)
{
deployRegistrar();
string name = "x";
RegistrarInterface registrar(*this);
size_t startTime = currentTimestamp();
// register name by auction
registrar.setNextValue(8);
registrar.reserve(name);
m_rpc.test_modifyTimestamp(startTime + 4 * m_biddingTime);
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
// try to re-register before interval end
sendEther(account(1), 10 * ether);
m_sender = account(1);
m_rpc.test_modifyTimestamp(currentTimestamp() + m_renewalInterval - 1);
registrar.setNextValue(80);
registrar.reserve(name);
m_rpc.test_modifyTimestamp(currentTimestamp() + m_biddingTime);
// if there is a bug in the renewal logic, this would transfer the ownership to account(1),
// but if there is no bug, this will initiate the auction, albeit with a zero bid
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), account(0));
registrar.setNextValue(80);
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), account(1));
}
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()
} }

View File

@ -974,12 +974,12 @@ struct evmc_instance
evmc_execute_fn execute; evmc_execute_fn execute;
/** /**
* Pointer to function returning capabilities supported by the VM instance. * A method returning capabilities supported by the VM instance.
* *
* The value returned might change when different options are requested via set_option. * The value returned MAY change when different options are set via the set_option() method.
* *
* A Client SHOULD only rely on the value returned here if it has queried it after * A Client SHOULD only rely on the value returned if it has queried it after
* it has called set_option. * it has called the set_option().
* *
* This is a mandatory method and MUST NOT be set to NULL. * This is a mandatory method and MUST NOT be set to NULL.
*/ */

View File

@ -2,6 +2,7 @@
* Copyright 2018-2019 The EVMC Authors. * Copyright 2018-2019 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. * Licensed under the Apache License, Version 2.0.
*/ */
#pragma once
#include <evmc/evmc.h> #include <evmc/evmc.h>
#include <evmc/helpers.h> #include <evmc/helpers.h>
@ -104,6 +105,12 @@ public:
/// @copydoc evmc_instance::version /// @copydoc evmc_instance::version
char const* version() const noexcept { return m_instance->version; } char const* version() const noexcept { return m_instance->version; }
/// @copydoc evmc::instance::get_capabilities
evmc_capabilities_flagset get_capabilities() const noexcept
{
return m_instance->get_capabilities(m_instance);
}
/// @copydoc evmc_set_option() /// @copydoc evmc_set_option()
evmc_set_option_result set_option(const char name[], const char value[]) noexcept evmc_set_option_result set_option(const char name[], const char value[]) noexcept
{ {

View File

@ -42,18 +42,33 @@
#define ATTR_FORMAT(...) #define ATTR_FORMAT(...)
#endif #endif
#if !_WIN32 #if _WIN32
#define strcpy_sx strcpy_s
#else
/* /*
* Provide strcpy_s() for GNU libc. * Limited variant of strcpy_s().
*
* Provided for C standard libraries where strcpy_s() is not available.
* The availability check might need to adjusted for other C standard library implementations. * The availability check might need to adjusted for other C standard library implementations.
*/ */
static void strcpy_s(char* dest, size_t destsz, const char* src) #if !defined(EVMC_LOADER_MOCK)
static
#endif
int
strcpy_sx(char* restrict dest, size_t destsz, const char* restrict src)
{ {
size_t len = strlen(src); size_t len = strlen(src);
if (len > destsz - 1) if (len >= destsz)
len = destsz - 1; {
// The input src will not fit into the dest buffer.
// Set the first byte of the dest to null to make it effectively empty string
// and return error.
dest[0] = 0;
return 1;
}
memcpy(dest, src, len); memcpy(dest, src, len);
dest[len] = 0; dest[len] = 0;
return 0;
} }
#endif #endif
@ -124,7 +139,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
const char prefix[] = "evmc_create_"; const char prefix[] = "evmc_create_";
const size_t prefix_length = strlen(prefix); const size_t prefix_length = strlen(prefix);
char prefixed_name[sizeof(prefix) + PATH_MAX_LENGTH]; char prefixed_name[sizeof(prefix) + PATH_MAX_LENGTH];
strcpy_s(prefixed_name, sizeof(prefixed_name), prefix); strcpy_sx(prefixed_name, sizeof(prefixed_name), prefix);
// Find filename in the path. // Find filename in the path.
const char* sep_pos = strrchr(filename, '/'); const char* sep_pos = strrchr(filename, '/');
@ -142,7 +157,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
name_pos += lib_prefix_length; name_pos += lib_prefix_length;
char* base_name = prefixed_name + prefix_length; char* base_name = prefixed_name + prefix_length;
strcpy_s(base_name, PATH_MAX_LENGTH, name_pos); strcpy_sx(base_name, PATH_MAX_LENGTH, name_pos);
// Trim the file extension. // Trim the file extension.
char* ext_pos = strrchr(prefixed_name, '.'); char* ext_pos = strrchr(prefixed_name, '.');
@ -197,21 +212,29 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
if (!create_fn) if (!create_fn)
return NULL; return NULL;
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
struct evmc_instance* instance = create_fn(); struct evmc_instance* instance = create_fn();
if (!instance) if (!instance)
{ {
*error_code = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE, ec = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE,
"creating EVMC instance of %s has failed", filename); "creating EVMC instance of %s has failed", filename);
return NULL; goto exit;
} }
if (!evmc_is_abi_compatible(instance)) if (!evmc_is_abi_compatible(instance))
{ {
*error_code = set_error(EVMC_LOADER_ABI_VERSION_MISMATCH, ec = set_error(EVMC_LOADER_ABI_VERSION_MISMATCH,
"EVMC ABI version %d of %s mismatches the expected version %d", "EVMC ABI version %d of %s mismatches the expected version %d",
instance->abi_version, filename, EVMC_ABI_VERSION); instance->abi_version, filename, EVMC_ABI_VERSION);
return NULL; evmc_destroy(instance);
instance = NULL;
goto exit;
} }
exit:
if (error_code)
*error_code = ec;
return instance; return instance;
} }

View File

@ -44,10 +44,10 @@ enum evmc_loader_error_code
}; };
/** /**
* Dynamically loads the shared object (DLL) with an EVM implementation. * Dynamically loads the EVMC module with a VM implementation.
* *
* This function tries to open a DLL at the given `filename`. On UNIX-like systems dlopen() function * This function tries to open a dynamically loaded library (DLL) at the given `filename`.
* is used. On Windows LoadLibrary() function is used. * 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 * 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.
@ -77,18 +77,18 @@ enum evmc_loader_error_code
* It is safe to call this function with the same filename argument multiple times * It is safe to call this function with the same filename argument multiple times
* (the DLL is not going to be loaded 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 an EVMC module
* containing the EVM implementation. If the value is NULL, an empty C-string * (dynamically loaded library) containing the VM implementation.
* or longer than the path maximum length the ::EVMC_LOADER_INVALID_ARGUMENT is * If the value is NULL, an empty C-string or longer than the path maximum length
* signaled. * the ::EVMC_LOADER_INVALID_ARGUMENT is 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_LOADER_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 in case of error.
*/ */
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. * Dynamically loads the EVMC module and creates the VM instance.
* *
* This is a macro for creating the VM instance with the function returned from evmc_load(). * 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: * The function signals the same errors as evmc_load() and additionally:
@ -99,6 +99,14 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
* It is safe to call this function with the same filename argument multiple times: * 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 * the DLL is not going to be loaded multiple times, but the function will return new VM instance
* each time. * each time.
*
* @param filename The null terminated path (absolute or relative) to an EVMC module
* (dynamically loaded library) containing the VM 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 created VM or NULL in case of error.
*/ */
struct evmc_instance* evmc_load_and_create(const char* filename, struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code); enum evmc_loader_error_code* error_code);

View File

@ -377,11 +377,11 @@ BOOST_AUTO_TEST_CASE(transfer_ownership)
BOOST_REQUIRE(callContractFunction("setOwner(bytes32,address)", 0x00, ACCOUNT(1)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("setOwner(bytes32,address)", 0x00, ACCOUNT(1)) == encodeArgs());
// Check that an event was raised and contents are correct. // Check that an event was raised and contents are correct.
BOOST_REQUIRE(m_logs.size() == 1); BOOST_REQUIRE(numLogs() == 1);
BOOST_CHECK(m_logs[0].data == encodeArgs(ACCOUNT(1))); BOOST_CHECK(logData(0) == encodeArgs(ACCOUNT(1)));
BOOST_REQUIRE(m_logs[0].topics.size() == 2); BOOST_REQUIRE(numLogTopics(0) == 2);
BOOST_CHECK(m_logs[0].topics[0] == keccak256(string("Transfer(bytes32,address)"))); BOOST_CHECK(logTopic(0, 0) == keccak256(string("Transfer(bytes32,address)")));
BOOST_CHECK(m_logs[0].topics[1] == u256(0x00)); BOOST_CHECK(logTopic(0, 1) == u256(0x00));
// Verify that owner of 0x00 is now account(1). // Verify that owner of 0x00 is now account(1).
BOOST_CHECK(callContractFunction("owner(bytes32)", 0x00) == encodeArgs(ACCOUNT(1))); BOOST_CHECK(callContractFunction("owner(bytes32)", 0x00) == encodeArgs(ACCOUNT(1)));
@ -406,11 +406,11 @@ BOOST_AUTO_TEST_CASE(set_resolver)
BOOST_REQUIRE(callContractFunction("setResolver(bytes32,address)", 0x00, ACCOUNT(1)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("setResolver(bytes32,address)", 0x00, ACCOUNT(1)) == encodeArgs());
// Check that an event was raised and contents are correct. // Check that an event was raised and contents are correct.
BOOST_REQUIRE(m_logs.size() == 1); BOOST_REQUIRE(numLogs() == 1);
BOOST_CHECK(m_logs[0].data == encodeArgs(ACCOUNT(1))); BOOST_CHECK(logData(0) == encodeArgs(ACCOUNT(1)));
BOOST_REQUIRE(m_logs[0].topics.size() == 2); BOOST_REQUIRE(numLogTopics(0) == 2);
BOOST_CHECK(m_logs[0].topics[0] == keccak256(string("NewResolver(bytes32,address)"))); BOOST_CHECK(logTopic(0, 0) == keccak256(string("NewResolver(bytes32,address)")));
BOOST_CHECK(m_logs[0].topics[1] == u256(0x00)); BOOST_CHECK(logTopic(0, 1) == u256(0x00));
// Verify that the resolver is changed to account(1). // Verify that the resolver is changed to account(1).
BOOST_CHECK(callContractFunction("resolver(bytes32)", 0x00) == encodeArgs(ACCOUNT(1))); BOOST_CHECK(callContractFunction("resolver(bytes32)", 0x00) == encodeArgs(ACCOUNT(1)));
@ -435,11 +435,11 @@ BOOST_AUTO_TEST_CASE(set_ttl)
BOOST_REQUIRE(callContractFunction("setTTL(bytes32,uint64)", 0x00, 3600) == encodeArgs()); BOOST_REQUIRE(callContractFunction("setTTL(bytes32,uint64)", 0x00, 3600) == encodeArgs());
// Check that an event was raised and contents are correct. // Check that an event was raised and contents are correct.
BOOST_REQUIRE(m_logs.size() == 1); BOOST_REQUIRE(numLogs() == 1);
BOOST_CHECK(m_logs[0].data == encodeArgs(3600)); BOOST_CHECK(logData(0) == encodeArgs(3600));
BOOST_REQUIRE(m_logs[0].topics.size() == 2); BOOST_REQUIRE(numLogTopics(0) == 2);
BOOST_CHECK(m_logs[0].topics[0] == keccak256(string("NewTTL(bytes32,uint64)"))); BOOST_CHECK(logTopic(0, 0) == keccak256(string("NewTTL(bytes32,uint64)")));
BOOST_CHECK(m_logs[0].topics[1] == u256(0x00)); BOOST_CHECK(logTopic(0, 1) == u256(0x00));
// Verify that the TTL has been set. // Verify that the TTL has been set.
BOOST_CHECK(callContractFunction("ttl(bytes32)", 0x00) == encodeArgs(3600)); BOOST_CHECK(callContractFunction("ttl(bytes32)", 0x00) == encodeArgs(3600));
@ -464,12 +464,12 @@ BOOST_AUTO_TEST_CASE(create_subnode)
BOOST_REQUIRE(callContractFunction("setSubnodeOwner(bytes32,bytes32,address)", 0x00, keccak256(string("eth")), ACCOUNT(1)) == encodeArgs()); BOOST_REQUIRE(callContractFunction("setSubnodeOwner(bytes32,bytes32,address)", 0x00, keccak256(string("eth")), ACCOUNT(1)) == encodeArgs());
// Check that an event was raised and contents are correct. // Check that an event was raised and contents are correct.
BOOST_REQUIRE(m_logs.size() == 1); BOOST_REQUIRE(numLogs() == 1);
BOOST_CHECK(m_logs[0].data == encodeArgs(ACCOUNT(1))); BOOST_CHECK(logData(0) == encodeArgs(ACCOUNT(1)));
BOOST_REQUIRE(m_logs[0].topics.size() == 3); BOOST_REQUIRE(numLogTopics(0) == 3);
BOOST_CHECK(m_logs[0].topics[0] == keccak256(string("NewOwner(bytes32,bytes32,address)"))); BOOST_CHECK(logTopic(0, 0) == keccak256(string("NewOwner(bytes32,bytes32,address)")));
BOOST_CHECK(m_logs[0].topics[1] == u256(0x00)); BOOST_CHECK(logTopic(0, 1) == u256(0x00));
BOOST_CHECK(m_logs[0].topics[2] == keccak256(string("eth"))); BOOST_CHECK(logTopic(0, 2) == keccak256(string("eth")));
// Verify that the sub-node owner is now account(1). // Verify that the sub-node owner is now account(1).
u256 namehash = keccak256(h256(0x00).asBytes() + keccak256("eth").asBytes()); u256 namehash = keccak256(h256(0x00).asBytes() + keccak256("eth").asBytes());

View File

@ -494,12 +494,12 @@ BOOST_AUTO_TEST_CASE(transfer_event)
BOOST_REQUIRE(callContractFunction("transfer(address,uint256)", ACCOUNT(1), u256(transfer)) == SUCCESS); BOOST_REQUIRE(callContractFunction("transfer(address,uint256)", ACCOUNT(1), u256(transfer)) == SUCCESS);
// Check that a Transfer event was recorded and contents are correct. // Check that a Transfer event was recorded and contents are correct.
BOOST_REQUIRE(m_logs.size() == 1); BOOST_REQUIRE(numLogs() == 1);
BOOST_CHECK(m_logs[0].data == encodeArgs(transfer)); BOOST_CHECK(logData(0) == encodeArgs(transfer));
BOOST_REQUIRE(m_logs[0].topics.size() == 3); BOOST_REQUIRE(numLogTopics(0) == 3);
BOOST_CHECK(m_logs[0].topics[0] == keccak256(string("Transfer(address,address,uint256)"))); BOOST_CHECK(logTopic(0, 0) == keccak256(string("Transfer(address,address,uint256)")));
BOOST_CHECK(m_logs[0].topics[1] == ACCOUNT(0)); BOOST_CHECK(logTopic(0, 1) == ACCOUNT(0));
BOOST_CHECK(m_logs[0].topics[2] == ACCOUNT(1)); BOOST_CHECK(logTopic(0, 2) == ACCOUNT(1));
} }
BOOST_AUTO_TEST_CASE(transfer_zero_no_event) BOOST_AUTO_TEST_CASE(transfer_zero_no_event)
@ -512,7 +512,7 @@ BOOST_AUTO_TEST_CASE(transfer_zero_no_event)
BOOST_REQUIRE(callContractFunction("transfer(address,uint256)", ACCOUNT(1), u256(transfer)) == SUCCESS); BOOST_REQUIRE(callContractFunction("transfer(address,uint256)", ACCOUNT(1), u256(transfer)) == SUCCESS);
// Check that no Event was recorded. // Check that no Event was recorded.
BOOST_CHECK(m_logs.size() == 0); BOOST_CHECK(numLogs() == 0);
// Check that balances have not changed. // Check that balances have not changed.
BOOST_CHECK(callContractFunction("balanceOf(address)", ACCOUNT(0)) == encodeArgs(TOKENSUPPLY - transfer)); BOOST_CHECK(callContractFunction("balanceOf(address)", ACCOUNT(0)) == encodeArgs(TOKENSUPPLY - transfer));
@ -529,12 +529,12 @@ BOOST_AUTO_TEST_CASE(approval_and_transfer_events)
BOOST_REQUIRE(callContractFunction("approve(address,uint256)", ACCOUNT(1), u256(allow)) == SUCCESS); BOOST_REQUIRE(callContractFunction("approve(address,uint256)", ACCOUNT(1), u256(allow)) == SUCCESS);
// Check that an Approval event was recorded and contents are correct. // Check that an Approval event was recorded and contents are correct.
BOOST_REQUIRE(m_logs.size() == 1); BOOST_REQUIRE(numLogs() == 1);
BOOST_CHECK(m_logs[0].data == encodeArgs(allow)); BOOST_CHECK(logData(0) == encodeArgs(allow));
BOOST_REQUIRE(m_logs[0].topics.size() == 3); BOOST_REQUIRE(numLogTopics(0) == 3);
BOOST_CHECK(m_logs[0].topics[0] == keccak256(string("Approval(address,address,uint256)"))); BOOST_CHECK(logTopic(0, 0) == keccak256(string("Approval(address,address,uint256)")));
BOOST_CHECK(m_logs[0].topics[1] == ACCOUNT(0)); BOOST_CHECK(logTopic(0, 1) == ACCOUNT(0));
BOOST_CHECK(m_logs[0].topics[2] == ACCOUNT(1)); BOOST_CHECK(logTopic(0, 2) == ACCOUNT(1));
// Send account(1) some ether for gas. // Send account(1) some ether for gas.
sendEther(account(1), 1000 * ether); sendEther(account(1), 1000 * ether);
@ -546,12 +546,12 @@ BOOST_AUTO_TEST_CASE(approval_and_transfer_events)
BOOST_REQUIRE(callContractFunction("transferFrom(address,address,uint256)", ACCOUNT(0), ACCOUNT(2), u256(transfer)) == SUCCESS); BOOST_REQUIRE(callContractFunction("transferFrom(address,address,uint256)", ACCOUNT(0), ACCOUNT(2), u256(transfer)) == SUCCESS);
// Check that a Transfer event was recorded and contents are correct. // Check that a Transfer event was recorded and contents are correct.
BOOST_REQUIRE(m_logs.size() == 1); BOOST_REQUIRE(numLogs() == 1);
BOOST_CHECK(m_logs[0].data == encodeArgs(transfer)); BOOST_CHECK(logData(0) == encodeArgs(transfer));
BOOST_REQUIRE(m_logs[0].topics.size() == 3); BOOST_REQUIRE(numLogTopics(0) == 3);
BOOST_CHECK(m_logs[0].topics[0] == keccak256(string("Transfer(address,address,uint256)"))); BOOST_CHECK(logTopic(0, 0) == keccak256(string("Transfer(address,address,uint256)")));
BOOST_CHECK(m_logs[0].topics[1] == ACCOUNT(0)); BOOST_CHECK(logTopic(0, 1) == ACCOUNT(0));
BOOST_CHECK(m_logs[0].topics[2] == ACCOUNT(2)); BOOST_CHECK(logTopic(0, 2) == ACCOUNT(2));
} }
BOOST_AUTO_TEST_CASE(invalid_transfer_1) BOOST_AUTO_TEST_CASE(invalid_transfer_1)

View File

@ -43,9 +43,9 @@ namespace test
{ {
#define REQUIRE_LOG_DATA(DATA) do { \ #define REQUIRE_LOG_DATA(DATA) do { \
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); \ BOOST_REQUIRE_EQUAL(numLogs(), 1); \
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); \ BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress); \
ABI_CHECK(m_logs[0].data, DATA); \ ABI_CHECK(logData(0), DATA); \
} while (false) } while (false)
BOOST_FIXTURE_TEST_SUITE(ABIEncoderTest, SolidityExecutionFramework) BOOST_FIXTURE_TEST_SUITE(ABIEncoderTest, SolidityExecutionFramework)
@ -451,7 +451,7 @@ BOOST_AUTO_TEST_CASE(structs)
); );
BOOST_CHECK(callContractFunction("f()") == encoded); BOOST_CHECK(callContractFunction("f()") == encoded);
REQUIRE_LOG_DATA(encoded); REQUIRE_LOG_DATA(encoded);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("e(uint16,(uint16,uint16,(uint64[2])[],uint16))"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("e(uint16,(uint16,uint16,(uint64[2])[],uint16))")));
) )
} }

View File

@ -36,8 +36,8 @@ using namespace boost::unit_test;
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
SemanticTest::SemanticTest(string const& _filename, string const& _ipcPath, langutil::EVMVersion _evmVersion): SemanticTest::SemanticTest(string const& _filename, langutil::EVMVersion _evmVersion):
SolidityExecutionFramework(_ipcPath, _evmVersion) SolidityExecutionFramework(_evmVersion)
{ {
ifstream file(_filename); ifstream file(_filename);
soltestAssert(file, "Cannot open test contract: \"" + _filename + "\"."); soltestAssert(file, "Cannot open test contract: \"" + _filename + "\".");

View File

@ -44,9 +44,9 @@ class SemanticTest: public SolidityExecutionFramework, public EVMVersionRestrict
{ {
public: public:
static std::unique_ptr<TestCase> create(Config const& _options) static std::unique_ptr<TestCase> create(Config const& _options)
{ return std::make_unique<SemanticTest>(_options.filename, _options.ipcPath, _options.evmVersion); } { return std::make_unique<SemanticTest>(_options.filename, _options.evmVersion); }
explicit SemanticTest(std::string const& _filename, std::string const& _ipcPath, langutil::EVMVersion _evmVersion); explicit SemanticTest(std::string const& _filename, langutil::EVMVersion _evmVersion);
TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override; TestResult run(std::ostream& _stream, std::string const& _linePrefix = "", bool _formatted = false) override;
void printSource(std::ostream &_stream, std::string const& _linePrefix = "", bool _formatted = false) const override; void printSource(std::ostream &_stream, std::string const& _linePrefix = "", bool _formatted = false) const override;

View File

@ -24,6 +24,7 @@
#include <test/libsolidity/SolidityExecutionFramework.h> #include <test/libsolidity/SolidityExecutionFramework.h>
#include <test/Options.h> #include <test/Options.h>
#include <test/EVMHost.h>
#include <liblangutil/Exceptions.h> #include <liblangutil/Exceptions.h>
#include <liblangutil/EVMVersion.h> #include <liblangutil/EVMVersion.h>
@ -1133,8 +1134,12 @@ BOOST_AUTO_TEST_CASE(blockchain)
} }
} }
)"; )";
BOOST_CHECK(m_rpc.rpcCall("miner_setEtherbase", {"\"0x1212121212121212121212121212121212121212\""}).asBool() == true); m_evmHost->m_coinbase = EVMHost::convertToEVMC(Address("0x1212121212121212121212121212121212121212"));
m_rpc.test_mineBlocks(5); m_evmHost->newBlock();
m_evmHost->newBlock();
m_evmHost->newBlock();
m_evmHost->newBlock();
m_evmHost->newBlock();
compileAndRun(sourceCode, 27); compileAndRun(sourceCode, 27);
ABI_CHECK(callContractFunctionWithValue("someInfo()", 28), encodeArgs(28, u256("0x1212121212121212121212121212121212121212"), 7)); ABI_CHECK(callContractFunctionWithValue("someInfo()", 28), encodeArgs(28, u256("0x1212121212121212121212121212121212121212"), 7));
} }
@ -1184,10 +1189,10 @@ BOOST_AUTO_TEST_CASE(now)
)"; )";
ALSO_VIA_YUL( ALSO_VIA_YUL(
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 startBlock = m_blockNumber; u256 startBlock = blockNumber();
size_t startTime = blockTimestamp(startBlock); size_t startTime = blockTimestamp(startBlock);
auto ret = callContractFunction("someInfo()"); auto ret = callContractFunction("someInfo()");
u256 endBlock = m_blockNumber; u256 endBlock = blockNumber();
size_t endTime = blockTimestamp(endBlock); size_t endTime = blockTimestamp(endBlock);
BOOST_CHECK(startBlock != endBlock); BOOST_CHECK(startBlock != endBlock);
BOOST_CHECK(startTime != endTime); BOOST_CHECK(startTime != endTime);
@ -1276,10 +1281,10 @@ BOOST_AUTO_TEST_CASE(log0)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("a()"); callContractFunction("a()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
BOOST_CHECK_EQUAL(m_logs[0].topics.size(), 0); BOOST_CHECK_EQUAL(numLogTopics(0), 0);
} }
BOOST_AUTO_TEST_CASE(log1) BOOST_AUTO_TEST_CASE(log1)
@ -1293,11 +1298,11 @@ BOOST_AUTO_TEST_CASE(log1)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("a()"); callContractFunction("a()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(u256(2))); BOOST_CHECK_EQUAL(logTopic(0, 0), h256(u256(2)));
} }
BOOST_AUTO_TEST_CASE(log2) BOOST_AUTO_TEST_CASE(log2)
@ -1311,12 +1316,12 @@ BOOST_AUTO_TEST_CASE(log2)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("a()"); callContractFunction("a()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
for (unsigned i = 0; i < 2; ++i) for (unsigned i = 0; i < 2; ++i)
BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2))); BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
} }
BOOST_AUTO_TEST_CASE(log3) BOOST_AUTO_TEST_CASE(log3)
@ -1330,12 +1335,12 @@ BOOST_AUTO_TEST_CASE(log3)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("a()"); callContractFunction("a()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
for (unsigned i = 0; i < 3; ++i) for (unsigned i = 0; i < 3; ++i)
BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2))); BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
} }
BOOST_AUTO_TEST_CASE(log4) BOOST_AUTO_TEST_CASE(log4)
@ -1349,12 +1354,12 @@ BOOST_AUTO_TEST_CASE(log4)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("a()"); callContractFunction("a()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 4); BOOST_REQUIRE_EQUAL(numLogTopics(0), 4);
for (unsigned i = 0; i < 4; ++i) for (unsigned i = 0; i < 4; ++i)
BOOST_CHECK_EQUAL(m_logs[0].topics[i], h256(u256(i + 2))); BOOST_CHECK_EQUAL(logTopic(0, i), h256(u256(i + 2)));
} }
BOOST_AUTO_TEST_CASE(log_in_constructor) BOOST_AUTO_TEST_CASE(log_in_constructor)
@ -1367,11 +1372,11 @@ BOOST_AUTO_TEST_CASE(log_in_constructor)
} }
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(1))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(u256(2))); BOOST_CHECK_EQUAL(logTopic(0, 0), h256(u256(2)));
} }
BOOST_AUTO_TEST_CASE(selfdestruct) BOOST_AUTO_TEST_CASE(selfdestruct)
@ -2615,13 +2620,13 @@ BOOST_AUTO_TEST_CASE(event)
for (bool manually: {true, false}) for (bool manually: {true, false})
{ {
callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually); callContractFunctionWithValue("deposit(bytes32,bool)", value, id, manually);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address,bytes32,uint256)")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender, h256::AlignRight)); BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id)); BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id));
} }
} }
@ -2640,13 +2645,13 @@ BOOST_AUTO_TEST_CASE(event_emit)
u256 value(18); u256 value(18);
u256 id(0x1234); u256 id(0x1234);
callContractFunctionWithValue("deposit(bytes32)", value, id); callContractFunctionWithValue("deposit(bytes32)", value, id);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(value))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(value)));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address,bytes32,uint256)")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(m_sender, h256::AlignRight)); BOOST_CHECK_EQUAL(logTopic(0, 1), h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(id)); BOOST_CHECK_EQUAL(logTopic(0, 2), h256(id));
) )
} }
@ -2664,11 +2669,11 @@ BOOST_AUTO_TEST_CASE(event_no_arguments)
ALSO_VIA_YUL( ALSO_VIA_YUL(
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data.empty()); BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit()")));
) )
} }
@ -2687,11 +2692,11 @@ BOOST_AUTO_TEST_CASE(event_access_through_base_name_emit)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("f()"); callContractFunction("f()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data.empty()); BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("x()"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("x()")));
} }
BOOST_AUTO_TEST_CASE(events_with_same_name) BOOST_AUTO_TEST_CASE(events_with_same_name)
@ -2725,32 +2730,32 @@ BOOST_AUTO_TEST_CASE(events_with_same_name)
ALSO_VIA_YUL( ALSO_VIA_YUL(
compileAndRun(sourceCode); compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data.empty()); BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit()")));
ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(2))); ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(2)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(m_logs[0].data, encodeArgs(c_loggedAddress)); ABI_CHECK(logData(0), encodeArgs(c_loggedAddress));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address)")));
ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(3))); ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(3)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(m_logs[0].data, encodeArgs(c_loggedAddress, 100)); ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address,uint256)")));
ABI_CHECK(callContractFunction("deposit(address,bool)", c_loggedAddress, false), encodeArgs(u256(4))); ABI_CHECK(callContractFunction("deposit(address,bool)", c_loggedAddress, false), encodeArgs(u256(4)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(m_logs[0].data, encodeArgs(c_loggedAddress, false)); ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, false));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bool)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address,bool)")));
) )
} }
@ -2786,25 +2791,25 @@ BOOST_AUTO_TEST_CASE(events_with_same_name_inherited_emit)
ALSO_VIA_YUL( ALSO_VIA_YUL(
compileAndRun(sourceCode); compileAndRun(sourceCode);
ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1))); ABI_CHECK(callContractFunction("deposit()"), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data.empty()); BOOST_CHECK(logData(0).empty());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit()")));
ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(1))); ABI_CHECK(callContractFunction("deposit(address)", c_loggedAddress), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(c_loggedAddress)); BOOST_CHECK(logData(0) == encodeArgs(c_loggedAddress));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address)")));
ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(1))); ABI_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
ABI_CHECK(m_logs[0].data, encodeArgs(c_loggedAddress, 100)); ABI_CHECK(logData(0), encodeArgs(c_loggedAddress, 100));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address,uint256)")));
) )
} }
@ -2821,7 +2826,7 @@ BOOST_AUTO_TEST_CASE(event_anonymous)
ALSO_VIA_YUL( ALSO_VIA_YUL(
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 0); BOOST_REQUIRE_EQUAL(numLogTopics(0), 0);
) )
} }
@ -2840,14 +2845,14 @@ BOOST_AUTO_TEST_CASE(event_anonymous_with_topics)
u256 value(18); u256 value(18);
u256 id(0x1234); u256 id(0x1234);
callContractFunctionWithValue("deposit(bytes32)", value, id); callContractFunctionWithValue("deposit(bytes32)", value, id);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs("abc")); BOOST_CHECK(logData(0) == encodeArgs("abc"));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 4); BOOST_REQUIRE_EQUAL(numLogTopics(0), 4);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], h256(m_sender, h256::AlignRight)); BOOST_CHECK_EQUAL(logTopic(0, 0), h256(m_sender, h256::AlignRight));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], h256(id)); BOOST_CHECK_EQUAL(logTopic(0, 1), h256(id));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], h256(value)); BOOST_CHECK_EQUAL(logTopic(0, 2), h256(value));
BOOST_CHECK_EQUAL(m_logs[0].topics[3], h256(2)); BOOST_CHECK_EQUAL(logTopic(0, 3), h256(2));
) )
} }
@ -2866,11 +2871,11 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data)
u256 value(18); u256 value(18);
u256 id(0x1234); u256 id(0x1234);
callContractFunctionWithValue("deposit(bytes32)", value, id); callContractFunctionWithValue("deposit(bytes32)", value, id);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs((u160)m_sender, id, value, true)); BOOST_CHECK(logData(0) == encodeArgs((u160)m_sender, id, value, true));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256,bool)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address,bytes32,uint256,bool)")));
) )
} }
@ -2886,11 +2891,11 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(toHex(m_logs[0].data), toHex(encodeArgs(10, 0x60, 15, 4, asString(FixedHash<4>(dev::keccak256("deposit()")).asBytes())))); BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 4, asString(FixedHash<4>(dev::keccak256("deposit()")).asBytes()))));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(uint256,bytes,uint256)")));
} }
BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage) BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage)
@ -2910,11 +2915,11 @@ BOOST_AUTO_TEST_CASE(event_really_lots_of_data_from_storage)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK_EQUAL(toHex(m_logs[0].data), toHex(encodeArgs(10, 0x60, 15, 3, string("ABC")))); BOOST_CHECK_EQUAL(toHex(logData(0)), toHex(encodeArgs(10, 0x60, 15, 3, string("ABC"))));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(uint256,bytes,uint256)")));
} }
BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage) BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage)
@ -2935,11 +2940,11 @@ BOOST_AUTO_TEST_CASE(event_really_really_lots_of_data_from_storage)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(10, 0x60, 15, 31, string("ABC") + string(27, 0) + "Z")); BOOST_CHECK(logData(0) == encodeArgs(10, 0x60, 15, 31, string("ABC") + string(27, 0) + "Z"));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(uint256,bytes,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(uint256,bytes,uint256)")));
} }
BOOST_AUTO_TEST_CASE(event_struct_memory_v2) BOOST_AUTO_TEST_CASE(event_struct_memory_v2)
@ -2957,11 +2962,11 @@ BOOST_AUTO_TEST_CASE(event_struct_memory_v2)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(x)); BOOST_CHECK(logData(0) == encodeArgs(x));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint256))"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E((uint256))")));
} }
BOOST_AUTO_TEST_CASE(event_struct_storage_v2) BOOST_AUTO_TEST_CASE(event_struct_storage_v2)
@ -2981,11 +2986,11 @@ BOOST_AUTO_TEST_CASE(event_struct_storage_v2)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(x)); BOOST_CHECK(logData(0) == encodeArgs(x));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint256))"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E((uint256))")));
} }
BOOST_AUTO_TEST_CASE(event_dynamic_array_memory) BOOST_AUTO_TEST_CASE(event_dynamic_array_memory)
@ -3005,11 +3010,11 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_memory)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(uint256[])")));
} }
BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2) BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2)
@ -3030,11 +3035,11 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_memory_v2)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(uint256[])")));
} }
BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2) BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2)
@ -3058,11 +3063,11 @@ BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_memory_v2)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(uint256[][])")));
} }
BOOST_AUTO_TEST_CASE(event_dynamic_array_storage) BOOST_AUTO_TEST_CASE(event_dynamic_array_storage)
@ -3084,11 +3089,11 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_storage)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(uint256[])")));
) )
} }
@ -3112,11 +3117,11 @@ BOOST_AUTO_TEST_CASE(event_dynamic_array_storage_v2)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 3, x, x + 1, x + 2)); BOOST_CHECK(logData(0) == encodeArgs(0x20, 3, x, x + 1, x + 2));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(uint256[])")));
) )
} }
@ -3143,11 +3148,11 @@ BOOST_AUTO_TEST_CASE(event_dynamic_nested_array_storage_v2)
compileAndRun(sourceCode); compileAndRun(sourceCode);
u256 x(42); u256 x(42);
callContractFunction("createEvent(uint256)", x); callContractFunction("createEvent(uint256)", x);
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3)); BOOST_CHECK(logData(0) == encodeArgs(0x20, 2, 0x40, 0xa0, 2, x, x + 1, 2, x + 2, x + 3));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(uint256[][])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(uint256[][])")));
); );
} }
@ -3172,18 +3177,18 @@ BOOST_AUTO_TEST_CASE(event_indexed_string)
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
callContractFunction("deposit()"); callContractFunction("deposit()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
string dynx(90, 0); string dynx(90, 0);
for (size_t i = 0; i < dynx.size(); ++i) for (size_t i = 0; i < dynx.size(); ++i)
dynx[i] = i; dynx[i] = i;
BOOST_CHECK(m_logs[0].data == bytes()); BOOST_CHECK(logData(0) == bytes());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(dynx)); BOOST_CHECK_EQUAL(logTopic(0, 1), dev::keccak256(dynx));
BOOST_CHECK_EQUAL(m_logs[0].topics[2], dev::keccak256( BOOST_CHECK_EQUAL(logTopic(0, 2), dev::keccak256(
encodeArgs(u256(4), u256(5), u256(6), u256(7)) encodeArgs(u256(4), u256(5), u256(6), u256(7))
)); ));
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(string,uint256[4])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(string,uint256[4])")));
} }
BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one)
@ -3981,11 +3986,11 @@ BOOST_AUTO_TEST_CASE(storing_invalid_boolean)
ABI_CHECK(callContractFunction("perm()"), encodeArgs(1)); ABI_CHECK(callContractFunction("perm()"), encodeArgs(1));
ABI_CHECK(callContractFunction("ret()"), encodeArgs(1)); ABI_CHECK(callContractFunction("ret()"), encodeArgs(1));
ABI_CHECK(callContractFunction("ev()"), encodeArgs(1)); ABI_CHECK(callContractFunction("ev()"), encodeArgs(1));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_CHECK(m_logs[0].data == encodeArgs(1)); BOOST_CHECK(logData(0) == encodeArgs(1));
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Ev(bool)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Ev(bool)")));
} }
@ -5907,11 +5912,11 @@ BOOST_AUTO_TEST_CASE(invalid_enum_logged)
)"; )";
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
ABI_CHECK(callContractFunction("test_log_ok()"), encodeArgs(u256(1))); ABI_CHECK(callContractFunction("test_log_ok()"), encodeArgs(u256(1)));
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); BOOST_REQUIRE_EQUAL(numLogTopics(0), 1);
BOOST_REQUIRE_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Log(uint8)"))); BOOST_REQUIRE_EQUAL(logTopic(0, 0), dev::keccak256(string("Log(uint8)")));
BOOST_CHECK_EQUAL(h256(m_logs[0].data), h256(u256(0))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(0)));
// should throw // should throw
ABI_CHECK(callContractFunction("test_log()"), encodeArgs()); ABI_CHECK(callContractFunction("test_log()"), encodeArgs());
@ -13554,13 +13559,13 @@ BOOST_AUTO_TEST_CASE(abi_encodePackedV2_structs)
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
bytes structEnc = encodeArgs(int(0x12), u256(-7), int(2), int(3), u256(-7), u256(-8)); bytes structEnc = encodeArgs(int(0x12), u256(-7), int(2), int(3), u256(-7), u256(-8));
ABI_CHECK(callContractFunction("testStorage()"), encodeArgs()); ABI_CHECK(callContractFunction("testStorage()"), encodeArgs());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint8,int16,uint8[2],int16[]))"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E((uint8,int16,uint8[2],int16[]))")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(asString(structEnc))); BOOST_CHECK_EQUAL(logTopic(0, 1), dev::keccak256(asString(structEnc)));
ABI_CHECK(callContractFunction("testMemory()"), encodeArgs()); ABI_CHECK(callContractFunction("testMemory()"), encodeArgs());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint8,int16,uint8[2],int16[]))"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E((uint8,int16,uint8[2],int16[]))")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(asString(structEnc))); BOOST_CHECK_EQUAL(logTopic(0, 1), dev::keccak256(asString(structEnc)));
} }
BOOST_AUTO_TEST_CASE(abi_encodePackedV2_nestedArray) BOOST_AUTO_TEST_CASE(abi_encodePackedV2_nestedArray)
@ -13587,9 +13592,9 @@ BOOST_AUTO_TEST_CASE(abi_encodePackedV2_nestedArray)
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
bytes structEnc = encodeArgs(1, 2, 3, 0, 0, 0, 0, 4); bytes structEnc = encodeArgs(1, 2, 3, 0, 0, 0, 0, 4);
ABI_CHECK(callContractFunction("testNestedArrays()"), encodeArgs()); ABI_CHECK(callContractFunction("testNestedArrays()"), encodeArgs());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint8,int16)[2][][3])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E((uint8,int16)[2][][3])")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(asString(structEnc))); BOOST_CHECK_EQUAL(logTopic(0, 1), dev::keccak256(asString(structEnc)));
} }
BOOST_AUTO_TEST_CASE(abi_encodePackedV2_arrayOfStrings) BOOST_AUTO_TEST_CASE(abi_encodePackedV2_arrayOfStrings)
@ -13616,13 +13621,13 @@ BOOST_AUTO_TEST_CASE(abi_encodePackedV2_arrayOfStrings)
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
bytes arrayEncoding = encodeArgs("abc", "0123456789012345678901234567890123456789"); bytes arrayEncoding = encodeArgs("abc", "0123456789012345678901234567890123456789");
ABI_CHECK(callContractFunction("testStorage()"), encodeArgs()); ABI_CHECK(callContractFunction("testStorage()"), encodeArgs());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(string[])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(string[])")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(asString(arrayEncoding))); BOOST_CHECK_EQUAL(logTopic(0, 1), dev::keccak256(asString(arrayEncoding)));
ABI_CHECK(callContractFunction("testMemory()"), encodeArgs()); ABI_CHECK(callContractFunction("testMemory()"), encodeArgs());
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E(string[])"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E(string[])")));
BOOST_CHECK_EQUAL(m_logs[0].topics[1], dev::keccak256(asString(arrayEncoding))); BOOST_CHECK_EQUAL(logTopic(0, 1), dev::keccak256(asString(arrayEncoding)));
} }
BOOST_AUTO_TEST_CASE(event_signature_in_library) BOOST_AUTO_TEST_CASE(event_signature_in_library)
@ -13649,8 +13654,8 @@ BOOST_AUTO_TEST_CASE(event_signature_in_library)
} }
)"; )";
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 2); BOOST_REQUIRE_EQUAL(numLogTopics(0), 2);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("E((uint8,int16),(uint8,int16))"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("E((uint8,int16),(uint8,int16))")));
} }
@ -14730,10 +14735,10 @@ BOOST_AUTO_TEST_CASE(event_wrong_abi_name)
u256 id(0x1234); u256 id(0x1234);
callContractFunction("f()"); callContractFunction("f()");
BOOST_REQUIRE_EQUAL(m_logs.size(), 1); BOOST_REQUIRE_EQUAL(numLogs(), 1);
BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(0), m_contractAddress);
BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 3); BOOST_REQUIRE_EQUAL(numLogTopics(0), 3);
BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,bytes32,uint256)"))); BOOST_CHECK_EQUAL(logTopic(0, 0), dev::keccak256(string("Deposit(address,bytes32,uint256)")));
} }
BOOST_AUTO_TEST_CASE(uninitialized_internal_storage_function) BOOST_AUTO_TEST_CASE(uninitialized_internal_storage_function)
@ -14801,10 +14806,10 @@ BOOST_AUTO_TEST_CASE(dirty_scratch_space_prior_to_constant_optimiser)
} }
)"; )";
compileAndRun(sourceCode, 0, "C"); compileAndRun(sourceCode, 0, "C");
BOOST_REQUIRE_EQUAL(m_logs.size(), 2); BOOST_REQUIRE_EQUAL(numLogs(), 2);
BOOST_CHECK_EQUAL(m_logs[1].address, m_contractAddress); BOOST_CHECK_EQUAL(logAddress(1), m_contractAddress);
ABI_CHECK( ABI_CHECK(
m_logs[1].data, logData(1),
encodeArgs(u256("0x0000000000001234123412431234123412412342112341234124312341234124")) encodeArgs(u256("0x0000000000001234123412431234123412412342112341234124312341234124"))
); );
} }

View File

@ -30,16 +30,6 @@ using namespace dev::solidity;
using namespace dev::solidity::test; using namespace dev::solidity::test;
using namespace std; using namespace std;
SolidityExecutionFramework::SolidityExecutionFramework():
ExecutionFramework()
{
}
SolidityExecutionFramework::SolidityExecutionFramework(std::string const& _ipcPath, langutil::EVMVersion _evmVersion):
ExecutionFramework(_ipcPath, _evmVersion)
{
}
bytes SolidityExecutionFramework::compileContract( bytes SolidityExecutionFramework::compileContract(
string const& _sourceCode, string const& _sourceCode,
string const& _contractName, string const& _contractName,

View File

@ -45,8 +45,10 @@ class SolidityExecutionFramework: public dev::test::ExecutionFramework
{ {
public: public:
SolidityExecutionFramework(); SolidityExecutionFramework() {}
SolidityExecutionFramework(std::string const& _ipcPath, langutil::EVMVersion _evmVersion); explicit SolidityExecutionFramework(langutil::EVMVersion _evmVersion):
ExecutionFramework(_evmVersion)
{}
virtual bytes const& compileAndRunWithoutCheck( virtual bytes const& compileAndRunWithoutCheck(
std::string const& _sourceCode, std::string const& _sourceCode,

View File

@ -485,7 +485,15 @@ BOOST_AUTO_TEST_CASE(constant_optimization_early_exit)
auto start = std::chrono::steady_clock::now(); auto start = std::chrono::steady_clock::now();
compileBothVersions(sourceCode); compileBothVersions(sourceCode);
double duration = std::chrono::duration<double>(std::chrono::steady_clock::now() - start).count(); double duration = std::chrono::duration<double>(std::chrono::steady_clock::now() - start).count();
BOOST_CHECK_MESSAGE(duration < 20, "Compilation of constants took longer than 20 seconds."); // Since run time on an ASan build is not really realistic, we disable this test for those builds.
size_t maxDuration = 20;
#if defined(__has_feature)
#if __has_feature(address_sanitizer)
maxDuration = size_t(-1);
BOOST_TEST_MESSAGE("Disabled constant optimizer run time check for address sanitizer build.");
#endif
#endif
BOOST_CHECK_MESSAGE(duration <= maxDuration, "Compilation of constants took longer than 20 seconds.");
compareVersions("hexEncodeTest(address)", u256(0x123456789)); compareVersions("hexEncodeTest(address)", u256(0x123456789));
} }

View File

@ -15,6 +15,7 @@ add_executable(isoltest
IsolTestOptions.cpp IsolTestOptions.cpp
../Options.cpp ../Options.cpp
../Common.cpp ../Common.cpp
../EVMHost.cpp
../TestCase.cpp ../TestCase.cpp
../libsolidity/util/BytesUtils.cpp ../libsolidity/util/BytesUtils.cpp
../libsolidity/util/ContractABIUtils.cpp ../libsolidity/util/ContractABIUtils.cpp
@ -26,7 +27,6 @@ add_executable(isoltest
../libsolidity/AnalysisFramework.cpp ../libsolidity/AnalysisFramework.cpp
../libsolidity/SolidityExecutionFramework.cpp ../libsolidity/SolidityExecutionFramework.cpp
../ExecutionFramework.cpp ../ExecutionFramework.cpp
../RPCSession.cpp
../libsolidity/ABIJsonTest.cpp ../libsolidity/ABIJsonTest.cpp
../libsolidity/ASTJSONTest.cpp ../libsolidity/ASTJSONTest.cpp
../libsolidity/SMTCheckerJSONTest.cpp ../libsolidity/SMTCheckerJSONTest.cpp

View File

@ -22,6 +22,7 @@
#include <test/tools/IsolTestOptions.h> #include <test/tools/IsolTestOptions.h>
#include <test/libsolidity/AnalysisFramework.h> #include <test/libsolidity/AnalysisFramework.h>
#include <test/InteractiveTests.h> #include <test/InteractiveTests.h>
#include <test/EVMHost.h>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/replace.hpp> #include <boost/algorithm/string/replace.hpp>
@ -156,7 +157,7 @@ TestTool::Result TestTool::process()
{ {
(AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush(); (AnsiColorized(cout, formatted, {BOLD}) << m_name << ": ").flush();
m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.ipcPath.string(), m_options.evmVersion()}); m_test = m_testCaseCreator(TestCase::Config{m_path.string(), m_options.evmVersion()});
if (m_test->validateSettings(m_options.evmVersion())) if (m_test->validateSettings(m_options.evmVersion()))
switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted)) switch (TestCase::TestResult result = m_test->run(outputMessages, " ", formatted))
{ {
@ -413,6 +414,15 @@ int main(int argc, char const *argv[])
return 1; return 1;
} }
bool disableSemantics = !dev::test::EVMHost::getVM(options.evmonePath.string());
if (disableSemantics)
{
cout << "Unable to find libevmone.so. Please provide the path using --evmonepath <path>." << endl;
cout << "You can download it at" << endl;
cout << "https://github.com/ethereum/evmone/releases/download/v0.1.0/evmone-0.1.0-linux-x86_64.tar.gz" << endl;
cout << endl << "--- SKIPPING ALL SEMANTICS TESTS ---" << endl << endl;
}
TestStats global_stats{0, 0}; TestStats global_stats{0, 0};
cout << "Running tests..." << endl << endl; cout << "Running tests..." << endl << endl;
@ -420,7 +430,7 @@ int main(int argc, char const *argv[])
// Interactive tests are added in InteractiveTests.h // Interactive tests are added in InteractiveTests.h
for (auto const& ts: g_interactiveTestsuites) for (auto const& ts: g_interactiveTestsuites)
{ {
if (ts.ipc && options.disableIPC) if (ts.needsVM && disableSemantics)
continue; continue;
if (ts.smt && options.disableSMT) if (ts.smt && options.disableSMT)
@ -451,5 +461,8 @@ int main(int argc, char const *argv[])
} }
cout << "." << endl; cout << "." << endl;
if (disableSemantics)
cout << "\nNOTE: Skipped semantics tests because libevmone.so could not be found.\n" << endl;
return global_stats ? 0 : 1; return global_stats ? 0 : 1;
} }

View File

@ -64,7 +64,7 @@ if (OSSFUZZ)
/usr/include/libprotobuf-mutator /usr/include/libprotobuf-mutator
) )
target_link_libraries(abiv2_proto_ossfuzz PRIVATE solidity target_link_libraries(abiv2_proto_ossfuzz PRIVATE solidity
evmone intx ethash evmc-instructions evmc evmone intx ethash evmc-instructions
protobuf-mutator-libfuzzer.a protobuf-mutator-libfuzzer.a
protobuf-mutator.a protobuf-mutator.a
protobuf.a protobuf.a

View File

@ -142,7 +142,7 @@ DEFINE_PROTO_FUZZER(Contract const& _input)
// We target the default EVM which is the latest // We target the default EVM which is the latest
langutil::EVMVersion version = {}; langutil::EVMVersion version = {};
EVMHost hostContext(version, evmone); EVMHost hostContext(version, &evmone);
// Deploy contract and signal failure if deploy failed // Deploy contract and signal failure if deploy failed
evmc::result createResult = deployContract(hostContext, byteCode); evmc::result createResult = deployContract(hostContext, byteCode);