Skip to content

Commit

Permalink
Merge pull request #208 from vulcanize/feature/gh-208-add-foundry
Browse files Browse the repository at this point in the history
Add Foundry for Manual Integration Testing
  • Loading branch information
abdulrabbani00 authored Mar 16, 2022
2 parents f4b7bd4 + 0d70b7c commit 6b74310
Show file tree
Hide file tree
Showing 14 changed files with 445 additions and 14 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ profile.cov
/dashboard/assets/package-lock.json

**/yarn-error.log
foundry/deployments/local-private-network/geth-linux-amd64
foundry/projects/local-private-network/geth-linux-amd64
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@
path = tests/evm-benchmarks
url = https://github.com/ipsilon/evm-benchmarks
shallow = true
[submodule "foundry/projects/local-private-network/Stateful/lib/ds-test"]
path = foundry/projects/local-private-network/Stateful/lib/ds-test
url = https://github.com/dapphub/ds-test
14 changes: 0 additions & 14 deletions cmd/geth/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,20 +273,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
return stack, backend
}

func makeLightNode(ctx *cli.Context, stack *node.Node, cfg gethConfig) (*node.Node, ethapi.Backend) {
backend := utils.RegisterLesEthService(stack, &cfg.Eth)

// Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
utils.RegisterGraphQLService(stack, backend.ApiBackend, cfg.Node)
}
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
utils.RegisterEthStatsService(stack, backend.ApiBackend, cfg.Ethstats.URL)
}
return stack, backend.ApiBackend
}

