Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update ganache dependency #106

Merged
merged 35 commits into from
Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f9ad032
Pin web3 dependency to >=3.16.4
elopez Dec 30, 2021
2b6186a
Pin manticore dependency to <=0.3.6
elopez Dec 30, 2021
a4cff34
Pin rlp version to <3 to stay compatible with manticore
elopez Dec 30, 2021
3a0902c
Update base image and Dockerfile format
elopez Dec 29, 2021
d8d8a60
Remove extra apt-get clean
elopez Dec 29, 2021
2b78c20
Drop Parity installation
elopez Dec 29, 2021
6d0829f
Install etheno globally
elopez Dec 29, 2021
5c8b29a
Update node to latest LTS version (16.x)
elopez Dec 30, 2021
ded7f1d
Simplify user creation
elopez Dec 30, 2021
de5a2c4
Fix Debian interactive installation, drop extra PATH environment
elopez Dec 30, 2021
d7d9df1
Use a separate stage to build python wheels
elopez Dec 30, 2021
1fc4b2d
Reorder apt packages
elopez Dec 30, 2021
24403e6
Re-add pip, use mount points in mnt
elopez Dec 30, 2021
06ff7e8
Drop locales-all to reduce image size
elopez Dec 30, 2021
bb97179
Drop unused `install-libff.sh` script
elopez Dec 30, 2021
ccc8df7
Update GitHub Action to build new Dockerfile and push to GHCR
elopez Dec 30, 2021
47ddf60
initial commit of updating ganache to v7.0+
anishnaik Jun 29, 2022
acadd42
Added some todo and one bug fix
anishnaik Jun 30, 2022
40bfb8f
Minor bugfix during event logging
anishnaik Jul 5, 2022
6d7296f
Updated flask shutdown methodology, allow unlimited contract size by …
anishnaik Jul 5, 2022
1bb8ce6
updated flask version and added some todos
anishnaik Jul 5, 2022
411cd0a
remove print statements
anishnaik Jul 5, 2022
caa6758
pin web3 version
anishnaik Jul 5, 2022
73cccc8
Merge branch 'dev-update-ganache' into docker-improvements
anishnaik Jul 6, 2022
12f5c0e
Merge pull request #89 from elopez/docker-improvements
anishnaik Jul 6, 2022
aa52872
removed manticore related commands
anishnaik Jul 6, 2022
98ee4c3
dependency nightmare resolved for now
anishnaik Jul 6, 2022
24de259
Use docker stage for ganache, build rusty-rlp wheel
elopez Jul 6, 2022
6bf7b26
Comment disabled setup.py dependencies
elopez Jul 6, 2022
748e42e
Disable cache for pip upgrade
elopez Jul 6, 2022
4857054
Remove extra sudo from node installation
elopez Jul 6, 2022
2855ae4
Upgrade Docker actions
elopez Jul 6, 2022
a323909
Enable multi-arch docker builds
elopez Jul 6, 2022
f57851a
docker hostname is now set properly
anishnaik Jul 7, 2022
643f35d
Merge branch 'rc-1' into dev-update-ganache
anishnaik Jul 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 30 additions & 20 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,30 @@ jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up QEMU
uses: docker/setup-qemu-action@v2

- name: GitHub Login
uses: azure/docker-login@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
id: buildx
with:
login-server: docker.pkg.github.com
install: true

- name: GitHub Container Registry Login
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: DockerHub Login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }}

- name: Set Docker Package and Version
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
id: version
run: |
set +e
_=$(echo "$GITHUB_REF" | grep "^refs/heads/")
Expand All @@ -41,20 +53,18 @@ jobs:
PKG=etheno
fi
set -e
echo "::set-env name=PKG::$PKG"
echo "::set-env name=VER::$VER"
echo "::set-output name=PKG::$PKG"
echo "::set-output name=VER::$VER"

- name: Docker Build
run: docker build -t $PKG:$VER .

- name: DockerHub Login
uses: azure/docker-login@v1
- name: Docker build and push
uses: docker/build-push-action@v3
with:
login-server: registry.hub.docker.com
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }}

