Merge pull request #7745 from ethereum/develop

Merge develop into develop_060
This commit is contained in:
Erik K 2019-11-19 15:30:31 +01:00 committed by GitHub
commit 94272d44aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 831 additions and 778 deletions

View File

@ -7,22 +7,24 @@ The docker images are build locally on the developer machine:
```!sh ```!sh
cd .circleci/docker/ cd .circleci/docker/
docker build -t ethereum/solidity-buildpack-deps:ubuntu1904 -f Dockerfile.ubuntu1904 . docker build -t ethereum/solidity-buildpack-deps:ubuntu1904-<revision> -f Dockerfile.ubuntu1904 .
docker push ethereum/solidity-buildpack-deps:ubuntu1904 docker push ethereum/solidity-buildpack-deps:ubuntu1904-<revision>
``` ```
which you can find on Dockerhub after the push at: The current revision is `2`.
https://hub.docker.com/r/ethereum/solidity-buildpack-deps Once the docker image has been built and pushed to Dockerhub, you can find it at:
where the image tag reflects the target OS to build Solidity and run its test on. https://hub.docker.com/r/ethereum/solidity-buildpack-deps:ubuntu1904-<revision>
where the image tag reflects the target OS and revision to build Solidity and run its tests on.
### Testing docker images locally ### Testing docker images locally
```!sh ```!sh
cd solidity cd solidity
# Mounts your local solidity directory in docker container for testing # Mounts your local solidity directory in docker container for testing
docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu1904 /bin/bash docker run -v `pwd`:/src/solidity -ti ethereum/solidity-buildpack-deps:ubuntu1904-<revision> /bin/bash
cd /src/solidity cd /src/solidity
<commands_to_test_build_with_new_docker_image> <commands_to_test_build_with_new_docker_image>
``` ```

View File

@ -106,7 +106,7 @@ defaults:
- test_ubuntu1904_clang: &test_ubuntu1904_clang - test_ubuntu1904_clang: &test_ubuntu1904_clang
docker: docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904-clang - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang-2
steps: steps:
- checkout - checkout
- attach_workspace: - attach_workspace:
@ -117,7 +117,7 @@ defaults:
- test_ubuntu1904: &test_ubuntu1904 - test_ubuntu1904: &test_ubuntu1904
docker: docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904 - image: ethereum/solidity-buildpack-deps:ubuntu1904-2
steps: steps:
- checkout - checkout
- attach_workspace: - attach_workspace:
@ -287,7 +287,7 @@ jobs:
b_ubu_clang: &build_ubuntu1904_clang b_ubu_clang: &build_ubuntu1904_clang
docker: docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904-clang - image: ethereum/solidity-buildpack-deps:ubuntu1904-clang-2
environment: environment:
CC: clang CC: clang
CXX: clang++ CXX: clang++
@ -299,7 +299,7 @@ jobs:
b_ubu: &build_ubuntu1904 b_ubu: &build_ubuntu1904
docker: docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904 - image: ethereum/solidity-buildpack-deps:ubuntu1904-2
steps: steps:
- checkout - checkout
- run: *run_build - run: *run_build
@ -313,7 +313,7 @@ jobs:
b_ubu18: &build_ubuntu1804 b_ubu18: &build_ubuntu1804
docker: docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1804 - image: ethereum/solidity-buildpack-deps:ubuntu1804-2
environment: environment:
CMAKE_OPTIONS: -DCMAKE_CXX_FLAGS=-O2 CMAKE_OPTIONS: -DCMAKE_CXX_FLAGS=-O2
CMAKE_BUILD_TYPE: RelWithDebugInfo CMAKE_BUILD_TYPE: RelWithDebugInfo
@ -519,7 +519,7 @@ jobs:
b_docs: b_docs:
docker: docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904 - image: ethereum/solidity-buildpack-deps:ubuntu1904-2
steps: steps:
- checkout - checkout
- run: *setup_prerelease_commit_hash - run: *setup_prerelease_commit_hash
@ -544,7 +544,7 @@ jobs:
t_ubu_cli: &t_ubu_cli t_ubu_cli: &t_ubu_cli
docker: docker:
- image: ethereum/solidity-buildpack-deps:ubuntu1904 - image: ethereum/solidity-buildpack-deps:ubuntu1904-2
environment: environment:
TERM: xterm TERM: xterm
steps: steps:

View File

@ -89,40 +89,21 @@ RUN set -ex; \
ninja install/strip; \ ninja install/strip; \
rm -rf /usr/src/libprotobuf-mutator rm -rf /usr/src/libprotobuf-mutator
# ETHASH
RUN set -ex; \
cd /usr/src; \
git clone --branch="v0.4.4" https://github.com/chfast/ethash.git; \
cd ethash; \
mkdir build; \
cd build; \
cmake .. -G Ninja -DBUILD_SHARED_LIBS=ON -DETHASH_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX="/usr"; \
ninja; \
ninja install/strip; \
rm -rf /usr/src/ethash
# INTX
RUN set -ex; \
cd /usr/src; \
git clone --branch="v0.2.0" https://github.com/chfast/intx.git; \
cd intx; \
mkdir build; \
cd build; \
cmake .. -G Ninja -DBUILD_SHARED_LIBS=ON -DINTX_TESTING=OFF -DINTX_BENCHMARKING=OFF -DCMAKE_INSTALL_PREFIX="/usr"; \
ninja; \
ninja install/strip; \
rm -rf /usr/src/intx;
# EVMONE # EVMONE
RUN set -ex; \ RUN set -ex; \
cd /usr/src; \ cd /usr/src; \
git clone --branch="v0.1.0" --recurse-submodules https://github.com/ethereum/evmone.git; \ git clone --branch="v0.3.0" --recurse-submodules https://github.com/ethereum/evmone.git; \
cd evmone; \ cd evmone; \
mkdir build; \ mkdir build; \
cd build; \ cd build; \
# isoltest links against the evmone shared library
cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \
ninja; \ ninja; \
ninja install/strip; \ ninja install/strip; \
# abiv2_proto_ossfuzz links against the evmone standalone static library
cmake -G Ninja -DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="/usr" ..; \
ninja; \
ninja install/strip; \
rm -rf /usr/src/evmone rm -rf /usr/src/evmone
FROM base FROM base

View File

@ -74,34 +74,10 @@ RUN set -ex; \
ar r /usr/lib/libFuzzingEngine.a *.o; \ ar r /usr/lib/libFuzzingEngine.a *.o; \
rm -rf /var/lib/libfuzzer rm -rf /var/lib/libfuzzer
# ETHASH
RUN set -ex; \
cd /usr/src; \
git clone --branch="v0.4.4" https://github.com/chfast/ethash.git; \
cd ethash; \
mkdir build; \
cd build; \
cmake .. -G Ninja -DBUILD_SHARED_LIBS=OFF -DETHASH_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX="/usr"; \
ninja; \
ninja install/strip; \
rm -rf /usr/src/ethash
# INTX
RUN set -ex; \
cd /usr/src; \
git clone --branch="v0.2.0" https://github.com/chfast/intx.git; \
cd intx; \
mkdir build; \
cd build; \
cmake .. -G Ninja -DBUILD_SHARED_LIBS=OFF -DINTX_TESTING=OFF -DINTX_BENCHMARKING=OFF -DCMAKE_INSTALL_PREFIX="/usr"; \
ninja; \
ninja install/strip; \
rm -rf /usr/src/intx;
# EVMONE # EVMONE
ARG EVMONE_HASH="f10d12c190f55a9d373e78b2dc0074d35d752c02cb536bb6fe754fb3719dd69e" ARG EVMONE_HASH="fa4f40daf7cf9ccbcca6c78345977e084ea2136a8eae661e4d19471be852b15b"
ARG EVMONE_MAJOR="0" ARG EVMONE_MAJOR="0"
ARG EVMONE_MINOR="1" ARG EVMONE_MINOR="3"
ARG EVMONE_MICRO="0" ARG EVMONE_MICRO="0"
RUN set -ex; \ RUN set -ex; \
EVMONE_VERSION="$EVMONE_MAJOR.$EVMONE_MINOR.$EVMONE_MICRO"; \ EVMONE_VERSION="$EVMONE_MAJOR.$EVMONE_MINOR.$EVMONE_MICRO"; \

View File

@ -74,37 +74,14 @@ RUN set -ex; \
ar r /usr/lib/libFuzzingEngine.a *.o; \ ar r /usr/lib/libFuzzingEngine.a *.o; \
rm -rf /var/lib/libfuzzer rm -rf /var/lib/libfuzzer
# ETHASH
RUN set -ex; \
cd /usr/src; \
git clone --branch="v0.4.4" https://github.com/chfast/ethash.git; \
cd ethash; \
mkdir build; \
cd build; \
cmake .. -G Ninja -DBUILD_SHARED_LIBS=OFF -DETHASH_BUILD_TESTS=OFF -DCMAKE_INSTALL_PREFIX="/usr"; \
ninja; \
ninja install/strip; \
rm -rf /usr/src/ethash
# INTX
RUN set -ex; \
cd /usr/src; \
git clone --branch="v0.2.0" https://github.com/chfast/intx.git; \
cd intx; \
mkdir build; \
cd build; \
cmake .. -G Ninja -DBUILD_SHARED_LIBS=OFF -DINTX_TESTING=OFF -DINTX_BENCHMARKING=OFF -DCMAKE_INSTALL_PREFIX="/usr"; \
ninja; \
ninja install/strip; \
rm -rf /usr/src/intx;
# EVMONE # EVMONE
RUN set -ex; \ RUN set -ex; \
cd /usr/src; \ cd /usr/src; \
git clone --branch="v0.1.0" --recurse-submodules https://github.com/ethereum/evmone.git; \ git clone --branch="v0.3.0" --recurse-submodules https://github.com/ethereum/evmone.git; \
cd evmone; \ cd evmone; \
mkdir build; \ mkdir build; \
cd build; \ cd build; \
# isoltest links against the evmone shared library
cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \ cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCMAKE_INSTALL_PREFIX="/usr" ..; \
ninja; \ ninja; \
ninja install/strip; \ ninja install/strip; \

17
.github/workflows/stale.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Mark stale pull requests
on:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: "A reminder that this pull request has had no activity for 14 days"
stale-pr-label: "no-pr-activity"
days-before-stale: 14

View File

@ -42,6 +42,7 @@ Compiler Features:
Bugfixes: Bugfixes:
* SMTChecker: Fix internal error when using ``abi.decode``.

View File