// dumpConfig is the dumpconfig command.
func dumpConfig(ctx *cli.Context) error {
_, cfg := makeConfigNode(ctx)
Expand Down
59 changes: 59 additions & 0 deletions foundry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Foundry README

# Overview

This document will go through the steps needed to test using Foundry. Currently, we use Foundry in the following capacity.

1. Create a private network with our internal version of Geth.
2. Deploy a smart contract to the private network.
3. Test the smart contract on the private network.
4. Create a transaction on the private network.

# Steps

The steps to create a new project are as follows.

## 1. Creating New Project

1. `cd foundry/projects`.
2. Create a directory that captures your project: `mkdir local-private-network; cd local-private-network`.
3. Create a [new foundry project](https://onbjerg.github.io/foundry-book/forge/creating-a-new-project.html): `forge init stateful`.
4. Follow the foundry [documentation](https://onbjerg.github.io/foundry-book/forge/tests.html) for writing smart contract tests.

## 2. Deployments

You can choose to have custom deployments for your workflow. However, it is recommended to utilize Docker.

# Existing Projects

Below, you can find existing projects and their descriptions.

## `local-private-network`

The purpose of this project is as follows:

1. Compile the geth from the local source.
2. Build a docker container with `ipld-eth-db` and another container for the `local-private-network`.
3. Run the compiled version of geth.
4. Deploy a smart contract to the private blockchain.
5. Trigger a transaction on the newly deployed smart contract.

## Using This Project

If you want to test your local geth code, do the following:

1. cd `foundry/projects/local-private-network`.
2. `./wrapper.sh` - This script will do all the heavy lifting for you.
3. Keep an eye out for the outputs from the docker container.
4. Enter the docker container and do as you please.
5. If you want to change your geth code, you will have to run `./wrapper.sh` for subsequent runs.
6. If you do not change your geth code, you have to run: `docker-compose up --build`.

### Key Notes:

- The command to [deploy](https://onbjerg.github.io/foundry-book/forge/deploying.html) the smart contract is: `forge create --keystore $ETH_KEYSTORE_FILE --rpc-url [http://127.0.0.1:8545](http://127.0.0.1:8545/) --constructor-args 1 --password "" --legacy /root/stateful/src/Stateful.sol:Stateful`
- The command to interact create a [transaction](https://onbjerg.github.io/foundry-book/reference/cast.html) is: `cast send --keystore $ETH_KEYSTORE_FILE --rpc-url [http://127.0.0.1:8545](http://127.0.0.1:8545/) --password "" --legacy $DEPLOYED_ADDRESS "off()"`
- The `Dockerfile` compiles `cast` and `forge`.
- The `foundry/projects/local-private-network/deploy-local-network.sh` file does most heavy lifting. It spins up geth and triggers various events.
- The `foundry/projects/local-private-network/start-private-network.sh` file triggers `deploy-local-network.sh`. This file runs all the tests.
- The `geth` node will stay running even after the tests are terminated.
37 changes: 37 additions & 0 deletions foundry/projects/local-private-network/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
FROM frolvlad/alpine-bash

# copy all files

RUN apk update ; apk add --no-cache --allow-untrusted ca-certificates curl bash git jq

ENV GLIBC_REPO=https://github.com/sgerrand/alpine-pkg-glibc
ENV GLIBC_VERSION=2.35-r0

RUN set -ex && \
apk --update add libstdc++ curl ca-certificates && \
for pkg in glibc-${GLIBC_VERSION} glibc-bin-${GLIBC_VERSION}; \
do curl -sSL ${GLIBC_REPO}/releases/download/${GLIBC_VERSION}/${pkg}.apk -o /tmp/${pkg}.apk; done && \
apk add --allow-untrusted /tmp/*.apk ; \
rm -v /tmp/*.apk ;/usr/glibc-compat/sbin/ldconfig /lib /usr/glibc-compat/lib

RUN apk add gcompat; echo "Sorry"
WORKDIR /root

COPY stateful ./stateful
ADD ./start-private-network.sh .
ADD ./deploy-local-network.sh .
ADD ../../geth-linux-amd64 /bin/geth

RUN curl -L https://foundry.paradigm.xyz | bash; \
/bin/bash -c 'source $HOME/.bashrc'; \
/root/.foundry/bin/foundryup

ENV PATH "$PATH:/root/.foundry/bin/"
RUN echo "export PATH=${PATH}" >> $HOME/.bashrc;

RUN chmod +x /bin/geth


EXPOSE 8545
EXPOSE 8546
ENTRYPOINT ["./start-private-network.sh"]
Submodule ds-test added at 0a5da5
16 changes: 16 additions & 0 deletions foundry/projects/local-private-network/compile-geth.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash
set -e

GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'

start_path=$(pwd)
cd ../../../
echo -e "${GREEN}Building geth!${NC}"
docker build -t vulcanize/go-ethereum -f Dockerfile .
docker run --rm --entrypoint cat vulcanize/go-ethereum /usr/local/bin/geth > foundry/projects/local-private-network/geth-linux-amd64
chmod +x foundry/projects/local-private-network/geth-linux-amd64

echo -e "${GREEN}geth build complete!${NC}"
cd $start_path
187 changes: 187 additions & 0 deletions foundry/projects/local-private-network/deploy-local-network.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#!/bin/bash
set -e

OPTS="./deploy-local-network.sh [<options>] <args>...
./deploy-local-network.sh --help
--
db-user=name database user
db-password=password database password
db-name=name database name
db-host=address database host
db-port=port database port
db-write=bool turn on database write mode
db-type=name the type of database
db-driver=name the driver used for the database
db-waitforsync=bool Should the statediff service start once geth has synced to head (default: false)
rpc-port=port change RPC port (default: 8545)
rpc-addr=address change RPC address (default: 127.0.0.1)
chain-id=number change chain ID (default: 99)
period=seconds use a block time instead of instamine
accounts=number create multiple accounts (default: 1)
address=address eth address to add to genesis
save=name after finishing, save snapshot
load=name start from a previously saved snapshot
dir=directory testnet directory
"

eval "$(
git rev-parse --parseopt -- "$@" <<<"$OPTS" || echo exit $?
)"

DB_USER=vdbm
DB_PASSWORD=password
DB_NAME=vulcanize_public
DB_HOST=127.0.0.1
DB_PORT=5432
DB_TYPE=postgres
DB_DRIVER=sqlx
DB_WAIT_FOR_SYNC=false
RPC_PORT=8545
RPC_ADDRESS=127.0.0.1
PERIOD=0
CHAINID=99
ACCOUNTS=0
ADDRESS=
gethdir=$HOME/testnet

while [[ $1 ]]; do
case $1 in
--) shift; break;;
--db-user) shift; DB_USER=$1;;
--db-password) shift; DB_PASSWORD=$1;;
--db-name) shift; DB_NAME=$1;;
--db-host) shift; DB_HOST=$1;;
--db-port) shift; DB_PORT=$1;;
--db-write) shift; DB_WRITE=$1;;
--db-type) shift; DB_TYPE=$1;;
--db-driver) shift; DB_DRIVER=$1;;
--db-waitforsync) shift; DB_WAIT_FOR_SYNC=$1;;
--rpc-port) shift; RPC_PORT=$1;;
--rpc-addr) shift; RPC_ADDRESS=$1;;
--chain-id) shift; CHAINID=$1;;
--period) shift; PERIOD=$1;;
--accounts) shift; ACCOUNTS=$1;;
--save) shift; SAVE=$1;;
--address) shift; ADDRESS=$1;;
--load) shift; LOAD=$1;;
--dir) shift; gethdir=$1;;
*) printf "${0##*/}: internal error: %q\\n" "$1"; exit 1
esac; shift
done

chaindir=$gethdir/$RPC_PORT
#while true; do
# if [[ ! -d "$gethdir/$CHAINID" ]]; then break; fi
# CHAINID=$((CHAINID + 1))
#done

mkdir -p "$chaindir/config"
#if [ -n "$ADDRESS" ]; then
# balance+=(-n {} -s "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" -i balance \
# -i "$ADDRESS")
#fi
for i in $(seq 0 "$ACCOUNTS"); do
address+=( "$(
geth 2>/dev/null account new --datadir "$chaindir" --password=<(exit) 2>/dev/null \
| grep -o -E "0x[A-Fa-f0-9]*" )" )
# balance+=(-n {} -s "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" -i balance \
# -i "${address[i]}")
balance+=(' "'"${address[i]}"'": { "balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"}')
done

#ALLOC_CLEAN=$(echo ${ALLOC} | jq .)
EXTRA_DATA="0x3132333400000000000000000000000000000000000000000000000000000000${address[0]#0x}0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
JSON_VAL='{
"config": {
"chainId": '"$CHAINID"',
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"clique": {
"period": '"$PERIOD"',
"epoch": 3000
}
},
"difficulty": "0x1",
"gaslimit": "0xffffffffffff",
"extraData": "'"$EXTRA_DATA"'",
"alloc": {'"$balance"'}
}'
echo $JSON_VAL | jq . > $chaindir/config/genesis.json

geth 2>/dev/null --datadir "$chaindir" init "$chaindir/config/genesis.json"

export ETH_RPC_URL=http://$RPC_ADDRESS:$RPC_PORT

port=$((RPC_PORT + 30000))

geth version
echo >&2 "dapp-testnet: RPC URL: $ETH_RPC_URL"
echo >&2 "dapp-testnet: TCP port: $port"
echo >&2 "dapp-testnet: Chain ID: $CHAINID"
echo >&2 "dapp-testnet: Database: $chaindir"
echo >&2 "dapp-testnet: Geth log: $chaindir/geth.log"

printf "%s\n" "${address[@]}" > "$chaindir/config/account"
echo "$ETH_RPC_URL" > "$chaindir/config/rpc-url"
echo "$port" > "$chaindir/config/node-port"

set +m
# Uncomment below once waitforsync has been merged
# geth \
# 2> >(tee "$chaindir/geth.log" | grep --line-buffered Success | sed 's/^/geth: /' >&2) \
# --datadir "$chaindir" --networkid "$CHAINID" --port="$port" \
# --mine --miner.threads=1 --allow-insecure-unlock \
# --http --http.api "web3,eth,net,debug,personal,statediff" --http.corsdomain '*' --http.vhosts '*' --nodiscover \
# --http.addr="$RPC_ADDRESS" --http.port="$RPC_PORT" --syncmode=full --gcmode=archive \
# --statediff --statediff.db.host="$DB_HOST" --statediff.db.port="$DB_PORT" --statediff.db.user="$DB_USER" \
# --statediff.db.password="$DB_PASSWORD" --statediff.db.name="$DB_NAME" \
# --statediff.db.nodeid 1 --statediff.db.clientname test1 --statediff.writing="$DB_WRITE" \
# --statediff.db.type="$DB_TYPE" --statediff.db.driver="$DB_DRIVER" --statediff.waitforsync="$DB_WAIT_FOR_SYNC" \
# --ws --ws.addr="0.0.0.0" --unlock="$(IFS=,; echo "${address[*]}")" --password=<(exit) &

geth \
2> >(tee "$chaindir/geth.log" | grep --line-buffered Success | sed 's/^/geth: /' >&2) \
--datadir "$chaindir" --networkid "$CHAINID" --port="$port" \
--mine --miner.threads=1 --allow-insecure-unlock \
--http --http.api "web3,eth,net,debug,personal,statediff" --http.corsdomain '*' --http.vhosts '*' --nodiscover \
--http.addr="$RPC_ADDRESS" --http.port="$RPC_PORT" --syncmode=full --gcmode=archive \
--statediff --statediff.db.host="$DB_HOST" --statediff.db.port="$DB_PORT" --statediff.db.user="$DB_USER" \
--statediff.db.password="$DB_PASSWORD" --statediff.db.name="$DB_NAME" \
--statediff.db.nodeid 1 --statediff.db.clientname test1 --statediff.writing="$DB_WRITE" \
--statediff.db.type="$DB_TYPE" --statediff.db.driver="$DB_DRIVER" \
--ws --ws.addr="0.0.0.0" --unlock="$(IFS=,; echo "${address[*]}")" --password=<(exit) &

gethpid=$!

clean() {
( set -x; kill -INT $gethpid; wait )
if [[ $SAVE ]]; then
echo >&2 "dapp-testnet: saving $gethdir/snapshots/$SAVE"
mkdir -p "$gethdir/snapshots/$SAVE"
cp -r "$chaindir/keystore" "$gethdir/snapshots/$SAVE"
cp -r "$chaindir/config" "$gethdir/snapshots/$SAVE"
geth >/dev/null 2>&1 --datadir "$chaindir" \
export "$gethdir/snapshots/$SAVE/backup"
fi
( set -x; rm -rf "$chaindir" )
}
trap clean EXIT

until curl -s "$ETH_RPC_URL"; do sleep 1; done

# UPDATE
#ETH_FROM=$(seth --rpc-url="$ETH_RPC_URL" rpc eth_coinbase)
#export ETH_FROM
export ETH_KEYSTORE=$chaindir/keystore
export ETH_PASSWORD=/dev/null
printf 'dapp-testnet: Account: %s (default)\n' "${address[0]}" >&2

[[ "${#address[@]}" -gt 1 ]] && printf 'dapp-testnet: Account: %s\n' "${address[@]:1}" >&2

while true; do sleep 3600; done
37 changes: 37 additions & 0 deletions foundry/projects/local-private-network/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
version: "3.2"

services:
foundry:
restart: unless-stopped
depends_on:
- ipld-eth-db
build: ./
environment:
DB_USER: vdbm
DB_NAME: vulcanize_testing
DB_HOST: ipld-eth-db
DB_PORT: 5432
DB_PASSWORD: password
DB_WRITE: "true"
DB_TYPE: postgres
DB_DRIVER: sqlx
DB_WAIT_FOR_SYNC: "true"
ports:
- "127.0.0.1:8545:8545"
- "127.0.0.1:8546:8546"

ipld-eth-db:
restart: always
image: vulcanize/ipld-eth-db:v3.0.6
environment:
POSTGRES_USER: "vdbm"
POSTGRES_DB: "vulcanize_testing"
POSTGRES_PASSWORD: "password"
volumes:
- vdb_db_eth_server:/var/lib/postgresql/data
ports:
- "127.0.0.1:8077:5432"
command: ["postgres", "-c", "log_statement=all"]

volumes:
vdb_db_eth_server:
Loading

0 comments on commit 6b74310

Please sign in to comment.