- name: Docker Push
run: |
docker tag $PKG:$VER registry.hub.docker.com/trailofbits/$PKG:$VER
docker push registry.hub.docker.com/trailofbits/$PKG:$VER
push: true
target: final
platforms: |
linux/arm64/v8
linux/amd64
tags: |
ghcr.io/${{ github.repository }}/${{ steps.version.outputs.PKG }}:${{ steps.version.outputs.VER }}
registry.hub.docker.com/trailofbits/${{ steps.version.outputs.PKG }}:${{ steps.version.outputs.VER }}
99 changes: 61 additions & 38 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,61 +1,84 @@
FROM ubuntu:bionic
MAINTAINER Evan Sultanik

RUN DEBIAN_FRONTEND=noninteractive \
apt-get update && apt-get install -y --no-install-recommends \
# syntax=docker/dockerfile:1.3
FROM ubuntu:focal AS python-wheels
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
cmake \
curl \
python3-dev \
python3-pip \
python3-setuptools

# Needed for rusty-rlp wheel
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"

RUN --mount=type=bind,target=/etheno \
cd /etheno && \
pip3 install --no-cache-dir --upgrade pip setuptools && \
pip3 wheel --no-cache-dir -w /wheels \
https://github.com/cburgdorf/rusty-rlp/archive/refs/tags/0.1.15.tar.gz \
.


FROM ubuntu:focal AS ganache
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential \
ca-certificates \
curl \
gnupg \
lsb-release
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends nodejs
RUN npm install --omit=dev --location=global --prefix /opt/node ganache truffle


FROM ubuntu:focal AS final
LABEL org.opencontainers.image.authors="Evan Sultanik"

RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
bash-completion \
sudo \
ca-certificates \
curl \
gpg-agent \
libudev-dev \
locales \
python3 \
libpython3-dev \
python3-pip \
python3-setuptools \
git \
build-essential \
software-properties-common \
locales-all locales \
libudev-dev \
gpg-agent \
&& apt-get clean \
sudo \
&& rm -rf /var/lib/apt/lists/*

RUN DEBIAN_FRONTEND=noninteractive add-apt-repository -y ppa:ethereum/ethereum && \
# NOTE: solc was removed from the below command since the echidna integration is being removed
# If the solc option is added back, --platform linux-amd64 needs to be added to the `docker build` command for M1 machines
RUN add-apt-repository -y ppa:ethereum/ethereum && \
apt-get update && apt-get install -y --no-install-recommends \
solc \
ethereum \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

RUN curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash - && sudo apt-get install -y --no-install-recommends nodejs && apt-get clean && rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://deb.nodesource.com/setup_16.x | bash && \
apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*

RUN npm install --production -g ganache-cli truffle && npm --force cache clean
COPY --from=ganache /opt/node /usr/local/

RUN useradd -m etheno
RUN usermod -aG sudo etheno
USER etheno
WORKDIR /home/etheno
USER root
WORKDIR /root
# BEGIN Install Etheno
RUN --mount=type=bind,target=/mnt/etheno \
--mount=type=bind,target=/mnt/wheels,source=/wheels,from=python-wheels \
cd /mnt/etheno && \
pip3 install --no-cache-dir --upgrade pip setuptools && \
pip3 install --no-cache-dir --no-index --find-links /mnt/wheels .

# Install Parity
RUN curl https://get.parity.io -L | bash
RUN useradd -m -G sudo etheno

# Allow passwordless sudo for etheno
RUN echo 'etheno ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers

USER etheno
ENV HOME=/home/etheno PATH=$PATH:/home/etheno/.local/bin
WORKDIR /home/etheno
ENV HOME=/home/etheno

COPY --chown=etheno:etheno LICENSE setup.py etheno/
COPY --chown=etheno:etheno etheno/*.py etheno/etheno/

RUN cd etheno && \
pip3 install --no-cache-dir && \
cd .. && \
rm -rf etheno

COPY --chown=etheno:etheno examples examples/
# Use the DOCKER env variable to set hostname accordingly
ENV DOCKER=1
WORKDIR /home/etheno

CMD ["/bin/bash"]
24 changes: 0 additions & 24 deletions docker/install-libff.sh

This file was deleted.

21 changes: 14 additions & 7 deletions etheno/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@
from . import parity
from . import truffle

# Constant for converting whole units to wei
ETHER = 1e18


def main(argv = None):
parser = argparse.ArgumentParser(description='An Ethereum JSON RPC multiplexer, differential fuzzer, and test framework integration tool.')
parser.add_argument('--debug', action='store_true', default=False, help='Enable debugging from within the web server')
parser.add_argument('--run-publicly', action='store_true', default=False, help='Allow the web server to accept external connections')
parser.add_argument('-p', '--port', type=int, default=GETH_DEFAULT_RPC_PORT, help='Port on which to run the JSON RPC webserver (default=%d)' % GETH_DEFAULT_RPC_PORT)
parser.add_argument('-a', '--accounts', type=int, default=None, help='Number of accounts to create in the client (default=10)')
parser.add_argument('-b', '--balance', type=float, default=100.0, help='Default balance (in Ether) to seed to each account (default=100.0)')
parser.add_argument('-c', '--gas-price', type=int, default=None, help='Default gas price (default=20000000000)')
parser.add_argument('-a', '--accounts', type=int, default=10, help='Number of accounts to create in the client (default=10)')
parser.add_argument('-b', '--balance', type=float, default=1000.0, help='Default balance (in Ether) to seed to each account (default=100.0)')
# TODO: do we really need a gas price specified for ganache? is there a use case here?
parser.add_argument('-c', '--gas-price', type=int, default=20000000000, help='Default gas price (default=20000000000)')
# TODO: networkID can have a default value it seems like
parser.add_argument('-i', '--network-id', type=int, default=None, help='Specify a network ID (default is the network ID of the master client)')
'''
We might need the Echidna feature later for differential fuzz testing but for reducing confusion we will remove the command-line arguments
Expand All @@ -42,7 +47,7 @@ def main(argv = None):
parser.add_argument('-g', '--ganache', action='store_true', default=False,
help='Run Ganache as a master JSON RPC client (cannot be used in conjunction with --master)')
parser.add_argument('--ganache-cmd', type=str, default=None, help='Specify a command that runs Ganache '
'(default="/usr/bin/env ganache-cli")')
'(default="/usr/bin/env ganache")')
parser.add_argument('--ganache-args', type=str, default=None,
help='Additional arguments to pass to Ganache')
parser.add_argument('--ganache-port', type=int, default=None,
Expand Down Expand Up @@ -164,6 +169,7 @@ def main(argv = None):

accounts = []

# TODO: args.gas_price is not set if a genesis file is provided
if args.genesis:
with open(args.genesis, 'rb') as f:
genesis = json.load(f)
Expand All @@ -186,7 +192,7 @@ def main(argv = None):
# We will generate it further below once we've resolved all of the parameters
genesis = None

accounts += make_accounts(args.accounts, default_balance=int(args.balance * 1000000000000000000))
accounts += make_accounts(args.accounts, default_balance=int(args.balance * ETHER))

if genesis is not None:
# add the new accounts to the genesis
Expand Down Expand Up @@ -214,13 +220,14 @@ def main(argv = None):
if args.network_id is None:
args.network_id = 0x657468656E6F # 'etheno' in hex

ganache_accounts = ["--account=%s,0x%x" % (acct.private_key, acct.balance) for acct in accounts]
# Have to use hex() so that string is hex-encoded (prefixed with 0x) that is necessary for Ganache v7.0+
# https://github.com/trufflesuite/ganache/discussions/1075
ganache_accounts = ["--account=%s,0x%x" % (hex(acct.private_key), acct.balance) for acct in accounts]

ganache_args = ganache_accounts + ['-g', str(args.gas_price), '-i', str(args.network_id)]

if args.ganache_args is not None:
ganache_args += shlex.split(args.ganache_args)

ganache_instance = ganache.Ganache(cmd=args.ganache_cmd, args=ganache_args, port=args.ganache_port)

ETHENO.master_client = ganache.GanacheClient(ganache_instance)
Expand Down
3 changes: 2 additions & 1 deletion etheno/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,8 @@ def create_account(self, balance: int = 0, address: Optional[int] = None):

def wait_until_running(self):
pass


# TODO: need to ensure that JSON RPC calls match latest API spec
def post(self, data: Dict[str, Any]) -> Optional[Dict[str, Any]]:
ret = self.client.post(data)
if ret is not None and 'error' in ret:
Expand Down
26 changes: 19 additions & 7 deletions etheno/etheno.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pkg_resources
import os
from threading import Thread
from typing import Any, Dict, List, Optional
from werkzeug.serving import make_server

from flask import Flask, jsonify, request, abort
from flask.views import MethodView
Expand Down Expand Up @@ -31,6 +33,8 @@ def to_account_address(raw_address: int) -> str:
_CONTROLLER = threadwrapper.MainThreadController()


# Using 'werkzeug.server.shutdown' is deprecated after Flask 2.1.x
# TODO: Will probably remove this function
@app.route('/shutdown')
def _etheno_shutdown():
# shut down the Flask server
Expand Down Expand Up @@ -320,6 +324,9 @@ def shutdown(self, port: int = GETH_DEFAULT_RPC_PORT):
for client in self.clients:
client.shutdown()
self.logger.close()
_CONTROLLER.quit()
"""
Won't need this if shutdown() function is removed
from urllib.request import urlopen
import socket
import urllib
Expand All @@ -329,29 +336,34 @@ def shutdown(self, port: int = GETH_DEFAULT_RPC_PORT):
pass
except urllib.error.URLError:
pass
"""

def run(self, debug=True, run_publicly=False, port=GETH_DEFAULT_RPC_PORT):
# Manticore only works in the main thread, so use a threadsafe wrapper:
def flask_thread():
if run_publicly:
def server_thread():
IS_DOCKER = os.environ.get("DOCKER", 0)
if run_publicly or IS_DOCKER:
host='0.0.0.0'
else:
host = None
host = "127.0.0.1"
# Do not use the reloader, because Flask needs to run in the main thread to use the reloader
app.run(debug=debug, host=host, port=port, use_reloader=False)
thread = Thread(target=flask_thread)
server = make_server(host=host, port=port, app=app, threaded=True)
return server
# app.run(debug=debug, host=host, port=port, use_reloader=False)
server = server_thread()
thread = Thread(target=server.serve_forever)
thread.start()

self.logger.info("Etheno v%s" % VERSION)

for plugin in self.plugins:
plugin.run()

_CONTROLLER.run()
self.shutdown()
self.logger.info("Shutting Etheno down")
server.shutdown()
thread.join()


ETHENO = Etheno()


Expand Down
8 changes: 4 additions & 4 deletions etheno/ganache.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ def __init__(self, cmd=None, args=None, port=8546):
if cmd is not None:
cmd = shlex.split(cmd)
else:
cmd = ['/usr/bin/env', 'ganache-cli']
cmd = ['/usr/bin/env', 'ganache']
if args is None:
args = []
self.args = cmd + ['-d', '-p', str(port)] + args
self.args = cmd + ['-d', '-p', str(port), '--chain.allowUnlimitedContractSize'] + args
self.ganache = None
self._client = None

def start(self):
if self.ganache:
return
if shutil.which("ganache-cli") is None:
raise ValueError("`ganache-cli` is not installed! Install it by running `npm -g i ganache-cli`")
if shutil.which("ganache") is None:
raise ValueError("`ganache` is not installed! Install it by running `npm -g i ganache`")
if self._client:
self.ganache = PtyLogger(self._client.logger, self.args)
self.ganache.start()
Expand Down
Loading