@ -67,47 +67,48 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart1(
) )
{ {
using Word = typename Pattern::Word; using Word = typename Pattern::Word;
using Builtins = typename Pattern::Builtins;
return std::vector<SimplificationRule<Pattern>> { return std::vector<SimplificationRule<Pattern>> {
// arithmetic on constants // arithmetic on constants
{{Pattern::Builtins::ADD, {A, B}}, [=]{ return A.d() + B.d(); }, false}, {Builtins::ADD(A, B), [=]{ return A.d() + B.d(); }, false},
{{Pattern::Builtins::MUL, {A, B}}, [=]{ return A.d() * B.d(); }, false}, {Builtins::MUL(A, B), [=]{ return A.d() * B.d(); }, false},
{{Pattern::Builtins::SUB, {A, B}}, [=]{ return A.d() - B.d(); }, false}, {Builtins::SUB(A, B), [=]{ return A.d() - B.d(); }, false},
{{Pattern::Builtins::DIV, {A, B}}, [=]{ return B.d() == 0 ? 0 : divWorkaround(A.d(), B.d()); }, false}, {Builtins::DIV(A, B), [=]{ return B.d() == 0 ? 0 : divWorkaround(A.d(), B.d()); }, false},
{{Pattern::Builtins::SDIV, {A, B}}, [=]{ return B.d() == 0 ? 0 : s2u(divWorkaround(u2s(A.d()), u2s(B.d()))); }, false}, {Builtins::SDIV(A, B), [=]{ return B.d() == 0 ? 0 : s2u(divWorkaround(u2s(A.d()), u2s(B.d()))); }, false},
{{Pattern::Builtins::MOD, {A, B}}, [=]{ return B.d() == 0 ? 0 : modWorkaround(A.d(), B.d()); }, false}, {Builtins::MOD(A, B), [=]{ return B.d() == 0 ? 0 : modWorkaround(A.d(), B.d()); }, false},
{{Pattern::Builtins::SMOD, {A, B}}, [=]{ return B.d() == 0 ? 0 : s2u(modWorkaround(u2s(A.d()), u2s(B.d()))); }, false}, {Builtins::SMOD(A, B), [=]{ return B.d() == 0 ? 0 : s2u(modWorkaround(u2s(A.d()), u2s(B.d()))); }, false},
{{Pattern::Builtins::EXP, {A, B}}, [=]{ return Word(boost::multiprecision::powm(bigint(A.d()), bigint(B.d()), bigint(1) << Pattern::WordSize)); }, false}, {Builtins::EXP(A, B), [=]{ return Word(boost::multiprecision::powm(bigint(A.d()), bigint(B.d()), bigint(1) << Pattern::WordSize)); }, false},
{{Pattern::Builtins::NOT, {A}}, [=]{ return ~A.d(); }, false}, {Builtins::NOT(A), [=]{ return ~A.d(); }, false},
{{Pattern::Builtins::LT, {A, B}}, [=]() -> Word { return A.d() < B.d() ? 1 : 0; }, false}, {Builtins::LT(A, B), [=]() -> Word { return A.d() < B.d() ? 1 : 0; }, false},
{{Pattern::Builtins::GT, {A, B}}, [=]() -> Word { return A.d() > B.d() ? 1 : 0; }, false}, {Builtins::GT(A, B), [=]() -> Word { return A.d() > B.d() ? 1 : 0; }, false},
{{Pattern::Builtins::SLT, {A, B}}, [=]() -> Word { return u2s(A.d()) < u2s(B.d()) ? 1 : 0; }, false}, {Builtins::SLT(A, B), [=]() -> Word { return u2s(A.d()) < u2s(B.d()) ? 1 : 0; }, false},
{{Pattern::Builtins::SGT, {A, B}}, [=]() -> Word { return u2s(A.d()) > u2s(B.d()) ? 1 : 0; }, false}, {Builtins::SGT(A, B), [=]() -> Word { return u2s(A.d()) > u2s(B.d()) ? 1 : 0; }, false},
{{Pattern::Builtins::EQ, {A, B}}, [=]() -> Word { return A.d() == B.d() ? 1 : 0; }, false}, {Builtins::EQ(A, B), [=]() -> Word { return A.d() == B.d() ? 1 : 0; }, false},
{{Pattern::Builtins::ISZERO, {A}}, [=]() -> Word { return A.d() == 0 ? 1 : 0; }, false}, {Builtins::ISZERO(A), [=]() -> Word { return A.d() == 0 ? 1 : 0; }, false},
{{Pattern::Builtins::AND, {A, B}}, [=]{ return A.d() & B.d(); }, false}, {Builtins::AND(A, B), [=]{ return A.d() & B.d(); }, false},
{{Pattern::Builtins::OR, {A, B}}, [=]{ return A.d() | B.d(); }, false}, {Builtins::OR(A, B), [=]{ return A.d() | B.d(); }, false},
{{Pattern::Builtins::XOR, {A, B}}, [=]{ return A.d() ^ B.d(); }, false}, {Builtins::XOR(A, B), [=]{ return A.d() ^ B.d(); }, false},
{{Pattern::Builtins::BYTE, {A, B}}, [=]{ {Builtins::BYTE(A, B), [=]{
return return
A.d() >= Pattern::WordSize / 8 ? A.d() >= Pattern::WordSize / 8 ?
0 : 0 :
(B.d() >> unsigned(8 * (Pattern::WordSize / 8 - 1 - A.d()))) & 0xff; (B.d() >> unsigned(8 * (Pattern::WordSize / 8 - 1 - A.d()))) & 0xff;
}, false}, }, false},
{{Pattern::Builtins::ADDMOD, {A, B, C}}, [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) + bigint(B.d())) % C.d()); }, false}, {Builtins::ADDMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) + bigint(B.d())) % C.d()); }, false},
{{Pattern::Builtins::MULMOD, {A, B, C}}, [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) * bigint(B.d())) % C.d()); }, false}, {Builtins::MULMOD(A, B, C), [=]{ return C.d() == 0 ? 0 : Word((bigint(A.d()) * bigint(B.d())) % C.d()); }, false},
{{Pattern::Builtins::SIGNEXTEND, {A, B}}, [=]() -> Word { {Builtins::SIGNEXTEND(A, B), [=]() -> Word {
if (A.d() >= Pattern::WordSize / 8 - 1) if (A.d() >= Pattern::WordSize / 8 - 1)
return B.d(); return B.d();
unsigned testBit = unsigned(A.d()) * 8 + 7; unsigned testBit = unsigned(A.d()) * 8 + 7;
Word mask = (Word(1) << testBit) - 1; Word mask = (Word(1) << testBit) - 1;
return boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask; return boost::multiprecision::bit_test(B.d(), testBit) ? B.d() | ~mask : B.d() & mask;
}, false}, }, false},
{{Pattern::Builtins::SHL, {A, B}}, [=]{ {Builtins::SHL(A, B), [=]{
if (A.d() >= Pattern::WordSize) if (A.d() >= Pattern::WordSize)
return Word(0); return Word(0);
return shlWorkaround(B.d(), unsigned(A.d())); return shlWorkaround(B.d(), unsigned(A.d()));
}, false}, }, false},
{{Pattern::Builtins::SHR, {A, B}}, [=]{ {Builtins::SHR(A, B), [=]{
if (A.d() >= Pattern::WordSize) if (A.d() >= Pattern::WordSize)
return Word(0); return Word(0);
return B.d() >> unsigned(A.d()); return B.d() >> unsigned(A.d());
@ -115,6 +116,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart1(
}; };
} }
template <class Pattern> template <class Pattern>
std::vector<SimplificationRule<Pattern>> simplificationRuleListPart2( std::vector<SimplificationRule<Pattern>> simplificationRuleListPart2(
Pattern, Pattern,
@ -125,50 +127,51 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart2(
) )
{ {
using Word = typename Pattern::Word; using Word = typename Pattern::Word;
using Builtins = typename Pattern::Builtins;
return std::vector<SimplificationRule<Pattern>> { return std::vector<SimplificationRule<Pattern>> {
// invariants involving known constants // invariants involving known constants
{{Pattern::Builtins::ADD, {X, 0}}, [=]{ return X; }, false}, {Builtins::ADD(X, 0), [=]{ return X; }, false},
{{Pattern::Builtins::ADD, {0, X}}, [=]{ return X; }, false}, {Builtins::ADD(0, X), [=]{ return X; }, false},
{{Pattern::Builtins::SUB, {X, 0}}, [=]{ return X; }, false}, {Builtins::SUB(X, 0), [=]{ return X; }, false},
{{Pattern::Builtins::SUB, {~Word(0), X}}, [=]() -> Pattern { return {Pattern::Builtins::NOT, {X}}; }, false}, {Builtins::SUB(~Word(0), X), [=]() -> Pattern { return Builtins::NOT(X); }, false},
{{Pattern::Builtins::MUL, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::MUL(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::MUL, {0, X}}, [=]{ return Word(0); }, true}, {Builtins::MUL(0, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::MUL, {X, 1}}, [=]{ return X; }, false}, {Builtins::MUL(X, 1), [=]{ return X; }, false},
{{Pattern::Builtins::MUL, {1, X}}, [=]{ return X; }, false}, {Builtins::MUL(1, X), [=]{ return X; }, false},
{{Pattern::Builtins::MUL, {X, Word(-1)}}, [=]() -> Pattern { return {Pattern::Builtins::SUB, {0, X}}; }, false}, {Builtins::MUL(X, Word(-1)), [=]() -> Pattern { return Builtins::SUB(0, X); }, false},
{{Pattern::Builtins::MUL, {Word(-1), X}}, [=]() -> Pattern { return {Pattern::Builtins::SUB, {0, X}}; }, false}, {Builtins::MUL(Word(-1), X), [=]() -> Pattern { return Builtins::SUB(0, X); }, false},
{{Pattern::Builtins::DIV, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::DIV(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::DIV, {0, X}}, [=]{ return Word(0); }, true}, {Builtins::DIV(0, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::DIV, {X, 1}}, [=]{ return X; }, false}, {Builtins::DIV(X, 1), [=]{ return X; }, false},
{{Pattern::Builtins::SDIV, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::SDIV(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::SDIV, {0, X}}, [=]{ return Word(0); }, true}, {Builtins::SDIV(0, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::SDIV, {X, 1}}, [=]{ return X; }, false}, {Builtins::SDIV(X, 1), [=]{ return X; }, false},
{{Pattern::Builtins::AND, {X, ~Word(0)}}, [=]{ return X; }, false}, {Builtins::AND(X, ~Word(0)), [=]{ return X; }, false},
{{Pattern::Builtins::AND, {~Word(0), X}}, [=]{ return X; }, false}, {Builtins::AND(~Word(0), X), [=]{ return X; }, false},
{{Pattern::Builtins::AND, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::AND(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::AND, {0, X}}, [=]{ return Word(0); }, true}, {Builtins::AND(0, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::OR, {X, 0}}, [=]{ return X; }, false}, {Builtins::OR(X, 0), [=]{ return X; }, false},
{{Pattern::Builtins::OR, {0, X}}, [=]{ return X; }, false}, {Builtins::OR(0, X), [=]{ return X; }, false},
{{Pattern::Builtins::OR, {X, ~Word(0)}}, [=]{ return ~Word(0); }, true}, {Builtins::OR(X, ~Word(0)), [=]{ return ~Word(0); }, true},
{{Pattern::Builtins::OR, {~Word(0), X}}, [=]{ return ~Word(0); }, true}, {Builtins::OR(~Word(0), X), [=]{ return ~Word(0); }, true},
{{Pattern::Builtins::XOR, {X, 0}}, [=]{ return X; }, false}, {Builtins::XOR(X, 0), [=]{ return X; }, false},
{{Pattern::Builtins::XOR, {0, X}}, [=]{ return X; }, false}, {Builtins::XOR(0, X), [=]{ return X; }, false},
{{Pattern::Builtins::MOD, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::MOD(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::MOD, {0, X}}, [=]{ return Word(0); }, true}, {Builtins::MOD(0, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::EQ, {X, 0}}, [=]() -> Pattern { return {Pattern::Builtins::ISZERO, {X}}; }, false }, {Builtins::EQ(X, 0), [=]() -> Pattern { return Builtins::ISZERO(X); }, false },
{{Pattern::Builtins::EQ, {0, X}}, [=]() -> Pattern { return {Pattern::Builtins::ISZERO, {X}}; }, false }, {Builtins::EQ(0, X), [=]() -> Pattern { return Builtins::ISZERO(X); }, false },
{{Pattern::Builtins::SHL, {0, X}}, [=]{ return X; }, false}, {Builtins::SHL(0, X), [=]{ return X; }, false},
{{Pattern::Builtins::SHR, {0, X}}, [=]{ return X; }, false}, {Builtins::SHR(0, X), [=]{ return X; }, false},
{{Pattern::Builtins::SHL, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::SHL(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::SHR, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::SHR(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::GT, {X, 0}}, [=]() -> Pattern { return {Pattern::Builtins::ISZERO, {{Pattern::Builtins::ISZERO, {X}}}}; }, false}, {Builtins::GT(X, 0), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }, false},
{{Pattern::Builtins::LT, {0, X}}, [=]() -> Pattern { return {Pattern::Builtins::ISZERO, {{Pattern::Builtins::ISZERO, {X}}}}; }, false}, {Builtins::LT(0, X), [=]() -> Pattern { return Builtins::ISZERO(Builtins::ISZERO(X)); }, false},
{{Pattern::Builtins::GT, {X, ~Word(0)}}, [=]{ return Word(0); }, true}, {Builtins::GT(X, ~Word(0)), [=]{ return Word(0); }, true},
{{Pattern::Builtins::LT, {~Word(0), X}}, [=]{ return Word(0); }, true}, {Builtins::LT(~Word(0), X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::GT, {0, X}}, [=]{ return Word(0); }, true}, {Builtins::GT(0, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::LT, {X, 0}}, [=]{ return Word(0); }, true}, {Builtins::LT(X, 0), [=]{ return Word(0); }, true},
{{Pattern::Builtins::AND, {{Pattern::Builtins::BYTE, {X, Y}}, {Word(0xff)}}}, [=]() -> Pattern { return {Pattern::Builtins::BYTE, {X, Y}}; }, false}, {Builtins::AND(Builtins::BYTE(X, Y), Word(0xff)), [=]() -> Pattern { return Builtins::BYTE(X, Y); }, false},
{{Pattern::Builtins::BYTE, {Pattern::WordSize / 8 - 1, X}}, [=]() -> Pattern { return {Pattern::Builtins::AND, {X, Word(0xff)}}; }, false} {Builtins::BYTE(Word(Pattern::WordSize / 8 - 1), X), [=]() -> Pattern { return Builtins::AND(X, Word(0xff)); }, false}
}; };
} }
@ -182,18 +185,19 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart3(
) )
{ {
using Word = typename Pattern::Word; using Word = typename Pattern::Word;
using Builtins = typename Pattern::Builtins;
return std::vector<SimplificationRule<Pattern>> { return std::vector<SimplificationRule<Pattern>> {
// operations involving an expression and itself // operations involving an expression and itself
{{Pattern::Builtins::AND, {X, X}}, [=]{ return X; }, true}, {Builtins::AND(X, X), [=]{ return X; }, true},
{{Pattern::Builtins::OR, {X, X}}, [=]{ return X; }, true}, {Builtins::OR(X, X), [=]{ return X; }, true},
{{Pattern::Builtins::XOR, {X, X}}, [=]{ return Word(0); }, true}, {Builtins::XOR(X, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::SUB, {X, X}}, [=]{ return Word(0); }, true}, {Builtins::SUB(X, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::EQ, {X, X}}, [=]{ return Word(1); }, true}, {Builtins::EQ(X, X), [=]{ return Word(1); }, true},
{{Pattern::Builtins::LT, {X, X}}, [=]{ return Word(0); }, true}, {Builtins::LT(X, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::SLT, {X, X}}, [=]{ return Word(0); }, true}, {Builtins::SLT(X, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::GT, {X, X}}, [=]{ return Word(0); }, true}, {Builtins::GT(X, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::SGT, {X, X}}, [=]{ return Word(0); }, true}, {Builtins::SGT(X, X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::MOD, {X, X}}, [=]{ return Word(0); }, true} {Builtins::MOD(X, X), [=]{ return Word(0); }, true}
}; };
} }
@ -207,25 +211,26 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart4(
) )
{ {
using Word = typename Pattern::Word; using Word = typename Pattern::Word;
using Builtins = typename Pattern::Builtins;
return std::vector<SimplificationRule<Pattern>> { return std::vector<SimplificationRule<Pattern>> {
// logical instruction combinations // logical instruction combinations
{{Pattern::Builtins::NOT, {{Pattern::Builtins::NOT, {X}}}}, [=]{ return X; }, false}, {Builtins::NOT(Builtins::NOT(X)), [=]{ return X; }, false},
{{Pattern::Builtins::XOR, {X, {Pattern::Builtins::XOR, {X, Y}}}}, [=]{ return Y; }, true}, {Builtins::XOR(X, Builtins::XOR(X, Y)), [=]{ return Y; }, true},
{{Pattern::Builtins::XOR, {X, {Pattern::Builtins::XOR, {Y, X}}}}, [=]{ return Y; }, true}, {Builtins::XOR(X, Builtins::XOR(Y, X)), [=]{ return Y; }, true},
{{Pattern::Builtins::XOR, {{Pattern::Builtins::XOR, {X, Y}}, X}}, [=]{ return Y; }, true}, {Builtins::XOR(Builtins::XOR(X, Y), X), [=]{ return Y; }, true},
{{Pattern::Builtins::XOR, {{Pattern::Builtins::XOR, {Y, X}}, X}}, [=]{ return Y; }, true}, {Builtins::XOR(Builtins::XOR(Y, X), X), [=]{ return Y; }, true},
{{Pattern::Builtins::OR, {X, {Pattern::Builtins::AND, {X, Y}}}}, [=]{ return X; }, true}, {Builtins::OR(X, Builtins::AND(X, Y)), [=]{ return X; }, true},
{{Pattern::Builtins::OR, {X, {Pattern::Builtins::AND, {Y, X}}}}, [=]{ return X; }, true}, {Builtins::OR(X, Builtins::AND(Y, X)), [=]{ return X; }, true},
{{Pattern::Builtins::OR, {{Pattern::Builtins::AND, {X, Y}}, X}}, [=]{ return X; }, true}, {Builtins::OR(Builtins::AND(X, Y), X), [=]{ return X; }, true},
{{Pattern::Builtins::OR, {{Pattern::Builtins::AND, {Y, X}}, X}}, [=]{ return X; }, true}, {Builtins::OR(Builtins::AND(Y, X), X), [=]{ return X; }, true},
{{Pattern::Builtins::AND, {X, {Pattern::Builtins::OR, {X, Y}}}}, [=]{ return X; }, true}, {Builtins::AND(X, Builtins::OR(X, Y)), [=]{ return X; }, true},
{{Pattern::Builtins::AND, {X, {Pattern::Builtins::OR, {Y, X}}}}, [=]{ return X; }, true}, {Builtins::AND(X, Builtins::OR(Y, X)), [=]{ return X; }, true},
{{Pattern::Builtins::AND, {{Pattern::Builtins::OR, {X, Y}}, X}}, [=]{ return X; }, true}, {Builtins::AND(Builtins::OR(X, Y), X), [=]{ return X; }, true},
{{Pattern::Builtins::AND, {{Pattern::Builtins::OR, {Y, X}}, X}}, [=]{ return X; }, true}, {Builtins::AND(Builtins::OR(Y, X), X), [=]{ return X; }, true},
{{Pattern::Builtins::AND, {X, {Pattern::Builtins::NOT, {X}}}}, [=]{ return Word(0); }, true}, {Builtins::AND(X, Builtins::NOT(X)), [=]{ return Word(0); }, true},
{{Pattern::Builtins::AND, {{Pattern::Builtins::NOT, {X}}, X}}, [=]{ return Word(0); }, true}, {Builtins::AND(Builtins::NOT(X), X), [=]{ return Word(0); }, true},
{{Pattern::Builtins::OR, {X, {Pattern::Builtins::NOT, {X}}}}, [=]{ return ~Word(0); }, true}, {Builtins::OR(X, Builtins::NOT(X)), [=]{ return ~Word(0); }, true},
{{Pattern::Builtins::OR, {{Pattern::Builtins::NOT, {X}}, X}}, [=]{ return ~Word(0); }, true}, {Builtins::OR(Builtins::NOT(X), X), [=]{ return ~Word(0); }, true},
}; };
} }
@ -240,6 +245,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
) )
{ {
using Word = typename Pattern::Word; using Word = typename Pattern::Word;
using Builtins = typename Pattern::Builtins;
std::vector<SimplificationRule<Pattern>> rules; std::vector<SimplificationRule<Pattern>> rules;
@ -248,15 +254,15 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
{ {
Word value = Word(1) << i; Word value = Word(1) << i;
rules.push_back({ rules.push_back({
{Pattern::Builtins::MOD, {X, value}}, Builtins::MOD(X, value),
[=]() -> Pattern { return {Pattern::Builtins::AND, {X, value - 1}}; }, [=]() -> Pattern { return Builtins::AND(X, value - 1); },
false false
}); });
} }
// Replace SHL >=256, X with 0 // Replace SHL >=256, X with 0
rules.push_back({ rules.push_back({
{Pattern::Builtins::SHL, {A, X}}, Builtins::SHL(A, X),
[=]() -> Pattern { return Word(0); }, [=]() -> Pattern { return Word(0); },
true, true,
[=]() { return A.d() >= Pattern::WordSize; } [=]() { return A.d() >= Pattern::WordSize; }
@ -264,7 +270,7 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
// Replace SHR >=256, X with 0 // Replace SHR >=256, X with 0
rules.push_back({ rules.push_back({
{Pattern::Builtins::SHR, {A, X}}, Builtins::SHR(A, X),
[=]() -> Pattern { return Word(0); }, [=]() -> Pattern { return Word(0); },
true, true,
[=]() { return A.d() >= Pattern::WordSize; } [=]() { return A.d() >= Pattern::WordSize; }
@ -272,29 +278,29 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
// Replace BYTE(A, X), A >= 32 with 0 // Replace BYTE(A, X), A >= 32 with 0
rules.push_back({ rules.push_back({
{Pattern::Builtins::BYTE, {A, X}}, Builtins::BYTE(A, X),
[=]() -> Pattern { return Word(0); }, [=]() -> Pattern { return Word(0); },
true, true,
[=]() { return A.d() >= Pattern::WordSize / 8; } [=]() { return A.d() >= Pattern::WordSize / 8; }
}); });
for (auto const& op: std::vector<Instruction>{ for (auto instr: {
Pattern::Builtins::ADDRESS, Instruction::ADDRESS,
Pattern::Builtins::CALLER, Instruction::CALLER,
Pattern::Builtins::ORIGIN, Instruction::ORIGIN,
Pattern::Builtins::COINBASE Instruction::COINBASE
}) })
{ {
assertThrow(Pattern::WordSize > 160, OptimizerException, ""); assertThrow(Pattern::WordSize > 160, OptimizerException, "");
Word const mask = (Word(1) << 160) - 1; Word const mask = (Word(1) << 160) - 1;
rules.push_back({ rules.push_back({
{Pattern::Builtins::AND, {{op, mask}}}, Builtins::AND(Pattern{instr}, mask),
[=]() -> Pattern { return op; }, [=]() -> Pattern { return {instr}; },
false false
}); });
rules.push_back({ rules.push_back({
{Pattern::Builtins::AND, {{mask, op}}}, Builtins::AND(mask, Pattern{instr}),
[=]() -> Pattern { return op; }, [=]() -> Pattern { return {instr}; },
false false
}); });
} }
@ -311,30 +317,35 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart6(
Pattern Y Pattern Y
) )
{ {
using Builtins = typename Pattern::Builtins;
std::vector<SimplificationRule<Pattern>> rules; std::vector<SimplificationRule<Pattern>> rules;
// Double negation of opcodes with boolean result // Double negation of opcodes with boolean result
for (auto const& op: std::vector<Instruction>{ for (auto instr: {
Pattern::Builtins::EQ, Instruction::EQ,
Pattern::Builtins::LT, Instruction::LT,
Pattern::Builtins::SLT, Instruction::SLT,
Pattern::Builtins::GT, Instruction::GT,
Pattern::Builtins::SGT Instruction::SGT
}) })
{
typename Builtins::PatternGeneratorInstance op{instr};
rules.push_back({ rules.push_back({
{Pattern::Builtins::ISZERO, {{Pattern::Builtins::ISZERO, {{op, {X, Y}}}}}}, Builtins::ISZERO(Builtins::ISZERO(op(X, Y))),
[=]() -> Pattern { return {op, {X, Y}}; }, [=]() -> Pattern { return op(X, Y); },
false
});
}
rules.push_back({
Builtins::ISZERO(Builtins::ISZERO(Builtins::ISZERO(X))),
[=]() -> Pattern { return Builtins::ISZERO(X); },
false false
}); });
rules.push_back({ rules.push_back({
{Pattern::Builtins::ISZERO, {{Pattern::Builtins::ISZERO, {{Pattern::Builtins::ISZERO, {X}}}}}}, Builtins::ISZERO(Builtins::XOR(X, Y)),
[=]() -> Pattern { return {Pattern::Builtins::ISZERO, {X}}; }, [=]() -> Pattern { return Builtins::EQ(X, Y); },
false
});
rules.push_back({
{Pattern::Builtins::ISZERO, {{Pattern::Builtins::XOR, {X, Y}}}},
[=]() -> Pattern { return { Pattern::Builtins::EQ, {X, Y} }; },
false false
}); });
@ -351,42 +362,44 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
) )
{ {
using Word = typename Pattern::Word; using Word = typename Pattern::Word;
using Builtins = typename Pattern::Builtins;
std::vector<SimplificationRule<Pattern>> rules; std::vector<SimplificationRule<Pattern>> rules;
// Associative operations // Associative operations
for (auto const& opFun: std::vector<std::pair<Instruction,std::function<Word(Word const&,Word const&)>>>{ for (auto&& instrAndFunc: std::vector<std::pair<Instruction, std::function<Word(Word, Word)>>>{
{Pattern::Builtins::ADD, std::plus<Word>()}, {Instruction::ADD, std::plus<Word>()},
{Pattern::Builtins::MUL, std::multiplies<Word>()}, {Instruction::MUL, std::multiplies<Word>()},
{Pattern::Builtins::AND, std::bit_and<Word>()}, {Instruction::AND, std::bit_and<Word>()},
{Pattern::Builtins::OR, std::bit_or<Word>()}, {Instruction::OR, std::bit_or<Word>()},
{Pattern::Builtins::XOR, std::bit_xor<Word>()} {Instruction::XOR, std::bit_xor<Word>()}
}) })
{ {
auto op = opFun.first; typename Builtins::PatternGeneratorInstance op{instrAndFunc.first};
auto fun = opFun.second; std::function<Word(Word, Word)> fun = instrAndFunc.second;
// Moving constants to the outside, order matters here - we first add rules // Moving constants to the outside, order matters here - we first add rules
// for constants and then for non-constants. // for constants and then for non-constants.
// xa can be (X, A) or (A, X) // xa can be (X, A) or (A, X)
for (auto xa: {std::vector<Pattern>{X, A}, std::vector<Pattern>{A, X}}) for (auto const& opXA: {op(X, A), op(A, X)})
{ {
rules += std::vector<SimplificationRule<Pattern>>{{ rules += std::vector<SimplificationRule<Pattern>>{{
// (X+A)+B -> X+(A+B) // (X+A)+B -> X+(A+B)
{op, {{op, xa}, B}}, op(opXA, B),
[=]() -> Pattern { return {op, {X, fun(A.d(), B.d())}}; }, [=]() -> Pattern { return op(X, fun(A.d(), B.d())); },
false false
}, { }, {
// (X+A)+Y -> (X+Y)+A // (X+A)+Y -> (X+Y)+A
{op, {{op, xa}, Y}}, op(opXA, Y),
[=]() -> Pattern { return {op, {{op, {X, Y}}, A}}; }, [=]() -> Pattern { return op(op(X, Y), A); },
false false
}, { }, {
// B+(X+A) -> X+(A+B) // B+(X+A) -> X+(A+B)
{op, {B, {op, xa}}}, op(B, opXA),
[=]() -> Pattern { return {op, {X, fun(A.d(), B.d())}}; }, [=]() -> Pattern { return op(X, fun(A.d(), B.d())); },
false false
}, { }, {
// Y+(X+A) -> (Y+X)+A // Y+(X+A) -> (Y+X)+A
{op, {Y, {op, xa}}}, op(Y, opXA),
[=]() -> Pattern { return {op, {{op, {Y, X}}, A}}; }, [=]() -> Pattern { return op(op(Y, X), A); },
false false
}}; }};
} }
@ -395,13 +408,13 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
// Combine two SHL by constant // Combine two SHL by constant
rules.push_back({ rules.push_back({
// SHL(B, SHL(A, X)) -> SHL(min(A+B, 256), X) // SHL(B, SHL(A, X)) -> SHL(min(A+B, 256), X)
{Pattern::Builtins::SHL, {{B}, {Pattern::Builtins::SHL, {{A}, {X}}}}}, Builtins::SHL(B, Builtins::SHL(A, X)),
[=]() -> Pattern { [=]() -> Pattern {
bigint sum = bigint(A.d()) + B.d(); bigint sum = bigint(A.d()) + B.d();
if (sum >= Pattern::WordSize) if (sum >= Pattern::WordSize)
return {Pattern::Builtins::AND, {X, Word(0)}}; return Builtins::AND(X, Word(0));
else else
return {Pattern::Builtins::SHL, {Word(sum), X}}; return Builtins::SHL(Word(sum), X);
}, },
false false
}); });
@ -409,13 +422,13 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
// Combine two SHR by constant // Combine two SHR by constant
rules.push_back({ rules.push_back({
// SHR(B, SHR(A, X)) -> SHR(min(A+B, 256), X) // SHR(B, SHR(A, X)) -> SHR(min(A+B, 256), X)
{Pattern::Builtins::SHR, {{B}, {Pattern::Builtins::SHR, {{A}, {X}}}}}, Builtins::SHR(B, Builtins::SHR(A, X)),
[=]() -> Pattern { [=]() -> Pattern {
bigint sum = bigint(A.d()) + B.d(); bigint sum = bigint(A.d()) + B.d();
if (sum >= Pattern::WordSize) if (sum >= Pattern::WordSize)
return {Pattern::Builtins::AND, {X, Word(0)}}; return Builtins::AND(X, Word(0));
else else
return {Pattern::Builtins::SHR, {Word(sum), X}}; return Builtins::SHR(Word(sum), X);
}, },
false false
}); });
@ -423,16 +436,16 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
// Combine SHL-SHR by constant // Combine SHL-SHR by constant
rules.push_back({ rules.push_back({
// SHR(B, SHL(A, X)) -> AND(SH[L/R]([B - A / A - B], X), Mask) // SHR(B, SHL(A, X)) -> AND(SH[L/R]([B - A / A - B], X), Mask)
{Pattern::Builtins::SHR, {{B}, {Pattern::Builtins::SHL, {{A}, {X}}}}}, Builtins::SHR(B, Builtins::SHL(A, X)),
[=]() -> Pattern { [=]() -> Pattern {
Word mask = shlWorkaround(~Word(0), unsigned(A.d())) >> unsigned(B.d()); Word mask = shlWorkaround(~Word(0), unsigned(A.d())) >> unsigned(B.d());
if (A.d() > B.d()) if (A.d() > B.d())
return {Pattern::Builtins::AND, {{Pattern::Builtins::SHL, {A.d() - B.d(), X}}, mask}}; return Builtins::AND(Builtins::SHL(A.d() - B.d(), X), mask);
else if (B.d() > A.d()) else if (B.d() > A.d())
return {Pattern::Builtins::AND, {{Pattern::Builtins::SHR, {B.d() - A.d(), X}}, mask}}; return Builtins::AND(Builtins::SHR(B.d() - A.d(), X), mask);
else else
return {Pattern::Builtins::AND, {X, mask}}; return Builtins::AND(X, mask);
}, },
false, false,
[=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; } [=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; }
@ -441,41 +454,42 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
// Combine SHR-SHL by constant // Combine SHR-SHL by constant
rules.push_back({ rules.push_back({
// SHL(B, SHR(A, X)) -> AND(SH[L/R]([B - A / A - B], X), Mask) // SHL(B, SHR(A, X)) -> AND(SH[L/R]([B - A / A - B], X), Mask)
{Pattern::Builtins::SHL, {{B}, {Pattern::Builtins::SHR, {{A}, {X}}}}}, Builtins::SHL(B, Builtins::SHR(A, X)),
[=]() -> Pattern { [=]() -> Pattern {
Word mask = shlWorkaround((~Word(0)) >> unsigned(A.d()), unsigned(B.d())); Word mask = shlWorkaround((~Word(0)) >> unsigned(A.d()), unsigned(B.d()));
if (A.d() > B.d()) if (A.d() > B.d())
return {Pattern::Builtins::AND, {{Pattern::Builtins::SHR, {A.d() - B.d(), X}}, mask}}; return Builtins::AND(Builtins::SHR(A.d() - B.d(), X), mask);
else if (B.d() > A.d()) else if (B.d() > A.d())
return {Pattern::Builtins::AND, {{Pattern::Builtins::SHL, {B.d() - A.d(), X}}, mask}}; return Builtins::AND(Builtins::SHL(B.d() - A.d(), X), mask);
else else
return {Pattern::Builtins::AND, {X, mask}}; return Builtins::AND(X, mask);
}, },
false, false,
[=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; } [=] { return A.d() < Pattern::WordSize && B.d() < Pattern::WordSize; }
}); });
// Move AND with constant across SHL and SHR by constant // Move AND with constant across SHL and SHR by constant
for (auto shiftOp: {Pattern::Builtins::SHL, Pattern::Builtins::SHR}) for (auto instr: {Instruction::SHL, Instruction::SHR})
{ {
typename Builtins::PatternGeneratorInstance shiftOp{instr};
auto replacement = [=]() -> Pattern { auto replacement = [=]() -> Pattern {
Word mask = Word mask =
shiftOp == Pattern::Builtins::SHL ? instr == Instruction::SHL ?
shlWorkaround(A.d(), unsigned(B.d())) : shlWorkaround(A.d(), unsigned(B.d())) :
A.d() >> unsigned(B.d()); A.d() >> unsigned(B.d());
return {Pattern::Builtins::AND, {{shiftOp, {B.d(), X}}, std::move(mask)}}; return Builtins::AND(shiftOp(B.d(), X), std::move(mask));
}; };
rules.push_back({ rules.push_back({
// SH[L/R](B, AND(X, A)) -> AND(SH[L/R](B, X), [ A << B / A >> B ]) // SH[L/R](B, AND(X, A)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
{shiftOp, {{B}, {Pattern::Builtins::AND, {{X}, {A}}}}}, shiftOp(B, Builtins::AND(X, A)),
replacement, replacement,
false, false,
[=] { return B.d() < Pattern::WordSize; } [=] { return B.d() < Pattern::WordSize; }
}); });
rules.push_back({ rules.push_back({
// SH[L/R](B, AND(A, X)) -> AND(SH[L/R](B, X), [ A << B / A >> B ]) // SH[L/R](B, AND(A, X)) -> AND(SH[L/R](B, X), [ A << B / A >> B ])
{shiftOp, {{B}, {Pattern::Builtins::AND, {{A}, {X}}}}}, shiftOp(B, Builtins::AND(A, X)),
replacement, replacement,
false, false,
[=] { return B.d() < Pattern::WordSize; } [=] { return B.d() < Pattern::WordSize; }
@ -484,27 +498,27 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
rules.push_back({ rules.push_back({
// MUL(X, SHL(Y, 1)) -> SHL(Y, X) // MUL(X, SHL(Y, 1)) -> SHL(Y, X)
{Pattern::Builtins::MUL, {X, {Pattern::Builtins::SHL, {Y, Word(1)}}}}, Builtins::MUL(X, Builtins::SHL(Y, Word(1))),
[=]() -> Pattern { [=]() -> Pattern {
return {Pattern::Builtins::SHL, {Y, X}}; return Builtins::SHL(Y, X);
}, },
// Actually only changes the order, does not remove. // Actually only changes the order, does not remove.
true true
}); });
rules.push_back({ rules.push_back({
// MUL(SHL(X, 1), Y) -> SHL(X, Y) // MUL(SHL(X, 1), Y) -> SHL(X, Y)
{Pattern::Builtins::MUL, {{Pattern::Builtins::SHL, {X, Word(1)}}, Y}}, Builtins::MUL(Builtins::SHL(X, Word(1)), Y),
[=]() -> Pattern { [=]() -> Pattern {
return {Pattern::Builtins::SHL, {X, Y}}; return Builtins::SHL(X, Y);
}, },
false false
}); });
rules.push_back({ rules.push_back({
// DIV(X, SHL(Y, 1)) -> SHR(Y, X) // DIV(X, SHL(Y, 1)) -> SHR(Y, X)
{Pattern::Builtins::DIV, {X, {Pattern::Builtins::SHL, {Y, Word(1)}}}}, Builtins::DIV(X, Builtins::SHL(Y, Word(1))),
[=]() -> Pattern { [=]() -> Pattern {
return {Pattern::Builtins::SHR, {Y, X}}; return Builtins::SHR(Y, X);
}, },
// Actually only changes the order, does not remove. // Actually only changes the order, does not remove.
true true
@ -519,16 +533,16 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart7(
rules.push_back({ rules.push_back({
// AND(A, SHR(B, X)) -> A & ((2^256-1) >> B) == ((2^256-1) >> B) // AND(A, SHR(B, X)) -> A & ((2^256-1) >> B) == ((2^256-1) >> B)
{Pattern::Builtins::AND, {A, {Pattern::Builtins::SHR, {B, X}}}}, Builtins::AND(A, Builtins::SHR(B, X)),
[=]() -> Pattern { return {Pattern::Builtins::SHR, {B, X}}; }, [=]() -> Pattern { return Builtins::SHR(B, X); },
false, false,
feasibilityFunction feasibilityFunction
}); });
rules.push_back({ rules.push_back({
// AND(SHR(B, X), A) -> ((2^256-1) >> B) & A == ((2^256-1) >> B) // AND(SHR(B, X), A) -> ((2^256-1) >> B) & A == ((2^256-1) >> B)
{Pattern::Builtins::AND, {{Pattern::Builtins::SHR, {B, X}}, A}}, Builtins::AND(Builtins::SHR(B, X), A),
[=]() -> Pattern { return {Pattern::Builtins::SHR, {B, X}}; }, [=]() -> Pattern { return Builtins::SHR(B, X); },
false, false,
feasibilityFunction feasibilityFunction
}); });
@ -545,34 +559,35 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart8(
Pattern Y Pattern Y
) )
{ {
using Builtins = typename Pattern::Builtins;
std::vector<SimplificationRule<Pattern>> rules; std::vector<SimplificationRule<Pattern>> rules;
// move constants across subtractions // move constants across subtractions
rules += std::vector<SimplificationRule<Pattern>>{ rules += std::vector<SimplificationRule<Pattern>>{
{ {
// X - A -> X + (-A) // X - A -> X + (-A)
{Pattern::Builtins::SUB, {X, A}}, Builtins::SUB(X, A),
[=]() -> Pattern { return {Pattern::Builtins::ADD, {X, 0 - A.d()}}; }, [=]() -> Pattern { return Builtins::ADD(X, 0 - A.d()); },
false false
}, { }, {
// (X + A) - Y -> (X - Y) + A // (X + A) - Y -> (X - Y) + A
{Pattern::Builtins::SUB, {{Pattern::Builtins::ADD, {X, A}}, Y}}, Builtins::SUB(Builtins::ADD(X, A), Y),
[=]() -> Pattern { return {Pattern::Builtins::ADD, {{Pattern::Builtins::SUB, {X, Y}}, A}}; }, [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); },
false false
}, { }, {
// (A + X) - Y -> (X - Y) + A // (A + X) - Y -> (X - Y) + A
{Pattern::Builtins::SUB, {{Pattern::Builtins::ADD, {A, X}}, Y}}, Builtins::SUB(Builtins::ADD(A, X), Y),
[=]() -> Pattern { return {Pattern::Builtins::ADD, {{Pattern::Builtins::SUB, {X, Y}}, A}}; }, [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), A); },
false false
}, { }, {
// X - (Y + A) -> (X - Y) + (-A) // X - (Y + A) -> (X - Y) + (-A)
{Pattern::Builtins::SUB, {X, {Pattern::Builtins::ADD, {Y, A}}}}, Builtins::SUB(X, Builtins::ADD(Y, A)),
[=]() -> Pattern { return {Pattern::Builtins::ADD, {{Pattern::Builtins::SUB, {X, Y}}, 0 - A.d()}}; }, [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); },
false false
}, { }, {
// X - (A + Y) -> (X - Y) + (-A) // X - (A + Y) -> (X - Y) + (-A)
{Pattern::Builtins::SUB, {X, {Pattern::Builtins::ADD, {A, Y}}}}, Builtins::SUB(X, Builtins::ADD(A, Y)),
[=]() -> Pattern { return {Pattern::Builtins::ADD, {{Pattern::Builtins::SUB, {X, Y}}, 0 - A.d()}}; }, [=]() -> Pattern { return Builtins::ADD(Builtins::SUB(X, Y), 0 - A.d()); },
false false
} }
}; };
@ -591,30 +606,31 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart9(
) )
{ {
using Word = typename Pattern::Word; using Word = typename Pattern::Word;
using Builtins = typename Pattern::Builtins;
std::vector<SimplificationRule<Pattern>> rules; std::vector<SimplificationRule<Pattern>> rules;
assertThrow(Pattern::WordSize > 160, OptimizerException, ""); assertThrow(Pattern::WordSize > 160, OptimizerException, "");
Word const mask = (Word(1) << 160) - 1; Word const mask = (Word(1) << 160) - 1;
// CREATE // CREATE
rules.push_back({ rules.push_back({
{Pattern::Builtins::AND, {{Pattern::Builtins::CREATE, {W, X, Y}}, mask}}, Builtins::AND(Builtins::CREATE(W, X, Y), mask),
[=]() -> Pattern { return {Pattern::Builtins::CREATE, {W, X, Y}}; }, [=]() -> Pattern { return Builtins::CREATE(W, X, Y); },
false false
}); });
rules.push_back({ rules.push_back({
{Pattern::Builtins::AND, {{mask, {Pattern::Builtins::CREATE, {W, X, Y}}}}}, Builtins::AND(mask, Builtins::CREATE(W, X, Y)),
[=]() -> Pattern { return {Pattern::Builtins::CREATE, {W, X, Y}}; }, [=]() -> Pattern { return Builtins::CREATE(W, X, Y); },
false false
}); });
// CREATE2 // CREATE2
rules.push_back({ rules.push_back({
{Pattern::Builtins::AND, {{Pattern::Builtins::CREATE2, {W, X, Y, Z}}, mask}}, Builtins::AND(Builtins::CREATE2(W, X, Y, Z), mask),
[=]() -> Pattern { return {Pattern::Builtins::CREATE2, {W, X, Y, Z}}; }, [=]() -> Pattern { return Builtins::CREATE2(W, X, Y, Z); },
false false
}); });
rules.push_back({ rules.push_back({
{Pattern::Builtins::AND, {{mask, {Pattern::Builtins::CREATE2, {W, X, Y, Z}}}}}, Builtins::AND(mask, Builtins::CREATE2(W, X, Y, Z)),
[=]() -> Pattern { return {Pattern::Builtins::CREATE2, {W, X, Y, Z}}; }, [=]() -> Pattern { return Builtins::CREATE2(W, X, Y, Z); },
false false
}); });

View File

@ -21,6 +21,7 @@
#pragma once #pragma once
#include <libevmasm/Instruction.h> #include <libevmasm/Instruction.h>
#include <libdevcore/CommonData.h>
#include <functional> #include <functional>
namespace dev namespace dev
@ -55,84 +56,105 @@ struct SimplificationRule
std::function<bool()> feasible; std::function<bool()> feasible;
}; };
template <typename Pattern>
struct EVMBuiltins struct EVMBuiltins
{ {
using InstrType = Instruction; using InstrType = Instruction;
static auto constexpr STOP = Instruction::STOP;
static auto constexpr ADD = Instruction::ADD; template<Instruction inst>
static auto constexpr SUB = Instruction::SUB; struct PatternGenerator
static auto constexpr MUL = Instruction::MUL; {
static auto constexpr DIV = Instruction::DIV; template<typename... Args> constexpr Pattern operator()(Args&&... _args) const
static auto constexpr SDIV = Instruction::SDIV; {
static auto constexpr MOD = Instruction::MOD; return {inst, {std::forward<Args>(_args)...}};
static auto constexpr SMOD = Instruction::SMOD; };
static auto constexpr EXP = Instruction::EXP; };
static auto constexpr NOT = Instruction::NOT;
static auto constexpr LT = Instruction::LT; struct PatternGeneratorInstance
static auto constexpr GT = Instruction::GT; {
static auto constexpr SLT = Instruction::SLT; Instruction instruction;
static auto constexpr SGT = Instruction::SGT; template<typename... Args> constexpr Pattern operator()(Args&&... _args) const
static auto constexpr EQ = Instruction::EQ; {
static auto constexpr ISZERO = Instruction::ISZERO; return {instruction, {std::forward<Args>(_args)...}};
static auto constexpr AND = Instruction::AND; };
static auto constexpr OR = Instruction::OR; };
static auto constexpr XOR = Instruction::XOR;
static auto constexpr BYTE = Instruction::BYTE;
static auto constexpr SHL = Instruction::SHL; static auto constexpr STOP = PatternGenerator<Instruction::STOP>{};
static auto constexpr SHR = Instruction::SHR; static auto constexpr ADD = PatternGenerator<Instruction::ADD>{};
static auto constexpr SAR = Instruction::SAR; static auto constexpr SUB = PatternGenerator<Instruction::SUB>{};
static auto constexpr ADDMOD = Instruction::ADDMOD; static auto constexpr MUL = PatternGenerator<Instruction::MUL>{};
static auto constexpr MULMOD = Instruction::MULMOD; static auto constexpr DIV = PatternGenerator<Instruction::DIV>{};
static auto constexpr SIGNEXTEND = Instruction::SIGNEXTEND; static auto constexpr SDIV = PatternGenerator<Instruction::SDIV>{};
static auto constexpr KECCAK256 = Instruction::KECCAK256; static auto constexpr MOD = PatternGenerator<Instruction::MOD>{};
static auto constexpr ADDRESS = Instruction::ADDRESS; static auto constexpr SMOD = PatternGenerator<Instruction::SMOD>{};
static auto constexpr BALANCE = Instruction::BALANCE; static auto constexpr EXP = PatternGenerator<Instruction::EXP>{};
static auto constexpr ORIGIN = Instruction::ORIGIN; static auto constexpr NOT = PatternGenerator<Instruction::NOT>{};
static auto constexpr CALLER = Instruction::CALLER; static auto constexpr LT = PatternGenerator<Instruction::LT>{};
static auto constexpr CALLVALUE = Instruction::CALLVALUE; static auto constexpr GT = PatternGenerator<Instruction::GT>{};
static auto constexpr CALLDATALOAD = Instruction::CALLDATALOAD; static auto constexpr SLT = PatternGenerator<Instruction::SLT>{};
static auto constexpr CALLDATASIZE = Instruction::CALLDATASIZE; static auto constexpr SGT = PatternGenerator<Instruction::SGT>{};
static auto constexpr CALLDATACOPY = Instruction::CALLDATACOPY; static auto constexpr EQ = PatternGenerator<Instruction::EQ>{};
static auto constexpr CODESIZE = Instruction::CODESIZE; static auto constexpr ISZERO = PatternGenerator<Instruction::ISZERO>{};
static auto constexpr CODECOPY = Instruction::CODECOPY; static auto constexpr AND = PatternGenerator<Instruction::AND>{};
static auto constexpr GASPRICE = Instruction::GASPRICE; static auto constexpr OR = PatternGenerator<Instruction::OR>{};
static auto constexpr EXTCODESIZE = Instruction::EXTCODESIZE; static auto constexpr XOR = PatternGenerator<Instruction::XOR>{};
static auto constexpr EXTCODECOPY = Instruction::EXTCODECOPY; static auto constexpr BYTE = PatternGenerator<Instruction::BYTE>{};
static auto constexpr RETURNDATASIZE = Instruction::RETURNDATASIZE; static auto constexpr SHL = PatternGenerator<Instruction::SHL>{};
static auto constexpr RETURNDATACOPY = Instruction::RETURNDATACOPY; static auto constexpr SHR = PatternGenerator<Instruction::SHR>{};
static auto constexpr EXTCODEHASH = Instruction::EXTCODEHASH; static auto constexpr SAR = PatternGenerator<Instruction::SAR>{};
static auto constexpr BLOCKHASH = Instruction::BLOCKHASH; static auto constexpr ADDMOD = PatternGenerator<Instruction::ADDMOD>{};
static auto constexpr COINBASE = Instruction::COINBASE; static auto constexpr MULMOD = PatternGenerator<Instruction::MULMOD>{};
static auto constexpr TIMESTAMP = Instruction::TIMESTAMP; static auto constexpr SIGNEXTEND = PatternGenerator<Instruction::SIGNEXTEND>{};
static auto constexpr NUMBER = Instruction::NUMBER; static auto constexpr KECCAK256 = PatternGenerator<Instruction::KECCAK256>{};
static auto constexpr DIFFICULTY = Instruction::DIFFICULTY; static auto constexpr ADDRESS = PatternGenerator<Instruction::ADDRESS>{};
static auto constexpr GASLIMIT = Instruction::GASLIMIT; static auto constexpr BALANCE = PatternGenerator<Instruction::BALANCE>{};
static auto constexpr CHAINID = Instruction::CHAINID; static auto constexpr ORIGIN = PatternGenerator<Instruction::ORIGIN>{};
static auto constexpr SELFBALANCE = Instruction::SELFBALANCE; static auto constexpr CALLER = PatternGenerator<Instruction::CALLER>{};
static auto constexpr POP = Instruction::POP; static auto constexpr CALLVALUE = PatternGenerator<Instruction::CALLVALUE>{};
static auto constexpr MLOAD = Instruction::MLOAD; static auto constexpr CALLDATALOAD = PatternGenerator<Instruction::CALLDATALOAD>{};
static auto constexpr MSTORE = Instruction::MSTORE; static auto constexpr CALLDATASIZE = PatternGenerator<Instruction::CALLDATASIZE>{};
static auto constexpr MSTORE8 = Instruction::MSTORE8; static auto constexpr CALLDATACOPY = PatternGenerator<Instruction::CALLDATACOPY>{};
static auto constexpr SLOAD = Instruction::SLOAD; static auto constexpr CODESIZE = PatternGenerator<Instruction::CODESIZE>{};
static auto constexpr SSTORE = Instruction::SSTORE; static auto constexpr CODECOPY = PatternGenerator<Instruction::CODECOPY>{};
static auto constexpr PC = Instruction::PC; static auto constexpr GASPRICE = PatternGenerator<Instruction::GASPRICE>{};
static auto constexpr MSIZE = Instruction::MSIZE; static auto constexpr EXTCODESIZE = PatternGenerator<Instruction::EXTCODESIZE>{};
static auto constexpr GAS = Instruction::GAS; static auto constexpr EXTCODECOPY = PatternGenerator<Instruction::EXTCODECOPY>{};
static auto constexpr LOG0 = Instruction::LOG0; static auto constexpr RETURNDATASIZE = PatternGenerator<Instruction::RETURNDATASIZE>{};
static auto constexpr LOG1 = Instruction::LOG1; static auto constexpr RETURNDATACOPY = PatternGenerator<Instruction::RETURNDATACOPY>{};
static auto constexpr LOG2 = Instruction::LOG2; static auto constexpr EXTCODEHASH = PatternGenerator<Instruction::EXTCODEHASH>{};
static auto constexpr LOG3 = Instruction::LOG3; static auto constexpr BLOCKHASH = PatternGenerator<Instruction::BLOCKHASH>{};
static auto constexpr LOG4 = Instruction::LOG4; static auto constexpr COINBASE = PatternGenerator<Instruction::COINBASE>{};
static auto constexpr CREATE = Instruction::CREATE; static auto constexpr TIMESTAMP = PatternGenerator<Instruction::TIMESTAMP>{};
static auto constexpr CALL = Instruction::CALL; static auto constexpr NUMBER = PatternGenerator<Instruction::NUMBER>{};
static auto constexpr CALLCODE = Instruction::CALLCODE; static auto constexpr DIFFICULTY = PatternGenerator<Instruction::DIFFICULTY>{};
static auto constexpr STATICCALL = Instruction::STATICCALL; static auto constexpr GASLIMIT = PatternGenerator<Instruction::GASLIMIT>{};
static auto constexpr RETURN = Instruction::RETURN; static auto constexpr CHAINID = PatternGenerator<Instruction::CHAINID>{};
static auto constexpr DELEGATECALL = Instruction::DELEGATECALL; static auto constexpr SELFBALANCE = PatternGenerator<Instruction::SELFBALANCE>{};
static auto constexpr CREATE2 = Instruction::CREATE2; static auto constexpr POP = PatternGenerator<Instruction::POP>{};
static auto constexpr REVERT = Instruction::REVERT; static auto constexpr MLOAD = PatternGenerator<Instruction::MLOAD>{};
static auto constexpr INVALID = Instruction::INVALID; static auto constexpr MSTORE = PatternGenerator<Instruction::MSTORE>{};
static auto constexpr SELFDESTRUCT = Instruction::SELFDESTRUCT; static auto constexpr MSTORE8 = PatternGenerator<Instruction::MSTORE8>{};
static auto constexpr SLOAD = PatternGenerator<Instruction::SLOAD>{};
static auto constexpr SSTORE = PatternGenerator<Instruction::SSTORE>{};
static auto constexpr PC = PatternGenerator<Instruction::PC>{};
static auto constexpr MSIZE = PatternGenerator<Instruction::MSIZE>{};
static auto constexpr GAS = PatternGenerator<Instruction::GAS>{};
static auto constexpr LOG0 = PatternGenerator<Instruction::LOG0>{};
static auto constexpr LOG1 = PatternGenerator<Instruction::LOG1>{};
static auto constexpr LOG2 = PatternGenerator<Instruction::LOG2>{};
static auto constexpr LOG3 = PatternGenerator<Instruction::LOG3>{};
static auto constexpr LOG4 = PatternGenerator<Instruction::LOG4>{};
static auto constexpr CREATE = PatternGenerator<Instruction::CREATE>{};
static auto constexpr CALL = PatternGenerator<Instruction::CALL>{};
static auto constexpr CALLCODE = PatternGenerator<Instruction::CALLCODE>{};
static auto constexpr STATICCALL = PatternGenerator<Instruction::STATICCALL>{};
static auto constexpr RETURN = PatternGenerator<Instruction::RETURN>{};
static auto constexpr DELEGATECALL = PatternGenerator<Instruction::DELEGATECALL>{};
static auto constexpr CREATE2 = PatternGenerator<Instruction::CREATE2>{};
static auto constexpr REVERT = PatternGenerator<Instruction::REVERT>{};
static auto constexpr INVALID = PatternGenerator<Instruction::INVALID>{};
static auto constexpr SELFDESTRUCT = PatternGenerator<Instruction::SELFDESTRUCT>{};
}; };
} }

View File

@ -99,7 +99,7 @@ Rules::Rules()
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
} }
Pattern::Pattern(Instruction _instruction, std::vector<Pattern> const& _arguments): Pattern::Pattern(Instruction _instruction, std::initializer_list<Pattern> _arguments):
m_type(Operation), m_type(Operation),
m_instruction(_instruction), m_instruction(_instruction),
m_arguments(_arguments) m_arguments(_arguments)

View File

@ -26,6 +26,8 @@
#include <libevmasm/ExpressionClasses.h> #include <libevmasm/ExpressionClasses.h>
#include <libevmasm/SimplificationRule.h> #include <libevmasm/SimplificationRule.h>
#include <libdevcore/CommonData.h>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <functional> #include <functional>
@ -87,18 +89,20 @@ public:
using Expression = ExpressionClasses::Expression; using Expression = ExpressionClasses::Expression;
using Id = ExpressionClasses::Id; using Id = ExpressionClasses::Id;
using Builtins = dev::eth::EVMBuiltins; using Builtins = dev::eth::EVMBuiltins<Pattern>;
static constexpr size_t WordSize = 256; static constexpr size_t WordSize = 256;
using Word = u256; using Word = u256;
// Matches a specific constant value. // Matches a specific constant value.
Pattern(unsigned _value): Pattern(u256(_value)) {} Pattern(unsigned _value): Pattern(u256(_value)) {}
Pattern(int _value): Pattern(u256(_value)) {}
Pattern(long unsigned _value): Pattern(u256(_value)) {}
// Matches a specific constant value. // Matches a specific constant value.
Pattern(u256 const& _value): m_type(Push), m_requireDataMatch(true), m_data(std::make_shared<u256>(_value)) {} Pattern(u256 const& _value): m_type(Push), m_requireDataMatch(true), m_data(std::make_shared<u256>(_value)) {}
// Matches a specific assembly item type or anything if not given. // Matches a specific assembly item type or anything if not given.
Pattern(AssemblyItemType _type = UndefinedItem): m_type(_type) {} Pattern(AssemblyItemType _type = UndefinedItem): m_type(_type) {}
// Matches a given instruction with given arguments // Matches a given instruction with given arguments
Pattern(Instruction _instruction, std::vector<Pattern> const& _arguments = {}); Pattern(Instruction _instruction, std::initializer_list<Pattern> _arguments = {});
/// Sets this pattern to be part of the match group with the identifier @a _group. /// Sets this pattern to be part of the match group with the identifier @a _group.
/// Inside one rule, all patterns in the same match group have to match expressions from the /// Inside one rule, all patterns in the same match group have to match expressions from the
/// same expression equivalence class. /// same expression equivalence class.

View File

@ -209,8 +209,6 @@ void SMTEncoder::endVisit(VariableDeclarationStatement const& _varDecl)
solAssert(symbTuple, ""); solAssert(symbTuple, "");
auto const& components = symbTuple->components(); auto const& components = symbTuple->components();
auto const& declarations = _varDecl.declarations(); auto const& declarations = _varDecl.declarations();
if (!components.empty())
{
solAssert(components.size() == declarations.size(), ""); solAssert(components.size() == declarations.size(), "");
for (unsigned i = 0; i < declarations.size(); ++i) for (unsigned i = 0; i < declarations.size(); ++i)
if ( if (
@ -221,7 +219,6 @@ void SMTEncoder::endVisit(VariableDeclarationStatement const& _varDecl)
assignment(*declarations.at(i), components.at(i)->currentValue(declarations.at(i)->type())); assignment(*declarations.at(i), components.at(i)->currentValue(declarations.at(i)->type()));
} }
} }
}
else if (m_context.knownVariable(*_varDecl.declarations().front())) else if (m_context.knownVariable(*_varDecl.declarations().front()))
{ {
if (_varDecl.initialValue()) if (_varDecl.initialValue())
@ -321,24 +318,23 @@ void SMTEncoder::endVisit(TupleExpression const& _tuple)
{ {
auto const& symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_tuple)); auto const& symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_tuple));
solAssert(symbTuple, ""); solAssert(symbTuple, "");
if (symbTuple->components().empty()) auto const& symbComponents = symbTuple->components();
auto const& tupleComponents = _tuple.components();
solAssert(symbComponents.size() == _tuple.components().size(), "");
for (unsigned i = 0; i < symbComponents.size(); ++i)
{ {
vector<shared_ptr<smt::SymbolicVariable>> components; auto sComponent = symbComponents.at(i);
for (auto const& component: _tuple.components()) auto tComponent = tupleComponents.at(i);
if (component) if (sComponent && tComponent)
{ {
if (auto varDecl = identifierToVariable(*component)) if (auto varDecl = identifierToVariable(*tComponent))
components.push_back(m_context.variable(*varDecl)); m_context.addAssertion(sComponent->currentValue() == currentValue(*varDecl));
else else
{ {
solAssert(m_context.knownExpression(*component), ""); solAssert(m_context.knownExpression(*tComponent), "");
components.push_back(m_context.expression(*component)); m_context.addAssertion(sComponent->currentValue() == expr(*tComponent));
} }
} }
else
components.push_back(nullptr);
solAssert(components.size() == _tuple.components().size(), "");
symbTuple->setComponents(move(components));
} }
} }
else else
@ -610,12 +606,22 @@ void SMTEncoder::endVisit(Identifier const& _identifier)
defineExpr(_identifier, m_context.thisAddress()); defineExpr(_identifier, m_context.thisAddress());
m_uninterpretedTerms.insert(&_identifier); m_uninterpretedTerms.insert(&_identifier);
} }
else if (smt::isSupportedType(_identifier.annotation().type->category())) else if (
// TODO: handle MagicVariableDeclaration here _identifier.annotation().type->category() != Type::Category::Modifier
m_errorReporter.warning( )
_identifier.location(), createExpr(_identifier);
"Assertion checker does not yet support the type of this variable." }
void SMTEncoder::endVisit(ElementaryTypeNameExpression const& _typeName)
{
auto const& typeType = dynamic_cast<TypeType const&>(*_typeName.annotation().type);
auto result = smt::newSymbolicVariable(
*TypeProvider::uint256(),
typeType.actualType()->toString(false),
m_context
); );
solAssert(!result.first && result.second, "");
m_context.createExpression(_typeName, result.second);
} }
void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall) void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall)
@ -1513,15 +1519,18 @@ void SMTEncoder::createReturnedExpressions(FunctionCall const& _funCall)
{ {
auto const& symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_funCall)); auto const& symbTuple = dynamic_pointer_cast<smt::SymbolicTupleVariable>(m_context.expression(_funCall));
solAssert(symbTuple, ""); solAssert(symbTuple, "");
if (symbTuple->components().empty()) auto const& symbComponents = symbTuple->components();
solAssert(symbComponents.size() == returnParams.size(), "");
for (unsigned i = 0; i < symbComponents.size(); ++i)
{ {
vector<shared_ptr<smt::SymbolicVariable>> components; auto sComponent = symbComponents.at(i);
for (auto param: returnParams) auto param = returnParams.at(i);
solAssert(param, "");
if (sComponent)
{ {
solAssert(m_context.knownVariable(*param), ""); solAssert(m_context.knownVariable(*param), "");
components.push_back(m_context.variable(*param)); m_context.addAssertion(sComponent->currentValue() == currentValue(*param));
} }
symbTuple->setComponents(move(components));
} }
} }
else if (returnParams.size() == 1) else if (returnParams.size() == 1)

View File

@ -27,6 +27,7 @@
#include <libsolidity/formal/SymbolicVariables.h> #include <libsolidity/formal/SymbolicVariables.h>
#include <libsolidity/formal/VariableUsage.h> #include <libsolidity/formal/VariableUsage.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTVisitor.h> #include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/interface/ReadFile.h> #include <libsolidity/interface/ReadFile.h>
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
@ -82,6 +83,7 @@ protected:
void endVisit(BinaryOperation const& _node) override; void endVisit(BinaryOperation const& _node) override;
void endVisit(FunctionCall const& _node) override; void endVisit(FunctionCall const& _node) override;
void endVisit(Identifier const& _node) override; void endVisit(Identifier const& _node) override;
void endVisit(ElementaryTypeNameExpression const& _node) override;
void endVisit(Literal const& _node) override; void endVisit(Literal const& _node) override;
void endVisit(Return const& _node) override; void endVisit(Return const& _node) override;
bool visit(MemberAccess const& _node) override; bool visit(MemberAccess const& _node) override;

View File

@ -248,12 +248,16 @@ SymbolicTupleVariable::SymbolicTupleVariable(
SymbolicVariable(_type, _type, move(_uniqueName), _context) SymbolicVariable(_type, _type, move(_uniqueName), _context)
{ {
solAssert(isTuple(m_type->category()), ""); solAssert(isTuple(m_type->category()), "");
} auto const& tupleType = dynamic_cast<TupleType const&>(*m_type);
auto const& componentsTypes = tupleType.components();
void SymbolicTupleVariable::setComponents(vector<shared_ptr<SymbolicVariable>> _components) for (unsigned i = 0; i < componentsTypes.size(); ++i)
{ if (componentsTypes.at(i))
solAssert(m_components.empty(), ""); {
auto const& tupleType = dynamic_cast<solidity::TupleType const*>(m_type); string componentName = m_uniqueName + "_component_" + to_string(i);
solAssert(_components.size() == tupleType->components().size(), ""); auto result = smt::newSymbolicVariable(*componentsTypes.at(i), componentName, m_context);
m_components = move(_components); solAssert(result.second, "");
m_components.emplace_back(move(result.second));
}
else
m_components.emplace_back(nullptr);
} }

View File

@ -250,8 +250,6 @@ public:
return m_components; return m_components;
} }
void setComponents(std::vector<std::shared_ptr<SymbolicVariable>> _components);
private: private:
std::vector<std::shared_ptr<SymbolicVariable>> m_components; std::vector<std::shared_ptr<SymbolicVariable>> m_components;
}; };

View File

@ -111,7 +111,7 @@ SimplificationRules::SimplificationRules()
assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized."); assertThrow(isInitialized(), OptimizerException, "Rule list not properly initialized.");
} }
yul::Pattern::Pattern(dev::eth::Instruction _instruction, vector<Pattern> const& _arguments): yul::Pattern::Pattern(dev::eth::Instruction _instruction, initializer_list<Pattern> _arguments):
m_kind(PatternKind::Operation), m_kind(PatternKind::Operation),
m_instruction(_instruction), m_instruction(_instruction),
m_arguments(_arguments) m_arguments(_arguments)

View File

@ -25,6 +25,8 @@
#include <libyul/AsmDataForward.h> #include <libyul/AsmDataForward.h>
#include <libyul/AsmData.h> #include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <functional> #include <functional>
@ -85,7 +87,7 @@ enum class PatternKind
class Pattern class Pattern
{ {
public: public:
using Builtins = dev::eth::EVMBuiltins; using Builtins = dev::eth::EVMBuiltins<Pattern>;
static constexpr size_t WordSize = 256; static constexpr size_t WordSize = 256;
using Word = dev::u256; using Word = dev::u256;
@ -93,10 +95,12 @@ public:
Pattern(PatternKind _kind = PatternKind::Any): m_kind(_kind) {} Pattern(PatternKind _kind = PatternKind::Any): m_kind(_kind) {}
// Matches a specific constant value. // Matches a specific constant value.
Pattern(unsigned _value): Pattern(dev::u256(_value)) {} Pattern(unsigned _value): Pattern(dev::u256(_value)) {}
Pattern(int _value): Pattern(dev::u256(_value)) {}
Pattern(long unsigned _value): Pattern(dev::u256(_value)) {}
// Matches a specific constant value. // Matches a specific constant value.
Pattern(dev::u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<dev::u256>(_value)) {} Pattern(dev::u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<dev::u256>(_value)) {}
// Matches a given instruction with given arguments // Matches a given instruction with given arguments
Pattern(dev::eth::Instruction _instruction, std::vector<Pattern> const& _arguments = {}); Pattern(dev::eth::Instruction _instruction, std::initializer_list<Pattern> _arguments = {});
/// Sets this pattern to be part of the match group with the identifier @a _group. /// Sets this pattern to be part of the match group with the identifier @a _group.
/// Inside one rule, all patterns in the same match group have to match expressions from the /// Inside one rule, all patterns in the same match group have to match expressions from the
/// same expression equivalence class. /// same expression equivalence class.

View File

@ -35,17 +35,17 @@ using namespace dev;
using namespace dev::test; using namespace dev::test;
evmc::vm* EVMHost::getVM(string const& _path) evmc::VM* EVMHost::getVM(string const& _path)
{ {
static unique_ptr<evmc::vm> theVM; static unique_ptr<evmc::VM> theVM;
if (!theVM && !_path.empty()) if (!theVM && !_path.empty())
{ {
evmc_loader_error_code errorCode = {}; evmc_loader_error_code errorCode = {};
evmc_instance* vm = evmc_load_and_configure(_path.c_str(), &errorCode); evmc_vm* vm = evmc_load_and_configure(_path.c_str(), &errorCode);
if (vm && errorCode == EVMC_LOADER_SUCCESS) if (vm && errorCode == EVMC_LOADER_SUCCESS)
{ {
if (evmc_vm_has_capability(vm, EVMC_CAPABILITY_EVM1)) if (evmc_vm_has_capability(vm, EVMC_CAPABILITY_EVM1))
theVM = make_unique<evmc::vm>(vm); theVM = make_unique<evmc::VM>(vm);
else else
{ {
evmc_destroy(vm); evmc_destroy(vm);
@ -63,7 +63,7 @@ evmc::vm* EVMHost::getVM(string const& _path)
return theVM.get(); return theVM.get();
} }
EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm): EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm):
m_vm(_vm) m_vm(_vm)
{ {
if (!m_vm) if (!m_vm)
@ -83,7 +83,7 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm):
else if (_evmVersion == langutil::EVMVersion::constantinople()) else if (_evmVersion == langutil::EVMVersion::constantinople())
m_evmVersion = EVMC_CONSTANTINOPLE; m_evmVersion = EVMC_CONSTANTINOPLE;
else if (_evmVersion == langutil::EVMVersion::istanbul()) else if (_evmVersion == langutil::EVMVersion::istanbul())
assertThrow(false, Exception, "Istanbul is not supported yet."); m_evmVersion = EVMC_ISTANBUL;
else if (_evmVersion == langutil::EVMVersion::berlin()) else if (_evmVersion == langutil::EVMVersion::berlin())
assertThrow(false, Exception, "Berlin is not supported yet."); assertThrow(false, Exception, "Berlin is not supported yet.");
else //if (_evmVersion == langutil::EVMVersion::petersburg()) else //if (_evmVersion == langutil::EVMVersion::petersburg())
@ -227,6 +227,8 @@ evmc_tx_context EVMHost::get_tx_context() noexcept
ctx.block_gas_limit = 20000000; ctx.block_gas_limit = 20000000;
ctx.tx_gas_price = convertToEVMC(u256("3000000000")); ctx.tx_gas_price = convertToEVMC(u256("3000000000"));
ctx.tx_origin = convertToEVMC(Address("0x9292929292929292929292929292929292929292")); ctx.tx_origin = convertToEVMC(Address("0x9292929292929292929292929292929292929292"));
// Mainnet according to EIP-155
ctx.chain_id = convertToEVMC(u256(1));
return ctx; return ctx;
} }

View File

@ -40,9 +40,9 @@ public:
/// Tries to dynamically load libevmone. @returns nullptr on failure. /// Tries to dynamically load libevmone. @returns nullptr on failure.
/// The path has to be provided for the first successful run and will be ignored /// The path has to be provided for the first successful run and will be ignored
/// afterwards. /// afterwards.
static evmc::vm* getVM(std::string const& _path = {}); static evmc::VM* getVM(std::string const& _path = {});
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm = getVM()); explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm = getVM());
struct Account struct Account
{ {
@ -179,7 +179,7 @@ private:
/// @note The return value is only valid as long as @a _data is alive! /// @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; static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept;
evmc::vm* m_vm = nullptr; evmc::VM* m_vm = nullptr;
evmc_revision m_evmVersion; evmc_revision m_evmVersion;
}; };

View File

@ -44,7 +44,7 @@ enum
* *
* @see @ref versioning * @see @ref versioning
*/ */
EVMC_ABI_VERSION = 6 EVMC_ABI_VERSION = 7
}; };
@ -153,9 +153,15 @@ struct evmc_tx_context
int64_t block_timestamp; /**< The block timestamp. */ int64_t block_timestamp; /**< The block timestamp. */
int64_t block_gas_limit; /**< The block gas limit. */ int64_t block_gas_limit; /**< The block gas limit. */
evmc_uint256be block_difficulty; /**< The block difficulty. */ evmc_uint256be block_difficulty; /**< The block difficulty. */
evmc_uint256be chain_id; /**< The blockchain's ChainID. */
}; };
struct evmc_context; /**
* @struct evmc_host_context
* The opaque data type representing the Host execution context.
* @see evmc_execute_fn().
*/
struct evmc_host_context;
/** /**
* Get transaction context callback function. * Get transaction context callback function.
@ -166,7 +172,7 @@ struct evmc_context;
* @param context The pointer to the Host execution context. * @param context The pointer to the Host execution context.
* @return The transaction context. * @return The transaction context.
*/ */
typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_context* context); typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_host_context* context);
/** /**
* Get block hash callback function. * Get block hash callback function.
@ -180,7 +186,7 @@ typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_context* co
* @return The block hash or null bytes * @return The block hash or null bytes
* if the information about the block is not available. * if the information about the block is not available.
*/ */
typedef evmc_bytes32 (*evmc_get_block_hash_fn)(struct evmc_context* context, int64_t number); typedef evmc_bytes32 (*evmc_get_block_hash_fn)(struct evmc_host_context* context, int64_t number);
/** /**
* The execution status code. * The execution status code.
@ -420,7 +426,8 @@ struct evmc_result
* @param address The address of the account the query is about. * @param address The address of the account the query is about.
* @return true if exists, false otherwise. * @return true if exists, false otherwise.
*/ */
typedef bool (*evmc_account_exists_fn)(struct evmc_context* context, const evmc_address* address); typedef bool (*evmc_account_exists_fn)(struct evmc_host_context* context,
const evmc_address* address);
/** /**
* Get storage callback function. * Get storage callback function.
@ -433,7 +440,7 @@ typedef bool (*evmc_account_exists_fn)(struct evmc_context* context, const evmc_
* @return The storage value at the given storage key or null bytes * @return The storage value at the given storage key or null bytes
* if the account does not exist. * if the account does not exist.
*/ */
typedef evmc_bytes32 (*evmc_get_storage_fn)(struct evmc_context* context, typedef evmc_bytes32 (*evmc_get_storage_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const evmc_bytes32* key); const evmc_bytes32* key);
@ -492,7 +499,7 @@ enum evmc_storage_status
* @param value The value to be stored. * @param value The value to be stored.
* @return The effect on the storage item. * @return The effect on the storage item.
*/ */
typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* context, typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const evmc_bytes32* key, const evmc_bytes32* key,
const evmc_bytes32* value); const evmc_bytes32* value);
@ -506,7 +513,7 @@ typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* con
* @param address The address of the account. * @param address The address of the account.
* @return The balance of the given account or 0 if the account does not exist. * @return The balance of the given account or 0 if the account does not exist.
*/ */
typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_context* context, typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_host_context* context,
const evmc_address* address); const evmc_address* address);
/** /**
@ -519,7 +526,8 @@ typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_context* context,
* @param address The address of the account. * @param address The address of the account.
* @return The size of the code in the account or 0 if the account does not exist. * @return The size of the code in the account or 0 if the account does not exist.
*/ */
typedef size_t (*evmc_get_code_size_fn)(struct evmc_context* context, const evmc_address* address); typedef size_t (*evmc_get_code_size_fn)(struct evmc_host_context* context,
const evmc_address* address);
/** /**
* Get code size callback function. * Get code size callback function.
@ -532,7 +540,7 @@ typedef size_t (*evmc_get_code_size_fn)(struct evmc_context* context, const evmc
* @param address The address of the account. * @param address The address of the account.
* @return The hash of the code in the account or null bytes if the account does not exist. * @return The hash of the code in the account or null bytes if the account does not exist.
*/ */
typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_context* context, typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_host_context* context,
const evmc_address* address); const evmc_address* address);
/** /**
@ -544,8 +552,7 @@ typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_context* context,
* to the provided memory buffer up to the size of the buffer or the size of * to the provided memory buffer up to the size of the buffer or the size of
* the code, whichever is smaller. * the code, whichever is smaller.
* *
* @param context The pointer to the Client execution context. * @param context The pointer to the Host execution context. See ::evmc_host_context.
* @see ::evmc_context.
* @param address The address of the account. * @param address The address of the account.
* @param code_offset The offset of the code to copy. * @param code_offset The offset of the code to copy.
* @param buffer_data The pointer to the memory buffer allocated by the EVM * @param buffer_data The pointer to the memory buffer allocated by the EVM
@ -553,7 +560,7 @@ typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_context* context,
* @param buffer_size The size of the memory buffer. * @param buffer_size The size of the memory buffer.
* @return The number of bytes copied to the buffer by the Client. * @return The number of bytes copied to the buffer by the Client.
*/ */
typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context, typedef size_t (*evmc_copy_code_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
size_t code_offset, size_t code_offset,
uint8_t* buffer_data, uint8_t* buffer_data,
@ -565,13 +572,11 @@ typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context,
* This callback function is used by an EVM to SELFDESTRUCT given contract. * This callback function is used by an EVM to SELFDESTRUCT given contract.
* The execution of the contract will not be stopped, that is up to the EVM. * The execution of the contract will not be stopped, that is up to the EVM.
* *
* @param context The pointer to the Host execution context. * @param context The pointer to the Host execution context. See ::evmc_host_context.
* @see ::evmc_context.
* @param address The address of the contract to be selfdestructed. * @param address The address of the contract to be selfdestructed.
* @param beneficiary The address where the remaining ETH is going to be * @param beneficiary The address where the remaining ETH is going to be transferred.
* transferred.
*/ */
typedef void (*evmc_selfdestruct_fn)(struct evmc_context* context, typedef void (*evmc_selfdestruct_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const evmc_address* beneficiary); const evmc_address* beneficiary);
@ -580,16 +585,15 @@ typedef void (*evmc_selfdestruct_fn)(struct evmc_context* context,
* *
* This callback function is used by an EVM to inform about a LOG that happened * This callback function is used by an EVM to inform about a LOG that happened
* during an EVM bytecode execution. * during an EVM bytecode execution.
* @param context The pointer to the Host execution context. *
* @see ::evmc_context. * @param context The pointer to the Host execution context. See ::evmc_host_context.
* @param address The address of the contract that generated the log. * @param address The address of the contract that generated the log.
* @param data The pointer to unindexed data attached to the log. * @param data The pointer to unindexed data attached to the log.
* @param data_size The length of the data. * @param data_size The length of the data.
* @param topics The pointer to the array of topics attached to the log. * @param topics The pointer to the array of topics attached to the log.
* @param topics_count The number of the topics. Valid values are between * @param topics_count The number of the topics. Valid values are between 0 and 4 inclusively.
* 0 and 4 inclusively.
*/ */
typedef void (*evmc_emit_log_fn)(struct evmc_context* context, typedef void (*evmc_emit_log_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const uint8_t* data, const uint8_t* data,
size_t data_size, size_t data_size,
@ -603,7 +607,7 @@ typedef void (*evmc_emit_log_fn)(struct evmc_context* context,
* @param msg The call parameters. * @param msg The call parameters.
* @return The result of the call. * @return The result of the call.
*/ */
typedef struct evmc_result (*evmc_call_fn)(struct evmc_context* context, typedef struct evmc_result (*evmc_call_fn)(struct evmc_host_context* context,
const struct evmc_message* msg); const struct evmc_message* msg);
/** /**
@ -654,31 +658,15 @@ struct evmc_host_interface
}; };
/**
* Execution context managed by the Host.
*
* The Host MUST pass the pointer to the execution context to ::evmc_execute_fn.
* The VM MUST pass the same pointer back to the Host in every callback function.
* The context MUST contain at least the function table defining
* the context callback interface.
* Optionally, the Host MAY include in the context additional data.
*/
struct evmc_context
{
/** The Host interface. */
const struct evmc_host_interface* host;
};
/* Forward declaration. */ /* Forward declaration. */
struct evmc_instance; struct evmc_vm;
/** /**
* Destroys the EVM instance. * Destroys the VM instance.
* *
* @param evm The EVM instance to be destroyed. * @param vm The VM instance to be destroyed.
*/ */
typedef void (*evmc_destroy_fn)(struct evmc_instance* evm); typedef void (*evmc_destroy_fn)(struct evmc_vm* vm);
/** /**
* Possible outcomes of evmc_set_option. * Possible outcomes of evmc_set_option.
@ -691,19 +679,19 @@ enum evmc_set_option_result
}; };
/** /**
* Configures the EVM instance. * Configures the VM instance.
* *
* Allows modifying options of the EVM instance. * Allows modifying options of the VM instance.
* Options: * Options:
* - code cache behavior: on, off, read-only, ... * - code cache behavior: on, off, read-only, ...
* - optimizations, * - optimizations,
* *
* @param evm The EVM instance to be configured. * @param vm The VM instance to be configured.
* @param name The option name. NULL-terminated string. Cannot be NULL. * @param name The option name. NULL-terminated string. Cannot be NULL.
* @param value The new option value. NULL-terminated string. Cannot be NULL. * @param value The new option value. NULL-terminated string. Cannot be NULL.
* @return The outcome of the operation. * @return The outcome of the operation.
*/ */
typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_instance* evm, typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_vm* vm,
char const* name, char const* name,
char const* value); char const* value);
@ -762,6 +750,7 @@ enum evmc_revision
* The Petersburg revision. * The Petersburg revision.
* *
* Other names: Constantinople2, ConstantinopleFix. * Other names: Constantinople2, ConstantinopleFix.
*
* https://eips.ethereum.org/EIPS/eip-1716 * https://eips.ethereum.org/EIPS/eip-1716
*/ */
EVMC_PETERSBURG = 6, EVMC_PETERSBURG = 6,
@ -773,23 +762,15 @@ enum evmc_revision
*/ */
EVMC_ISTANBUL = 7, EVMC_ISTANBUL = 7,
/**
* The Berlin revision.
*
* The spec draft: https://eips.ethereum.org/EIPS/eip-2070.
*/
EVMC_BERLIN = 8,
/** The maximum EVM revision supported. */ /** The maximum EVM revision supported. */
EVMC_MAX_REVISION = EVMC_ISTANBUL, EVMC_MAX_REVISION = EVMC_BERLIN
/**
* Reserved for the post-Constantinople upgrade.
*
* @deprecated Replaced with ::EVMC_PETERSBURG.
*/
EVMC_CONSTANTINOPLE2 EVMC_DEPRECATED = EVMC_PETERSBURG,
/**
* The latests EVM revision supported.
*
* @deprecated Replaced with ::EVMC_MAX_REVISION.
*/
EVMC_LATEST_REVISION EVMC_DEPRECATED = EVMC_MAX_REVISION
}; };
@ -798,19 +779,22 @@ enum evmc_revision
* *
* This function MAY be invoked multiple times for a single VM instance. * This function MAY be invoked multiple times for a single VM instance.
* *
* @param instance The VM instance. This argument MUST NOT be NULL. * @param vm The VM instance. This argument MUST NOT be NULL.
* @param context The pointer to the Host execution context to be passed * @param host The Host interface. This argument MUST NOT be NULL unless
* to the Host interface methods (::evmc_host_interface). * the @p vm has the ::EVMC_CAPABILITY_PRECOMPILES capability.
* This argument MUST NOT be NULL unless * @param context The opaque pointer to the Host execution context.
* the @p instance has the ::EVMC_CAPABILITY_PRECOMPILES capability. * This argument MAY be NULL. The VM MUST pass the same
* pointer to the methods of the @p host interface.
* The VM MUST NOT dereference the pointer.
* @param rev The requested EVM specification revision. * @param rev The requested EVM specification revision.
* @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL. * @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL.
* @param code The reference to the code to be executed. This argument MAY be NULL. * @param code The reference to the code to be executed. This argument MAY be NULL.
* @param code_size The length of the code. If @p code is NULL this argument MUST be 0. * @param code_size The length of the code. If @p code is NULL this argument MUST be 0.
* @return The execution result. * @return The execution result.
*/ */
typedef struct evmc_result (*evmc_execute_fn)(struct evmc_instance* instance, typedef struct evmc_result (*evmc_execute_fn)(struct evmc_vm* vm,
struct evmc_context* context, const struct evmc_host_interface* host,
struct evmc_host_context* context,
enum evmc_revision rev, enum evmc_revision rev,
const struct evmc_message* msg, const struct evmc_message* msg,
uint8_t const* code, uint8_t const* code,
@ -855,98 +839,20 @@ typedef uint32_t evmc_capabilities_flagset;
* Return the supported capabilities of the VM instance. * Return the supported capabilities of the VM instance.
* *
* This function MAY be invoked multiple times for a single VM instance, * This function MAY be invoked multiple times for a single VM instance,
* and its value MAY be influenced by calls to evmc_instance::set_option. * and its value MAY be influenced by calls to evmc_vm::set_option.
* *
* @param instance The EVM instance. * @param vm The VM instance.
* @return The supported capabilities of the VM. @see evmc_capabilities. * @return The supported capabilities of the VM. @see evmc_capabilities.
*/ */
typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_instance* instance); typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_vm* vm);
/**
* The opaque type representing a Client-side tracer object.
*
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
*/
struct evmc_tracer_context;
/**
* The callback to trace instructions execution in an EVM.
*
* This function informs the Client what instruction has been executed in the EVM implementation
* and what are the results of executing this particular instruction.
* The message level information (like call depth, destination address, etc.) are not provided here.
* This piece of information can be acquired by inspecting messages being sent to the EVM in
* ::evmc_execute_fn and the results of the messages execution.
*
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
*
* @param context The pointer to the Client-side tracing context. This allows to
* implement the tracer in OOP manner.
* @param code_offset The current instruction position in the code.
* @param status_code The status code of the instruction execution.
* @param gas_left The amount of the gas left after the instruction execution.
* @param stack_num_items The current EVM stack height after the instruction execution.
* @param pushed_stack_item The top EVM stack item pushed as the result of the instruction
* execution. This value is null when the instruction does not push
* anything to the stack.
* @param memory_size The size of the EVM memory after the instruction execution.
* @param changed_memory_offset The offset in number of bytes of the beginning of the memory area
* modified as the result of the instruction execution.
* The Client MAY use this information together with
* @p changed_memory_size and @p changed_memory to incrementally
* update the copy of the full VM's memory.
* @param changed_memory_size The size of the memory area modified as the result of
* the instruction execution.
* @param changed_memory The pointer to the memory area modified as the result of
* the instruction execution.
* The Client MAY access the pointed memory area
* (limited by the @p changed_memory_size) only during the current
* execution of the evmc_trace_callback().
* The pointer MUST NOT be stored by the Client.
* The Client MUST NOT assume that
* `changed_memory - changed_memory_offset` is a valid base pointer
* of the VM memory.
*/
typedef void (*evmc_trace_callback)(struct evmc_tracer_context* context,
size_t code_offset,
enum evmc_status_code status_code,
int64_t gas_left,
size_t stack_num_items,
const evmc_uint256be* pushed_stack_item,
size_t memory_size,
size_t changed_memory_offset,
size_t changed_memory_size,
const uint8_t* changed_memory);
/**
* Sets the EVM instruction tracer.
*
* When the tracer is set in the EVM instance, the EVM SHOULD call back the tracer with information
* about instructions execution in the EVM.
* @see ::evmc_trace_callback.
*
* This will overwrite the previous settings (the callback and the context).
*
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
*
* @param instance The EVM instance.
* @param callback The tracer callback function. This argument MAY be NULL to disable previously
* set tracer.
* @param context The Client-side tracer context. This argument MAY be NULL in case the tracer
* does not require any context. This argument MUST be NULL if the callback
* argument is NULL.
*/
typedef void (*evmc_set_tracer_fn)(struct evmc_instance* instance,
evmc_trace_callback callback,
struct evmc_tracer_context* context);
/** /**
* The EVM instance. * The VM instance.
* *
* Defines the base struct of the VM implementation. * Defines the base struct of the VM implementation.
*/ */
struct evmc_instance struct evmc_vm
{ {
/** /**
* EVMC ABI version implemented by the VM instance. * EVMC ABI version implemented by the VM instance.
@ -973,14 +879,14 @@ struct evmc_instance
const char* version; const char* version;
/** /**
* Pointer to function destroying the EVM instance. * Pointer to function destroying the VM instance.
* *
* This is a mandatory method and MUST NOT be set to NULL. * This is a mandatory method and MUST NOT be set to NULL.
*/ */
evmc_destroy_fn destroy; evmc_destroy_fn destroy;
/** /**
* Pointer to function executing a code by the EVM instance. * Pointer to function executing a code by the VM instance.
* *
* This is a mandatory method and MUST NOT be set to NULL. * This is a mandatory method and MUST NOT be set to NULL.
*/ */
@ -998,17 +904,6 @@ struct evmc_instance
*/ */
evmc_get_capabilities_fn get_capabilities; evmc_get_capabilities_fn get_capabilities;
/**
* Optional pointer to function setting the EVM instruction tracer.
*
* If the EVM does not support this feature the pointer can be NULL.
*
* @deprecated
* Since EVMC 6.3, the tracing API has been deprecated as there have been some
* design flaws discovered. New API is expected to be introduced in future.
*/
evmc_set_tracer_fn set_tracer;
/** /**
* Optional pointer to function modifying VM's options. * Optional pointer to function modifying VM's options.
* *
@ -1033,9 +928,9 @@ struct evmc_instance
* For example, the shared library with the "beta-interpreter" implementation may be named * For example, the shared library with the "beta-interpreter" implementation may be named
* `libbeta-interpreter.so`. * `libbeta-interpreter.so`.
* *
* @return EVM instance or NULL indicating instance creation failure. * @return The VM instance or NULL indicating instance creation failure.
*/ */
struct evmc_instance* evmc_create_example_vm(void); struct evmc_vm* evmc_create_example_vm(void);
#endif #endif
#if __cplusplus #if __cplusplus

View File

@ -334,49 +334,46 @@ public:
} }
}; };
/// @copybrief evmc_instance class Host;
/// @copybrief evmc_vm
/// ///
/// This is a RAII wrapper for evmc_instance and objects of this type /// This is a RAII wrapper for evmc_vm and objects of this type
/// automatically destroys the VM instance. /// automatically destroys the VM instance.
class vm class VM
{ {
public: public:
vm() noexcept = default; VM() noexcept = default;
/// Converting constructor from evmc_instance. /// Converting constructor from evmc_vm.
explicit vm(evmc_instance* instance) noexcept : m_instance{instance} {} explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {}
/// Destructor responsible for automatically destroying the VM instance. /// Destructor responsible for automatically destroying the VM instance.
~vm() noexcept ~VM() noexcept
{ {
if (m_instance) if (m_instance)
m_instance->destroy(m_instance); m_instance->destroy(m_instance);
} }
vm(const vm&) = delete; VM(const VM&) = delete;
vm& operator=(const vm&) = delete; VM& operator=(const VM&) = delete;
/// Move constructor. /// Move constructor.
vm(vm&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; } VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; }
/// Move assignment operator. /// Move assignment operator.
vm& operator=(vm&& other) noexcept VM& operator=(VM&& other) noexcept
{ {
this->~vm(); this->~VM();
m_instance = other.m_instance; m_instance = other.m_instance;
other.m_instance = nullptr; other.m_instance = nullptr;
return *this; return *this;
} }
/// The constructor that captures a VM instance and configures the instance /// The constructor that captures a VM instance and configures the instance
/// with provided list of options. /// with the provided list of options.
vm(evmc_instance* instance, inline VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept std::initializer_list<std::pair<const char*, const char*>> options) noexcept;
: m_instance{instance}
{
for (auto option : options)
set_option(option.first, option.second);
}
/// Checks if contains a valid pointer to the VM instance. /// Checks if contains a valid pointer to the VM instance.
explicit operator bool() const noexcept { return m_instance != nullptr; } explicit operator bool() const noexcept { return m_instance != nullptr; }
@ -384,13 +381,13 @@ public:
/// Checks whenever the VM instance is ABI compatible with the current EVMC API. /// Checks whenever the VM instance is ABI compatible with the current EVMC API.
bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; } bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
/// @copydoc evmc_instance::name /// @copydoc evmc_vm::name
char const* name() const noexcept { return m_instance->name; } char const* name() const noexcept { return m_instance->name; }
/// @copydoc evmc_instance::version /// @copydoc evmc_vm::version
char const* version() const noexcept { return m_instance->version; } char const* version() const noexcept { return m_instance->version; }
/// @copydoc evmc::instance::get_capabilities /// @copydoc evmc::vm::get_capabilities
evmc_capabilities_flagset get_capabilities() const noexcept evmc_capabilities_flagset get_capabilities() const noexcept
{ {
return m_instance->get_capabilities(m_instance); return m_instance->get_capabilities(m_instance);
@ -403,19 +400,53 @@ public:
} }
/// @copydoc evmc_execute() /// @copydoc evmc_execute()
result execute(evmc_context& ctx, result execute(const evmc_host_interface& host,
evmc_host_context* ctx,
evmc_revision rev, evmc_revision rev,
const evmc_message& msg, const evmc_message& msg,
const uint8_t* code, const uint8_t* code,
size_t code_size) noexcept size_t code_size) noexcept
{ {
return result{m_instance->execute(m_instance, &ctx, rev, &msg, code, code_size)}; return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)};
}
/// Convenient variant of the VM::execute() that takes reference to evmc::Host class.
inline result execute(Host& host,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept;
/// Executes code without the Host context.
///
/// The same as
/// execute(const evmc_host_interface&, evmc_host_context*, evmc_revision,
/// const evmc_message&, const uint8_t*, size_t),
/// but without providing the Host context and interface.
/// This method is for experimental precompiles support where execution is
/// guaranteed not to require any Host access.
result execute(evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return result{
m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)};
} }
private: private:
evmc_instance* m_instance = nullptr; evmc_vm* m_instance = nullptr;
}; };
inline VM::VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept
: m_instance{vm}
{
for (const auto& option : options)
set_option(option.first, option.second);
}
/// The EVMC Host interface /// The EVMC Host interface
class HostInterface class HostInterface
{ {
@ -471,46 +502,52 @@ public:
/// Wrapper around EVMC host context / host interface. /// Wrapper around EVMC host context / host interface.
/// ///
/// To be used by VM implementations as better alternative to using ::evmc_context directly. /// To be used by VM implementations as better alternative to using ::evmc_host_context directly.
class HostContext : public HostInterface class HostContext : public HostInterface
{ {
evmc_context* context = nullptr; const evmc_host_interface* host = nullptr;
evmc_host_context* context = nullptr;
evmc_tx_context tx_context = {}; evmc_tx_context tx_context = {};
public: public:
/// Implicit converting constructor from evmc_context. /// Default constructor for null Host context.
HostContext(evmc_context* ctx) noexcept : context{ctx} {} // NOLINT HostContext() = default;
/// Constructor from the EVMC Host primitives.
HostContext(const evmc_host_interface* interface, evmc_host_context* ctx) noexcept
: host{interface}, context{ctx}
{}
bool account_exists(const address& address) noexcept final bool account_exists(const address& address) noexcept final
{ {
return context->host->account_exists(context, &address); return host->account_exists(context, &address);
} }
bytes32 get_storage(const address& address, const bytes32& key) noexcept final bytes32 get_storage(const address& address, const bytes32& key) noexcept final
{ {
return context->host->get_storage(context, &address, &key); return host->get_storage(context, &address, &key);
} }
evmc_storage_status set_storage(const address& address, evmc_storage_status set_storage(const address& address,
const bytes32& key, const bytes32& key,
const bytes32& value) noexcept final const bytes32& value) noexcept final
{ {
return context->host->set_storage(context, &address, &key, &value); return host->set_storage(context, &address, &key, &value);
} }
uint256be get_balance(const address& address) noexcept final uint256be get_balance(const address& address) noexcept final
{ {
return context->host->get_balance(context, &address); return host->get_balance(context, &address);
} }
size_t get_code_size(const address& address) noexcept final size_t get_code_size(const address& address) noexcept final
{ {
return context->host->get_code_size(context, &address); return host->get_code_size(context, &address);
} }
bytes32 get_code_hash(const address& address) noexcept final bytes32 get_code_hash(const address& address) noexcept final
{ {
return context->host->get_code_hash(context, &address); return host->get_code_hash(context, &address);
} }
size_t copy_code(const address& address, size_t copy_code(const address& address,
@ -518,17 +555,17 @@ public:
uint8_t* buffer_data, uint8_t* buffer_data,
size_t buffer_size) noexcept final size_t buffer_size) noexcept final
{ {
return context->host->copy_code(context, &address, code_offset, buffer_data, buffer_size); return host->copy_code(context, &address, code_offset, buffer_data, buffer_size);
} }
void selfdestruct(const address& addr, const address& beneficiary) noexcept final void selfdestruct(const address& addr, const address& beneficiary) noexcept final
{ {
context->host->selfdestruct(context, &addr, &beneficiary); host->selfdestruct(context, &addr, &beneficiary);
} }
result call(const evmc_message& message) noexcept final result call(const evmc_message& message) noexcept final
{ {
return result{context->host->call(context, &message)}; return result{host->call(context, &message)};
} }
/// @copydoc HostInterface::get_tx_context() /// @copydoc HostInterface::get_tx_context()
@ -540,13 +577,13 @@ public:
evmc_tx_context get_tx_context() noexcept final evmc_tx_context get_tx_context() noexcept final
{ {
if (tx_context.block_timestamp == 0) if (tx_context.block_timestamp == 0)
tx_context = context->host->get_tx_context(context); tx_context = host->get_tx_context(context);
return tx_context; return tx_context;
} }
bytes32 get_block_hash(int64_t number) noexcept final bytes32 get_block_hash(int64_t number) noexcept final
{ {
return context->host->get_block_hash(context, number); return host->get_block_hash(context, number);
} }
void emit_log(const address& addr, void emit_log(const address& addr,
@ -555,7 +592,7 @@ public:
const bytes32 topics[], const bytes32 topics[],
size_t topics_count) noexcept final size_t topics_count) noexcept final
{ {
context->host->emit_log(context, &addr, data, data_size, topics, topics_count); host->emit_log(context, &addr, data, data_size, topics, topics_count);
} }
}; };
@ -563,89 +600,135 @@ public:
/// ///
/// When implementing EVMC Host, you can directly inherit from the evmc::Host class. /// When implementing EVMC Host, you can directly inherit from the evmc::Host class.
/// This way your implementation will be simpler by avoiding manual handling /// This way your implementation will be simpler by avoiding manual handling
/// of the ::evmc_context and the ::evmc_context::host. /// of the ::evmc_host_context and the ::evmc_host_interface.
class Host : public HostInterface, public evmc_context class Host : public HostInterface
{ {
public: public:
inline Host() noexcept; /// Provides access to the global host interface.
/// @returns Reference to the host interface object.
static const evmc_host_interface& get_interface() noexcept;
/// Converts the Host object to the opaque host context pointer.
/// @returns Pointer to evmc_host_context.
evmc_host_context* to_context() noexcept { return reinterpret_cast<evmc_host_context*>(this); }
/// Converts the opaque host context pointer back to the original Host object.
/// @tparam DerivedClass The class derived from the Host class.
/// @param context The opaque host context pointer.
/// @returns The pointer to DerivedClass.
template <typename DerivedClass = Host>
static DerivedClass* from_context(evmc_host_context* context) noexcept
{
// Get pointer of the Host base class.
auto* h = reinterpret_cast<Host*>(context);
// Additional downcast, only possible if DerivedClass inherits from Host.
return static_cast<DerivedClass*>(h);
}
}; };
inline result VM::execute(Host& host,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size);
}
namespace internal namespace internal
{ {
inline bool account_exists(evmc_context* h, const evmc_address* addr) noexcept inline bool account_exists(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->account_exists(*addr); return Host::from_context(h)->account_exists(*addr);
} }
inline evmc_bytes32 get_storage(evmc_context* h,
inline evmc_bytes32 get_storage(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const evmc_bytes32* key) noexcept const evmc_bytes32* key) noexcept
{ {
return static_cast<Host*>(h)->get_storage(*addr, *key); return Host::from_context(h)->get_storage(*addr, *key);
} }
inline evmc_storage_status set_storage(evmc_context* h,
inline evmc_storage_status set_storage(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const evmc_bytes32* key, const evmc_bytes32* key,
const evmc_bytes32* value) noexcept const evmc_bytes32* value) noexcept
{ {
return static_cast<Host*>(h)->set_storage(*addr, *key, *value); return Host::from_context(h)->set_storage(*addr, *key, *value);
} }
inline evmc_uint256be get_balance(evmc_context* h, const evmc_address* addr) noexcept
inline evmc_uint256be get_balance(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->get_balance(*addr); return Host::from_context(h)->get_balance(*addr);
} }
inline size_t get_code_size(evmc_context* h, const evmc_address* addr) noexcept
inline size_t get_code_size(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->get_code_size(*addr); return Host::from_context(h)->get_code_size(*addr);
} }
inline evmc_bytes32 get_code_hash(evmc_context* h, const evmc_address* addr) noexcept
inline evmc_bytes32 get_code_hash(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->get_code_hash(*addr); return Host::from_context(h)->get_code_hash(*addr);
} }
inline size_t copy_code(evmc_context* h,
inline size_t copy_code(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
size_t code_offset, size_t code_offset,
uint8_t* buffer_data, uint8_t* buffer_data,
size_t buffer_size) noexcept size_t buffer_size) noexcept
{ {
return static_cast<Host*>(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); return Host::from_context(h)->copy_code(*addr, code_offset, buffer_data, buffer_size);
} }
inline void selfdestruct(evmc_context* h,
inline void selfdestruct(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const evmc_address* beneficiary) noexcept const evmc_address* beneficiary) noexcept
{ {
static_cast<Host*>(h)->selfdestruct(*addr, *beneficiary); Host::from_context(h)->selfdestruct(*addr, *beneficiary);
} }
inline evmc_result call(evmc_context* h, const evmc_message* msg) noexcept
inline evmc_result call(evmc_host_context* h, const evmc_message* msg) noexcept
{ {
return static_cast<Host*>(h)->call(*msg).release_raw(); return Host::from_context(h)->call(*msg).release_raw();
} }
inline evmc_tx_context get_tx_context(evmc_context* h) noexcept
inline evmc_tx_context get_tx_context(evmc_host_context* h) noexcept
{ {
return static_cast<Host*>(h)->get_tx_context(); return Host::from_context(h)->get_tx_context();
} }
inline evmc_bytes32 get_block_hash(evmc_context* h, int64_t block_number) noexcept
inline evmc_bytes32 get_block_hash(evmc_host_context* h, int64_t block_number) noexcept
{ {
return static_cast<Host*>(h)->get_block_hash(block_number); return Host::from_context(h)->get_block_hash(block_number);
} }
inline void emit_log(evmc_context* h,
inline void emit_log(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const uint8_t* data, const uint8_t* data,
size_t data_size, size_t data_size,
const evmc_bytes32 topics[], const evmc_bytes32 topics[],
size_t num_topics) noexcept size_t num_topics) noexcept
{ {
static_cast<Host*>(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics), Host::from_context(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics),
num_topics); num_topics);
} }
constexpr evmc_host_interface interface{
account_exists, get_storage, set_storage, get_balance, get_code_size, get_code_hash,
copy_code, selfdestruct, call, get_tx_context, get_block_hash, emit_log,
};
} // namespace internal } // namespace internal
inline Host::Host() noexcept : evmc_context{&evmc::internal::interface} {} inline const evmc_host_interface& Host::get_interface() noexcept
{
static constexpr evmc_host_interface interface{
::evmc::internal::account_exists, ::evmc::internal::get_storage,
::evmc::internal::set_storage, ::evmc::internal::get_balance,
::evmc::internal::get_code_size, ::evmc::internal::get_code_hash,
::evmc::internal::copy_code, ::evmc::internal::selfdestruct,
::evmc::internal::call, ::evmc::internal::get_tx_context,
::evmc::internal::get_block_hash, ::evmc::internal::emit_log};
return interface;
}
} // namespace evmc } // namespace evmc

