From df55a62430698e145cfed591e516d5ba3a3fb738 Mon Sep 17 00:00:00 2001 From: Abdul Rabbani Date: Mon, 14 Mar 2022 15:16:12 -0400 Subject: [PATCH] Working Foundry --- .gitignore | 1 + foundry/README.md | 59 +++++++++++++++++++ .../local-private-network/Dockerfile | 21 ------- .../start-private-network.sh | 36 ----------- .../projects/local-private-network/Dockerfile | 37 ++++++++++++ .../local-private-network/compile-geth.sh | 4 +- .../deploy-local-network.sh | 6 +- .../local-private-network/docker-compose.yml | 0 .../start-private-network.sh | 50 ++++++++++++++++ .../stateful/foundry.toml | 7 +++ .../stateful/src/Stateful.sol | 20 +++++++ .../stateful/src/test/Stateful.t.sol | 19 ++++++ .../projects/local-private-network/wrapper.sh | 7 +++ 13 files changed, 205 insertions(+), 62 deletions(-) create mode 100644 foundry/README.md delete mode 100644 foundry/deployments/local-private-network/Dockerfile delete mode 100755 foundry/deployments/local-private-network/start-private-network.sh create mode 100644 foundry/projects/local-private-network/Dockerfile rename foundry/{deployments => projects}/local-private-network/compile-geth.sh (69%) rename foundry/{deployments => projects}/local-private-network/deploy-local-network.sh (98%) rename foundry/{deployments => projects}/local-private-network/docker-compose.yml (100%) create mode 100755 foundry/projects/local-private-network/start-private-network.sh create mode 100644 foundry/projects/local-private-network/stateful/foundry.toml create mode 100644 foundry/projects/local-private-network/stateful/src/Stateful.sol create mode 100644 foundry/projects/local-private-network/stateful/src/test/Stateful.t.sol create mode 100755 foundry/projects/local-private-network/wrapper.sh diff --git a/.gitignore b/.gitignore index aadc8de4b..ea78e6c56 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ profile.cov **/yarn-error.log foundry/deployments/local-private-network/geth-linux-amd64 +foundry/projects/local-private-network/geth-linux-amd64 diff --git a/foundry/README.md b/foundry/README.md new file mode 100644 index 000000000..1e0dca3f8 --- /dev/null +++ b/foundry/README.md @@ -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. diff --git a/foundry/deployments/local-private-network/Dockerfile b/foundry/deployments/local-private-network/Dockerfile deleted file mode 100644 index 0a75c05fd..000000000 --- a/foundry/deployments/local-private-network/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM frolvlad/alpine-bash - -RUN apk update ; apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted ca-certificates curl bash git jshon jq - -#USER guest -WORKDIR /root - -# copy all files -ADD ./deploy-local-network.sh . -ADD ./geth-linux-amd64 /bin/geth -ADD ./start-private-network.sh . - -RUN curl -L https://foundry.paradigm.xyz | bash; \ - /bin/bash -c 'source $HOME/.bashrc'; \ - /root/.foundry/bin/foundryup - -RUN chmod +x /bin/geth - -EXPOSE 8545 -EXPOSE 8546 -ENTRYPOINT ["./start-private-network.sh"] \ No newline at end of file diff --git a/foundry/deployments/local-private-network/start-private-network.sh b/foundry/deployments/local-private-network/start-private-network.sh deleted file mode 100755 index 0b8117ffb..000000000 --- a/foundry/deployments/local-private-network/start-private-network.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash - -set -ex - -# clean up -trap 'killall geth && rm -rf "$TMPDIR"' EXIT -trap "exit 1" SIGINT SIGTERM - -TMPDIR=$(mktemp -d) -/bin/bash deploy-local-network.sh --rpc-addr 0.0.0.0 --chain-id 4 --db-user $DB_USER --db-password $DB_PASSWORD --db-name $DB_NAME \ - --db-host $DB_HOST --db-port $DB_PORT --db-write $DB_WRITE --dir "$TMPDIR" --address $ADDRESS \ - --db-type $DB_TYPE --db-driver $DB_DRIVER --db-waitforsync $DB_WAIT_FOR_SYNC & -echo "sleeping 90 sec" -# give it a few secs to start up -sleep 90 - -#read -r ACC BAL <<< "$(seth ls --keystore "$TMPDIR/8545/keystore")" -#echo $ACC -#echo $BAL -# -# -## Deploy a contract: -#solc --bin --bin-runtime docker/stateful.sol -o "$TMPDIR" -#A_ADDR=$(seth send --create "$(<"$TMPDIR"/A.bin)" "constructor(uint y)" 1 --from "$ACC" --keystore "$TMPDIR"/8545/keystore --password /dev/null --gas 0xfffffff) -# -#echo $A_ADDR -# -## Call transaction -# -#TX=$(seth send "$A_ADDR" "off()" --gas 0xffff --password /dev/null --from "$ACC" --keystore "$TMPDIR"/8545/keystore --async) -#echo $TX -#RESULT=$(seth run-tx "$TX") -#echo $RESULT - -# Run forever -tail -f /dev/null \ No newline at end of file diff --git a/foundry/projects/local-private-network/Dockerfile b/foundry/projects/local-private-network/Dockerfile new file mode 100644 index 000000000..a618b609f --- /dev/null +++ b/foundry/projects/local-private-network/Dockerfile @@ -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"] \ No newline at end of file diff --git a/foundry/deployments/local-private-network/compile-geth.sh b/foundry/projects/local-private-network/compile-geth.sh similarity index 69% rename from foundry/deployments/local-private-network/compile-geth.sh rename to foundry/projects/local-private-network/compile-geth.sh index 93d40538e..75b2435a6 100755 --- a/foundry/deployments/local-private-network/compile-geth.sh +++ b/foundry/projects/local-private-network/compile-geth.sh @@ -9,8 +9,8 @@ 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/deployments/local-private-network/geth-linux-amd64 -chmod +x foundry/deployments/local-private-network/geth-linux-amd64 +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 diff --git a/foundry/deployments/local-private-network/deploy-local-network.sh b/foundry/projects/local-private-network/deploy-local-network.sh similarity index 98% rename from foundry/deployments/local-private-network/deploy-local-network.sh rename to foundry/projects/local-private-network/deploy-local-network.sh index 949ee0063..74c410c86 100755 --- a/foundry/deployments/local-private-network/deploy-local-network.sh +++ b/foundry/projects/local-private-network/deploy-local-network.sh @@ -1,8 +1,8 @@ #!/bin/bash set -e -OPTS="dapp testnet [] ... -dapp testnet --help +OPTS="./deploy-local-network.sh [] ... +./deploy-local-network.sh --help -- db-user=name database user db-password=password database password @@ -184,4 +184,4 @@ 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 \ No newline at end of file +while true; do sleep 3600; done diff --git a/foundry/deployments/local-private-network/docker-compose.yml b/foundry/projects/local-private-network/docker-compose.yml similarity index 100% rename from foundry/deployments/local-private-network/docker-compose.yml rename to foundry/projects/local-private-network/docker-compose.yml diff --git a/foundry/projects/local-private-network/start-private-network.sh b/foundry/projects/local-private-network/start-private-network.sh new file mode 100755 index 000000000..d4c7d3340 --- /dev/null +++ b/foundry/projects/local-private-network/start-private-network.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +set -ex + +# clean up +trap 'killall geth && rm -rf "$TMPDIR"' EXIT +trap "exit 1" SIGINT SIGTERM + +TMPDIR=$(mktemp -d) +/bin/bash deploy-local-network.sh --rpc-addr 0.0.0.0 --chain-id 4 --db-user $DB_USER --db-password $DB_PASSWORD --db-name $DB_NAME \ + --db-host $DB_HOST --db-port $DB_PORT --db-write $DB_WRITE --dir "$TMPDIR" --address $ADDRESS \ + --db-type $DB_TYPE --db-driver $DB_DRIVER --db-waitforsync $DB_WAIT_FOR_SYNC & +echo "sleeping 90 sec" +# give it a few secs to start up +sleep 90 + +# Run tests +cd stateful +forge build +forge test --fork-url http://localhost:8545 + +# Deploy contracts + +ETH_KEYSTORE_FILES=() +echo "ETH KEYSTORE: $TMPDIR/8545/keystore" +for entry in `ls $TMPDIR/8545/keystore`; do + ETH_KEYSTORE_FILES+=("${TMPDIR}/8545/keystore/${entry}") +done + +echo "ETH_KEYSTORE_FILES: $ETH_KEYSTORE_FILES" +ETH_KEYSTORE_FILE=${ETH_KEYSTORE_FILES[0]} + +if [ "${#ETH_KEYSTORE_FILES[@]}" -eq 1 ]; then + echo "Only one KEYSTORE" +else + echo "WARNING: More than one file in keystore: ${ETH_KEYSTORE_FILES}" +fi + +DEPLOYED_ADDRESS=$(forge create --keystore $ETH_KEYSTORE_FILE --rpc-url http://127.0.0.1:8545 --constructor-args 1 --password "" --legacy /root/stateful/src/Stateful.sol:Stateful | grep "Deployed to:" | cut -d " " -f 3) +echo "Contract has been deployed to: $DEPLOYED_ADDRESS" + +# Call a transaction + +TX_OUT=$(cast send --keystore $ETH_KEYSTORE_FILE --rpc-url http://127.0.0.1:8545 --password "" --legacy $DEPLOYED_ADDRESS "off()") + +echo "TX OUTPUT: $TX_OUT" + + +# Run forever +tail -f /dev/null \ No newline at end of file diff --git a/foundry/projects/local-private-network/stateful/foundry.toml b/foundry/projects/local-private-network/stateful/foundry.toml new file mode 100644 index 000000000..19903e0b2 --- /dev/null +++ b/foundry/projects/local-private-network/stateful/foundry.toml @@ -0,0 +1,7 @@ +[default] +src = 'src' +out = 'out' +libs = ['lib'] +remappings = ['ds-test/=lib/ds-test/src/'] + +# See more config options https://github.com/gakonst/foundry/tree/master/config \ No newline at end of file diff --git a/foundry/projects/local-private-network/stateful/src/Stateful.sol b/foundry/projects/local-private-network/stateful/src/Stateful.sol new file mode 100644 index 000000000..e56c15691 --- /dev/null +++ b/foundry/projects/local-private-network/stateful/src/Stateful.sol @@ -0,0 +1,20 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.10; + +contract Stateful { + uint x; + + constructor(uint y) public { + x = y; + } + + function off() public { + require(x == 1); + x = 0; + } + + function on() public { + require(x == 0); + x = 1; + } +} \ No newline at end of file diff --git a/foundry/projects/local-private-network/stateful/src/test/Stateful.t.sol b/foundry/projects/local-private-network/stateful/src/test/Stateful.t.sol new file mode 100644 index 000000000..fb2e97e6e --- /dev/null +++ b/foundry/projects/local-private-network/stateful/src/test/Stateful.t.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity 0.8.10; + +import "ds-test/test.sol"; +import {Stateful} from "../Stateful.sol"; + +contract StatefulTest is DSTest { + Stateful contractA; + //contractA A; + uint x; + function setUp() public { + x = 1; + contractA = new Stateful(x); + } + + function testExample() public { + contractA.off(); + } +} diff --git a/foundry/projects/local-private-network/wrapper.sh b/foundry/projects/local-private-network/wrapper.sh new file mode 100755 index 000000000..cc4481876 --- /dev/null +++ b/foundry/projects/local-private-network/wrapper.sh @@ -0,0 +1,7 @@ +#!/bin/bash +# This script will run everthing for you. Sit back and enjoy they show. + +set -e + +./compile-geth.sh +docker-compose up --build \ No newline at end of file