View File

@ -22,36 +22,35 @@
#include <string.h> #include <string.h>
/** /**
* Returns true if the VM instance has a compatible ABI version. * Returns true if the VM has a compatible ABI version.
*/ */
static inline int evmc_is_abi_compatible(struct evmc_instance* instance) static inline bool evmc_is_abi_compatible(struct evmc_vm* vm)
{ {
return instance->abi_version == EVMC_ABI_VERSION; return vm->abi_version == EVMC_ABI_VERSION;
} }
/** /**
* Returns the name of the VM instance. * Returns the name of the VM.
*/ */
static inline const char* evmc_vm_name(struct evmc_instance* instance) static inline const char* evmc_vm_name(struct evmc_vm* vm)
{ {
return instance->name; return vm->name;
} }
/** /**
* Returns the version of the VM instance. * Returns the version of the VM.
*/ */
static inline const char* evmc_vm_version(struct evmc_instance* instance) static inline const char* evmc_vm_version(struct evmc_vm* vm)
{ {
return instance->version; return vm->version;
} }
/** /**
* Checks if the VM instance has the given capability. * Checks if the VM has the given capability.
* *
* @see evmc_get_capabilities_fn * @see evmc_get_capabilities_fn
*/ */
static inline bool evmc_vm_has_capability(struct evmc_instance* vm, static inline bool evmc_vm_has_capability(struct evmc_vm* vm, enum evmc_capabilities capability)
enum evmc_capabilities capability)
{ {
return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0; return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0;
} }
@ -61,52 +60,39 @@ static inline bool evmc_vm_has_capability(struct evmc_instance* vm,
* *
* @see evmc_destroy_fn * @see evmc_destroy_fn
*/ */
static inline void evmc_destroy(struct evmc_instance* instance) static inline void evmc_destroy(struct evmc_vm* vm)
{ {
instance->destroy(instance); vm->destroy(vm);
} }
/** /**
* Sets the option for the VM instance, if the feature is supported by the VM. * Sets the option for the VM, if the feature is supported by the VM.
* *
* @see evmc_set_option_fn * @see evmc_set_option_fn
*/ */
static inline enum evmc_set_option_result evmc_set_option(struct evmc_instance* instance, static inline enum evmc_set_option_result evmc_set_option(struct evmc_vm* vm,
char const* name, char const* name,
char const* value) char const* value)
{ {
if (instance->set_option) if (vm->set_option)
return instance->set_option(instance, name, value); return vm->set_option(vm, name, value);
return EVMC_SET_OPTION_INVALID_NAME; return EVMC_SET_OPTION_INVALID_NAME;
} }
/**
* Sets the tracer callback for the VM instance, if the feature is supported by the VM.
*
* @see evmc_set_tracer_fn
*/
EVMC_DEPRECATED
static inline void evmc_set_tracer(struct evmc_instance* instance,
evmc_trace_callback callback,
struct evmc_tracer_context* context)
{
if (instance->set_tracer)
instance->set_tracer(instance, callback, context);
}
/** /**
* Executes code in the VM instance. * Executes code in the VM instance.
* *
* @see evmc_execute_fn. * @see evmc_execute_fn.
*/ */
static inline struct evmc_result evmc_execute(struct evmc_instance* instance, static inline struct evmc_result evmc_execute(struct evmc_vm* vm,
struct evmc_context* context, const struct evmc_host_interface* host,
struct evmc_host_context* context,
enum evmc_revision rev, enum evmc_revision rev,
const struct evmc_message* msg, const struct evmc_message* msg,
uint8_t const* code, uint8_t const* code,
size_t code_size) size_t code_size)
{ {
return instance->execute(instance, context, rev, msg, code, code_size); return vm->execute(vm, host, context, rev, msg, code, code_size);
} }
/// The evmc_result release function using free() for releasing the memory. /// The evmc_result release function using free() for releasing the memory.

View File

@ -152,8 +152,8 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
char* base_name = prefixed_name + prefix_length; char* base_name = prefixed_name + prefix_length;
strcpy_sx(base_name, PATH_MAX_LENGTH, name_pos); strcpy_sx(base_name, PATH_MAX_LENGTH, name_pos);
// Trim the file extension. // Trim all file extensions.
char* ext_pos = strrchr(prefixed_name, '.'); char* ext_pos = strchr(prefixed_name, '.');
if (ext_pos) if (ext_pos)
*ext_pos = 0; *ext_pos = 0;
@ -163,15 +163,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
*dash_pos++ = '_'; *dash_pos++ = '_';
// Search for the built function name. // Search for the built function name.
while ((create_fn = DLL_GET_CREATE_FN(handle, prefixed_name)) == NULL) create_fn = DLL_GET_CREATE_FN(handle, prefixed_name);
{
// Shorten the base name by skipping the `word_` segment.
const char* shorter_name_pos = strchr(base_name, '_');
if (!shorter_name_pos)
break;
memmove(base_name, shorter_name_pos + 1, strlen(shorter_name_pos) + 1);
}
if (!create_fn) if (!create_fn)
create_fn = DLL_GET_CREATE_FN(handle, "evmc_create"); create_fn = DLL_GET_CREATE_FN(handle, "evmc_create");
@ -196,8 +188,7 @@ const char* evmc_last_error_msg()
return m; return m;
} }
struct evmc_instance* evmc_load_and_create(const char* filename, struct evmc_vm* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code)
enum evmc_loader_error_code* error_code)
{ {
// First load the DLL. This also resets the last_error_msg; // First load the DLL. This also resets the last_error_msg;
evmc_create_fn create_fn = evmc_load(filename, error_code); evmc_create_fn create_fn = evmc_load(filename, error_code);
@ -207,21 +198,21 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS; enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
struct evmc_instance* instance = create_fn(); struct evmc_vm* vm = create_fn();
if (!instance) if (!vm)
{ {
ec = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE, ec = set_error(EVMC_LOADER_VM_CREATION_FAILURE, "creating EVMC VM of %s has failed",
"creating EVMC instance of %s has failed", filename); filename);
goto exit; goto exit;
} }
if (!evmc_is_abi_compatible(instance)) if (!evmc_is_abi_compatible(vm))
{ {
ec = 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); vm->abi_version, filename, EVMC_ABI_VERSION);
evmc_destroy(instance); evmc_destroy(vm);
instance = NULL; vm = NULL;
goto exit; goto exit;
} }
@ -229,7 +220,7 @@ exit:
if (error_code) if (error_code)
*error_code = ec; *error_code = ec;
return instance; return vm;
} }
/// Gets the token delimited by @p delim character of the string pointed by the @p str_ptr. /// Gets the token delimited by @p delim character of the string pointed by the @p str_ptr.
@ -255,11 +246,10 @@ static char* get_token(char** str_ptr, char delim)
return str; return str;
} }
struct evmc_instance* evmc_load_and_configure(const char* config, struct evmc_vm* evmc_load_and_configure(const char* config, enum evmc_loader_error_code* error_code)
enum evmc_loader_error_code* error_code)
{ {
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS; enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
struct evmc_instance* instance = NULL; struct evmc_vm* vm = NULL;
char config_copy_buffer[PATH_MAX_LENGTH]; char config_copy_buffer[PATH_MAX_LENGTH];
if (strcpy_sx(config_copy_buffer, sizeof(config_copy_buffer), config) != 0) if (strcpy_sx(config_copy_buffer, sizeof(config_copy_buffer), config) != 0)
@ -273,14 +263,14 @@ struct evmc_instance* evmc_load_and_configure(const char* config,
char* options = config_copy_buffer; char* options = config_copy_buffer;
const char* path = get_token(&options, ','); const char* path = get_token(&options, ',');
instance = evmc_load_and_create(path, error_code); vm = evmc_load_and_create(path, error_code);
if (!instance) if (!vm)
return NULL; return NULL;
if (instance->set_option == NULL && strlen(options) != 0) if (vm->set_option == NULL && strlen(options) != 0)
{ {
ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s) does not support any options", ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s) does not support any options",
instance->name, path); vm->name, path);
goto exit; goto exit;
} }
@ -293,18 +283,18 @@ struct evmc_instance* evmc_load_and_configure(const char* config,
// The option variable will have the value, can be empty. // The option variable will have the value, can be empty.
const char* name = get_token(&option, '='); const char* name = get_token(&option, '=');
enum evmc_set_option_result r = instance->set_option(instance, name, option); enum evmc_set_option_result r = vm->set_option(vm, name, option);
switch (r) switch (r)
{ {
case EVMC_SET_OPTION_SUCCESS: case EVMC_SET_OPTION_SUCCESS:
break; break;
case EVMC_SET_OPTION_INVALID_NAME: case EVMC_SET_OPTION_INVALID_NAME:
ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s): unknown option '%s'", ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s): unknown option '%s'",
instance->name, path, name); vm->name, path, name);
goto exit; goto exit;
case EVMC_SET_OPTION_INVALID_VALUE: case EVMC_SET_OPTION_INVALID_VALUE:
ec = set_error(EVMC_LOADER_INVALID_OPTION_VALUE, ec = set_error(EVMC_LOADER_INVALID_OPTION_VALUE,
"%s (%s): unsupported value '%s' for option '%s'", instance->name, path, "%s (%s): unsupported value '%s' for option '%s'", vm->name, path,
option, name); option, name);
goto exit; goto exit;
} }
@ -315,9 +305,9 @@ exit:
*error_code = ec; *error_code = ec;
if (ec == EVMC_LOADER_SUCCESS) if (ec == EVMC_LOADER_SUCCESS)
return instance; return vm;
if (instance) if (vm)
evmc_destroy(instance); evmc_destroy(vm);
return NULL; return NULL;
} }

View File

@ -19,7 +19,7 @@ extern "C" {
#endif #endif
/** The function pointer type for EVMC create functions. */ /** The function pointer type for EVMC create functions. */
typedef struct evmc_instance* (*evmc_create_fn)(void); typedef struct evmc_vm* (*evmc_create_fn)(void);
/** Error codes for the EVMC loader. */ /** Error codes for the EVMC loader. */
enum evmc_loader_error_code enum evmc_loader_error_code
@ -37,7 +37,7 @@ enum evmc_loader_error_code
EVMC_LOADER_INVALID_ARGUMENT = 3, EVMC_LOADER_INVALID_ARGUMENT = 3,
/** The creation of a VM instance has failed. */ /** The creation of a VM instance has failed. */
EVMC_LOADER_INSTANCE_CREATION_FAILURE = 4, EVMC_LOADER_VM_CREATION_FAILURE = 4,
/** The ABI version of the VM instance has mismatched. */ /** The ABI version of the VM instance has mismatched. */
EVMC_LOADER_ABI_VERSION_MISMATCH = 5, EVMC_LOADER_ABI_VERSION_MISMATCH = 5,
@ -61,21 +61,16 @@ enum evmc_loader_error_code
* After the DLL is successfully loaded the function tries to find the EVM create function in the * After the DLL is successfully loaded the function tries to find the EVM create function in the
* library. The `filename` is used to guess the EVM name and the name of the create function. * library. The `filename` is used to guess the EVM name and the name of the create function.
* The create function name is constructed by the following rules. Consider example path: * The create function name is constructed by the following rules. Consider example path:
* "/ethereum/libexample-interpreter.so". * "/ethereum/libexample-interpreter.so.1.0".
* - the filename is taken from the path: * - the filename is taken from the path:
* "libexample-interpreter.so", * "libexample-interpreter.so.1.0",
* - the "lib" prefix and file extension are stripped from the name: * - the "lib" prefix and all file extensions are stripped from the name:
* "example-interpreter" * "example-interpreter"
* - all "-" are replaced with "_" to construct _base name_: * - all "-" are replaced with "_" to construct _base name_:
* "example_interpreter", * "example_interpreter",
* - the function name "evmc_create_" + _base name_ is searched in the library: * - the function name "evmc_create_" + _base name_ is searched in the library:
* "evmc_create_example_interpreter", * "evmc_create_example_interpreter",
* - if function not found, the _base name_ is shorten by skipping the first word separated by "_": * - if the function is not found, the function name "evmc_create" is searched in the library.
* "interpreter",
* - then, the function of the shorter name "evmc_create_" + _base name_ is searched in the library:
* "evmc_create_interpreter",
* - the name shortening continues until a function is found or the name cannot be shorten more,
* - lastly, when no function found, the function name "evmc_create" is searched in the library.
* *
* If the create function is found in the library, the pointer to the function is returned. * If the create function is found in the library, the pointer to the function is returned.
* Otherwise, the ::EVMC_LOADER_SYMBOL_NOT_FOUND error code is signaled and NULL is returned. * Otherwise, the ::EVMC_LOADER_SYMBOL_NOT_FOUND error code is signaled and NULL is returned.
@ -98,7 +93,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
* *
* 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:
* - ::EVMC_LOADER_INSTANCE_CREATION_FAILURE when the create function returns NULL, * - ::EVMC_LOADER_VM_CREATION_FAILURE when the create function returns NULL,
* - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different * - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different
* from the ABI version of this library (::EVMC_ABI_VERSION). * from the ABI version of this library (::EVMC_ABI_VERSION).
* *
@ -114,8 +109,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
* ::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 created VM or NULL in case of error. * @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_vm* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code);
enum evmc_loader_error_code* error_code);
/** /**
* Dynamically loads the EVMC module, then creates and configures the VM instance. * Dynamically loads the EVMC module, then creates and configures the VM instance.
@ -151,7 +145,7 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
* ::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 created VM or NULL in case of error. * @return The pointer to the created VM or NULL in case of error.
*/ */
struct evmc_instance* evmc_load_and_configure(const char* config, struct evmc_vm* evmc_load_and_configure(const char* config,
enum evmc_loader_error_code* error_code); enum evmc_loader_error_code* error_code);
/** /**

View File

@ -35,6 +35,8 @@ library MerkleProof {
// ---- // ----
// Warning: (755-767): Assertion checker does not yet support this expression. // Warning: (755-767): Assertion checker does not yet support this expression.
// Warning: (988-991): Assertion checker does not yet implement type abi
// Warning: (988-1032): Assertion checker does not yet implement this type of function call. // Warning: (988-1032): Assertion checker does not yet implement this type of function call.
// Warning: (1175-1178): Assertion checker does not yet implement type abi
// Warning: (1175-1219): Assertion checker does not yet implement this type of function call. // Warning: (1175-1219): Assertion checker does not yet implement this type of function call.
// Warning: (755-767): Assertion checker does not yet support this expression. // Warning: (755-767): Assertion checker does not yet support this expression.

View File

@ -83,7 +83,7 @@ contract InternalCall {
// Warning: (1144-1206): Function state mutability can be restricted to pure // Warning: (1144-1206): Function state mutability can be restricted to pure
// Warning: (1212-1274): Function state mutability can be restricted to pure // Warning: (1212-1274): Function state mutability can be restricted to pure
// Warning: (1280-1342): Function state mutability can be restricted to pure // Warning: (1280-1342): Function state mutability can be restricted to pure
// Warning: (771-774): Assertion checker does not yet implement type abi
// Warning: (782-813): Type conversion is not yet fully supported and might yield false positives. // Warning: (782-813): Type conversion is not yet fully supported and might yield false positives.
// Warning: (771-814): Assertion checker does not yet implement this type of function call. // Warning: (771-814): Assertion checker does not yet implement this type of function call.
// Warning: (825-830): Assertion checker does not yet support the type of this variable.
// Warning: (1403-1408): Assertion checker does not yet implement this type of function call. // Warning: (1403-1408): Assertion checker does not yet implement this type of function call.

View File

@ -9,5 +9,6 @@ contract C {
// ---- // ----
// Warning: (133-143): Unused local variable. // Warning: (133-143): Unused local variable.
// Warning: (133-143): Assertion checker does not yet support the type of this variable. // Warning: (133-143): Assertion checker does not yet support the type of this variable.
// Warning: (146-147): Assertion checker does not yet implement type type(struct C.A storage pointer)
// Warning: (146-163): Assertion checker does not yet implement type struct C.A memory // Warning: (146-163): Assertion checker does not yet implement type struct C.A memory
// Warning: (146-163): Assertion checker does not yet implement this expression. // Warning: (146-163): Assertion checker does not yet implement this expression.

View File

@ -6,5 +6,7 @@ contract C {
} }
// ---- // ----
// Warning: (31-64): Experimental features are turned on. Do not use experimental features on live deployments. // Warning: (31-64): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (162-165): Assertion checker does not yet implement type abi
// Warning: (162-176): Assertion checker does not yet implement this type of function call. // Warning: (162-176): Assertion checker does not yet implement this type of function call.
// Warning: (178-181): Assertion checker does not yet implement type abi
// Warning: (178-203): Assertion checker does not yet implement this type of function call. // Warning: (178-203): Assertion checker does not yet implement this type of function call.

View File

@ -16,3 +16,5 @@ contract C
assert(y < 10000); assert(y < 10000);
} }
} }
// ----
// Warning: (228-229): Assertion checker does not yet implement type type(library L)

View File

@ -17,4 +17,5 @@ contract C
} }
} }
// ---- // ----
// Warning: (228-229): Assertion checker does not yet implement type type(library L)
// Warning: (245-261): Assertion violation happens here // Warning: (245-261): Assertion violation happens here

View File

@ -0,0 +1,15 @@
pragma experimental SMTChecker;
pragma experimental "ABIEncoderV2";
contract C {
struct S { uint x; uint[] b; }
function f() public pure returns (S memory, bytes memory) {
return abi.decode("abc", (S, bytes));
}
}
// ----
// Warning: (32-67): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (151-159): Assertion checker does not yet support the type of this variable.
// Warning: (188-191): Assertion checker does not yet implement type abi
// Warning: (207-208): Assertion checker does not yet implement type type(struct C.S storage pointer)
// Warning: (188-217): Assertion checker does not yet implement this type of function call.

View File

@ -0,0 +1,20 @@
pragma experimental SMTChecker;
pragma experimental "ABIEncoderV2";
contract C {
function f() public pure {
(uint x1, bool b1) = abi.decode("abc", (uint, bool));
(uint x2, bool b2) = abi.decode("abc", (uint, bool));
// False positive until abi.* are implemented as uninterpreted functions.
assert(x1 == x2);
}
}
// ----
// Warning: (32-67): Experimental features are turned on. Do not use experimental features on live deployments.
// Warning: (125-132): Unused local variable.
// Warning: (183-190): Unused local variable.
// Warning: (136-139): Assertion checker does not yet implement type abi
// Warning: (136-167): Assertion checker does not yet implement this type of function call.
// Warning: (194-197): Assertion checker does not yet implement type abi
// Warning: (194-225): Assertion checker does not yet implement this type of function call.
// Warning: (303-319): Assertion violation happens here

View File

@ -0,0 +1,24 @@
pragma experimental SMTChecker;
contract C {
function f() public pure {
(uint a1, bytes32 b1, C c1) = abi.decode("abc", (uint, bytes32, C));
(uint a2, bytes32 b2, C c2) = abi.decode("abc", (uint, bytes32, C));
// False positive until abi.* are implemented as uninterpreted functions.
assert(a1 == a2);
assert(a1 != a2);
}
}
// ----
// Warning: (88-98): Unused local variable.
// Warning: (100-104): Unused local variable.
// Warning: (161-171): Unused local variable.
// Warning: (173-177): Unused local variable.
// Warning: (108-111): Assertion checker does not yet implement type abi
// Warning: (142-143): Assertion checker does not yet implement type type(contract C)
// Warning: (108-145): Assertion checker does not yet implement this type of function call.
// Warning: (181-184): Assertion checker does not yet implement type abi
// Warning: (215-216): Assertion checker does not yet implement type type(contract C)
// Warning: (181-218): Assertion checker does not yet implement this type of function call.
// Warning: (296-312): Assertion violation happens here
// Warning: (315-331): Assertion violation happens here

View File

@ -10,5 +10,6 @@ contract C
} }
} }
// ---- // ----
// Warning: (132-133): Assertion checker does not yet implement type type(enum C.D)
// Warning: (132-136): Type conversion is not yet fully supported and might yield false positives. // Warning: (132-136): Type conversion is not yet fully supported and might yield false positives.
// Warning: (140-160): Assertion violation happens here // Warning: (140-160): Assertion violation happens here

View File

@ -20,3 +20,6 @@ contract C
// ---- // ----
// Warning: (224-240): Unused local variable. // Warning: (224-240): Unused local variable.
// Warning: (260-275): Assertion violation happens here // Warning: (260-275): Assertion violation happens here
// Warning: (279-293): Assertion violation happens here
// Warning: (297-316): Assertion violation happens here
// Warning: (320-344): Assertion violation happens here

View File

@ -20,3 +20,6 @@ contract C
// ---- // ----
// Warning: (224-240): Unused local variable. // Warning: (224-240): Unused local variable.
// Warning: (268-283): Assertion violation happens here // Warning: (268-283): Assertion violation happens here
// Warning: (287-301): Assertion violation happens here
// Warning: (305-324): Assertion violation happens here
// Warning: (328-352): Assertion violation happens here

View File

@ -20,3 +20,6 @@ contract C
// ---- // ----
// Warning: (224-240): Unused local variable. // Warning: (224-240): Unused local variable.
// Warning: (266-281): Assertion violation happens here // Warning: (266-281): Assertion violation happens here
// Warning: (285-299): Assertion violation happens here
// Warning: (303-322): Assertion violation happens here
// Warning: (326-350): Assertion violation happens here

View File

@ -17,8 +17,10 @@ contract C
// Warning: (157-170): Unused local variable. // Warning: (157-170): Unused local variable.
// Warning: (157-170): Assertion checker does not yet support the type of this variable. // Warning: (157-170): Assertion checker does not yet support the type of this variable.
// Warning: (139-146): Assertion checker does not yet implement type struct C.S storage ref // Warning: (139-146): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (149-150): Assertion checker does not yet implement type type(struct C.S storage pointer)
// Warning: (149-153): Assertion checker does not yet implement type struct C.S memory // Warning: (149-153): Assertion checker does not yet implement type struct C.S memory
// Warning: (149-153): Assertion checker does not yet implement this expression. // Warning: (149-153): Assertion checker does not yet implement this expression.
// Warning: (139-153): Assertion checker does not yet implement type struct C.S storage ref // Warning: (139-153): Assertion checker does not yet implement type struct C.S storage ref
// Warning: (173-174): Assertion checker does not yet implement type type(struct C.S storage pointer)
// Warning: (173-177): Assertion checker does not yet implement type struct C.S memory // Warning: (173-177): Assertion checker does not yet implement type struct C.S memory
// Warning: (173-177): Assertion checker does not yet implement this expression. // Warning: (173-177): Assertion checker does not yet implement this expression.

View File

@ -15,9 +15,11 @@ contract C {
} }
// ---- // ----
// Warning: (112-120): Assertion checker does not yet support the type of this variable. // Warning: (112-120): Assertion checker does not yet support the type of this variable.
// Warning: (137-138): Assertion checker does not yet implement type type(struct C.S storage pointer)
// Warning: (137-141): Assertion checker does not yet implement type struct C.S memory // Warning: (137-141): Assertion checker does not yet implement type struct C.S memory
// Warning: (137-141): Assertion checker does not yet implement this expression. // Warning: (137-141): Assertion checker does not yet implement this expression.
// Warning: (193-203): Assertion checker does not yet support the type of this variable. // Warning: (193-203): Assertion checker does not yet support the type of this variable.
// Warning: (137-138): Assertion checker does not yet implement type type(struct C.S storage pointer)
// Warning: (137-141): Assertion checker does not yet implement type struct C.S memory // Warning: (137-141): Assertion checker does not yet implement type struct C.S memory
// Warning: (137-141): Assertion checker does not yet implement this expression. // Warning: (137-141): Assertion checker does not yet implement this expression.
// Warning: (227-228): Assertion checker does not yet implement type struct C.S memory // Warning: (227-228): Assertion checker does not yet implement type struct C.S memory

View File

@ -71,7 +71,8 @@ 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
evmc evmone intx ethash evmc-instructions evmc
evmone-standalone
protobuf-mutator-libfuzzer.a protobuf-mutator-libfuzzer.a
protobuf-mutator.a protobuf-mutator.a
protobuf.a protobuf.a

View File

@ -24,7 +24,7 @@
#include <fstream> #include <fstream>
static evmc::vm evmone = evmc::vm{evmc_create_evmone()}; static evmc::VM evmone = evmc::VM{evmc_create_evmone()};
using namespace dev::test::abiv2fuzzer; using namespace dev::test::abiv2fuzzer;
using namespace dev::test; using namespace dev::test;

View File

@ -437,6 +437,12 @@ void ProtoConverter::visit(NullaryOp const& _x)
case NullaryOp::GASLIMIT: case NullaryOp::GASLIMIT:
m_output << "gaslimit()"; m_output << "gaslimit()";
break; break;
case NullaryOp::SELFBALANCE:
m_output << "selfbalance()";
break;
case NullaryOp::CHAINID:
m_output << "chainid()";
break;
} }
} }

View File

@ -237,6 +237,8 @@ message NullaryOp {
NUMBER = 14; NUMBER = 14;
DIFFICULTY = 15; DIFFICULTY = 15;
GASLIMIT = 16; GASLIMIT = 16;
SELFBALANCE = 17;
CHAINID = 18;
} }
required NOp op = 1; required NOp op = 1;
} }

View File

@ -70,7 +70,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
// AssemblyStack entry point // AssemblyStack entry point
AssemblyStack stack( AssemblyStack stack(
langutil::EVMVersion(), langutil::EVMVersion(langutil::EVMVersion::istanbul()),
AssemblyStack::Language::StrictAssembly, AssemblyStack::Language::StrictAssembly,
dev::solidity::OptimiserSettings::full() dev::solidity::OptimiserSettings::full()
); );
@ -95,7 +95,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret( yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret(
os1, os1,
stack.parserResult()->code, stack.parserResult()->code,
EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()) EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion(langutil::EVMVersion::istanbul()))
); );
if (termReason == yulFuzzerUtil::TerminationReason::StepLimitReached) if (termReason == yulFuzzerUtil::TerminationReason::StepLimitReached)
@ -105,7 +105,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
termReason = yulFuzzerUtil::interpret( termReason = yulFuzzerUtil::interpret(
os2, os2,
stack.parserResult()->code, stack.parserResult()->code,
EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion()), EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion(langutil::EVMVersion::istanbul())),
(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 4) (yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 4)
); );