Compare commits
168
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
491939b35f | ||
|
|
a3d2e71ca6 | ||
|
|
81884d4826 | ||
|
|
389ba2e360 | ||
|
|
c25d220f71 | ||
|
|
8ea4d1e40d | ||
|
|
ace12fbc35 | ||
|
|
8b8f644b2a | ||
|
|
8bfcce95ca | ||
|
|
0b12c3c329 | ||
|
|
037131528c | ||
|
|
be34f0e8fd | ||
|
|
04096fab0c | ||
|
|
dc14656bbc | ||
|
|
9676690a2d | ||
|
|
025b1c7c9e | ||
|
|
36e590c092 | ||
|
|
384d939dc2 | ||
|
|
24a45a3f00 | ||
|
|
867323a1ab | ||
|
|
da30a957a7 | ||
|
|
705835512e | ||
|
|
2a0e9f8dfd | ||
|
|
c8bdaefe97 | ||
|
|
a141d154b7 | ||
|
|
76986d9497 | ||
|
|
233fa29740 | ||
|
|
4883590d85 | ||
|
|
181e3745f1 | ||
|
|
4b697b2a98 | ||
|
|
77812f2673 | ||
|
|
849b17f4bd | ||
|
|
56c85709c1 | ||
|
|
2be2a06575 | ||
|
|
39fb9207b2 | ||
|
|
3914889d53 | ||
|
|
1a6ff273ba | ||
|
|
f57b816530 | ||
|
|
76aaa93c50 | ||
|
|
778bf82dfd | ||
|
|
e8c1db69b4 | ||
|
|
86eee94f9b | ||
|
|
d785fda414 | ||
|
|
41e04a1c30 | ||
|
|
3aa5cb36ef | ||
|
|
43ddbc7eea | ||
|
|
8df8b50cb1 | ||
|
|
072ba1edcc | ||
|
|
f61691a26e | ||
|
|
6ab34eb878 | ||
|
|
3e211d5978 | ||
|
|
f600ea46bc | ||
|
|
6fa38fd198 | ||
|
|
2fa941f084 | ||
|
|
14332c2cd9 | ||
|
|
a780782bb6 | ||
|
|
627f2c7f81 | ||
|
|
925b22869a | ||
|
|
e6fb859967 | ||
|
|
850b305bf6 | ||
|
|
2f6f939982 | ||
|
|
409521416b | ||
|
|
72d3174f63 | ||
|
|
e288a2933d | ||
|
|
1020ec18a4 | ||
|
|
3118bf4964 | ||
|
|
61e6585f1c | ||
|
|
e924974ece | ||
|
|
20b75ff18f | ||
|
|
ef65993412 | ||
|
|
520be6bc86 | ||
|
|
01074ab55c | ||
|
|
88e20dfc6e | ||
|
|
4446219c36 | ||
|
|
88a89c0cc2 | ||
|
|
63e77c9bc0 | ||
|
|
19570f733f | ||
|
|
3058dc48a8 | ||
|
|
5d86b6e029 | ||
|
|
3b863dc76b | ||
|
|
e92b66638e | ||
|
|
cb39a94792 | ||
|
|
ef4d1f958d | ||
|
|
de12fab935 | ||
|
|
34a6d3af4b | ||
|
|
c28ebcc4f2 | ||
|
|
93a995627c | ||
|
|
316bf0990a | ||
|
|
143d79fdfc | ||
|
|
c07ee1d78a | ||
|
|
c3bcb8138b | ||
|
|
f733250afe | ||
|
|
e6869f4236 | ||
|
|
f3c247b54b | ||
|
|
ace7eaad7d | ||
|
|
45de492b4c | ||
|
|
b56215db3f | ||
|
|
f9a31ed862 | ||
|
|
84e22e3b9c | ||
|
|
907c7132f4 | ||
|
|
373d24e26b | ||
|
|
34a2e2369c | ||
|
|
1b513a3c02 | ||
|
|
bd093e0ea6 | ||
|
|
19e3f04f29 | ||
|
|
140989cbf7 | ||
|
|
68152b0d77 | ||
|
|
6d676a342d | ||
|
|
b912b7e75a | ||
|
|
9347affb77 | ||
|
|
61e04e1d9a | ||
|
|
c3d267a6d4 | ||
|
|
fcd2b963b0 | ||
|
|
20c04a98bc | ||
|
|
25b49f784b | ||
|
|
2a1ec043b8 | ||
|
|
e9b5e6b995 | ||
|
|
d53bfae243 | ||
|
|
2fc57c2f31 | ||
|
|
f184b9fd49 | ||
|
|
bc986f7aad | ||
|
|
1973e8032d | ||
|
|
58cb6c252d | ||
|
|
9fef3687a0 | ||
|
|
88ced60707 | ||
|
|
cc6822f7a6 | ||
|
|
0f2b6fd843 | ||
|
|
13e0a5cd19 | ||
|
|
b0674df3ce | ||
|
|
e81da697bc | ||
|
|
7eb7849b5e | ||
|
|
500bba43b4 | ||
|
|
f09f665b11 | ||
|
|
a1781b1eeb | ||
|
|
f6a6a294bb | ||
|
|
81546618d3 | ||
|
|
54db8f23e0 | ||
|
|
1057b001f1 | ||
|
|
3a216b2ca3 | ||
|
|
bca33381dd | ||
|
|
70c539c8d7 | ||
|
|
ec3165f62c | ||
|
|
c3eab5d58e | ||
|
|
6d6f97169b | ||
|
|
77d28264f7 | ||
|
|
885d934c90 | ||
|
|
5acecec955 | ||
|
|
5772d52eb1 | ||
|
|
2de9c5bd48 | ||
|
|
838ed033f8 | ||
|
|
cf4543961c | ||
|
|
f9abcfd33c | ||
|
|
32b4f56557 | ||
|
|
ed4171a1ab | ||
|
|
7f0c8fb2a1 | ||
|
|
04a0f9a751 | ||
|
|
1467ea3924 | ||
|
|
458aae1c1e | ||
|
|
4d9edd2008 | ||
|
|
121c75cc1d | ||
|
|
967c148eff | ||
|
|
71837c4b24 | ||
|
|
d0c3241730 | ||
|
|
a28892f1d3 | ||
|
|
3d1b308326 | ||
|
|
c0a4600ce7 | ||
|
|
b3e4fbfa39 | ||
|
|
d8a5358a70 |
@@ -1,25 +0,0 @@
|
||||
name: Docker Compose Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Run docker build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Get the version
|
||||
id: vars
|
||||
run: echo ::set-output name=sha::$(echo ${GITHUB_SHA:0:7})
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
- name: Tag docker image
|
||||
run: docker tag vulcanize/ipld-eth-server docker.pkg.github.com/vulcanize/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Login
|
||||
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login https://docker.pkg.github.com -u vulcanize --password-stdin
|
||||
- name: Docker Push
|
||||
run: docker push docker.pkg.github.com/vulcanize/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
|
||||
@@ -1,60 +1,10 @@
|
||||
name: Docker Build
|
||||
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Run docker build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
test:
|
||||
name: Run unit tests
|
||||
env:
|
||||
GOPATH: /tmp/go
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.14.x, 1.15.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run database
|
||||
run: docker-compose up -d db
|
||||
- name: Test
|
||||
run: |
|
||||
sleep 10
|
||||
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8077 DATABASE_PASSWORD=password DATABASE_HOSTNAME=127.0.0.1 make test
|
||||
|
||||
integrationtest:
|
||||
name: Run integration tests
|
||||
env:
|
||||
GOPATH: /tmp/go
|
||||
strategy:
|
||||
matrix:
|
||||
go-version: [1.15.x]
|
||||
os: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run database
|
||||
run: docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server
|
||||
- name: Test
|
||||
run: |
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8081)" != "200" ]; do echo "waiting for ipld-eth-server..." && sleep 5; done && \
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8545)" != "200" ]; do echo "waiting for geth-statediff..." && sleep 5; done && \
|
||||
make integrationtest
|
||||
run-tests:
|
||||
uses: ./.github/workflows/tests.yaml
|
||||
secrets:
|
||||
BUILD_HOSTNAME: ${{ secrets.BUILD_HOSTNAME }}
|
||||
BUILD_USERNAME: ${{ secrets.BUILD_USERNAME }}
|
||||
BUILD_KEY: ${{ secrets.BUILD_KEY }}
|
||||
|
||||
@@ -3,9 +3,34 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
jobs:
|
||||
run-tests:
|
||||
uses: ./.github/workflows/tests.yaml
|
||||
secrets:
|
||||
BUILD_HOSTNAME: ${{ secrets.BUILD_HOSTNAME }}
|
||||
BUILD_USERNAME: ${{ secrets.BUILD_USERNAME }}
|
||||
BUILD_KEY: ${{ secrets.BUILD_KEY }}
|
||||
build:
|
||||
name: Run docker build
|
||||
runs-on: ubuntu-latest
|
||||
needs: run-tests
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Get the version
|
||||
id: vars
|
||||
run: echo ::set-output name=sha::$(echo ${GITHUB_SHA:0:7})
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
- name: Tag docker image
|
||||
run: docker tag vulcanize/ipld-eth-server docker.pkg.github.com/vulcanize/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Login
|
||||
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login https://docker.pkg.github.com -u vulcanize --password-stdin
|
||||
- name: Docker Push
|
||||
run: docker push docker.pkg.github.com/vulcanize/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
|
||||
push_to_registries:
|
||||
name: Push Docker image to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
steps:
|
||||
- name: Get the version
|
||||
id: vars
|
||||
@@ -22,4 +47,3 @@ jobs:
|
||||
run: docker tag docker.pkg.github.com/vulcanize/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}} vulcanize/ipld-eth-server:${{steps.vars.outputs.tag}}
|
||||
- name: Docker Push to Docker Hub
|
||||
run: docker push vulcanize/ipld-eth-server:${{steps.vars.outputs.tag}}
|
||||
|
||||
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
# Set up repo
|
||||
start_dir=$(pwd)
|
||||
temp_dir=$(mktemp -d)
|
||||
cd $temp_dir
|
||||
git clone -b $(cat /tmp/git_head_ref) "https://github.com/$(cat /tmp/git_repository).git"
|
||||
cd ipld-eth-server
|
||||
mkdir -p out
|
||||
|
||||
## Remove the branch and github related info. This way future runs wont be confused.
|
||||
rm -f /tmp/git_head_ref /tmp/git_repository
|
||||
|
||||
# Remove existing docker-tsdb directory
|
||||
rm -rf out/docker-tsdb/
|
||||
|
||||
# Copy over files to setup TimescaleDB
|
||||
ID=$(docker create vulcanize/ipld-eth-db:v4.1.1-alpha)
|
||||
docker cp $ID:/app/docker-tsdb out/docker-tsdb/
|
||||
docker rm -v $ID
|
||||
|
||||
# Spin up TimescaleDB
|
||||
docker-compose -f out/docker-tsdb/docker-compose.test.yml -f docker-compose.yml up ipld-eth-db
|
||||
trap "docker-compose -f out/docker-tsdb/docker-compose.test.yml -f docker-compose.yml down --remove-orphans --volumes; cd $start_dir ; rm -r $temp_dir" SIGINT SIGTERM ERR
|
||||
sleep 45
|
||||
|
||||
# Remove old logs so there's no confusion, then run test
|
||||
rm -f /tmp/test.log /tmp/return_test.txt
|
||||
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8066 DATABASE_PASSWORD=password DATABASE_HOSTNAME=127.0.0.1 DATABASE_NAME=vulcanize_testing_v4 make test > /tmp/test.log
|
||||
echo $? > /tmp/return_test.txt
|
||||
|
||||
# Clean up
|
||||
docker-compose -f out/docker-tsdb/docker-compose.test.yml -f docker-compose.yml down --remove-orphans --volumes
|
||||
cd $start_dir
|
||||
rm -fr $temp_dir
|
||||
@@ -0,0 +1,218 @@
|
||||
name: Test the stack.
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
BUILD_HOSTNAME:
|
||||
required: true
|
||||
BUILD_USERNAME:
|
||||
required: true
|
||||
BUILD_KEY:
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Run docker build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
test:
|
||||
name: Run unit tests
|
||||
env:
|
||||
GOPATH: /tmp/go
|
||||
# To run the unit tests you need to add secrets to your repository.
|
||||
BUILD_HOSTNAME: ${{ secrets.BUILD_HOSTNAME }}
|
||||
BUILD_USERNAME: ${{ secrets.BUILD_USERNAME }}
|
||||
BUILD_KEY: ${{ secrets.BUILD_KEY }}
|
||||
#strategy:
|
||||
# matrix:
|
||||
# go-version: [1.16.x, 1.17.x]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Passed experience with GHA has taught me to store variables in files instead of passing them as variables.
|
||||
- name: Output variables to files
|
||||
run: |
|
||||
echo $GITHUB_REPOSITORY > /tmp/git_repository
|
||||
[ -z "$GITHUB_HEAD_REF" ] && echo $GITHUB_REF_NAME > /tmp/git_head_ref || echo $GITHUB_HEAD_REF > /tmp/git_head_ref
|
||||
echo "-----BEGIN OPENSSH PRIVATE KEY-----" >> /tmp/key
|
||||
echo ${{ env.BUILD_KEY }} >> /tmp/key
|
||||
echo "-----END OPENSSH PRIVATE KEY-----" >> /tmp/key
|
||||
chmod 400 /tmp/key
|
||||
cat /tmp/git_repository
|
||||
cat /tmp/git_head_ref
|
||||
|
||||
- name: Raw SCP
|
||||
run: |
|
||||
scp -o 'StrictHostKeyChecking no' -o UserKnownHostsFile=/dev/null -q -i /tmp/key /tmp/git_repository ${{ env.BUILD_USERNAME }}@${{ env.BUILD_HOSTNAME }}:/tmp/git_repository
|
||||
scp -o 'StrictHostKeyChecking no' -o UserKnownHostsFile=/dev/null -q -i /tmp/key /tmp/git_head_ref ${{ env.BUILD_USERNAME }}@${{ env.BUILD_HOSTNAME }}:/tmp/git_head_ref
|
||||
scp -o 'StrictHostKeyChecking no' -o UserKnownHostsFile=/dev/null -q -i /tmp/key .github/workflows/run_unit_test.sh ${{ env.BUILD_USERNAME }}@${{ env.BUILD_HOSTNAME }}:/tmp/run_unit_test.sh
|
||||
|
||||
- name: Trigger Unit Test
|
||||
run: |
|
||||
ssh -o 'StrictHostKeyChecking no' -o UserKnownHostsFile=/dev/null -q -i /tmp/key ${{ env.BUILD_USERNAME }}@${{ env.BUILD_HOSTNAME }} go install github.com/onsi/ginkgo/ginkgo@latest
|
||||
ssh -o 'StrictHostKeyChecking no' -o UserKnownHostsFile=/dev/null -q -i /tmp/key ${{ env.BUILD_USERNAME }}@${{ env.BUILD_HOSTNAME }} /tmp/run_unit_test.sh
|
||||
|
||||
- name: Get the logs and cat them
|
||||
run: |
|
||||
scp -o 'StrictHostKeyChecking no' -o UserKnownHostsFile=/dev/null -q -i /tmp/key ${{ env.BUILD_USERNAME }}@${{ env.BUILD_HOSTNAME }}:/tmp/test.log .
|
||||
cat ./test.log
|
||||
|
||||
- name: Check Error Code
|
||||
run: |
|
||||
scp -o 'StrictHostKeyChecking no' -o UserKnownHostsFile=/dev/null -q -i /tmp/key ${{ env.BUILD_USERNAME }}@${{ env.BUILD_HOSTNAME }}:/tmp/return_test.txt .
|
||||
[ $(cat ./return_test.txt) -eq 0 ]
|
||||
|
||||
integrationtest:
|
||||
name: Run integration tests
|
||||
env:
|
||||
STACK_ORCHESTRATOR_REF: 418957a1f745c921b21286c13bb033f922a91ae9
|
||||
GO_ETHEREUM_REF: "v1.10.18-statediff-4.0.2-alpha"
|
||||
IPLD_ETH_DB_REF: 91d30b9ea1acecd0a7f4307390a98bf3e289b8d7
|
||||
GOPATH: /tmp/go
|
||||
DB_WRITE: true
|
||||
ETH_FORWARD_ETH_CALLS: false
|
||||
ETH_PROXY_ON_ERROR: false
|
||||
ETH_HTTP_PATH: "go-ethereum:8545"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.18.0"
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-server"
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ env.STACK_ORCHESTRATOR_REF }}
|
||||
path: "./stack-orchestrator/"
|
||||
repository: vulcanize/stack-orchestrator
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ env.GO_ETHEREUM_REF }}
|
||||
repository: vulcanize/go-ethereum
|
||||
path: "./go-ethereum/"
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ env.IPLD_ETH_DB_REF }}
|
||||
repository: vulcanize/ipld-eth-db
|
||||
path: "./ipld-eth-db/"
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_go_ethereum=$GITHUB_WORKSPACE/go-ethereum/ > ./config.sh
|
||||
echo vulcanize_ipld_eth_db=$GITHUB_WORKSPACE/ipld-eth-db/ >> ./config.sh
|
||||
echo vulcanize_ipld_eth_server=$GITHUB_WORKSPACE/ipld-eth-server/ >> ./config.sh
|
||||
echo vulcanize_test_contract=$GITHUB_WORKSPACE/ipld-eth-server/test/contract >> ./config.sh
|
||||
echo db_write=$DB_WRITE >> ./config.sh
|
||||
echo eth_forward_eth_calls=$ETH_FORWARD_ETH_CALLS >> ./config.sh
|
||||
echo eth_proxy_on_error=$ETH_PROXY_ON_ERROR >> ./config.sh
|
||||
echo eth_http_path=$ETH_HTTP_PATH >> ./config.sh
|
||||
echo ipld_eth_server_db_dependency=access-node >> ./config.sh
|
||||
echo go_ethereum_db_dependency=access-node >> ./config.sh
|
||||
echo connecting_db_name=vulcanize_testing_v4 >> ./config.sh
|
||||
echo watched_address_gap_filler_enabled=false >> ./config.sh
|
||||
echo watched_address_gap_filler_interval=5 >> ./config.sh
|
||||
cat ./config.sh
|
||||
- name: Build geth
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/stack-orchestrator/helper-scripts
|
||||
./compile-geth.sh \
|
||||
-p "$GITHUB_WORKSPACE/config.sh" \
|
||||
-e docker
|
||||
- name: Run docker compose
|
||||
run: |
|
||||
docker-compose \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-db-migration.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-go-ethereum.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-server.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-contract.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/latest/docker-compose-timescale-db.yml" \
|
||||
--env-file "$GITHUB_WORKSPACE/config.sh" \
|
||||
up -d --build
|
||||
- name: Test
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/ipld-eth-server
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8081)" != "200" ]; do echo "waiting for ipld-eth-server..." && sleep 5; done && \
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8545)" != "200" ]; do echo "waiting for geth-statediff..." && sleep 5; done && \
|
||||
make integrationtest
|
||||
|
||||
integrationtest_forwardethcalls:
|
||||
name: Run integration tests for direct proxy fall-through of eth_calls
|
||||
env:
|
||||
STACK_ORCHESTRATOR_REF: 418957a1f745c921b21286c13bb033f922a91ae9
|
||||
GO_ETHEREUM_REF: "v1.10.18-statediff-4.0.2-alpha"
|
||||
IPLD_ETH_DB_REF: 91d30b9ea1acecd0a7f4307390a98bf3e289b8d7
|
||||
GOPATH: /tmp/go
|
||||
DB_WRITE: false
|
||||
ETH_FORWARD_ETH_CALLS: true
|
||||
ETH_PROXY_ON_ERROR: false
|
||||
ETH_HTTP_PATH: "go-ethereum:8545"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: ">=1.18.0"
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-server"
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ env.STACK_ORCHESTRATOR_REF }}
|
||||
path: "./stack-orchestrator/"
|
||||
repository: vulcanize/stack-orchestrator
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ env.GO_ETHEREUM_REF }}
|
||||
repository: vulcanize/go-ethereum
|
||||
path: "./go-ethereum/"
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
ref: ${{ env.IPLD_ETH_DB_REF }}
|
||||
repository: vulcanize/ipld-eth-db
|
||||
path: "./ipld-eth-db/"
|
||||
- name: Create config file
|
||||
run: |
|
||||
echo vulcanize_go_ethereum=$GITHUB_WORKSPACE/go-ethereum/ > ./config.sh
|
||||
echo vulcanize_ipld_eth_db=$GITHUB_WORKSPACE/ipld-eth-db/ >> ./config.sh
|
||||
echo vulcanize_ipld_eth_server=$GITHUB_WORKSPACE/ipld-eth-server/ >> ./config.sh
|
||||
echo vulcanize_test_contract=$GITHUB_WORKSPACE/ipld-eth-server/test/contract >>./config.sh
|
||||
echo db_write=$DB_WRITE >> ./config.sh
|
||||
echo eth_forward_eth_calls=$ETH_FORWARD_ETH_CALLS >> ./config.sh
|
||||
echo eth_proxy_on_error=$ETH_PROXY_ON_ERROR >> ./config.sh
|
||||
echo eth_http_path=$ETH_HTTP_PATH >> ./config.sh
|
||||
echo ipld_eth_server_db_dependency=access-node >> ./config.sh
|
||||
echo go_ethereum_db_dependency=access-node >> ./config.sh
|
||||
echo connecting_db_name=vulcanize_testing_v4 >> ./config.sh
|
||||
echo watched_address_gap_filler_enabled=false >> ./config.sh
|
||||
echo watched_address_gap_filler_interval=5 >> ./config.sh
|
||||
cat ./config.sh
|
||||
- name: Build geth
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/stack-orchestrator/helper-scripts
|
||||
./compile-geth.sh \
|
||||
-p "$GITHUB_WORKSPACE/config.sh" \
|
||||
-e docker
|
||||
- name: Run docker compose
|
||||
run: |
|
||||
docker-compose \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-db-migration.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-go-ethereum.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-ipld-eth-server.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/local/docker-compose-contract.yml" \
|
||||
-f "$GITHUB_WORKSPACE/stack-orchestrator/docker/latest/docker-compose-timescale-db.yml" \
|
||||
--env-file "$GITHUB_WORKSPACE/config.sh" \
|
||||
up -d --build
|
||||
- name: Test
|
||||
run: |
|
||||
cd $GITHUB_WORKSPACE/ipld-eth-server
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8081)" != "200" ]; do echo "waiting for ipld-eth-server..." && sleep 5; done && \
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8545)" != "200" ]; do echo "waiting for geth-statediff..." && sleep 5; done && \
|
||||
make integrationtest
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.13-alpine as builder
|
||||
FROM golang:1.18-alpine as builder
|
||||
|
||||
RUN apk --update --no-cache add make git g++ linux-headers
|
||||
# DEBUG
|
||||
@@ -44,7 +44,6 @@ COPY --chown=5000:5000 --from=builder /go/src/github.com/vulcanize/ipld-eth-serv
|
||||
# keep binaries immutable
|
||||
COPY --from=builder /go/src/github.com/vulcanize/ipld-eth-server/ipld-eth-server ipld-eth-server
|
||||
COPY --from=builder /goose goose
|
||||
COPY --from=builder /go/src/github.com/vulcanize/ipld-eth-server/db/migrations migrations/vulcanizedb
|
||||
COPY --from=builder /go/src/github.com/vulcanize/ipld-eth-server/environments environments
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
|
||||
@@ -3,10 +3,6 @@ BASE = $(GOPATH)/src/$(PACKAGE)
|
||||
PKGS = go list ./... | grep -v "^vendor/"
|
||||
|
||||
# Tools
|
||||
## Testing library
|
||||
GINKGO = $(BIN)/ginkgo
|
||||
$(BIN)/ginkgo:
|
||||
go get -u github.com/onsi/ginkgo/ginkgo
|
||||
|
||||
## Migration tool
|
||||
GOOSE = $(BIN)/goose
|
||||
@@ -26,8 +22,9 @@ $(BIN)/gometalinter.v2:
|
||||
|
||||
|
||||
.PHONY: installtools
|
||||
installtools: | $(LINT) $(GOOSE) $(GINKGO)
|
||||
installtools: | $(LINT) $(GOOSE)
|
||||
echo "Installing tools"
|
||||
go mod download
|
||||
|
||||
.PHONY: metalint
|
||||
metalint: | $(METALINT)
|
||||
@@ -54,33 +51,23 @@ TEST_CONNECT_STRING = postgresql://$(DATABASE_USER):$(DATABASE_PASSWORD)@$(DATAB
|
||||
TEST_CONNECT_STRING_LOCAL = postgresql://$(USER)@$(HOST_NAME):$(PORT)/$(TEST_DB)?sslmode=disable
|
||||
|
||||
.PHONY: test
|
||||
test: | $(GINKGO) $(GOOSE)
|
||||
test: | $(GOOSE)
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
export PGPASSWORD=$(DATABASE_PASSWORD)
|
||||
dropdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) --if-exists $(TEST_DB)
|
||||
createdb -h $(DATABASE_HOSTNAME) -p $(DATABASE_PORT) -U $(DATABASE_USER) $(TEST_DB)
|
||||
$(GOOSE) -dir db/migrations postgres "$(TEST_CONNECT_STRING)" up
|
||||
$(GINKGO) -r --skipPackage=test
|
||||
go run github.com/onsi/ginkgo/ginkgo -r --skipPackage=test
|
||||
|
||||
.PHONY: integrationtest
|
||||
integrationtest: | $(GINKGO) $(GOOSE)
|
||||
integrationtest: | $(GOOSE)
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
$(GINKGO) -r test/ -v
|
||||
go run github.com/onsi/ginkgo/ginkgo -r test/ -v
|
||||
|
||||
.PHONY: test_local
|
||||
test_local: | $(GINKGO) $(GOOSE)
|
||||
test_local: | $(GOOSE)
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
./scripts/run_unit_test.sh
|
||||
|
||||
.PHONY: integrationtest_local
|
||||
integrationtest_local: | $(GINKGO) $(GOOSE)
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
./scripts/run_intregration_test.sh
|
||||
|
||||
build:
|
||||
go fmt ./...
|
||||
GO111MODULE=on go build
|
||||
@@ -148,4 +135,4 @@ import:
|
||||
## Build docker image
|
||||
.PHONY: docker-build
|
||||
docker-build:
|
||||
docker build -t vulcanize/ipld-eth-server .
|
||||
docker build -t vulcanize/ipld-eth-server .
|
||||
|
||||
@@ -33,9 +33,9 @@ External dependency
|
||||
## Install
|
||||
Start by downloading ipld-eth-server and moving into the repo:
|
||||
|
||||
`GO111MODULE=off go get -d github.com/vulcanize/ipld-eth-server`
|
||||
`GO111MODULE=off go get -d github.com/vulcanize/ipld-eth-server/v4`
|
||||
|
||||
`cd $GOPATH/src/github.com/vulcanize/ipld-eth-server`
|
||||
`cd $GOPATH/src/github.com/vulcanize/ipld-eth-server/v4@v4.x.x`
|
||||
|
||||
Then, build the binary:
|
||||
|
||||
@@ -148,8 +148,8 @@ TODO: Add the rest of the standard endpoints and unique endpoints (e.g. getSlice
|
||||
|
||||
|
||||
### Testing
|
||||
`make test` will run the unit tests
|
||||
`make test` setups a clean `vulcanize_testing` db
|
||||
|
||||
Follow steps in [test/README.md](./test/README.md)
|
||||
|
||||
## Monitoring
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright © 2021 Vulcanize, Inc
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func addDatabaseFlags(command *cobra.Command) {
|
||||
// database flags
|
||||
command.PersistentFlags().String("database-name", "vulcanize_public", "database name")
|
||||
command.PersistentFlags().Int("database-port", 5432, "database port")
|
||||
command.PersistentFlags().String("database-hostname", "localhost", "database hostname")
|
||||
command.PersistentFlags().String("database-user", "", "database user")
|
||||
command.PersistentFlags().String("database-password", "", "database password")
|
||||
|
||||
// database flag bindings
|
||||
viper.BindPFlag("database.name", command.PersistentFlags().Lookup("database-name"))
|
||||
viper.BindPFlag("database.port", command.PersistentFlags().Lookup("database-port"))
|
||||
viper.BindPFlag("database.hostname", command.PersistentFlags().Lookup("database-hostname"))
|
||||
viper.BindPFlag("database.user", command.PersistentFlags().Lookup("database-user"))
|
||||
viper.BindPFlag("database.password", command.PersistentFlags().Lookup("database-password"))
|
||||
}
|
||||
+31
-8
@@ -19,16 +19,20 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/prom"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/prom"
|
||||
)
|
||||
|
||||
var (
|
||||
cfgFile string
|
||||
envFile string
|
||||
subCommand string
|
||||
logWithCommand log.Entry
|
||||
)
|
||||
@@ -99,6 +103,7 @@ func init() {
|
||||
viper.AutomaticEnv()
|
||||
|
||||
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file location")
|
||||
rootCmd.PersistentFlags().StringVar(&envFile, "env", "", "environment file location")
|
||||
|
||||
rootCmd.PersistentFlags().String("client-ipcPath", "", "location of geth.ipc file")
|
||||
rootCmd.PersistentFlags().String("log-level", log.InfoLevel.String(), "log level (trace, debug, info, warn, error, fatal, panic)")
|
||||
@@ -121,14 +126,32 @@ func init() {
|
||||
}
|
||||
|
||||
func initConfig() {
|
||||
if cfgFile == "" && envFile == "" {
|
||||
log.Fatal("No configuration file specified, use --config , --env flag to provide configuration")
|
||||
}
|
||||
|
||||
if cfgFile != "" {
|
||||
viper.SetConfigFile(cfgFile)
|
||||
if err := viper.ReadInConfig(); err == nil {
|
||||
log.Printf("Using config file: %s", viper.ConfigFileUsed())
|
||||
} else {
|
||||
log.Fatal(fmt.Sprintf("Couldn't read config file: %s", err.Error()))
|
||||
if filepath.Ext(cfgFile) != ".toml" {
|
||||
log.Fatal("Provide .toml file for --config flag")
|
||||
}
|
||||
} else {
|
||||
log.Warn("No config file passed with --config flag")
|
||||
|
||||
viper.SetConfigFile(cfgFile)
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Fatalf("Couldn't read config file: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Infof("Using config file: %s", viper.ConfigFileUsed())
|
||||
}
|
||||
|
||||
if envFile != "" {
|
||||
if filepath.Ext(envFile) != ".env" {
|
||||
log.Fatal("Provide .env file for --env flag")
|
||||
}
|
||||
|
||||
if err := godotenv.Load(envFile); err != nil {
|
||||
log.Fatalf("Failed to set environment variable from env file: %s", err.Error())
|
||||
}
|
||||
|
||||
log.Infof("Using env file: %s", envFile)
|
||||
}
|
||||
}
|
||||
|
||||
+129
-22
@@ -23,18 +23,20 @@ import (
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/mailgun/groupcache/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/vulcanize/gap-filler/pkg/mux"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/graphql"
|
||||
srpc "github.com/vulcanize/ipld-eth-server/pkg/rpc"
|
||||
s "github.com/vulcanize/ipld-eth-server/pkg/serve"
|
||||
v "github.com/vulcanize/ipld-eth-server/version"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/graphql"
|
||||
srpc "github.com/vulcanize/ipld-eth-server/v4/pkg/rpc"
|
||||
s "github.com/vulcanize/ipld-eth-server/v4/pkg/serve"
|
||||
v "github.com/vulcanize/ipld-eth-server/v4/version"
|
||||
)
|
||||
|
||||
var ErrNoRpcEndpoints = errors.New("no rpc endpoints is available")
|
||||
@@ -86,7 +88,19 @@ func serve() {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
|
||||
shutdown := make(chan os.Signal)
|
||||
err = startGroupCacheService(serverConfig)
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
|
||||
if serverConfig.StateValidationEnabled {
|
||||
go startStateTrieValidator(serverConfig, server)
|
||||
logWithCommand.Info("state validator enabled")
|
||||
} else {
|
||||
logWithCommand.Info("state validator disabled")
|
||||
}
|
||||
|
||||
shutdown := make(chan os.Signal, 1)
|
||||
signal.Notify(shutdown, os.Interrupt)
|
||||
<-shutdown
|
||||
if graphQL != nil {
|
||||
@@ -119,7 +133,7 @@ func startServers(server s.Server, settings *s.Config) error {
|
||||
|
||||
if settings.HTTPEnabled {
|
||||
logWithCommand.Info("starting up HTTP server")
|
||||
_, err := srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"eth", "net"}, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
||||
_, err := srpc.StartHTTPEndpoint(settings.HTTPEndpoint, server.APIs(), []string{"vdb", "eth", "net"}, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -200,6 +214,83 @@ func startIpldGraphQL(settings *s.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func startGroupCacheService(settings *s.Config) error {
|
||||
gcc := settings.GroupCache
|
||||
|
||||
if gcc.Pool.Enabled {
|
||||
logWithCommand.Info("starting up groupcache pool HTTTP server")
|
||||
|
||||
pool := groupcache.NewHTTPPoolOpts(gcc.Pool.HttpEndpoint, &groupcache.HTTPPoolOptions{})
|
||||
pool.Set(gcc.Pool.PeerHttpEndpoints...)
|
||||
|
||||
httpURL, err := url.Parse(gcc.Pool.HttpEndpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server := http.Server{
|
||||
Addr: httpURL.Host,
|
||||
Handler: pool,
|
||||
}
|
||||
|
||||
// Start a HTTP server to listen for peer requests from the groupcache
|
||||
go server.ListenAndServe()
|
||||
|
||||
logWithCommand.Infof("groupcache pool endpoint opened for url %s", httpURL)
|
||||
} else {
|
||||
logWithCommand.Info("Groupcache pool is disabled")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startStateTrieValidator(config *s.Config, server s.Server) {
|
||||
validateEveryNthBlock := config.StateValidationEveryNthBlock
|
||||
|
||||
var lastBlockNumber uint64
|
||||
backend := server.Backend()
|
||||
|
||||
for {
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
block, err := backend.CurrentBlock()
|
||||
if err != nil {
|
||||
log.Errorln("Error fetching current block for state trie validator")
|
||||
continue
|
||||
}
|
||||
|
||||
stateRoot := block.Root()
|
||||
blockNumber := block.NumberU64()
|
||||
blockHash := block.Hash()
|
||||
|
||||
if validateEveryNthBlock <= 0 || // Used for static replicas where block number doesn't progress.
|
||||
(blockNumber > lastBlockNumber) && (blockNumber%validateEveryNthBlock == 0) {
|
||||
|
||||
// The validate trie call will take a long time on mainnet, e.g. a few hours.
|
||||
if err = backend.ValidateTrie(stateRoot); err != nil {
|
||||
log.Fatalf("Error validating trie for block number %d hash %s state root %s",
|
||||
blockNumber,
|
||||
blockHash,
|
||||
stateRoot,
|
||||
)
|
||||
}
|
||||
|
||||
log.Infof("Successfully validated trie for block number %d hash %s state root %s",
|
||||
blockNumber,
|
||||
blockHash,
|
||||
stateRoot,
|
||||
)
|
||||
|
||||
if validateEveryNthBlock <= 0 {
|
||||
// Static replica, sleep a long-ish time (1/2 of cache expiry time) since we only need to keep the cache warm.
|
||||
time.Sleep((time.Minute * time.Duration(config.GroupCache.StateDB.CacheExpiryInMins)) / 2)
|
||||
}
|
||||
|
||||
lastBlockNumber = blockNumber
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseRpcAddresses(value string) ([]*rpc.Client, error) {
|
||||
rpcAddresses := strings.Split(value, ",")
|
||||
rpcClients := make([]*rpc.Client, 0, len(rpcAddresses))
|
||||
@@ -224,12 +315,7 @@ func parseRpcAddresses(value string) ([]*rpc.Client, error) {
|
||||
func init() {
|
||||
rootCmd.AddCommand(serveCmd)
|
||||
|
||||
// database credentials
|
||||
serveCmd.PersistentFlags().String("database-name", "vulcanize_public", "database name")
|
||||
serveCmd.PersistentFlags().Int("database-port", 5432, "database port")
|
||||
serveCmd.PersistentFlags().String("database-hostname", "localhost", "database hostname")
|
||||
serveCmd.PersistentFlags().String("database-user", "", "database user")
|
||||
serveCmd.PersistentFlags().String("database-password", "", "database password")
|
||||
addDatabaseFlags(serveCmd)
|
||||
|
||||
// flags for all config variables
|
||||
// eth graphql and json-rpc parameters
|
||||
@@ -258,16 +344,23 @@ func init() {
|
||||
serveCmd.PersistentFlags().String("eth-default-sender", "", "default sender address")
|
||||
serveCmd.PersistentFlags().String("eth-rpc-gas-cap", "", "rpc gas cap (for eth_Call execution)")
|
||||
serveCmd.PersistentFlags().String("eth-chain-config", "", "json chain config file location")
|
||||
serveCmd.PersistentFlags().Bool("eth-supports-state-diff", false, "whether or not the proxy ethereum client supports statediffing endpoints")
|
||||
serveCmd.PersistentFlags().Bool("eth-supports-state-diff", false, "whether the proxy ethereum client supports statediffing endpoints")
|
||||
serveCmd.PersistentFlags().Bool("eth-forward-eth-calls", false, "whether to immediately forward eth_calls to proxy client")
|
||||
serveCmd.PersistentFlags().Bool("eth-proxy-on-error", true, "whether to forward all failed calls to proxy client")
|
||||
|
||||
// groupcache flags
|
||||
serveCmd.PersistentFlags().Bool("gcache-pool-enabled", false, "turn on the groupcache pool")
|
||||
serveCmd.PersistentFlags().String("gcache-pool-http-path", "", "http url for groupcache node")
|
||||
serveCmd.PersistentFlags().StringArray("gcache-pool-http-peers", []string{}, "http urls for groupcache peers")
|
||||
serveCmd.PersistentFlags().Int("gcache-statedb-cache-size", 16, "state DB cache size in MB")
|
||||
serveCmd.PersistentFlags().Int("gcache-statedb-cache-expiry", 60, "state DB cache expiry time in mins")
|
||||
serveCmd.PersistentFlags().Int("gcache-statedb-log-stats-interval", 60, "state DB cache stats log interval in secs")
|
||||
|
||||
// state validator flags
|
||||
serveCmd.PersistentFlags().Bool("validator-enabled", false, "turn on the state validator")
|
||||
serveCmd.PersistentFlags().Uint("validator-every-nth-block", 1500, "only validate every Nth block")
|
||||
|
||||
// and their bindings
|
||||
// database
|
||||
viper.BindPFlag("database.name", serveCmd.PersistentFlags().Lookup("database-name"))
|
||||
viper.BindPFlag("database.port", serveCmd.PersistentFlags().Lookup("database-port"))
|
||||
viper.BindPFlag("database.hostname", serveCmd.PersistentFlags().Lookup("database-hostname"))
|
||||
viper.BindPFlag("database.user", serveCmd.PersistentFlags().Lookup("database-user"))
|
||||
viper.BindPFlag("database.password", serveCmd.PersistentFlags().Lookup("database-password"))
|
||||
|
||||
// eth graphql server
|
||||
viper.BindPFlag("eth.server.graphql", serveCmd.PersistentFlags().Lookup("eth-server-graphql"))
|
||||
viper.BindPFlag("eth.server.graphqlPath", serveCmd.PersistentFlags().Lookup("eth-server-graphql-path"))
|
||||
@@ -301,4 +394,18 @@ func init() {
|
||||
viper.BindPFlag("ethereum.rpcGasCap", serveCmd.PersistentFlags().Lookup("eth-rpc-gas-cap"))
|
||||
viper.BindPFlag("ethereum.chainConfig", serveCmd.PersistentFlags().Lookup("eth-chain-config"))
|
||||
viper.BindPFlag("ethereum.supportsStateDiff", serveCmd.PersistentFlags().Lookup("eth-supports-state-diff"))
|
||||
viper.BindPFlag("ethereum.forwardEthCalls", serveCmd.PersistentFlags().Lookup("eth-forward-eth-calls"))
|
||||
viper.BindPFlag("ethereum.proxyOnError", serveCmd.PersistentFlags().Lookup("eth-proxy-on-error"))
|
||||
|
||||
// groupcache flags
|
||||
viper.BindPFlag("groupcache.pool.enabled", serveCmd.PersistentFlags().Lookup("gcache-pool-enabled"))
|
||||
viper.BindPFlag("groupcache.pool.httpEndpoint", serveCmd.PersistentFlags().Lookup("gcache-pool-http-path"))
|
||||
viper.BindPFlag("groupcache.pool.peerHttpEndpoints", serveCmd.PersistentFlags().Lookup("gcache-pool-http-peers"))
|
||||
viper.BindPFlag("groupcache.statedb.cacheSizeInMB", serveCmd.PersistentFlags().Lookup("gcache-statedb-cache-size"))
|
||||
viper.BindPFlag("groupcache.statedb.cacheExpiryInMins", serveCmd.PersistentFlags().Lookup("gcache-statedb-cache-expiry"))
|
||||
viper.BindPFlag("groupcache.statedb.logStatsIntervalInSecs", serveCmd.PersistentFlags().Lookup("gcache-statedb-log-stats-interval"))
|
||||
|
||||
// state validator flags
|
||||
viper.BindPFlag("validator.enabled", serveCmd.PersistentFlags().Lookup("validator-enabled"))
|
||||
viper.BindPFlag("validator.everyNthBlock", serveCmd.PersistentFlags().Lookup("validator-every-nth-block"))
|
||||
}
|
||||
|
||||
+4
-5
@@ -20,7 +20,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
@@ -28,9 +27,9 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/client"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
w "github.com/vulcanize/ipld-eth-server/pkg/serve"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/client"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
w "github.com/vulcanize/ipld-eth-server/v4/pkg/serve"
|
||||
)
|
||||
|
||||
// subscribeCmd represents the subscribe command
|
||||
@@ -129,7 +128,7 @@ func subscribe() {
|
||||
}
|
||||
// This assumes leafs only
|
||||
for _, stateNode := range ethData.StateNodes {
|
||||
var acct state.Account
|
||||
var acct types.StateAccount
|
||||
err = rlp.DecodeBytes(stateNode.IPLD.Data, &acct)
|
||||
if err != nil {
|
||||
logWithCommand.Error(err)
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
// Copyright © 2021 Vulcanize, Inc
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
validator "github.com/vulcanize/eth-ipfs-state-validator/v4/pkg"
|
||||
ipfsethdb "github.com/vulcanize/ipfs-ethdb/v4/postgres"
|
||||
|
||||
s "github.com/vulcanize/ipld-eth-server/v4/pkg/serve"
|
||||
)
|
||||
|
||||
const GroupName = "statedb-validate"
|
||||
const CacheExpiryInMins = 8 * 60 // 8 hours
|
||||
const CacheSizeInMB = 16 // 16 MB
|
||||
|
||||
var validateCmd = &cobra.Command{
|
||||
Use: "validate",
|
||||
Short: "valdiate state",
|
||||
Long: `This command validates the trie for the given state root`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
subCommand = cmd.CalledAs()
|
||||
logWithCommand = *log.WithField("SubCommand", subCommand)
|
||||
validate()
|
||||
},
|
||||
}
|
||||
|
||||
func validate() {
|
||||
config, err := s.NewConfig()
|
||||
if err != nil {
|
||||
logWithCommand.Fatal(err)
|
||||
}
|
||||
|
||||
stateRootStr := viper.GetString("stateRoot")
|
||||
if stateRootStr == "" {
|
||||
logWithCommand.Fatal("must provide a state root for state validation")
|
||||
}
|
||||
|
||||
stateRoot := common.HexToHash(stateRootStr)
|
||||
cacheSize := viper.GetInt("cacheSize")
|
||||
|
||||
ethDB := ipfsethdb.NewDatabase(config.DB, ipfsethdb.CacheConfig{
|
||||
Name: GroupName,
|
||||
Size: cacheSize * 1024 * 1024,
|
||||
ExpiryDuration: time.Minute * time.Duration(CacheExpiryInMins),
|
||||
})
|
||||
|
||||
val := validator.NewValidator(nil, ethDB)
|
||||
if err = val.ValidateTrie(stateRoot); err != nil {
|
||||
log.Fatalln("Error validating state root")
|
||||
}
|
||||
|
||||
stats := ethDB.(*ipfsethdb.Database).GetCacheStats()
|
||||
log.Debugf("groupcache stats %+v", stats)
|
||||
|
||||
log.Infoln("Successfully validated state root")
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(validateCmd)
|
||||
|
||||
addDatabaseFlags(validateCmd)
|
||||
|
||||
validateCmd.PersistentFlags().String("state-root", "", "root of the state trie we wish to validate")
|
||||
viper.BindPFlag("stateRoot", validateCmd.PersistentFlags().Lookup("state-root"))
|
||||
|
||||
validateCmd.PersistentFlags().Int("cache-size", CacheSizeInMB, "cache size in MB")
|
||||
viper.BindPFlag("cacheSize", validateCmd.PersistentFlags().Lookup("cache-size"))
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
v "github.com/vulcanize/ipld-eth-server/version"
|
||||
v "github.com/vulcanize/ipld-eth-server/v4/version"
|
||||
)
|
||||
|
||||
// versionCmd represents the version command
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE IF NOT EXISTS public.blocks (
|
||||
key TEXT UNIQUE NOT NULL,
|
||||
data BYTEA NOT NULL
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE public.blocks;
|
||||
@@ -1,13 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE nodes (
|
||||
id SERIAL PRIMARY KEY,
|
||||
client_name VARCHAR,
|
||||
genesis_block VARCHAR(66),
|
||||
network_id VARCHAR,
|
||||
node_id VARCHAR(128),
|
||||
chain_id INTEGER DEFAULT 1,
|
||||
CONSTRAINT node_uc UNIQUE (genesis_block, network_id, node_id, chain_id)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE nodes;
|
||||
@@ -1,5 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE SCHEMA eth;
|
||||
|
||||
-- +goose Down
|
||||
DROP SCHEMA eth;
|
||||
@@ -1,23 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE eth.header_cids (
|
||||
id SERIAL PRIMARY KEY,
|
||||
block_number BIGINT NOT NULL,
|
||||
block_hash VARCHAR(66) NOT NULL,
|
||||
parent_hash VARCHAR(66) NOT NULL,
|
||||
cid TEXT NOT NULL,
|
||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
td NUMERIC NOT NULL,
|
||||
node_id INTEGER NOT NULL REFERENCES nodes (id) ON DELETE CASCADE,
|
||||
reward NUMERIC NOT NULL,
|
||||
state_root VARCHAR(66) NOT NULL,
|
||||
tx_root VARCHAR(66) NOT NULL,
|
||||
receipt_root VARCHAR(66) NOT NULL,
|
||||
uncle_root VARCHAR(66) NOT NULL,
|
||||
bloom BYTEA NOT NULL,
|
||||
timestamp NUMERIC NOT NULL,
|
||||
times_validated INTEGER NOT NULL DEFAULT 1,
|
||||
UNIQUE (block_number, block_hash)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE eth.header_cids;
|
||||
@@ -1,14 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE eth.uncle_cids (
|
||||
id SERIAL PRIMARY KEY,
|
||||
header_id INTEGER NOT NULL REFERENCES eth.header_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
block_hash VARCHAR(66) NOT NULL,
|
||||
parent_hash VARCHAR(66) NOT NULL,
|
||||
cid TEXT NOT NULL,
|
||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
reward NUMERIC NOT NULL,
|
||||
UNIQUE (header_id, block_hash)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE eth.uncle_cids;
|
||||
@@ -1,16 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE eth.transaction_cids (
|
||||
id SERIAL PRIMARY KEY,
|
||||
header_id INTEGER NOT NULL REFERENCES eth.header_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
tx_hash VARCHAR(66) NOT NULL,
|
||||
index INTEGER NOT NULL,
|
||||
cid TEXT NOT NULL,
|
||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
dst VARCHAR(66) NOT NULL,
|
||||
src VARCHAR(66) NOT NULL,
|
||||
tx_data BYTEA,
|
||||
UNIQUE (header_id, tx_hash)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE eth.transaction_cids;
|
||||
@@ -1,20 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE eth.receipt_cids (
|
||||
id SERIAL PRIMARY KEY,
|
||||
tx_id INTEGER NOT NULL REFERENCES eth.transaction_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
cid TEXT NOT NULL,
|
||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
contract VARCHAR(66),
|
||||
contract_hash VARCHAR(66),
|
||||
topic0s VARCHAR(66)[],
|
||||
topic1s VARCHAR(66)[],
|
||||
topic2s VARCHAR(66)[],
|
||||
topic3s VARCHAR(66)[],
|
||||
log_contracts VARCHAR(66)[],
|
||||
post_state VARCHAR(66),
|
||||
post_status INTEGER,
|
||||
UNIQUE (tx_id)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE eth.receipt_cids;
|
||||
@@ -1,15 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE eth.state_cids (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
header_id INTEGER NOT NULL REFERENCES eth.header_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
state_leaf_key VARCHAR(66),
|
||||
cid TEXT NOT NULL,
|
||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
state_path BYTEA,
|
||||
node_type INTEGER NOT NULL,
|
||||
diff BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
UNIQUE (header_id, state_path)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE eth.state_cids;
|
||||
@@ -1,15 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE eth.storage_cids (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
state_id BIGINT NOT NULL REFERENCES eth.state_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
storage_leaf_key VARCHAR(66),
|
||||
cid TEXT NOT NULL,
|
||||
mh_key TEXT NOT NULL REFERENCES public.blocks (key) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
storage_path BYTEA,
|
||||
node_type INTEGER NOT NULL,
|
||||
diff BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
UNIQUE (state_id, storage_path)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE eth.storage_cids;
|
||||
@@ -1,13 +0,0 @@
|
||||
-- +goose Up
|
||||
CREATE TABLE eth.state_accounts (
|
||||
id SERIAL PRIMARY KEY,
|
||||
state_id BIGINT NOT NULL REFERENCES eth.state_cids (id) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED,
|
||||
balance NUMERIC NOT NULL,
|
||||
nonce INTEGER NOT NULL,
|
||||
code_hash BYTEA NOT NULL,
|
||||
storage_root VARCHAR(66) NOT NULL,
|
||||
UNIQUE (state_id)
|
||||
);
|
||||
|
||||
-- +goose Down
|
||||
DROP TABLE eth.state_accounts;
|
||||
@@ -1,6 +0,0 @@
|
||||
-- +goose Up
|
||||
COMMENT ON TABLE public.nodes IS E'@name NodeInfo';
|
||||
COMMENT ON TABLE eth.transaction_cids IS E'@name EthTransactionCids';
|
||||
COMMENT ON TABLE eth.header_cids IS E'@name EthHeaderCids';
|
||||
COMMENT ON COLUMN public.nodes.node_id IS E'@name ChainNodeID';
|
||||
COMMENT ON COLUMN eth.header_cids.node_id IS E'@name EthNodeID';
|
||||
@@ -1,69 +0,0 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
CREATE FUNCTION eth.graphql_subscription() returns TRIGGER as $$
|
||||
declare
|
||||
table_name text = TG_ARGV[0];
|
||||
attribute text = TG_ARGV[1];
|
||||
id text;
|
||||
begin
|
||||
execute 'select $1.' || quote_ident(attribute)
|
||||
using new
|
||||
into id;
|
||||
perform pg_notify('postgraphile:' || table_name,
|
||||
json_build_object(
|
||||
'__node__', json_build_array(
|
||||
table_name,
|
||||
id
|
||||
)
|
||||
)::text
|
||||
);
|
||||
return new;
|
||||
end;
|
||||
$$ language plpgsql;
|
||||
-- +goose StatementEnd
|
||||
|
||||
CREATE TRIGGER header_cids_ai
|
||||
after INSERT ON eth.header_cids
|
||||
for each row
|
||||
execute procedure eth.graphql_subscription('header_cids', 'id');
|
||||
|
||||
CREATE TRIGGER receipt_cids_ai
|
||||
after INSERT ON eth.receipt_cids
|
||||
for each row
|
||||
execute procedure eth.graphql_subscription('receipt_cids', 'id');
|
||||
|
||||
CREATE TRIGGER state_accounts_ai
|
||||
after INSERT ON eth.state_accounts
|
||||
for each row
|
||||
execute procedure eth.graphql_subscription('state_accounts', 'id');
|
||||
|
||||
CREATE TRIGGER state_cids_ai
|
||||
after INSERT ON eth.state_cids
|
||||
for each row
|
||||
execute procedure eth.graphql_subscription('state_cids', 'id');
|
||||
|
||||
CREATE TRIGGER storage_cids_ai
|
||||
after INSERT ON eth.storage_cids
|
||||
for each row
|
||||
execute procedure eth.graphql_subscription('storage_cids', 'id');
|
||||
|
||||
CREATE TRIGGER transaction_cids_ai
|
||||
after INSERT ON eth.transaction_cids
|
||||
for each row
|
||||
execute procedure eth.graphql_subscription('transaction_cids', 'id');
|
||||
|
||||
CREATE TRIGGER uncle_cids_ai
|
||||
after INSERT ON eth.uncle_cids
|
||||
for each row
|
||||
execute procedure eth.graphql_subscription('uncle_cids', 'id');
|
||||
|
||||
-- +goose Down
|
||||
DROP TRIGGER uncle_cids_ai ON eth.uncle_cids;
|
||||
DROP TRIGGER transaction_cids_ai ON eth.transaction_cids;
|
||||
DROP TRIGGER storage_cids_ai ON eth.storage_cids;
|
||||
DROP TRIGGER state_cids_ai ON eth.state_cids;
|
||||
DROP TRIGGER state_accounts_ai ON eth.state_accounts;
|
||||
DROP TRIGGER receipt_cids_ai ON eth.receipt_cids;
|
||||
DROP TRIGGER header_cids_ai ON eth.header_cids;
|
||||
|
||||
DROP FUNCTION eth.graphql_subscription();
|
||||
@@ -1,121 +0,0 @@
|
||||
-- +goose Up
|
||||
-- header indexes
|
||||
CREATE INDEX block_number_index ON eth.header_cids USING brin (block_number);
|
||||
|
||||
CREATE INDEX block_hash_index ON eth.header_cids USING btree (block_hash);
|
||||
|
||||
CREATE INDEX header_cid_index ON eth.header_cids USING btree (cid);
|
||||
|
||||
CREATE INDEX header_mh_index ON eth.header_cids USING btree (mh_key);
|
||||
|
||||
CREATE INDEX state_root_index ON eth.header_cids USING btree (state_root);
|
||||
|
||||
CREATE INDEX timestamp_index ON eth.header_cids USING brin (timestamp);
|
||||
|
||||
-- transaction indexes
|
||||
CREATE INDEX tx_header_id_index ON eth.transaction_cids USING btree (header_id);
|
||||
|
||||
CREATE INDEX tx_hash_index ON eth.transaction_cids USING btree (tx_hash);
|
||||
|
||||
CREATE INDEX tx_cid_index ON eth.transaction_cids USING btree (cid);
|
||||
|
||||
CREATE INDEX tx_mh_index ON eth.transaction_cids USING btree (mh_key);
|
||||
|
||||
CREATE INDEX tx_dst_index ON eth.transaction_cids USING btree (dst);
|
||||
|
||||
CREATE INDEX tx_src_index ON eth.transaction_cids USING btree (src);
|
||||
|
||||
-- receipt indexes
|
||||
CREATE INDEX rct_tx_id_index ON eth.receipt_cids USING btree (tx_id);
|
||||
|
||||
CREATE INDEX rct_cid_index ON eth.receipt_cids USING btree (cid);
|
||||
|
||||
CREATE INDEX rct_mh_index ON eth.receipt_cids USING btree (mh_key);
|
||||
|
||||
CREATE INDEX rct_contract_index ON eth.receipt_cids USING btree (contract);
|
||||
|
||||
CREATE INDEX rct_contract_hash_index ON eth.receipt_cids USING btree (contract_hash);
|
||||
|
||||
CREATE INDEX rct_topic0_index ON eth.receipt_cids USING gin (topic0s);
|
||||
|
||||
CREATE INDEX rct_topic1_index ON eth.receipt_cids USING gin (topic1s);
|
||||
|
||||
CREATE INDEX rct_topic2_index ON eth.receipt_cids USING gin (topic2s);
|
||||
|
||||
CREATE INDEX rct_topic3_index ON eth.receipt_cids USING gin (topic3s);
|
||||
|
||||
CREATE INDEX rct_log_contract_index ON eth.receipt_cids USING gin (log_contracts);
|
||||
|
||||
-- state node indexes
|
||||
CREATE INDEX state_header_id_index ON eth.state_cids USING btree (header_id);
|
||||
|
||||
CREATE INDEX state_leaf_key_index ON eth.state_cids USING btree (state_leaf_key);
|
||||
|
||||
CREATE INDEX state_cid_index ON eth.state_cids USING btree (cid);
|
||||
|
||||
CREATE INDEX state_mh_index ON eth.state_cids USING btree (mh_key);
|
||||
|
||||
CREATE INDEX state_path_index ON eth.state_cids USING btree (state_path);
|
||||
|
||||
-- storage node indexes
|
||||
CREATE INDEX storage_state_id_index ON eth.storage_cids USING btree (state_id);
|
||||
|
||||
CREATE INDEX storage_leaf_key_index ON eth.storage_cids USING btree (storage_leaf_key);
|
||||
|
||||
CREATE INDEX storage_cid_index ON eth.storage_cids USING btree (cid);
|
||||
|
||||
CREATE INDEX storage_mh_index ON eth.storage_cids USING btree (mh_key);
|
||||
|
||||
CREATE INDEX storage_path_index ON eth.storage_cids USING btree (storage_path);
|
||||
|
||||
-- state accounts indexes
|
||||
CREATE INDEX account_state_id_index ON eth.state_accounts USING btree (state_id);
|
||||
|
||||
CREATE INDEX storage_root_index ON eth.state_accounts USING btree (storage_root);
|
||||
|
||||
-- +goose Down
|
||||
-- state account indexes
|
||||
DROP INDEX eth.storage_root_index;
|
||||
DROP INDEX eth.account_state_id_index;
|
||||
|
||||
-- storage node indexes
|
||||
DROP INDEX eth.storage_path_index;
|
||||
DROP INDEX eth.storage_mh_index;
|
||||
DROP INDEX eth.storage_cid_index;
|
||||
DROP INDEX eth.storage_leaf_key_index;
|
||||
DROP INDEX eth.storage_state_id_index;
|
||||
|
||||
-- state node indexes
|
||||
DROP INDEX eth.state_path_index;
|
||||
DROP INDEX eth.state_mh_index;
|
||||
DROP INDEX eth.state_cid_index;
|
||||
DROP INDEX eth.state_leaf_key_index;
|
||||
DROP INDEX eth.state_header_id_index;
|
||||
|
||||
-- receipt indexes
|
||||
DROP INDEX eth.rct_log_contract_index;
|
||||
DROP INDEX eth.rct_topic3_index;
|
||||
DROP INDEX eth.rct_topic2_index;
|
||||
DROP INDEX eth.rct_topic1_index;
|
||||
DROP INDEX eth.rct_topic0_index;
|
||||
DROP INDEX eth.rct_contract_hash_index;
|
||||
DROP INDEX eth.rct_contract_index;
|
||||
DROP INDEX eth.rct_mh_index;
|
||||
DROP INDEX eth.rct_cid_index;
|
||||
DROP INDEX eth.rct_tx_id_index;
|
||||
|
||||
-- transaction indexes
|
||||
DROP INDEX eth.tx_src_index;
|
||||
DROP INDEX eth.tx_dst_index;
|
||||
DROP INDEX eth.tx_mh_index;
|
||||
DROP INDEX eth.tx_cid_index;
|
||||
DROP INDEX eth.tx_hash_index;
|
||||
DROP INDEX eth.tx_header_id_index;
|
||||
|
||||
-- header indexes
|
||||
DROP INDEX eth.timestamp_index;
|
||||
DROP INDEX eth.state_root_index;
|
||||
DROP INDEX eth.header_mh_index;
|
||||
DROP INDEX eth.header_cid_index;
|
||||
DROP INDEX eth.block_hash_index;
|
||||
DROP INDEX eth.block_number_index;
|
||||
@@ -1,158 +0,0 @@
|
||||
-- +goose Up
|
||||
-- +goose StatementBegin
|
||||
-- returns if a storage node at the provided path was removed in the range >= the provided height and <= the provided block hash
|
||||
CREATE OR REPLACE FUNCTION was_storage_removed(path BYTEA, height BIGINT, hash VARCHAR(66)) RETURNS BOOLEAN
|
||||
AS $$
|
||||
SELECT exists(SELECT 1
|
||||
FROM eth.storage_cids
|
||||
INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id)
|
||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||
WHERE storage_path = path
|
||||
AND block_number >= height
|
||||
AND block_number <= (SELECT block_number
|
||||
FROM eth.header_cids
|
||||
WHERE block_hash = hash)
|
||||
AND storage_cids.node_type = 3
|
||||
LIMIT 1);
|
||||
$$ LANGUAGE SQL;
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
-- returns if a state node at the provided path was removed in the range > the provided height and <= the provided block hash
|
||||
CREATE OR REPLACE FUNCTION was_state_removed(path BYTEA, height BIGINT, hash VARCHAR(66)) RETURNS BOOLEAN
|
||||
AS $$
|
||||
SELECT exists(SELECT 1
|
||||
FROM eth.state_cids
|
||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||
WHERE state_path = path
|
||||
AND block_number > height
|
||||
AND block_number <= (SELECT block_number
|
||||
FROM eth.header_cids
|
||||
WHERE block_hash = hash)
|
||||
AND state_cids.node_type = 3
|
||||
LIMIT 1);
|
||||
$$ LANGUAGE SQL;
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
CREATE TYPE child_result AS (
|
||||
has_child BOOLEAN,
|
||||
children eth.header_cids[]
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION has_child(hash VARCHAR(66), height BIGINT) RETURNS child_result AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
child_height INT;
|
||||
temp_child eth.header_cids;
|
||||
new_child_result child_result;
|
||||
BEGIN
|
||||
child_height = height + 1;
|
||||
-- short circuit if there are no children
|
||||
SELECT exists(SELECT 1
|
||||
FROM eth.header_cids
|
||||
WHERE parent_hash = hash
|
||||
AND block_number = child_height
|
||||
LIMIT 1)
|
||||
INTO new_child_result.has_child;
|
||||
-- collect all the children for this header
|
||||
IF new_child_result.has_child THEN
|
||||
FOR temp_child IN
|
||||
SELECT * FROM eth.header_cids WHERE parent_hash = hash AND block_number = child_height
|
||||
LOOP
|
||||
new_child_result.children = array_append(new_child_result.children, temp_child);
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN new_child_result;
|
||||
END
|
||||
$BODY$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
CREATE OR REPLACE FUNCTION canonical_header_from_array(headers eth.header_cids[]) RETURNS eth.header_cids AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
canonical_header eth.header_cids;
|
||||
canonical_child eth.header_cids;
|
||||
header eth.header_cids;
|
||||
current_child_result child_result;
|
||||
child_headers eth.header_cids[];
|
||||
current_header_with_child eth.header_cids;
|
||||
has_children_count INT DEFAULT 0;
|
||||
BEGIN
|
||||
-- for each header in the provided set
|
||||
FOREACH header IN ARRAY headers
|
||||
LOOP
|
||||
-- check if it has any children
|
||||
current_child_result = has_child(header.block_hash, header.block_number);
|
||||
IF current_child_result.has_child THEN
|
||||
-- if it does, take note
|
||||
has_children_count = has_children_count + 1;
|
||||
current_header_with_child = header;
|
||||
-- and add the children to the growing set of child headers
|
||||
child_headers = array_cat(child_headers, current_child_result.children);
|
||||
END IF;
|
||||
END LOOP;
|
||||
-- if none of the headers had children, none is more canonical than the other
|
||||
IF has_children_count = 0 THEN
|
||||
-- return the first one selected
|
||||
SELECT * INTO canonical_header FROM unnest(headers) LIMIT 1;
|
||||
-- if only one header had children, it can be considered the heaviest/canonical header of the set
|
||||
ELSIF has_children_count = 1 THEN
|
||||
-- return the only header with a child
|
||||
canonical_header = current_header_with_child;
|
||||
-- if there are multiple headers with children
|
||||
ELSE
|
||||
-- find the canonical header from the child set
|
||||
canonical_child = canonical_header_from_array(child_headers);
|
||||
-- the header that is parent to this header, is the canonical header at this level
|
||||
SELECT * INTO canonical_header FROM unnest(headers)
|
||||
WHERE block_hash = canonical_child.parent_hash;
|
||||
END IF;
|
||||
RETURN canonical_header;
|
||||
END
|
||||
$BODY$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose StatementBegin
|
||||
CREATE OR REPLACE FUNCTION canonical_header_id(height BIGINT) RETURNS INTEGER AS
|
||||
$BODY$
|
||||
DECLARE
|
||||
canonical_header eth.header_cids;
|
||||
headers eth.header_cids[];
|
||||
header_count INT;
|
||||
temp_header eth.header_cids;
|
||||
BEGIN
|
||||
-- collect all headers at this height
|
||||
FOR temp_header IN
|
||||
SELECT * FROM eth.header_cids WHERE block_number = height
|
||||
LOOP
|
||||
headers = array_append(headers, temp_header);
|
||||
END LOOP;
|
||||
-- count the number of headers collected
|
||||
header_count = array_length(headers, 1);
|
||||
-- if we have less than 1 header, return NULL
|
||||
IF header_count IS NULL OR header_count < 1 THEN
|
||||
RETURN NULL;
|
||||
-- if we have one header, return its id
|
||||
ELSIF header_count = 1 THEN
|
||||
RETURN headers[1].id;
|
||||
-- if we have multiple headers we need to determine which one is canonical
|
||||
ELSE
|
||||
canonical_header = canonical_header_from_array(headers);
|
||||
RETURN canonical_header.id;
|
||||
END IF;
|
||||
END;
|
||||
$BODY$
|
||||
LANGUAGE 'plpgsql';
|
||||
-- +goose StatementEnd
|
||||
|
||||
-- +goose Down
|
||||
DROP FUNCTION was_storage_removed;
|
||||
DROP FUNCTION was_state_removed;
|
||||
DROP FUNCTION canonical_header_id;
|
||||
DROP FUNCTION canonical_header_from_array;
|
||||
DROP FUNCTION has_child;
|
||||
DROP TYPE child_result;
|
||||
-1201
File diff suppressed because it is too large
Load Diff
@@ -2,13 +2,11 @@ version: '3.2'
|
||||
|
||||
services:
|
||||
contract:
|
||||
depends_on:
|
||||
- dapptools
|
||||
build:
|
||||
context: ./test/contract
|
||||
args:
|
||||
ETH_ADDR: "http://dapptools:8545"
|
||||
ETH_ADDR: "http://go-ethereum:8545"
|
||||
environment:
|
||||
ETH_ADDR: "http://dapptools:8545"
|
||||
ETH_ADDR: "http://go-ethereum:8545"
|
||||
ports:
|
||||
- "127.0.0.1:3000:3000"
|
||||
|
||||
+14
-38
@@ -1,49 +1,22 @@
|
||||
version: '3.2'
|
||||
|
||||
services:
|
||||
dapptools:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- statediff-migrations
|
||||
image: vulcanize/dapptools:v0.29.0-v1.10.2-statediff-0.0.19
|
||||
environment:
|
||||
DB_USER: vdbm
|
||||
DB_NAME: vulcanize_public
|
||||
DB_HOST: db
|
||||
DB_PORT: 5432
|
||||
DB_PASSWORD: password
|
||||
ports:
|
||||
- "127.0.0.1:8545:8545"
|
||||
- "127.0.0.1:8546:8546"
|
||||
|
||||
statediff-migrations:
|
||||
ipld-eth-db:
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- db
|
||||
image: vulcanize/statediff-migrations:v0.4.0
|
||||
- access-node
|
||||
image: vulcanize/ipld-eth-db:v4.1.1-alpha
|
||||
environment:
|
||||
DATABASE_USER: vdbm
|
||||
DATABASE_NAME: vulcanize_public
|
||||
DATABASE_HOSTNAME: db
|
||||
DATABASE_USER: "vdbm"
|
||||
DATABASE_NAME: "vulcanize_testing_v4"
|
||||
DATABASE_PASSWORD: "password"
|
||||
DATABASE_HOSTNAME: "access-node"
|
||||
DATABASE_PORT: 5432
|
||||
DATABASE_PASSWORD: password
|
||||
|
||||
db:
|
||||
restart: always
|
||||
image: postgres:10.12-alpine
|
||||
environment:
|
||||
POSTGRES_USER: "vdbm"
|
||||
POSTGRES_DB: "vulcanize_public"
|
||||
POSTGRES_PASSWORD: "password"
|
||||
volumes:
|
||||
- vdb_db_eth_server:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "127.0.0.1:8077:5432"
|
||||
|
||||
eth-server:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- ipld-eth-db
|
||||
build:
|
||||
context: ./
|
||||
cache_from:
|
||||
@@ -55,12 +28,15 @@ services:
|
||||
ETH_SERVER_HTTPPATH: 0.0.0.0:8081
|
||||
VDB_COMMAND: "serve"
|
||||
ETH_CHAIN_CONFIG: "/tmp/chain.json"
|
||||
DATABASE_NAME: "vulcanize_public"
|
||||
DATABASE_HOSTNAME: "db"
|
||||
DATABASE_NAME: "vulcanize_testing"
|
||||
DATABASE_HOSTNAME: "ipld-eth-db"
|
||||
DATABASE_PORT: 5432
|
||||
DATABASE_USER: "vdbm"
|
||||
DATABASE_PASSWORD: "password"
|
||||
ETH_CHAIN_ID: 4
|
||||
ETH_FORWARD_ETH_CALLS: $ETH_FORWARD_ETH_CALLS
|
||||
ETH_PROXY_ON_ERROR: $ETH_PROXY_ON_ERROR
|
||||
ETH_HTTP_PATH: $ETH_HTTP_PATH
|
||||
volumes:
|
||||
- type: bind
|
||||
source: ./chain.json
|
||||
@@ -71,7 +47,7 @@ services:
|
||||
graphql:
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- db
|
||||
- ipld-eth-db
|
||||
image: vulcanize/postgraphile:v1.0.1
|
||||
environment:
|
||||
- PG_HOST=db
|
||||
|
||||
+11
-11
@@ -12,7 +12,7 @@ We can expose a number of different APIs for remote access to ipld-eth-server da
|
||||
ipld-eth-server stores all processed data in Postgres using PG-IPFS, this includes all of the IPLD objects.
|
||||
[Postgraphile](https://www.graphile.org/postgraphile/) can be used to expose GraphQL endpoints for the Postgres tables.
|
||||
|
||||
e.g.
|
||||
e.g.
|
||||
|
||||
`postgraphile --plugins @graphile/pg-pubsub --subscriptions --simple-subscriptions -c postgres://localhost:5432/vulcanize_public?sslmode=disable -s public,btc,eth -a -j`
|
||||
|
||||
@@ -33,16 +33,16 @@ by ipld-eth-server to filter and return a requested subset of chain data to the
|
||||
An example of how to subscribe to a real-time Ethereum data feed from ipld-eth-server using the `Stream` RPC method is provided below
|
||||
|
||||
```go
|
||||
package main
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/client"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/watch"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/client"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/watch"
|
||||
)
|
||||
|
||||
config, _ := eth.NewEthSubscriptionConfig()
|
||||
@@ -153,16 +153,16 @@ the addresses in the `addresses` fields are pre-hashed ETH addresses.
|
||||
An example of how to subscribe to a real-time Bitcoin data feed from ipld-eth-server using the `Stream` RPC method is provided below
|
||||
|
||||
```go
|
||||
package main
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/btc"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/client"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/watch"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/btc"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/client"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/watch"
|
||||
)
|
||||
|
||||
config, _ := btc.NewBtcSubscriptionConfig()
|
||||
|
||||
@@ -1,20 +1,4 @@
|
||||
#!/bin/sh
|
||||
# Runs the db migrations and starts the watcher services
|
||||
|
||||
# Construct the connection string for postgres
|
||||
VDB_PG_CONNECT=postgresql://$DATABASE_USER:$DATABASE_PASSWORD@$DATABASE_HOSTNAME:$DATABASE_PORT/$DATABASE_NAME?sslmode=disable
|
||||
|
||||
# Run the DB migrations
|
||||
echo "Connecting with: $VDB_PG_CONNECT"
|
||||
echo "Running database migrations"
|
||||
./goose -dir migrations/vulcanizedb postgres "$VDB_PG_CONNECT" up
|
||||
rv=$?
|
||||
|
||||
if [ $rv != 0 ]; then
|
||||
echo "Could not run migrations. Are the database details correct?"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
echo "Beginning the ipld-eth-server process"
|
||||
|
||||
|
||||
@@ -16,12 +16,15 @@
|
||||
graphqlEndpoint = "127.0.0.1:8083" # $SERVER_GRAPHQL_ENDPOINT
|
||||
|
||||
[ethereum]
|
||||
chainConfig = "./chain.json" # ETH_CHAIN_CONFIG
|
||||
chainID = "1" # $ETH_CHAIN_ID
|
||||
defaultSender = "" # $ETH_DEFAULT_SENDER_ADDR
|
||||
rpcGasCap = "1000000000000" # $ETH_RPC_GAS_CAP
|
||||
httpPath = "127.0.0.1:8545" # $ETH_HTTP_PATH
|
||||
supportsStateDiff = true # $ETH_SUPPORTS_STATEDIFF
|
||||
forwardEthCalls = false # $ETH_FORWARD_ETH_CALLS
|
||||
proxyOnError = true # $ETH_PROXY_ON_ERROR
|
||||
nodeID = "arch1" # $ETH_NODE_ID
|
||||
clientName = "Geth" # $ETH_CLIENT_NAME
|
||||
genesisBlock = "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" # $ETH_GENESIS_BLOCK
|
||||
networkID = "1" # $ETH_NETWORK_ID
|
||||
networkID = "1" # $ETH_NETWORK_ID
|
||||
|
||||
@@ -1,32 +1,287 @@
|
||||
module github.com/vulcanize/ipld-eth-server
|
||||
module github.com/vulcanize/ipld-eth-server/v4
|
||||
|
||||
go 1.13
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
github.com/ethereum/go-ethereum v1.9.25
|
||||
github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29
|
||||
github.com/ipfs/go-block-format v0.0.2
|
||||
github.com/ethereum/go-ethereum v1.10.18
|
||||
github.com/graph-gophers/graphql-go v1.3.0
|
||||
github.com/ipfs/go-block-format v0.0.3
|
||||
github.com/ipfs/go-cid v0.0.7
|
||||
github.com/ipfs/go-ipfs-blockstore v1.0.1
|
||||
github.com/ipfs/go-ipfs-ds-help v1.0.0
|
||||
github.com/ipfs/go-ipld-format v0.2.0
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/lib/pq v1.10.5
|
||||
github.com/machinebox/graphql v0.2.2
|
||||
github.com/multiformats/go-multihash v0.0.14
|
||||
github.com/onsi/ginkgo v1.16.2
|
||||
github.com/onsi/gomega v1.10.1
|
||||
github.com/prometheus/client_golang v1.5.1
|
||||
github.com/shirou/gopsutil v3.21.5+incompatible // indirect
|
||||
github.com/sirupsen/logrus v1.7.0
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/spf13/viper v1.7.0
|
||||
github.com/tklauser/go-sysconf v0.3.6 // indirect
|
||||
github.com/mailgun/groupcache/v2 v2.3.0
|
||||
github.com/multiformats/go-multihash v0.1.0
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.19.0
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/sirupsen/logrus v1.8.1
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/viper v1.11.0
|
||||
github.com/vulcanize/eth-ipfs-state-validator/v4 v4.0.1-alpha
|
||||
github.com/vulcanize/gap-filler v0.3.1
|
||||
github.com/vulcanize/ipfs-ethdb v0.0.2-alpha
|
||||
github.com/vulcanize/ipld-eth-indexer v0.7.1-alpha.0.20210805022537-b4692fa49849
|
||||
github.com/vulcanize/ipfs-ethdb/v4 v4.0.1-alpha
|
||||
)
|
||||
|
||||
replace github.com/ethereum/go-ethereum v1.9.25 => github.com/vulcanize/go-ethereum v1.10.4-statediff-0.0.25
|
||||
require (
|
||||
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect
|
||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6 // indirect
|
||||
github.com/Stebalien/go-bitfield v0.0.1 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||
github.com/benbjohnson/clock v1.1.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/btcsuite/btcd v0.22.1 // indirect
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
|
||||
github.com/cskr/pubsub v1.0.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
|
||||
github.com/deckarep/golang-set v1.8.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect
|
||||
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5 // indirect
|
||||
github.com/flynn/noise v1.0.0 // indirect
|
||||
github.com/francoispqt/gojay v1.2.13 // indirect
|
||||
github.com/friendsofgo/graphiql v0.2.2 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
github.com/georgysavva/scany v0.2.9 // indirect
|
||||
github.com/go-ole/go-ole v1.2.1 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/graphql-go/graphql v0.7.9 // indirect
|
||||
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
|
||||
github.com/hashicorp/errwrap v1.0.0 // indirect
|
||||
github.com/hashicorp/go-bexpr v0.1.10 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
|
||||
github.com/holiman/uint256 v1.2.0 // indirect
|
||||
github.com/huin/goupnp v1.0.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/influxdata/influxdb v1.8.3 // indirect
|
||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
github.com/ipfs/bbloom v0.0.4 // indirect
|
||||
github.com/ipfs/go-bitswap v0.4.0 // indirect
|
||||
github.com/ipfs/go-blockservice v0.1.7 // indirect
|
||||
github.com/ipfs/go-cidutil v0.0.2 // indirect
|
||||
github.com/ipfs/go-datastore v0.4.6 // indirect
|
||||
github.com/ipfs/go-ds-measure v0.1.0 // indirect
|
||||
github.com/ipfs/go-fetcher v1.5.0 // indirect
|
||||
github.com/ipfs/go-filestore v1.0.0 // indirect
|
||||
github.com/ipfs/go-fs-lock v0.0.7 // indirect
|
||||
github.com/ipfs/go-graphsync v0.8.0 // indirect
|
||||
github.com/ipfs/go-ipfs v0.10.0 // indirect
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect
|
||||
github.com/ipfs/go-ipfs-config v0.16.0 // indirect
|
||||
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipfs-exchange-interface v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipfs-exchange-offline v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipfs-files v0.0.8 // indirect
|
||||
github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipfs-pinner v0.1.2 // indirect
|
||||
github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipfs-provider v0.6.1 // indirect
|
||||
github.com/ipfs/go-ipfs-routing v0.1.0 // indirect
|
||||
github.com/ipfs/go-ipfs-util v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipld-cbor v0.0.5 // indirect
|
||||
github.com/ipfs/go-ipld-format v0.2.0 // indirect
|
||||
github.com/ipfs/go-ipld-legacy v0.1.0 // indirect
|
||||
github.com/ipfs/go-ipns v0.1.2 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.3.0 // indirect
|
||||
github.com/ipfs/go-merkledag v0.4.0 // indirect
|
||||
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
|
||||
github.com/ipfs/go-mfs v0.1.2 // indirect
|
||||
github.com/ipfs/go-namesys v0.3.1 // indirect
|
||||
github.com/ipfs/go-path v0.1.2 // indirect
|
||||
github.com/ipfs/go-peertaskqueue v0.4.0 // indirect
|
||||
github.com/ipfs/go-unixfs v0.2.5 // indirect
|
||||
github.com/ipfs/go-unixfsnode v1.1.3 // indirect
|
||||
github.com/ipfs/go-verifcid v0.0.1 // indirect
|
||||
github.com/ipfs/interface-go-ipfs-core v0.5.1 // indirect
|
||||
github.com/ipld/go-codec-dagpb v1.3.0 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.12.2 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.10.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgproto3/v2 v2.1.1 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
|
||||
github.com/jackc/pgtype v1.8.1 // indirect
|
||||
github.com/jackc/pgx/v4 v4.13.0 // indirect
|
||||
github.com/jackc/puddle v1.1.3 // indirect
|
||||
github.com/jackpal/go-nat-pmp v1.0.2 // indirect
|
||||
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
|
||||
github.com/jbenet/goprocess v0.1.4 // indirect
|
||||
github.com/jinzhu/copier v0.2.4 // indirect
|
||||
github.com/klauspost/compress v1.11.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/koron/go-ssdp v0.0.2 // indirect
|
||||
github.com/libp2p/go-addr-util v0.1.0 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
github.com/libp2p/go-conn-security-multistream v0.2.1 // indirect
|
||||
github.com/libp2p/go-doh-resolver v0.3.1 // indirect
|
||||
github.com/libp2p/go-eventbus v0.2.1 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.0.3 // indirect
|
||||
github.com/libp2p/go-libp2p v0.15.0 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.0.0-20200825225859-85005c6cf052 // indirect
|
||||
github.com/libp2p/go-libp2p-autonat v0.4.2 // indirect
|
||||
github.com/libp2p/go-libp2p-blankhost v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-circuit v0.4.0 // indirect
|
||||
github.com/libp2p/go-libp2p-connmgr v0.2.4 // indirect
|
||||
github.com/libp2p/go-libp2p-core v0.9.0 // indirect
|
||||
github.com/libp2p/go-libp2p-discovery v0.5.1 // indirect
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.13.1 // indirect
|
||||
github.com/libp2p/go-libp2p-kbucket v0.4.7 // indirect
|
||||
github.com/libp2p/go-libp2p-loggables v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p-mplex v0.4.1 // indirect
|
||||
github.com/libp2p/go-libp2p-nat v0.0.6 // indirect
|
||||
github.com/libp2p/go-libp2p-noise v0.2.2 // indirect
|
||||
github.com/libp2p/go-libp2p-peerstore v0.2.8 // indirect
|
||||
github.com/libp2p/go-libp2p-pnet v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub v0.5.4 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.4.0 // indirect
|
||||
github.com/libp2p/go-libp2p-quic-transport v0.12.0 // indirect
|
||||
github.com/libp2p/go-libp2p-record v0.1.3 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect
|
||||
github.com/libp2p/go-libp2p-swarm v0.5.3 // indirect
|
||||
github.com/libp2p/go-libp2p-tls v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-transport-upgrader v0.4.6 // indirect
|
||||
github.com/libp2p/go-libp2p-xor v0.0.0-20210714161855-5c005aca55db // indirect
|
||||
github.com/libp2p/go-libp2p-yamux v0.5.4 // indirect
|
||||
github.com/libp2p/go-maddr-filter v0.1.0 // indirect
|
||||
github.com/libp2p/go-mplex v0.3.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.0.6 // indirect
|
||||
github.com/libp2p/go-nat v0.0.5 // indirect
|
||||
github.com/libp2p/go-netroute v0.1.6 // indirect
|
||||
github.com/libp2p/go-openssl v0.0.7 // indirect
|
||||
github.com/libp2p/go-reuseport v0.0.2 // indirect
|
||||
github.com/libp2p/go-reuseport-transport v0.0.5 // indirect
|
||||
github.com/libp2p/go-sockaddr v0.1.1 // indirect
|
||||
github.com/libp2p/go-stream-muxer-multistream v0.3.0 // indirect
|
||||
github.com/libp2p/go-tcp-transport v0.2.8 // indirect
|
||||
github.com/libp2p/go-ws-transport v0.5.0 // indirect
|
||||
github.com/libp2p/go-yamux/v2 v2.2.0 // indirect
|
||||
github.com/libp2p/zeroconf/v2 v2.0.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.26.0 // indirect
|
||||
github.com/magiconair/properties v1.8.6 // indirect
|
||||
github.com/marten-seemann/qtls-go1-16 v0.1.5 // indirect
|
||||
github.com/marten-seemann/qtls-go1-17 v0.1.1 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.1 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/matryer/is v1.4.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/miekg/dns v1.1.43 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/mitchellh/pointerstructure v1.2.0 // indirect
|
||||
github.com/mr-tron/base58 v1.2.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.0.3 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.4.0 // indirect
|
||||
github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect
|
||||
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.0.3 // indirect
|
||||
github.com/multiformats/go-multicodec v0.3.0 // indirect
|
||||
github.com/multiformats/go-multistream v0.2.2 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
|
||||
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect
|
||||
github.com/pganalyze/pg_query_go/v2 v2.1.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.30.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/tsdb v0.7.1 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/segmentio/fasthash v1.0.3 // indirect
|
||||
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect
|
||||
github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
|
||||
github.com/spaolacci/murmur3 v1.1.0 // indirect
|
||||
github.com/spf13/afero v1.8.2 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
github.com/stretchr/testify v1.7.1 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
|
||||
github.com/thoas/go-funk v0.9.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.5 // indirect
|
||||
github.com/tklauser/numcpus v0.2.2 // indirect
|
||||
github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef // indirect
|
||||
github.com/valyala/fastjson v1.6.3 // indirect
|
||||
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
|
||||
github.com/whyrusleeping/cbor-gen v0.0.0-20210219115102-f37d292932f2 // indirect
|
||||
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // indirect
|
||||
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
|
||||
github.com/whyrusleeping/mdns v0.0.0-20190826153040-b9b60ed33aa9 // indirect
|
||||
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opentelemetry.io/otel v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v0.20.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/dig v1.10.0 // indirect
|
||||
go.uber.org/fx v1.13.1 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.19.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57 // indirect
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/urfave/cli.v1 v1.20.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
lukechampine.com/blake3 v1.1.6 // indirect
|
||||
)
|
||||
|
||||
replace github.com/vulcanize/ipfs-ethdb v0.0.2-alpha => github.com/vulcanize/pg-ipfs-ethdb v0.0.2-alpha
|
||||
replace github.com/ethereum/go-ethereum v1.10.18 => github.com/vulcanize/go-ethereum v1.10.18-statediff-4.0.2-alpha
|
||||
|
||||
@@ -18,7 +18,7 @@ package main
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/cmd"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -20,11 +20,10 @@ package client
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/serve"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/serve"
|
||||
)
|
||||
|
||||
// Client is used to subscribe to the ipld-eth-server ipld data stream
|
||||
|
||||
+232
-168
@@ -24,12 +24,15 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/filters"
|
||||
@@ -39,7 +42,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/statediff"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
// APIName is the namespace for the watcher's eth api
|
||||
@@ -54,13 +57,21 @@ type PublicEthAPI struct {
|
||||
B *Backend
|
||||
|
||||
// Proxy node for forwarding cache misses
|
||||
supportsStateDiff bool // Whether or not the remote node supports the statediff_writeStateDiffAt endpoint, if it does we can fill the local cache when we hit a miss
|
||||
supportsStateDiff bool // Whether the remote node supports the statediff_writeStateDiffAt endpoint, if it does we can fill the local cache when we hit a miss
|
||||
rpc *rpc.Client
|
||||
ethClient *ethclient.Client
|
||||
forwardEthCalls bool // if true, forward eth_call calls directly to the configured proxy node
|
||||
proxyOnError bool // turn on regular proxy fall-through on errors; needed to test difference between direct and indirect fall-through
|
||||
}
|
||||
|
||||
// NewPublicEthAPI creates a new PublicEthAPI with the provided underlying Backend
|
||||
func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff bool) *PublicEthAPI {
|
||||
func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff, forwardEthCalls, proxyOnError bool) (*PublicEthAPI, error) {
|
||||
if forwardEthCalls && client == nil {
|
||||
return nil, errors.New("ipld-eth-server is configured to forward eth_calls to proxy node but no proxy node is configured")
|
||||
}
|
||||
if proxyOnError && client == nil {
|
||||
return nil, errors.New("ipld-eth-server is configured to forward all calls to proxy node on errors but no proxy node is configured")
|
||||
}
|
||||
var ethClient *ethclient.Client
|
||||
if client != nil {
|
||||
ethClient = ethclient.NewClient(client)
|
||||
@@ -70,7 +81,9 @@ func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff bool) *Pu
|
||||
supportsStateDiff: supportsStateDiff,
|
||||
rpc: client,
|
||||
ethClient: ethClient,
|
||||
}
|
||||
forwardEthCalls: forwardEthCalls,
|
||||
proxyOnError: proxyOnError,
|
||||
}, nil
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -87,12 +100,13 @@ func (pea *PublicEthAPI) GetHeaderByNumber(ctx context.Context, number rpc.Block
|
||||
if header != nil && err == nil {
|
||||
return pea.rpcMarshalHeader(header)
|
||||
}
|
||||
if pea.ethClient != nil {
|
||||
if pea.proxyOnError {
|
||||
if header, err := pea.ethClient.HeaderByNumber(ctx, big.NewInt(number.Int64())); header != nil && err == nil {
|
||||
go pea.writeStateDiffAt(number.Int64())
|
||||
return pea.rpcMarshalHeader(header)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -104,7 +118,8 @@ func (pea *PublicEthAPI) GetHeaderByHash(ctx context.Context, hash common.Hash)
|
||||
return res
|
||||
}
|
||||
}
|
||||
if pea.ethClient != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
if header, err := pea.ethClient.HeaderByHash(ctx, hash); header != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
if res, err := pea.rpcMarshalHeader(header); err != nil {
|
||||
@@ -112,6 +127,7 @@ func (pea *PublicEthAPI) GetHeaderByHash(ctx context.Context, hash common.Hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -122,7 +138,9 @@ func (pea *PublicEthAPI) rpcMarshalHeader(header *types.Header) (map[string]inte
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
fields["totalDifficulty"] = (*hexutil.Big)(td)
|
||||
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
@@ -142,12 +160,14 @@ func (pea *PublicEthAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockN
|
||||
if block != nil && err == nil {
|
||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||
}
|
||||
if pea.ethClient != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
if block, err := pea.ethClient.BlockByNumber(ctx, big.NewInt(number.Int64())); block != nil && err == nil {
|
||||
go pea.writeStateDiffAt(number.Int64())
|
||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -158,28 +178,33 @@ func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, f
|
||||
if block != nil && err == nil {
|
||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||
}
|
||||
if pea.ethClient != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
if block, err := pea.ethClient.BlockByHash(ctx, hash); block != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ChainId is the EIP-155 replay-protection chain id for the current ethereum chain config.
|
||||
func (pea *PublicEthAPI) ChainId() hexutil.Uint64 {
|
||||
chainID := new(big.Int)
|
||||
func (pea *PublicEthAPI) ChainId() (*hexutil.Big, error) {
|
||||
block, err := pea.B.CurrentBlock()
|
||||
if err != nil {
|
||||
logrus.Errorf("ChainId failed with err %s", err.Error())
|
||||
if pea.proxyOnError {
|
||||
if id, err := pea.ethClient.ChainID(context.Background()); err == nil {
|
||||
return (*hexutil.Big)(id), nil
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
if config := pea.B.Config.ChainConfig; config.IsEIP155(block.Number()) {
|
||||
chainID = config.ChainID
|
||||
return (*hexutil.Big)(config.ChainID), nil
|
||||
}
|
||||
return (hexutil.Uint64)(chainID.Uint64())
|
||||
return nil, fmt.Errorf("chain not synced beyond EIP-155 replay-protection fork block")
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -201,12 +226,14 @@ func (pea *PublicEthAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, bloc
|
||||
block = types.NewBlockWithHeader(uncles[index])
|
||||
return pea.rpcMarshalBlock(block, false, false)
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
if uncle, uncleHashes, err := getBlockAndUncleHashes(pea.rpc, ctx, "eth_getUncleByBlockNumberAndIndex", blockNr, index); uncle != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
return pea.rpcMarshalBlockWithUncleHashes(uncle, uncleHashes, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -223,12 +250,14 @@ func (pea *PublicEthAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockH
|
||||
block = types.NewBlockWithHeader(uncles[index])
|
||||
return pea.rpcMarshalBlock(block, false, false)
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
if uncle, uncleHashes, err := getBlockAndUncleHashes(pea.rpc, ctx, "eth_getUncleByBlockHashAndIndex", blockHash, index); uncle != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
return pea.rpcMarshalBlockWithUncleHashes(uncle, uncleHashes, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -238,13 +267,15 @@ func (pea *PublicEthAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr
|
||||
n := hexutil.Uint(len(block.Uncles()))
|
||||
return &n
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getUncleCountByBlockNumber", blockNr); num != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
return num
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -254,13 +285,15 @@ func (pea *PublicEthAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash
|
||||
n := hexutil.Uint(len(block.Uncles()))
|
||||
return &n
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getUncleCountByBlockHash", blockHash); num != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
return num
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -276,13 +309,15 @@ func (pea *PublicEthAPI) GetTransactionCount(ctx context.Context, address common
|
||||
if count != nil && err == nil {
|
||||
return count, nil
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
var num *hexutil.Uint64
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getTransactionCount", address, blockNrOrHash); num != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
return num, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -291,6 +326,7 @@ func (pea *PublicEthAPI) localGetTransactionCount(ctx context.Context, address c
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce := hexutil.Uint64(account.Nonce)
|
||||
return &nonce, nil
|
||||
}
|
||||
@@ -301,13 +337,15 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByNumber(ctx context.Context, b
|
||||
n := hexutil.Uint(len(block.Transactions()))
|
||||
return &n
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", blockNr); num != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
return num
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -317,13 +355,15 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByHash(ctx context.Context, blo
|
||||
n := hexutil.Uint(len(block.Transactions()))
|
||||
return &n
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash); num != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
return num
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -332,13 +372,15 @@ func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context
|
||||
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
|
||||
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
var tx *RPCTransaction
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByBlockNumberAndIndex", blockNr, index); tx != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
return tx
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -347,13 +389,15 @@ func (pea *PublicEthAPI) GetTransactionByBlockHashAndIndex(ctx context.Context,
|
||||
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
|
||||
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
|
||||
if pea.proxyOnError {
|
||||
var tx *RPCTransaction
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
return tx
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -362,7 +406,7 @@ func (pea *PublicEthAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Cont
|
||||
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
|
||||
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var tx hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getRawTransactionByBlockNumberAndIndex", blockNr, index); tx != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
@@ -377,7 +421,7 @@ func (pea *PublicEthAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Contex
|
||||
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
|
||||
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var tx hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getRawTransactionByBlockHashAndIndex", blockHash, index); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
@@ -399,7 +443,7 @@ func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.H
|
||||
|
||||
return NewRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee), nil
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var tx *RPCTransaction
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", hash); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
@@ -416,7 +460,7 @@ func (pea *PublicEthAPI) GetRawTransactionByHash(ctx context.Context, hash commo
|
||||
if tx != nil && err == nil {
|
||||
return rlp.EncodeToBytes(tx)
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var tx hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getRawTransactionByHash", hash); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
@@ -438,7 +482,7 @@ func (pea *PublicEthAPI) GetTransactionReceipt(ctx context.Context, hash common.
|
||||
if receipt != nil && err == nil {
|
||||
return receipt, nil
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
if receipt := pea.remoteGetTransactionReceipt(ctx, hash); receipt != nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
return receipt, nil
|
||||
@@ -536,7 +580,7 @@ func (pea *PublicEthAPI) remoteGetTransactionReceipt(ctx context.Context, hash c
|
||||
// https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getlogs
|
||||
func (pea *PublicEthAPI) GetLogs(ctx context.Context, crit filters.FilterCriteria) ([]*types.Log, error) {
|
||||
logs, err := pea.localGetLogs(crit)
|
||||
if err != nil && pea.rpc != nil {
|
||||
if err != nil && pea.proxyOnError {
|
||||
var res []*types.Log
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getLogs", crit); err == nil {
|
||||
go pea.writeStateDiffWithCriteria(crit)
|
||||
@@ -586,24 +630,14 @@ func (pea *PublicEthAPI) localGetLogs(crit filters.FilterCriteria) ([]*types.Log
|
||||
}
|
||||
}()
|
||||
|
||||
// If we have a blockhash to filter on, fire off single retrieval query
|
||||
// If we have a blockHash to filter on, fire off single retrieval query
|
||||
if crit.BlockHash != nil {
|
||||
rctCIDs, err := pea.B.Retriever.RetrieveRctCIDs(tx, filter, 0, crit.BlockHash, nil)
|
||||
filteredLogs, err := pea.B.Retriever.RetrieveFilteredLog(tx, filter, 0, crit.BlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rctIPLDs, err := pea.B.Fetcher.FetchRcts(tx, rctCIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
block, err := pea.B.BlockByHash(context.Background(), *crit.BlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return extractLogsOfInterest(pea.B.Config.ChainConfig, *crit.BlockHash, block.NumberU64(), block.Transactions(), rctIPLDs, filter)
|
||||
|
||||
return decomposeLogs(filteredLogs)
|
||||
}
|
||||
|
||||
// Otherwise, create block range from criteria
|
||||
@@ -626,27 +660,17 @@ func (pea *PublicEthAPI) localGetLogs(crit filters.FilterCriteria) ([]*types.Log
|
||||
end := endingBlock.Int64()
|
||||
var logs []*types.Log
|
||||
for i := start; i <= end; i++ {
|
||||
rctCIDs, err := pea.B.Retriever.RetrieveRctCIDs(tx, filter, i, nil, nil)
|
||||
filteredLogs, err := pea.B.Retriever.RetrieveFilteredLog(tx, filter, i, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block, err := pea.B.BlockByNumber(context.Background(), rpc.BlockNumber(i))
|
||||
logCIDs, err := decomposeLogs(filteredLogs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rctIPLDs, err := pea.B.Fetcher.FetchRcts(tx, rctCIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log, err := extractLogsOfInterest(pea.B.Config.ChainConfig, block.Hash(), uint64(i), block.Transactions(), rctIPLDs, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logs = append(logs, log...)
|
||||
logs = append(logs, logCIDs...)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
@@ -670,7 +694,7 @@ func (pea *PublicEthAPI) GetBalance(ctx context.Context, address common.Address,
|
||||
if bal != nil && err == nil {
|
||||
return bal, nil
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var res *hexutil.Big
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getBalance", address, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
@@ -710,7 +734,7 @@ func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Addres
|
||||
|
||||
return value[:], nil
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var res hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
@@ -729,7 +753,7 @@ func (pea *PublicEthAPI) GetCode(ctx context.Context, address common.Address, bl
|
||||
if code != nil && err == nil {
|
||||
return code, nil
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var res hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getCode", address, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
@@ -749,7 +773,7 @@ func (pea *PublicEthAPI) GetProof(ctx context.Context, address common.Address, s
|
||||
if proof != nil && err == nil {
|
||||
return proof, nil
|
||||
}
|
||||
if pea.rpc != nil {
|
||||
if pea.proxyOnError {
|
||||
var res *AccountResult
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getProof", address, storageKeys, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
@@ -808,50 +832,59 @@ func (pea *PublicEthAPI) localGetProof(ctx context.Context, address common.Addre
|
||||
}, state.Error()
|
||||
}
|
||||
|
||||
// Call executes the given transaction on the state for the given block number.
|
||||
//
|
||||
// Additionally, the caller can specify a batch of contract for fields overriding.
|
||||
//
|
||||
// Note, this function doesn't make and changes in the state/blockchain and is
|
||||
// useful to execute and retrieve values.
|
||||
func (pea *PublicEthAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *map[common.Address]account) (hexutil.Bytes, error) {
|
||||
var accounts map[common.Address]account
|
||||
if overrides != nil {
|
||||
accounts = *overrides
|
||||
}
|
||||
res, _, failed, err := DoCall(ctx, pea.B, args, blockNrOrHash, accounts, 5*time.Second, pea.B.Config.RPCGasCap)
|
||||
if (failed || err != nil) && pea.rpc != nil {
|
||||
var hex hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &hex, "eth_call", args, blockNrOrHash, overrides); hex != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
return hex, nil
|
||||
}
|
||||
}
|
||||
if failed && err == nil {
|
||||
return nil, errors.New("eth_call failed without error")
|
||||
}
|
||||
return (hexutil.Bytes)(res), err
|
||||
// revertError is an API error that encompassas an EVM revertal with JSON error
|
||||
// code and a binary data blob.
|
||||
type revertError struct {
|
||||
error
|
||||
reason string // revert reason hex encoded
|
||||
}
|
||||
|
||||
func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides map[common.Address]account, timeout time.Duration, globalGasCap *big.Int) ([]byte, uint64, bool, error) {
|
||||
defer func(start time.Time) {
|
||||
logrus.Debugf("Executing EVM call finished %s runtime %s", time.Now().String(), time.Since(start).String())
|
||||
}(time.Now())
|
||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
if state == nil || err != nil {
|
||||
return nil, 0, false, err
|
||||
// ErrorCode returns the JSON error code for a revertal.
|
||||
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
||||
func (e *revertError) ErrorCode() int {
|
||||
return 3
|
||||
}
|
||||
|
||||
// ErrorData returns the hex encoded revert reason.
|
||||
func (e *revertError) ErrorData() interface{} {
|
||||
return e.reason
|
||||
}
|
||||
|
||||
func newRevertError(result *core.ExecutionResult) *revertError {
|
||||
reason, errUnpack := abi.UnpackRevert(result.Revert())
|
||||
err := errors.New("execution reverted")
|
||||
if errUnpack == nil {
|
||||
err = fmt.Errorf("execution reverted: %v", reason)
|
||||
}
|
||||
// Set sender address or use a default if none specified
|
||||
var addr common.Address
|
||||
if args.From == nil {
|
||||
if b.Config.DefaultSender != nil {
|
||||
addr = *b.Config.DefaultSender
|
||||
}
|
||||
} else {
|
||||
addr = *args.From
|
||||
return &revertError{
|
||||
error: err,
|
||||
reason: hexutil.Encode(result.Revert()),
|
||||
}
|
||||
// Override the fields of specified contracts before execution.
|
||||
for addr, account := range overrides {
|
||||
}
|
||||
|
||||
// OverrideAccount indicates the overriding fields of account during the execution
|
||||
// of a message call.
|
||||
// Note, state and stateDiff can't be specified at the same time. If state is
|
||||
// set, message execution will only use the data in the given state. Otherwise
|
||||
// if statDiff is set, all diff will be applied first and then execute the call
|
||||
// message.
|
||||
type OverrideAccount struct {
|
||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||
Code *hexutil.Bytes `json:"code"`
|
||||
Balance **hexutil.Big `json:"balance"`
|
||||
State *map[common.Hash]common.Hash `json:"state"`
|
||||
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
|
||||
}
|
||||
|
||||
// StateOverride is the collection of overridden accounts.
|
||||
type StateOverride map[common.Address]OverrideAccount
|
||||
|
||||
// Apply overrides the fields of specified accounts into the given state.
|
||||
func (diff *StateOverride) Apply(state *state.StateDB) error {
|
||||
if diff == nil {
|
||||
return nil
|
||||
}
|
||||
for addr, account := range *diff {
|
||||
// Override account nonce.
|
||||
if account.Nonce != nil {
|
||||
state.SetNonce(addr, uint64(*account.Nonce))
|
||||
@@ -865,7 +898,7 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
||||
state.SetBalance(addr, (*big.Int)(*account.Balance))
|
||||
}
|
||||
if account.State != nil && account.StateDiff != nil {
|
||||
return nil, 0, false, fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
||||
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
|
||||
}
|
||||
// Replace entire state if caller requires.
|
||||
if account.State != nil {
|
||||
@@ -878,74 +911,57 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set default gas & gas price if none were set
|
||||
gas := uint64(math.MaxUint64 / 2)
|
||||
if args.Gas != nil {
|
||||
gas = uint64(*args.Gas)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Call executes the given transaction on the state for the given block number.
|
||||
//
|
||||
// Additionally, the caller can specify a batch of contract for fields overriding.
|
||||
//
|
||||
// Note, this function doesn't make and changes in the state/blockchain and is
|
||||
// useful to execute and retrieve values.
|
||||
func (pea *PublicEthAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride) (hexutil.Bytes, error) {
|
||||
if pea.forwardEthCalls {
|
||||
var hex hexutil.Bytes
|
||||
err := pea.rpc.CallContext(ctx, &hex, "eth_call", args, blockNrOrHash, overrides)
|
||||
return hex, err
|
||||
}
|
||||
|
||||
if globalGasCap != nil && globalGasCap.Uint64() < gas {
|
||||
logrus.Warnf("Caller gas above allowance, capping; requested: %d, cap: %d", gas, globalGasCap)
|
||||
gas = globalGasCap.Uint64()
|
||||
}
|
||||
result, err := DoCall(ctx, pea.B, args, blockNrOrHash, overrides, 5*time.Second, pea.B.Config.RPCGasCap.Uint64())
|
||||
|
||||
var (
|
||||
gasPrice *big.Int
|
||||
gasFeeCap *big.Int
|
||||
gasTipCap *big.Int
|
||||
)
|
||||
|
||||
if header.BaseFee == nil {
|
||||
// If there's no basefee, then it must be a non-1559 execution
|
||||
gasPrice = new(big.Int)
|
||||
if args.GasPrice != nil {
|
||||
gasPrice = args.GasPrice.ToInt()
|
||||
}
|
||||
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||
} else {
|
||||
// A basefee is provided, necessitating 1559-type execution
|
||||
if args.GasPrice != nil {
|
||||
// User specified the legacy gas field, convert to 1559 gas typing
|
||||
gasPrice = args.GasPrice.ToInt()
|
||||
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||
} else {
|
||||
// User specified 1559 gas feilds (or none), use those
|
||||
gasFeeCap = new(big.Int)
|
||||
if args.MaxFeePerGas != nil {
|
||||
gasFeeCap = args.MaxFeePerGas.ToInt()
|
||||
}
|
||||
gasTipCap = new(big.Int)
|
||||
if args.MaxPriorityFeePerGas != nil {
|
||||
gasTipCap = args.MaxPriorityFeePerGas.ToInt()
|
||||
}
|
||||
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
|
||||
gasPrice = new(big.Int)
|
||||
if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
|
||||
gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, header.BaseFee), gasFeeCap)
|
||||
}
|
||||
// If the result contains a revert reason, try to unpack and return it.
|
||||
if err == nil {
|
||||
if len(result.Revert()) > 0 {
|
||||
err = newRevertError(result)
|
||||
} else if result.Err != nil {
|
||||
err = result.Err
|
||||
}
|
||||
}
|
||||
|
||||
value := new(big.Int)
|
||||
if args.Value != nil {
|
||||
value = args.Value.ToInt()
|
||||
if err != nil && pea.proxyOnError {
|
||||
var hex hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &hex, "eth_call", args, blockNrOrHash, overrides); hex != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
return hex, nil
|
||||
}
|
||||
}
|
||||
return result.Return(), err
|
||||
}
|
||||
|
||||
func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.BlockNumberOrHash, overrides *StateOverride, timeout time.Duration, globalGasCap uint64) (*core.ExecutionResult, error) {
|
||||
defer func(start time.Time) {
|
||||
logrus.Debugf("Executing EVM call finished %s runtime %s", time.Now().String(), time.Since(start).String())
|
||||
}(time.Now())
|
||||
|
||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
if state == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if args.Input != nil {
|
||||
data = *args.Input
|
||||
} else if args.Data != nil {
|
||||
data = *args.Data
|
||||
if err := overrides.Apply(state); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var accessList types.AccessList
|
||||
if args.AccessList != nil {
|
||||
accessList = *args.AccessList
|
||||
}
|
||||
|
||||
// Create new call message
|
||||
msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, false)
|
||||
|
||||
// Setup context so it may be cancelled the call has completed
|
||||
// or, in case of unmetered gas, setup a context with a timeout.
|
||||
var cancel context.CancelFunc
|
||||
@@ -959,10 +975,16 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
||||
defer cancel()
|
||||
|
||||
// Get a new instance of the EVM.
|
||||
evm, err := b.GetEVM(ctx, msg, state, header)
|
||||
msg, err := args.ToMessage(globalGasCap, header.BaseFee)
|
||||
if err != nil {
|
||||
return nil, 0, false, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
evm, vmError, err := b.GetEVM(ctx, msg, state, header)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Wait for the context to be done and cancel the evm. Even if the
|
||||
// EVM has finished, cancelling may be done (repeatedly)
|
||||
go func() {
|
||||
@@ -970,18 +992,21 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
||||
evm.Cancel()
|
||||
}()
|
||||
|
||||
// Setup the gas pool (also for unmetered requests)
|
||||
// and apply the message.
|
||||
// Execute the message.
|
||||
gp := new(core.GasPool).AddGas(math.MaxUint64)
|
||||
result, err := core.ApplyMessage(evm, msg, gp)
|
||||
if err != nil {
|
||||
return nil, 0, false, fmt.Errorf("execution failed: %v", err)
|
||||
if err := vmError(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If the timer caused an abort, return an appropriate error message
|
||||
if evm.Cancelled() {
|
||||
return nil, 0, false, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
||||
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
||||
}
|
||||
return result.Return(), result.UsedGas, result.Failed(), err
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// writeStateDiffAtOrFor calls out to the proxy statediffing geth client to fill in a gap in the index
|
||||
@@ -1105,3 +1130,42 @@ func toHexSlice(b [][]byte) []string {
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// decomposeLogs return logs from LogResult.
|
||||
func decomposeLogs(logCIDs []LogResult) ([]*types.Log, error) {
|
||||
logs := make([]*types.Log, len(logCIDs))
|
||||
for i, l := range logCIDs {
|
||||
topics := make([]common.Hash, 0)
|
||||
if l.Topic0 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic0))
|
||||
}
|
||||
if l.Topic1 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic1))
|
||||
}
|
||||
if l.Topic2 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic2))
|
||||
}
|
||||
if l.Topic3 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic3))
|
||||
}
|
||||
|
||||
// TODO: should we convert string to uint ?
|
||||
blockNum, err := strconv.ParseUint(l.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logs[i] = &types.Log{
|
||||
Address: common.HexToAddress(l.Address),
|
||||
Topics: topics,
|
||||
Data: l.Data,
|
||||
BlockNumber: blockNum,
|
||||
TxHash: common.HexToHash(l.TxHash),
|
||||
TxIndex: uint(l.TxnIndex),
|
||||
BlockHash: common.HexToHash(l.BlockHash),
|
||||
Index: uint(l.Index),
|
||||
}
|
||||
}
|
||||
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
+129
-57
@@ -30,28 +30,28 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/interfaces"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
ethServerShared "github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f")
|
||||
randomHash = crypto.Keccak256Hash(randomAddr.Bytes())
|
||||
number = rpc.BlockNumber(test_helpers.BlockNumber.Int64())
|
||||
londonBlockNum = rpc.BlockNumber(test_helpers.LondonBlockNum.Int64())
|
||||
wrongNumber = rpc.BlockNumber(number + 1)
|
||||
blockHash = test_helpers.MockBlock.Header().Hash()
|
||||
londonBlockHash = test_helpers.MockLondonBlock.Header().Hash()
|
||||
baseFee = test_helpers.MockLondonBlock.BaseFee()
|
||||
ctx = context.Background()
|
||||
expectedBlock = map[string]interface{}{
|
||||
randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f")
|
||||
randomHash = crypto.Keccak256Hash(randomAddr.Bytes())
|
||||
number = rpc.BlockNumber(test_helpers.BlockNumber.Int64())
|
||||
londonBlockNum = rpc.BlockNumber(test_helpers.LondonBlockNum.Int64())
|
||||
wrongNumber = number + 1
|
||||
blockHash = test_helpers.MockBlock.Header().Hash()
|
||||
baseFee = test_helpers.MockLondonBlock.BaseFee()
|
||||
ctx = context.Background()
|
||||
expectedBlock = map[string]interface{}{
|
||||
"number": (*hexutil.Big)(test_helpers.MockBlock.Number()),
|
||||
"hash": test_helpers.MockBlock.Hash(),
|
||||
"parentHash": test_helpers.MockBlock.ParentHash(),
|
||||
@@ -150,7 +150,7 @@ var (
|
||||
"contractAddress": nil,
|
||||
"logs": test_helpers.MockReceipts[0].Logs,
|
||||
"logsBloom": test_helpers.MockReceipts[0].Bloom,
|
||||
"root": hexutil.Bytes(test_helpers.MockReceipts[0].PostState),
|
||||
"status": hexutil.Uint(test_helpers.MockReceipts[0].Status),
|
||||
}
|
||||
expectedReceipt2 = map[string]interface{}{
|
||||
"blockHash": blockHash,
|
||||
@@ -184,28 +184,55 @@ var (
|
||||
|
||||
var _ = Describe("API", func() {
|
||||
var (
|
||||
db *postgres.DB
|
||||
db *sqlx.DB
|
||||
api *eth.PublicEthAPI
|
||||
chainConfig = params.TestChainConfig
|
||||
)
|
||||
// Test db setup, rather than using BeforeEach we only need to setup once since the tests do not mutate the database
|
||||
// Note: if you focus one of the tests be sure to focus this and the defered It()
|
||||
It("test init", func() {
|
||||
var err error
|
||||
db, err = shared.SetupDB()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
indexAndPublisher := eth2.NewIPLDPublisher(db)
|
||||
var (
|
||||
err error
|
||||
tx interfaces.Batch
|
||||
)
|
||||
|
||||
db = shared.SetupDB()
|
||||
indexAndPublisher := shared.SetupTestStateDiffIndexer(ctx, chainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
backend, err := eth.NewEthBackend(db, ð.Config{
|
||||
ChainConfig: chainConfig,
|
||||
VmConfig: vm.Config{},
|
||||
VMConfig: vm.Config{},
|
||||
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||
GroupCacheConfig: ðServerShared.GroupCacheConfig{
|
||||
StateDB: ethServerShared.GroupConfig{
|
||||
Name: "api_test",
|
||||
CacheSizeInMB: 8,
|
||||
CacheExpiryInMins: 60,
|
||||
LogStatsIntervalInSecs: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
api = eth.NewPublicEthAPI(backend, nil, false)
|
||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
||||
api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false)
|
||||
tx, err = indexAndPublisher.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = publishCode(db, test_helpers.ContractCodeHash, test_helpers.ContractCode)
|
||||
|
||||
ccHash := sdtypes.CodeAndCodeHash{
|
||||
Hash: test_helpers.ContractCodeHash,
|
||||
Code: test_helpers.ContractCode,
|
||||
}
|
||||
|
||||
err = indexAndPublisher.PushCodeAndCodeHash(tx, ccHash)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
for _, node := range test_helpers.MockStateNodes {
|
||||
err = indexAndPublisher.PushStateNode(tx, node, test_helpers.MockBlock.Hash().String())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
uncles := test_helpers.MockBlock.Uncles()
|
||||
uncleHashes := make([]common.Hash, len(uncles))
|
||||
for i, uncle := range uncles {
|
||||
@@ -213,12 +240,19 @@ var _ = Describe("API", func() {
|
||||
}
|
||||
expectedBlock["uncles"] = uncleHashes
|
||||
|
||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedLondonPayload)
|
||||
// setting chain config to for london block
|
||||
chainConfig.LondonBlock = big.NewInt(2)
|
||||
indexAndPublisher = shared.SetupTestStateDiffIndexer(ctx, chainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
tx, err = indexAndPublisher.PushBlock(test_helpers.MockLondonBlock, test_helpers.MockLondonReceipts, test_helpers.MockLondonBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
// Single test db tear down at end of all tests
|
||||
defer It("test teardown", func() { eth.TearDownDB(db) })
|
||||
defer It("test teardown", func() { shared.TearDownDB(db) })
|
||||
/*
|
||||
|
||||
Headers and blocks
|
||||
@@ -236,8 +270,6 @@ var _ = Describe("API", func() {
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err.Error()).To(ContainSubstring("sql: no rows in result set"))
|
||||
Expect(header).To(BeNil())
|
||||
_, err = api.B.DB.Beginx()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -339,8 +371,7 @@ var _ = Describe("API", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
_, ok := block["baseFee"]
|
||||
Expect(ok).To(Equal(false))
|
||||
|
||||
block, err = api.GetBlockByHash(ctx, londonBlockHash, false)
|
||||
block, err = api.GetBlockByHash(ctx, test_helpers.MockLondonBlock.Hash(), false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(block["baseFee"].(*big.Int)).To(Equal(baseFee))
|
||||
})
|
||||
@@ -440,14 +471,14 @@ var _ = Describe("API", func() {
|
||||
Describe("eth_getBlockTransactionCountByNumber", func() {
|
||||
It("Retrieves the number of transactions in the canonical block with the provided number", func() {
|
||||
count := api.GetBlockTransactionCountByNumber(ctx, number)
|
||||
Expect(uint64(*count)).To(Equal(uint64(3)))
|
||||
Expect(uint64(*count)).To(Equal(uint64(4)))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("eth_getBlockTransactionCountByHash", func() {
|
||||
It("Retrieves the number of transactions in the block with the provided hash ", func() {
|
||||
count := api.GetBlockTransactionCountByHash(ctx, blockHash)
|
||||
Expect(uint64(*count)).To(Equal(uint64(3)))
|
||||
Expect(uint64(*count)).To(Equal(uint64(4)))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -490,7 +521,7 @@ var _ = Describe("API", func() {
|
||||
})
|
||||
|
||||
It("Retrieves the GasFeeCap and GasTipCap for dynamic transaction from the london block hash", func() {
|
||||
tx := api.GetTransactionByBlockHashAndIndex(ctx, londonBlockHash, 0)
|
||||
tx := api.GetTransactionByBlockHashAndIndex(ctx, test_helpers.MockLondonBlock.Hash(), 0)
|
||||
Expect(tx).ToNot(BeNil())
|
||||
Expect(tx.GasFeeCap).To(Equal((*hexutil.Big)(test_helpers.MockLondonTransactions[0].GasFeeCap())))
|
||||
Expect(tx.GasTipCap).To(Equal((*hexutil.Big)(test_helpers.MockLondonTransactions[0].GasTipCap())))
|
||||
@@ -610,7 +641,13 @@ var _ = Describe("API", func() {
|
||||
crit := filters.FilterCriteria{
|
||||
Topics: [][]common.Hash{
|
||||
{
|
||||
common.HexToHash("0x04"),
|
||||
common.HexToHash("0x0c"),
|
||||
},
|
||||
{
|
||||
common.HexToHash("0x0a"),
|
||||
},
|
||||
{
|
||||
common.HexToHash("0x0b"),
|
||||
},
|
||||
},
|
||||
FromBlock: test_helpers.MockBlock.Number(),
|
||||
@@ -618,6 +655,58 @@ var _ = Describe("API", func() {
|
||||
}
|
||||
logs, err := api.GetLogs(ctx, crit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(0))
|
||||
|
||||
crit = filters.FilterCriteria{
|
||||
Topics: [][]common.Hash{
|
||||
{
|
||||
common.HexToHash("0x08"),
|
||||
},
|
||||
{
|
||||
common.HexToHash("0x0a"),
|
||||
},
|
||||
{
|
||||
common.HexToHash("0x0c"),
|
||||
},
|
||||
},
|
||||
FromBlock: test_helpers.MockBlock.Number(),
|
||||
ToBlock: test_helpers.MockBlock.Number(),
|
||||
}
|
||||
logs, err = api.GetLogs(ctx, crit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(0))
|
||||
|
||||
crit = filters.FilterCriteria{
|
||||
Topics: [][]common.Hash{
|
||||
{
|
||||
common.HexToHash("0x09"),
|
||||
},
|
||||
{
|
||||
common.HexToHash("0x0a"),
|
||||
},
|
||||
{
|
||||
common.HexToHash("0x0b"),
|
||||
},
|
||||
},
|
||||
FromBlock: test_helpers.MockBlock.Number(),
|
||||
ToBlock: test_helpers.MockBlock.Number(),
|
||||
}
|
||||
logs, err = api.GetLogs(ctx, crit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(1))
|
||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog4}))
|
||||
|
||||
crit = filters.FilterCriteria{
|
||||
Topics: [][]common.Hash{
|
||||
{
|
||||
common.HexToHash("0x04"),
|
||||
},
|
||||
},
|
||||
FromBlock: test_helpers.MockBlock.Number(),
|
||||
ToBlock: test_helpers.MockBlock.Number(),
|
||||
}
|
||||
logs, err = api.GetLogs(ctx, crit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(1))
|
||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1}))
|
||||
|
||||
@@ -775,8 +864,8 @@ var _ = Describe("API", func() {
|
||||
}
|
||||
logs, err = api.GetLogs(ctx, crit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(2))
|
||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
||||
Expect(len(logs)).To(Equal(6))
|
||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2, test_helpers.MockLog3, test_helpers.MockLog4, test_helpers.MockLog5, test_helpers.MockLog6}))
|
||||
})
|
||||
|
||||
It("Uses the provided blockhash if one is provided", func() {
|
||||
@@ -911,8 +1000,8 @@ var _ = Describe("API", func() {
|
||||
}
|
||||
logs, err = api.GetLogs(ctx, crit)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(2))
|
||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2}))
|
||||
Expect(len(logs)).To(Equal(6))
|
||||
Expect(logs).To(Equal([]*types.Log{test_helpers.MockLog1, test_helpers.MockLog2, test_helpers.MockLog3, test_helpers.MockLog4, test_helpers.MockLog5, test_helpers.MockLog6}))
|
||||
})
|
||||
|
||||
It("Filters on contract address if any are provided", func() {
|
||||
@@ -1034,20 +1123,3 @@ var _ = Describe("API", func() {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func publishCode(db *postgres.DB, codeHash common.Hash, code []byte) error {
|
||||
tx, err := db.Beginx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mhKey, err := shared.MultihashKeyFromKeccak256(codeHash)
|
||||
if err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
if err := shared.PublishDirect(tx, mhKey, code); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
+110
-44
@@ -22,10 +22,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
@@ -39,14 +39,16 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
validator "github.com/vulcanize/eth-ipfs-state-validator/v4/pkg"
|
||||
ipfsethdb "github.com/vulcanize/ipfs-ethdb/v4/postgres"
|
||||
|
||||
ipfsethdb "github.com/vulcanize/ipfs-ethdb"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
shared2 "github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
ethServerShared "github.com/ethereum/go-ethereum/statediff/indexer/shared"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -54,37 +56,56 @@ var (
|
||||
errNegativeBlockNumber = errors.New("negative block number not supported")
|
||||
errHeaderHashNotFound = errors.New("header for hash not found")
|
||||
errHeaderNotFound = errors.New("header not found")
|
||||
|
||||
// errMissingSignature is returned if a block's extra-data section doesn't seem
|
||||
// to contain a 65 byte secp256k1 signature.
|
||||
)
|
||||
|
||||
const (
|
||||
RetrieveCanonicalBlockHashByNumber = `SELECT block_hash FROM eth.header_cids
|
||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||
WHERE id = (SELECT canonical_header_id($1))`
|
||||
INNER JOIN public.blocks ON (
|
||||
header_cids.mh_key = blocks.key
|
||||
AND header_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = (SELECT canonical_header_hash($1))`
|
||||
RetrieveCanonicalHeaderByNumber = `SELECT cid, data FROM eth.header_cids
|
||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||
WHERE id = (SELECT canonical_header_id($1))`
|
||||
RetrieveTD = `SELECT td FROM eth.header_cids
|
||||
INNER JOIN public.blocks ON (
|
||||
header_cids.mh_key = blocks.key
|
||||
AND header_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = (SELECT canonical_header_hash($1))`
|
||||
RetrieveTD = `SELECT CAST(td as Text) FROM eth.header_cids
|
||||
WHERE header_cids.block_hash = $1`
|
||||
RetrieveRPCTransaction = `SELECT blocks.data, block_hash, block_number, index FROM public.blocks, eth.transaction_cids, eth.header_cids
|
||||
RetrieveRPCTransaction = `SELECT blocks.data, block_hash, transaction_cids.block_number, index
|
||||
FROM public.blocks, eth.transaction_cids, eth.header_cids
|
||||
WHERE blocks.key = transaction_cids.mh_key
|
||||
AND transaction_cids.header_id = header_cids.id
|
||||
AND blocks.block_number = transaction_cids.block_number
|
||||
AND transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
AND transaction_cids.tx_hash = $1`
|
||||
RetrieveCodeHashByLeafKeyAndBlockHash = `SELECT code_hash FROM eth.state_accounts, eth.state_cids, eth.header_cids
|
||||
WHERE state_accounts.state_id = state_cids.id
|
||||
AND state_cids.header_id = header_cids.id
|
||||
WHERE state_accounts.header_id = state_cids.header_id
|
||||
AND state_accounts.state_path = state_cids.state_path
|
||||
AND state_accounts.block_number = state_cids.block_number
|
||||
AND state_cids.header_id = header_cids.block_hash
|
||||
AND state_cids.block_number = header_cids.block_number
|
||||
AND state_leaf_key = $1
|
||||
AND block_number <= (SELECT block_number
|
||||
AND header_cids.block_number <= (SELECT block_number
|
||||
FROM eth.header_cids
|
||||
WHERE block_hash = $2)
|
||||
AND header_cids.id = (SELECT canonical_header_id(block_number))
|
||||
ORDER BY block_number DESC
|
||||
AND header_cids.block_hash = (SELECT canonical_header_hash(header_cids.block_number))
|
||||
ORDER BY header_cids.block_number DESC
|
||||
LIMIT 1`
|
||||
RetrieveCodeByMhKey = `SELECT data FROM public.blocks WHERE key = $1`
|
||||
)
|
||||
|
||||
const (
|
||||
StateDBGroupCacheName = "statedb"
|
||||
)
|
||||
|
||||
type Backend struct {
|
||||
// underlying postgres db
|
||||
DB *postgres.DB
|
||||
DB *sqlx.DB
|
||||
|
||||
// postgres db interfaces
|
||||
Retriever *CIDRetriever
|
||||
@@ -99,15 +120,30 @@ type Backend struct {
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
ChainConfig *params.ChainConfig
|
||||
VmConfig vm.Config
|
||||
DefaultSender *common.Address
|
||||
RPCGasCap *big.Int
|
||||
ChainConfig *params.ChainConfig
|
||||
VMConfig vm.Config
|
||||
DefaultSender *common.Address
|
||||
RPCGasCap *big.Int
|
||||
GroupCacheConfig *shared.GroupCacheConfig
|
||||
}
|
||||
|
||||
func NewEthBackend(db *postgres.DB, c *Config) (*Backend, error) {
|
||||
func NewEthBackend(db *sqlx.DB, c *Config) (*Backend, error) {
|
||||
gcc := c.GroupCacheConfig
|
||||
|
||||
groupName := gcc.StateDB.Name
|
||||
if groupName == "" {
|
||||
groupName = StateDBGroupCacheName
|
||||
}
|
||||
|
||||
r := NewCIDRetriever(db)
|
||||
ethDB := ipfsethdb.NewDatabase(db.DB)
|
||||
ethDB := ipfsethdb.NewDatabase(db, ipfsethdb.CacheConfig{
|
||||
Name: groupName,
|
||||
Size: gcc.StateDB.CacheSizeInMB * 1024 * 1024,
|
||||
ExpiryDuration: time.Minute * time.Duration(gcc.StateDB.CacheExpiryInMins),
|
||||
})
|
||||
|
||||
logStateDBStatsOnTimer(ethDB.(*ipfsethdb.Database), gcc)
|
||||
|
||||
return &Backend{
|
||||
DB: db,
|
||||
Retriever: r,
|
||||
@@ -299,7 +335,7 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
||||
}()
|
||||
|
||||
// Fetch and decode the header IPLD
|
||||
var headerIPLD ipfs.BlockModel
|
||||
var headerIPLD models.IPLDModel
|
||||
headerIPLD, err = b.Fetcher.FetchHeader(tx, headerCID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -313,7 +349,7 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
||||
return nil, err
|
||||
}
|
||||
// Fetch and decode the uncle IPLDs
|
||||
var uncleIPLDs []ipfs.BlockModel
|
||||
var uncleIPLDs []models.IPLDModel
|
||||
uncleIPLDs, err = b.Fetcher.FetchUncles(tx, uncleCIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -328,7 +364,7 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
||||
uncles = append(uncles, &uncle)
|
||||
}
|
||||
// Fetch and decode the transaction IPLDs
|
||||
var txIPLDs []ipfs.BlockModel
|
||||
var txIPLDs []models.IPLDModel
|
||||
txIPLDs, err = b.Fetcher.FetchTrxs(tx, txCIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -343,7 +379,7 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
||||
transactions = append(transactions, &transaction)
|
||||
}
|
||||
// Fetch and decode the receipt IPLDs
|
||||
var rctIPLDs []ipfs.BlockModel
|
||||
var rctIPLDs []models.IPLDModel
|
||||
rctIPLDs, err = b.Fetcher.FetchRcts(tx, rctCIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -351,7 +387,12 @@ func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber
|
||||
var receipts []*types.Receipt
|
||||
for _, rctIPLD := range rctIPLDs {
|
||||
var receipt types.Receipt
|
||||
err = receipt.UnmarshalBinary(rctIPLD.Data)
|
||||
nodeVal, err := DecodeLeafNode(rctIPLD.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = receipt.UnmarshalBinary(nodeVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -390,7 +431,7 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
}()
|
||||
|
||||
// Fetch and decode the header IPLD
|
||||
var headerIPLD ipfs.BlockModel
|
||||
var headerIPLD models.IPLDModel
|
||||
headerIPLD, err = b.Fetcher.FetchHeader(tx, headerCID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -404,7 +445,7 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
return nil, err
|
||||
}
|
||||
// Fetch and decode the uncle IPLDs
|
||||
var uncleIPLDs []ipfs.BlockModel
|
||||
var uncleIPLDs []models.IPLDModel
|
||||
uncleIPLDs, err = b.Fetcher.FetchUncles(tx, uncleCIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -422,7 +463,7 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
uncles = append(uncles, &uncle)
|
||||
}
|
||||
// Fetch and decode the transaction IPLDs
|
||||
var txIPLDs []ipfs.BlockModel
|
||||
var txIPLDs []models.IPLDModel
|
||||
txIPLDs, err = b.Fetcher.FetchTrxs(tx, txCIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -440,7 +481,7 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
transactions = append(transactions, &transaction)
|
||||
}
|
||||
// Fetch and decode the receipt IPLDs
|
||||
var rctIPLDs []ipfs.BlockModel
|
||||
var rctIPLDs []models.IPLDModel
|
||||
rctIPLDs, err = b.Fetcher.FetchRcts(tx, rctCIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
@@ -451,7 +492,12 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
var receipts []*types.Receipt
|
||||
for _, rctIPLD := range rctIPLDs {
|
||||
var receipt types.Receipt
|
||||
err = receipt.UnmarshalBinary(rctIPLD.Data)
|
||||
nodeVal, err := DecodeLeafNode(rctIPLD.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = receipt.UnmarshalBinary(nodeVal)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -585,15 +631,15 @@ func (b *Backend) GetCanonicalHeader(number uint64) (string, []byte, error) {
|
||||
}
|
||||
|
||||
// GetEVM constructs and returns a vm.EVM
|
||||
func (b *Backend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, error) {
|
||||
state.SetBalance(msg.From(), math.MaxBig256)
|
||||
vmctx := core.NewEVMBlockContext(header, b, nil)
|
||||
func (b *Backend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) {
|
||||
vmError := func() error { return nil }
|
||||
txContext := core.NewEVMTxContext(msg)
|
||||
return vm.NewEVM(vmctx, txContext, state, b.Config.ChainConfig, b.Config.VmConfig), nil
|
||||
context := core.NewEVMBlockContext(header, b, nil)
|
||||
return vm.NewEVM(context, txContext, state, b.Config.ChainConfig, b.Config.VMConfig), vmError, nil
|
||||
}
|
||||
|
||||
// GetAccountByNumberOrHash returns the account object for the provided address at the block corresponding to the provided number or hash
|
||||
func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*state.Account, error) {
|
||||
func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*types.StateAccount, error) {
|
||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||
return b.GetAccountByNumber(ctx, address, blockNr)
|
||||
}
|
||||
@@ -604,7 +650,7 @@ func (b *Backend) GetAccountByNumberOrHash(ctx context.Context, address common.A
|
||||
}
|
||||
|
||||
// GetAccountByNumber returns the account object for the provided address at the canonical block at the provided height
|
||||
func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address, blockNumber rpc.BlockNumber) (*state.Account, error) {
|
||||
func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address, blockNumber rpc.BlockNumber) (*types.StateAccount, error) {
|
||||
var err error
|
||||
number := blockNumber.Int64()
|
||||
if blockNumber == rpc.LatestBlockNumber {
|
||||
@@ -633,7 +679,7 @@ func (b *Backend) GetAccountByNumber(ctx context.Context, address common.Address
|
||||
}
|
||||
|
||||
// GetAccountByHash returns the account object for the provided address at the block with the provided hash
|
||||
func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address, hash common.Hash) (*state.Account, error) {
|
||||
func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address, hash common.Hash) (*types.StateAccount, error) {
|
||||
_, err := b.HeaderByHash(context.Background(), hash)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, errHeaderHashNotFound
|
||||
@@ -646,7 +692,7 @@ func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
acct := new(state.Account)
|
||||
acct := new(types.StateAccount)
|
||||
return acct, rlp.DecodeBytes(accountRlp, acct)
|
||||
}
|
||||
|
||||
@@ -714,7 +760,7 @@ func (b *Backend) GetCodeByHash(ctx context.Context, address common.Address, has
|
||||
return nil, err
|
||||
}
|
||||
var mhKey string
|
||||
mhKey, err = shared2.MultihashKeyFromKeccak256(common.BytesToHash(codeHash))
|
||||
mhKey, err = ethServerShared.MultihashKeyFromKeccak256(common.BytesToHash(codeHash))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -791,6 +837,11 @@ func (b *Backend) GetHeader(hash common.Hash, height uint64) *types.Header {
|
||||
return header
|
||||
}
|
||||
|
||||
// ValidateTrie validates the trie for the given stateRoot
|
||||
func (b *Backend) ValidateTrie(stateRoot common.Hash) error {
|
||||
return validator.NewValidator(nil, b.EthDB).ValidateTrie(stateRoot)
|
||||
}
|
||||
|
||||
// RPCGasCap returns the configured gas cap for the rpc server
|
||||
func (b *Backend) RPCGasCap() *big.Int {
|
||||
return b.Config.RPCGasCap
|
||||
@@ -823,3 +874,18 @@ func (b *Backend) BloomStatus() (uint64, uint64) {
|
||||
func (b *Backend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func logStateDBStatsOnTimer(ethDB *ipfsethdb.Database, gcc *shared.GroupCacheConfig) {
|
||||
// No stats logging if interval isn't a positive integer.
|
||||
if gcc.StateDB.LogStatsIntervalInSecs <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(time.Duration(gcc.StateDB.LogStatsIntervalInSecs) * time.Second)
|
||||
|
||||
go func() {
|
||||
for range ticker.C {
|
||||
log.Infof("%s groupcache stats: %+v", StateDBGroupCacheName, ethDB.GetCacheStats())
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
+1
-120
@@ -27,11 +27,8 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
)
|
||||
|
||||
// RPCMarshalHeader converts the given header to the RPC output.
|
||||
@@ -123,8 +120,8 @@ func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Has
|
||||
}
|
||||
fields["transactions"] = transactions
|
||||
}
|
||||
fields["uncles"] = uncleHashes
|
||||
|
||||
fields["uncles"] = uncleHashes
|
||||
return fields, nil
|
||||
}
|
||||
|
||||
@@ -271,122 +268,6 @@ func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransacti
|
||||
return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee())
|
||||
}
|
||||
|
||||
// extractLogsOfInterest returns logs from the receipt IPLD
|
||||
func extractLogsOfInterest(config *params.ChainConfig, blockHash common.Hash, blockNumber uint64,
|
||||
txs types.Transactions, rctIPLDs []ipfs.BlockModel, filter ReceiptFilter) ([]*types.Log, error) {
|
||||
receipts := make(types.Receipts, len(rctIPLDs))
|
||||
|
||||
for i, rctBytes := range rctIPLDs {
|
||||
rct := new(types.Receipt)
|
||||
if err := rct.UnmarshalBinary(rctBytes.Data); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
receipts[i] = rct
|
||||
}
|
||||
|
||||
err := receipts.DeriveFields(config, blockHash, blockNumber, txs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var unfilteredLogs []*types.Log
|
||||
for _, receipt := range receipts {
|
||||
unfilteredLogs = append(unfilteredLogs, receipt.Logs...)
|
||||
}
|
||||
|
||||
adders := make([]common.Address, len(filter.LogAddresses))
|
||||
for i, addr := range filter.LogAddresses {
|
||||
adders[i] = common.HexToAddress(addr)
|
||||
}
|
||||
|
||||
topics := make([][]common.Hash, len(filter.Topics))
|
||||
for i, v := range filter.Topics {
|
||||
topics[i] = make([]common.Hash, len(v))
|
||||
for j, topic := range v {
|
||||
topics[i][j] = common.HexToHash(topic)
|
||||
}
|
||||
}
|
||||
|
||||
logs := filterLogs(unfilteredLogs, nil, nil, adders, topics)
|
||||
return logs, nil
|
||||
}
|
||||
|
||||
func includes(addresses []common.Address, a common.Address) bool {
|
||||
for _, addr := range addresses {
|
||||
if addr == a {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// filterLogs creates a slice of logs matching the given criteria.
|
||||
func filterLogs(logs []*types.Log, fromBlock, toBlock *big.Int, addresses []common.Address, topics [][]common.Hash) []*types.Log {
|
||||
var ret []*types.Log
|
||||
Logs:
|
||||
for _, log := range logs {
|
||||
if fromBlock != nil && fromBlock.Int64() >= 0 && fromBlock.Uint64() > log.BlockNumber {
|
||||
continue
|
||||
}
|
||||
if toBlock != nil && toBlock.Int64() >= 0 && toBlock.Uint64() < log.BlockNumber {
|
||||
continue
|
||||
}
|
||||
|
||||
if len(addresses) > 0 && !includes(addresses, log.Address) {
|
||||
continue
|
||||
}
|
||||
// If the to filtered topics is greater than the amount of topics in logs, skip.
|
||||
if len(topics) > len(log.Topics) {
|
||||
continue
|
||||
}
|
||||
for i, sub := range topics {
|
||||
match := len(sub) == 0 // empty rule set == wildcard
|
||||
for _, topic := range sub {
|
||||
if log.Topics[i] == topic {
|
||||
match = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !match {
|
||||
continue Logs
|
||||
}
|
||||
}
|
||||
ret = append(ret, log)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// returns true if the log matches on the filter
|
||||
func wantedLog(wantedTopics [][]string, actualTopics []common.Hash) bool {
|
||||
// actualTopics will always have length <= 4
|
||||
// wantedTopics will always have length 4
|
||||
matches := 0
|
||||
for i, actualTopic := range actualTopics {
|
||||
// If we have topics in this filter slot, count as a match if the actualTopic matches one of the ones in this filter slot
|
||||
if len(wantedTopics[i]) > 0 {
|
||||
matches += sliceContainsHash(wantedTopics[i], actualTopic)
|
||||
} else {
|
||||
// Filter slot is empty, not matching any topics at this slot => counts as a match
|
||||
matches++
|
||||
}
|
||||
}
|
||||
if matches == len(actualTopics) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// returns 1 if the slice contains the hash, 0 if it does not
|
||||
func sliceContainsHash(slice []string, hash common.Hash) int {
|
||||
for _, str := range slice {
|
||||
if str == hash.String() {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func toFilterArg(q ethereum.FilterQuery) (interface{}, error) {
|
||||
arg := map[string]interface{}{
|
||||
"address": q.Addresses,
|
||||
|
||||
+274
-224
@@ -19,17 +19,16 @@ package eth
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/lib/pq"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
// Retriever interface for substituting mocks in tests
|
||||
@@ -41,11 +40,11 @@ type Retriever interface {
|
||||
|
||||
// CIDRetriever satisfies the CIDRetriever interface for ethereum
|
||||
type CIDRetriever struct {
|
||||
db *postgres.DB
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// NewCIDRetriever returns a pointer to a new CIDRetriever which supports the CIDRetriever interface
|
||||
func NewCIDRetriever(db *postgres.DB) *CIDRetriever {
|
||||
func NewCIDRetriever(db *sqlx.DB) *CIDRetriever {
|
||||
return &CIDRetriever{
|
||||
db: db,
|
||||
}
|
||||
@@ -61,7 +60,7 @@ func (ecr *CIDRetriever) RetrieveFirstBlockNumber() (int64, error) {
|
||||
// RetrieveLastBlockNumber is used to retrieve the latest block number in the db
|
||||
func (ecr *CIDRetriever) RetrieveLastBlockNumber() (int64, error) {
|
||||
var blockNumber int64
|
||||
err := ecr.db.Get(&blockNumber, "SELECT block_number FROM eth.header_cids ORDER BY block_number DESC LIMIT 1 ")
|
||||
err := ecr.db.Get(&blockNumber, "SELECT block_number FROM eth.header_cids ORDER BY block_number DESC LIMIT 1")
|
||||
return blockNumber, err
|
||||
}
|
||||
|
||||
@@ -86,10 +85,10 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
||||
}()
|
||||
|
||||
// Retrieve cached header CIDs at this block height
|
||||
var headers []eth.HeaderModel
|
||||
var headers []models.HeaderModel
|
||||
headers, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
||||
if err != nil {
|
||||
log.Error("header cid retrieval error")
|
||||
log.Error("header cid retrieval error", err)
|
||||
return nil, true, err
|
||||
}
|
||||
cws := make([]CIDWrapper, len(headers))
|
||||
@@ -102,8 +101,8 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
||||
empty = false
|
||||
if filter.HeaderFilter.Uncles {
|
||||
// Retrieve uncle cids for this header id
|
||||
var uncleCIDs []eth.UncleModel
|
||||
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, header.ID)
|
||||
var uncleCIDs []models.UncleModel
|
||||
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, header.BlockHash)
|
||||
if err != nil {
|
||||
log.Error("uncle cid retrieval error")
|
||||
return nil, true, err
|
||||
@@ -113,7 +112,7 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
||||
}
|
||||
// Retrieve cached trx CIDs
|
||||
if !filter.TxFilter.Off {
|
||||
cw.Transactions, err = ecr.RetrieveTxCIDs(tx, filter.TxFilter, header.ID)
|
||||
cw.Transactions, err = ecr.RetrieveTxCIDs(tx, filter.TxFilter, header.BlockHash)
|
||||
if err != nil {
|
||||
log.Error("transaction cid retrieval error")
|
||||
return nil, true, err
|
||||
@@ -122,13 +121,13 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
||||
empty = false
|
||||
}
|
||||
}
|
||||
trxIds := make([]int64, len(cw.Transactions))
|
||||
for j, tx := range cw.Transactions {
|
||||
trxIds[j] = tx.ID
|
||||
trxHashes := make([]string, len(cw.Transactions))
|
||||
for j, t := range cw.Transactions {
|
||||
trxHashes[j] = t.TxHash
|
||||
}
|
||||
// Retrieve cached receipt CIDs
|
||||
if !filter.ReceiptFilter.Off {
|
||||
cw.Receipts, err = ecr.RetrieveRctCIDsByHeaderID(tx, filter.ReceiptFilter, header.ID, trxIds)
|
||||
cw.Receipts, err = ecr.RetrieveRctCIDsByHeaderID(tx, filter.ReceiptFilter, header.BlockHash, trxHashes)
|
||||
if err != nil {
|
||||
log.Error("receipt cid retrieval error")
|
||||
return nil, true, err
|
||||
@@ -139,7 +138,7 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
||||
}
|
||||
// Retrieve cached state CIDs
|
||||
if !filter.StateFilter.Off {
|
||||
cw.StateNodes, err = ecr.RetrieveStateCIDs(tx, filter.StateFilter, header.ID)
|
||||
cw.StateNodes, err = ecr.RetrieveStateCIDs(tx, filter.StateFilter, header.BlockHash)
|
||||
if err != nil {
|
||||
log.Error("state cid retrieval error")
|
||||
return nil, true, err
|
||||
@@ -150,7 +149,7 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
||||
}
|
||||
// Retrieve cached storage CIDs
|
||||
if !filter.StorageFilter.Off {
|
||||
cw.StorageNodes, err = ecr.RetrieveStorageCIDs(tx, filter.StorageFilter, header.ID)
|
||||
cw.StorageNodes, err = ecr.RetrieveStorageCIDs(tx, filter.StorageFilter, header.BlockHash)
|
||||
if err != nil {
|
||||
log.Error("storage cid retrieval error")
|
||||
return nil, true, err
|
||||
@@ -166,35 +165,42 @@ func (ecr *CIDRetriever) Retrieve(filter SubscriptionSettings, blockNumber int64
|
||||
}
|
||||
|
||||
// RetrieveHeaderCIDs retrieves and returns all of the header cids at the provided blockheight
|
||||
func (ecr *CIDRetriever) RetrieveHeaderCIDs(tx *sqlx.Tx, blockNumber int64) ([]eth.HeaderModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveHeaderCIDs(tx *sqlx.Tx, blockNumber int64) ([]models.HeaderModel, error) {
|
||||
log.Debug("retrieving header cids for block ", blockNumber)
|
||||
headers := make([]eth.HeaderModel, 0)
|
||||
pgStr := `SELECT * FROM eth.header_cids
|
||||
headers := make([]models.HeaderModel, 0)
|
||||
pgStr := `SELECT CAST(block_number as Text), block_hash, parent_hash, cid, mh_key, CAST(td as Text), node_id,
|
||||
CAST(reward as Text), state_root, uncle_root,tx_root, receipt_root,bloom, timestamp, times_validated, coinbase
|
||||
FROM eth.header_cids
|
||||
WHERE block_number = $1`
|
||||
return headers, tx.Select(&headers, pgStr, blockNumber)
|
||||
}
|
||||
|
||||
// RetrieveUncleCIDsByHeaderID retrieves and returns all of the uncle cids for the provided header
|
||||
func (ecr *CIDRetriever) RetrieveUncleCIDsByHeaderID(tx *sqlx.Tx, headerID int64) ([]eth.UncleModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveUncleCIDsByHeaderID(tx *sqlx.Tx, headerID string) ([]models.UncleModel, error) {
|
||||
log.Debug("retrieving uncle cids for block id ", headerID)
|
||||
headers := make([]eth.UncleModel, 0)
|
||||
pgStr := `SELECT * FROM eth.uncle_cids
|
||||
headers := make([]models.UncleModel, 0)
|
||||
pgStr := `SELECT CAST(block_number as Text), header_id, block_hash, parent_hash, cid, mh_key, CAST(reward as text)
|
||||
FROM eth.uncle_cids
|
||||
WHERE header_id = $1`
|
||||
return headers, tx.Select(&headers, pgStr, headerID)
|
||||
}
|
||||
|
||||
// RetrieveTxCIDs retrieves and returns all of the trx cids at the provided blockheight that conform to the provided filter parameters
|
||||
// also returns the ids for the returned transaction cids
|
||||
func (ecr *CIDRetriever) RetrieveTxCIDs(tx *sqlx.Tx, txFilter TxFilter, headerID int64) ([]eth.TxModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveTxCIDs(tx *sqlx.Tx, txFilter TxFilter, headerID string) ([]models.TxModel, error) {
|
||||
log.Debug("retrieving transaction cids for header id ", headerID)
|
||||
args := make([]interface{}, 0, 3)
|
||||
results := make([]eth.TxModel, 0)
|
||||
results := make([]models.TxModel, 0)
|
||||
id := 1
|
||||
pgStr := fmt.Sprintf(`SELECT transaction_cids.id, transaction_cids.header_id,
|
||||
transaction_cids.tx_hash, transaction_cids.cid, transaction_cids.mh_key,
|
||||
transaction_cids.dst, transaction_cids.src, transaction_cids.index, transaction_cids.tx_data
|
||||
FROM eth.transaction_cids INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.id)
|
||||
WHERE header_cids.id = $%d`, id)
|
||||
pgStr := fmt.Sprintf(`SELECT CAST(transaction_cids.block_number as Text), transaction_cids.tx_hash,
|
||||
transaction_cids.header_id,transaction_cids.cid, transaction_cids.mh_key, transaction_cids.dst,
|
||||
transaction_cids.src, transaction_cids.index, transaction_cids.tx_data
|
||||
FROM eth.transaction_cids
|
||||
INNER JOIN eth.header_cids ON (
|
||||
transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
)
|
||||
WHERE header_cids.block_hash = $%d`, id)
|
||||
args = append(args, headerID)
|
||||
id++
|
||||
if len(txFilter.Dst) > 0 {
|
||||
@@ -210,97 +216,158 @@ func (ecr *CIDRetriever) RetrieveTxCIDs(tx *sqlx.Tx, txFilter TxFilter, headerID
|
||||
return results, tx.Select(&results, pgStr, args...)
|
||||
}
|
||||
|
||||
// RetrieveRctCIDsByHeaderID retrieves and returns all of the rct cids at the provided header ID that conform to the provided
|
||||
// filter parameters and correspond to the provided tx ids
|
||||
func (ecr *CIDRetriever) RetrieveRctCIDsByHeaderID(tx *sqlx.Tx, rctFilter ReceiptFilter, headerID int64, trxIds []int64) ([]eth.ReceiptModel, error) {
|
||||
log.Debug("retrieving receipt cids for header id ", headerID)
|
||||
args := make([]interface{}, 0, 4)
|
||||
pgStr := `SELECT receipt_cids.id, receipt_cids.tx_id, receipt_cids.cid, receipt_cids.mh_key,
|
||||
receipt_cids.contract, receipt_cids.contract_hash, receipt_cids.topic0s, receipt_cids.topic1s,
|
||||
receipt_cids.topic2s, receipt_cids.topic3s, receipt_cids.log_contracts
|
||||
FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
||||
WHERE receipt_cids.tx_id = transaction_cids.id
|
||||
AND transaction_cids.header_id = header_cids.id
|
||||
AND header_cids.id = $1`
|
||||
id := 2
|
||||
args = append(args, headerID)
|
||||
func topicFilterCondition(id *int, topics [][]string, args []interface{}, pgStr string, first bool) (string, []interface{}) {
|
||||
for i, topicSet := range topics {
|
||||
if len(topicSet) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !first {
|
||||
pgStr += " AND"
|
||||
} else {
|
||||
first = false
|
||||
}
|
||||
pgStr += fmt.Sprintf(` eth.log_cids.topic%d = ANY ($%d)`, i, *id)
|
||||
args = append(args, pq.Array(topicSet))
|
||||
*id++
|
||||
}
|
||||
return pgStr, args
|
||||
}
|
||||
|
||||
func logFilterCondition(id *int, pgStr string, args []interface{}, rctFilter ReceiptFilter) (string, []interface{}) {
|
||||
if len(rctFilter.LogAddresses) > 0 {
|
||||
pgStr += fmt.Sprintf(` AND eth.log_cids.address = ANY ($%d)`, *id)
|
||||
args = append(args, pq.Array(rctFilter.LogAddresses))
|
||||
*id++
|
||||
}
|
||||
|
||||
// Filter on topics if there are any
|
||||
if hasTopics(rctFilter.Topics) {
|
||||
pgStr, args = topicFilterCondition(id, rctFilter.Topics, args, pgStr, false)
|
||||
}
|
||||
|
||||
return pgStr, args
|
||||
}
|
||||
|
||||
func receiptFilterConditions(id *int, pgStr string, args []interface{}, rctFilter ReceiptFilter, txHashes []string) (string, []interface{}) {
|
||||
rctCond := " AND (receipt_cids.tx_id = ANY ( "
|
||||
logQuery := "SELECT rct_id FROM eth.log_cids WHERE"
|
||||
if len(rctFilter.LogAddresses) > 0 {
|
||||
// Filter on log contract addresses if there are any
|
||||
pgStr += fmt.Sprintf(` AND ((receipt_cids.log_contracts && $%d::VARCHAR(66)[]`, id)
|
||||
pgStr += fmt.Sprintf(`%s %s eth.log_cids.address = ANY ($%d)`, rctCond, logQuery, *id)
|
||||
args = append(args, pq.Array(rctFilter.LogAddresses))
|
||||
id++
|
||||
*id++
|
||||
|
||||
// Filter on topics if there are any
|
||||
if hasTopics(rctFilter.Topics) {
|
||||
pgStr += " AND ("
|
||||
first := true
|
||||
for i, topicSet := range rctFilter.Topics {
|
||||
if i < 4 && len(topicSet) > 0 {
|
||||
if first {
|
||||
pgStr += fmt.Sprintf(`receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
first = false
|
||||
} else {
|
||||
pgStr += fmt.Sprintf(` AND receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
}
|
||||
args = append(args, pq.Array(topicSet))
|
||||
id++
|
||||
}
|
||||
}
|
||||
pgStr += ")"
|
||||
pgStr, args = topicFilterCondition(id, rctFilter.Topics, args, pgStr, false)
|
||||
}
|
||||
|
||||
pgStr += ")"
|
||||
// Filter on txIDs if there are any and we are matching txs
|
||||
if rctFilter.MatchTxs && len(trxIds) > 0 {
|
||||
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d::INTEGER[])`, id)
|
||||
args = append(args, pq.Array(trxIds))
|
||||
|
||||
// Filter on txHashes if there are any, and we are matching txs
|
||||
if rctFilter.MatchTxs && len(txHashes) > 0 {
|
||||
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d)`, *id)
|
||||
args = append(args, pq.Array(txHashes))
|
||||
}
|
||||
pgStr += ")"
|
||||
} else { // If there are no contract addresses to filter on
|
||||
// Filter on topics if there are any
|
||||
if hasTopics(rctFilter.Topics) {
|
||||
pgStr += " AND (("
|
||||
first := true
|
||||
for i, topicSet := range rctFilter.Topics {
|
||||
if i < 4 && len(topicSet) > 0 {
|
||||
if first {
|
||||
pgStr += fmt.Sprintf(`receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
first = false
|
||||
} else {
|
||||
pgStr += fmt.Sprintf(` AND receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
}
|
||||
args = append(args, pq.Array(topicSet))
|
||||
id++
|
||||
}
|
||||
pgStr += rctCond + logQuery
|
||||
pgStr, args = topicFilterCondition(id, rctFilter.Topics, args, pgStr, true)
|
||||
pgStr += ")"
|
||||
// Filter on txHashes if there are any, and we are matching txs
|
||||
if rctFilter.MatchTxs && len(txHashes) > 0 {
|
||||
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d)`, *id)
|
||||
args = append(args, pq.Array(txHashes))
|
||||
}
|
||||
pgStr += ")"
|
||||
// Filter on txIDs if there are any and we are matching txs
|
||||
if rctFilter.MatchTxs && len(trxIds) > 0 {
|
||||
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d::INTEGER[])`, id)
|
||||
args = append(args, pq.Array(trxIds))
|
||||
}
|
||||
pgStr += ")"
|
||||
} else if rctFilter.MatchTxs && len(trxIds) > 0 {
|
||||
} else if rctFilter.MatchTxs && len(txHashes) > 0 {
|
||||
// If there are no contract addresses or topics to filter on,
|
||||
// Filter on txIDs if there are any and we are matching txs
|
||||
pgStr += fmt.Sprintf(` AND receipt_cids.tx_id = ANY($%d::INTEGER[])`, id)
|
||||
args = append(args, pq.Array(trxIds))
|
||||
// Filter on txHashes if there are any, and we are matching txs
|
||||
pgStr += fmt.Sprintf(` AND receipt_cids.tx_id = ANY($%d)`, *id)
|
||||
args = append(args, pq.Array(txHashes))
|
||||
}
|
||||
}
|
||||
|
||||
return pgStr, args
|
||||
}
|
||||
|
||||
// RetrieveRctCIDsByHeaderID retrieves and returns all of the rct cids at the provided header ID that conform to the provided
|
||||
// filter parameters and correspond to the provided tx ids
|
||||
func (ecr *CIDRetriever) RetrieveRctCIDsByHeaderID(tx *sqlx.Tx, rctFilter ReceiptFilter, headerID string, trxHashes []string) ([]models.ReceiptModel, error) {
|
||||
log.Debug("retrieving receipt cids for header id ", headerID)
|
||||
args := make([]interface{}, 0, 4)
|
||||
pgStr := `SELECT CAST(receipt_cids.block_number as Text), receipt_cids.tx_id, receipt_cids.leaf_cid,
|
||||
receipt_cids.leaf_mh_key, receipt_cids.contract, receipt_cids.contract_hash
|
||||
FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
||||
WHERE receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
AND transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
AND header_cids.block_hash = $1`
|
||||
id := 2
|
||||
args = append(args, headerID)
|
||||
|
||||
pgStr, args = receiptFilterConditions(&id, pgStr, args, rctFilter, trxHashes)
|
||||
|
||||
pgStr += ` ORDER BY transaction_cids.index`
|
||||
receiptCids := make([]eth.ReceiptModel, 0)
|
||||
receiptCids := make([]models.ReceiptModel, 0)
|
||||
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
||||
}
|
||||
|
||||
// RetrieveRctCIDs retrieves and returns all of the rct cids at the provided blockheight or block hash that conform to the provided
|
||||
// filter parameters and correspond to the provided tx ids
|
||||
func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, blockNumber int64, blockHash *common.Hash, trxIds []int64) ([]eth.ReceiptModel, error) {
|
||||
log.Debug("retrieving receipt cids for block ", blockNumber)
|
||||
args := make([]interface{}, 0, 5)
|
||||
pgStr := `SELECT receipt_cids.id, receipt_cids.tx_id, receipt_cids.cid, receipt_cids.mh_key,
|
||||
receipt_cids.contract, receipt_cids.contract_hash, receipt_cids.topic0s, receipt_cids.topic1s,
|
||||
receipt_cids.topic2s, receipt_cids.topic3s, receipt_cids.log_contracts
|
||||
FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
||||
WHERE receipt_cids.tx_id = transaction_cids.id
|
||||
AND transaction_cids.header_id = header_cids.id`
|
||||
// RetrieveFilteredGQLLogs retrieves and returns all the log CIDs provided blockHash that conform to the provided
|
||||
// filter parameters.
|
||||
func (ecr *CIDRetriever) RetrieveFilteredGQLLogs(tx *sqlx.Tx, rctFilter ReceiptFilter, blockHash *common.Hash) ([]LogResult, error) {
|
||||
log.Debug("retrieving log cids for receipt ids")
|
||||
args := make([]interface{}, 0, 4)
|
||||
id := 1
|
||||
pgStr := `SELECT CAST(eth.log_cids.block_number as Text), eth.log_cids.leaf_cid, eth.log_cids.index, eth.log_cids.rct_id,
|
||||
eth.log_cids.address, eth.log_cids.topic0, eth.log_cids.topic1, eth.log_cids.topic2, eth.log_cids.topic3,
|
||||
eth.log_cids.log_data, eth.transaction_cids.tx_hash, data, eth.receipt_cids.leaf_cid as cid, eth.receipt_cids.post_status
|
||||
FROM eth.log_cids, eth.receipt_cids, eth.transaction_cids, eth.header_cids, public.blocks
|
||||
WHERE eth.log_cids.rct_id = receipt_cids.tx_id
|
||||
AND eth.log_cids.block_number = eth.receipt_cids.block_number
|
||||
AND receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
AND transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
AND log_cids.leaf_mh_key = blocks.key
|
||||
AND log_cids.block_number = blocks.block_number
|
||||
AND header_cids.block_hash = $1`
|
||||
|
||||
args = append(args, blockHash.String())
|
||||
id++
|
||||
|
||||
pgStr, args = logFilterCondition(&id, pgStr, args, rctFilter)
|
||||
pgStr += ` ORDER BY log_cids.index`
|
||||
|
||||
logCIDs := make([]LogResult, 0)
|
||||
err := tx.Select(&logCIDs, pgStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return logCIDs, nil
|
||||
}
|
||||
|
||||
// RetrieveFilteredLog retrieves and returns all the log cIDs provided blockHeight or blockHash that conform to the provided
|
||||
// filter parameters.
|
||||
func (ecr *CIDRetriever) RetrieveFilteredLog(tx *sqlx.Tx, rctFilter ReceiptFilter, blockNumber int64, blockHash *common.Hash) ([]LogResult, error) {
|
||||
log.Debug("retrieving log cids for receipt ids")
|
||||
args := make([]interface{}, 0, 4)
|
||||
pgStr := `SELECT CAST(eth.log_cids.block_number as Text), eth.log_cids.leaf_cid, eth.log_cids.index, eth.log_cids.rct_id,
|
||||
eth.log_cids.address, eth.log_cids.topic0, eth.log_cids.topic1, eth.log_cids.topic2, eth.log_cids.topic3,
|
||||
eth.log_cids.log_data, eth.transaction_cids.tx_hash, eth.transaction_cids.index as txn_index,
|
||||
header_cids.block_hash, CAST(header_cids.block_number as Text)
|
||||
FROM eth.log_cids, eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
||||
WHERE eth.log_cids.rct_id = receipt_cids.tx_id
|
||||
AND eth.log_cids.block_number = eth.receipt_cids.block_number
|
||||
AND receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
AND transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number`
|
||||
id := 1
|
||||
if blockNumber > 0 {
|
||||
pgStr += fmt.Sprintf(` AND header_cids.block_number = $%d`, id)
|
||||
@@ -313,77 +380,46 @@ func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, b
|
||||
id++
|
||||
}
|
||||
|
||||
// TODO: Add the below filters when we have log index in DB.
|
||||
if true {
|
||||
pgStr += ` ORDER BY transaction_cids.index`
|
||||
receiptCids := make([]eth.ReceiptModel, 0)
|
||||
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
||||
pgStr, args = logFilterCondition(&id, pgStr, args, rctFilter)
|
||||
pgStr += ` ORDER BY log_cids.index`
|
||||
|
||||
logCIDs := make([]LogResult, 0)
|
||||
err := tx.Select(&logCIDs, pgStr, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(rctFilter.LogAddresses) > 0 {
|
||||
// Filter on log contract addresses if there are any
|
||||
pgStr += fmt.Sprintf(` AND ((receipt_cids.log_contracts && $%d::VARCHAR(66)[]`, id)
|
||||
args = append(args, pq.Array(rctFilter.LogAddresses))
|
||||
return logCIDs, nil
|
||||
}
|
||||
|
||||
// RetrieveRctCIDs retrieves and returns all of the rct cids at the provided blockheight or block hash that conform to the provided
|
||||
// filter parameters and correspond to the provided tx ids
|
||||
func (ecr *CIDRetriever) RetrieveRctCIDs(tx *sqlx.Tx, rctFilter ReceiptFilter, blockNumber int64, blockHash *common.Hash, txHashes []string) ([]models.ReceiptModel, error) {
|
||||
log.Debug("retrieving receipt cids for block ", blockNumber)
|
||||
args := make([]interface{}, 0, 5)
|
||||
pgStr := `SELECT CAST(receipt_cids.block_number as Text), receipt_cids.tx_id, receipt_cids.leaf_cid,
|
||||
receipt_cids.leaf_mh_key,
|
||||
FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
||||
WHERE receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
AND transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number`
|
||||
id := 1
|
||||
if blockNumber > 0 {
|
||||
pgStr += fmt.Sprintf(` AND header_cids.block_number = $%d`, id)
|
||||
args = append(args, blockNumber)
|
||||
id++
|
||||
// Filter on topics if there are any
|
||||
if hasTopics(rctFilter.Topics) {
|
||||
pgStr += " AND ("
|
||||
first := true
|
||||
for i, topicSet := range rctFilter.Topics {
|
||||
if i < 4 && len(topicSet) > 0 {
|
||||
if first {
|
||||
pgStr += fmt.Sprintf(`receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
first = false
|
||||
} else {
|
||||
pgStr += fmt.Sprintf(` AND receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
}
|
||||
args = append(args, pq.Array(topicSet))
|
||||
id++
|
||||
}
|
||||
}
|
||||
pgStr += ")"
|
||||
}
|
||||
pgStr += ")"
|
||||
// Filter on txIDs if there are any and we are matching txs
|
||||
if rctFilter.MatchTxs && len(trxIds) > 0 {
|
||||
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d::INTEGER[])`, id)
|
||||
args = append(args, pq.Array(trxIds))
|
||||
}
|
||||
pgStr += ")"
|
||||
} else { // If there are no contract addresses to filter on
|
||||
// Filter on topics if there are any
|
||||
if hasTopics(rctFilter.Topics) {
|
||||
pgStr += " AND (("
|
||||
first := true
|
||||
for i, topicSet := range rctFilter.Topics {
|
||||
if i < 4 && len(topicSet) > 0 {
|
||||
if first {
|
||||
pgStr += fmt.Sprintf(`receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
first = false
|
||||
} else {
|
||||
pgStr += fmt.Sprintf(` AND receipt_cids.topic%ds && $%d::VARCHAR(66)[]`, i, id)
|
||||
}
|
||||
args = append(args, pq.Array(topicSet))
|
||||
id++
|
||||
}
|
||||
}
|
||||
pgStr += ")"
|
||||
// Filter on txIDs if there are any and we are matching txs
|
||||
if rctFilter.MatchTxs && len(trxIds) > 0 {
|
||||
pgStr += fmt.Sprintf(` OR receipt_cids.tx_id = ANY($%d::INTEGER[])`, id)
|
||||
args = append(args, pq.Array(trxIds))
|
||||
}
|
||||
pgStr += ")"
|
||||
} else if rctFilter.MatchTxs && len(trxIds) > 0 {
|
||||
// If there are no contract addresses or topics to filter on,
|
||||
// Filter on txIDs if there are any and we are matching txs
|
||||
pgStr += fmt.Sprintf(` AND receipt_cids.tx_id = ANY($%d::INTEGER[])`, id)
|
||||
args = append(args, pq.Array(trxIds))
|
||||
}
|
||||
}
|
||||
if blockHash != nil {
|
||||
pgStr += fmt.Sprintf(` AND header_cids.block_hash = $%d`, id)
|
||||
args = append(args, blockHash.String())
|
||||
id++
|
||||
}
|
||||
|
||||
pgStr, args = receiptFilterConditions(&id, pgStr, args, rctFilter, txHashes)
|
||||
|
||||
pgStr += ` ORDER BY transaction_cids.index`
|
||||
receiptCids := make([]eth.ReceiptModel, 0)
|
||||
receiptCids := make([]models.ReceiptModel, 0)
|
||||
return receiptCids, tx.Select(&receiptCids, pgStr, args...)
|
||||
}
|
||||
|
||||
@@ -397,13 +433,17 @@ func hasTopics(topics [][]string) bool {
|
||||
}
|
||||
|
||||
// RetrieveStateCIDs retrieves and returns all of the state node cids at the provided header ID that conform to the provided filter parameters
|
||||
func (ecr *CIDRetriever) RetrieveStateCIDs(tx *sqlx.Tx, stateFilter StateFilter, headerID int64) ([]eth.StateNodeModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveStateCIDs(tx *sqlx.Tx, stateFilter StateFilter, headerID string) ([]models.StateNodeModel, error) {
|
||||
log.Debug("retrieving state cids for header id ", headerID)
|
||||
args := make([]interface{}, 0, 2)
|
||||
pgStr := `SELECT state_cids.id, state_cids.header_id,
|
||||
pgStr := `SELECT CAST(state_cids.block_number as Text), state_cids.header_id,
|
||||
state_cids.state_leaf_key, state_cids.node_type, state_cids.cid, state_cids.mh_key, state_cids.state_path
|
||||
FROM eth.state_cids INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||
WHERE header_cids.id = $1`
|
||||
FROM eth.state_cids
|
||||
INNER JOIN eth.header_cids ON (
|
||||
state_cids.header_id = header_cids.block_hash
|
||||
AND state_cids.block_number = header_cids.block_number
|
||||
)
|
||||
WHERE header_cids.block_hash = $1`
|
||||
args = append(args, headerID)
|
||||
addrLen := len(stateFilter.Addresses)
|
||||
if addrLen > 0 {
|
||||
@@ -417,20 +457,24 @@ func (ecr *CIDRetriever) RetrieveStateCIDs(tx *sqlx.Tx, stateFilter StateFilter,
|
||||
if !stateFilter.IntermediateNodes {
|
||||
pgStr += ` AND state_cids.node_type = 2`
|
||||
}
|
||||
stateNodeCIDs := make([]eth.StateNodeModel, 0)
|
||||
stateNodeCIDs := make([]models.StateNodeModel, 0)
|
||||
return stateNodeCIDs, tx.Select(&stateNodeCIDs, pgStr, args...)
|
||||
}
|
||||
|
||||
// RetrieveStorageCIDs retrieves and returns all of the storage node cids at the provided header id that conform to the provided filter parameters
|
||||
func (ecr *CIDRetriever) RetrieveStorageCIDs(tx *sqlx.Tx, storageFilter StorageFilter, headerID int64) ([]eth.StorageNodeWithStateKeyModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveStorageCIDs(tx *sqlx.Tx, storageFilter StorageFilter, headerID string) ([]models.StorageNodeWithStateKeyModel, error) {
|
||||
log.Debug("retrieving storage cids for header id ", headerID)
|
||||
args := make([]interface{}, 0, 3)
|
||||
pgStr := `SELECT storage_cids.id, storage_cids.state_id, storage_cids.storage_leaf_key, storage_cids.node_type,
|
||||
storage_cids.cid, storage_cids.mh_key, storage_cids.storage_path, state_cids.state_leaf_key
|
||||
pgStr := `SELECT CAST(storage_cids.block_number as Text), storage_cids.header_id, storage_cids.storage_leaf_key,
|
||||
storage_cids.node_type, storage_cids.cid, storage_cids.mh_key, storage_cids.storage_path, storage_cids.state_path,
|
||||
state_cids.state_leaf_key
|
||||
FROM eth.storage_cids, eth.state_cids, eth.header_cids
|
||||
WHERE storage_cids.state_id = state_cids.id
|
||||
AND state_cids.header_id = header_cids.id
|
||||
AND header_cids.id = $1`
|
||||
WHERE storage_cids.header_id = state_cids.header_id
|
||||
AND storage_cids.state_path = state_cids.state_path
|
||||
AND storage_cids.block_number = state_cids.block_number
|
||||
AND state_cids.header_id = header_cids.block_hash
|
||||
AND state_cids.block_number = header_cids.block_number
|
||||
AND header_cids.block_hash = $1`
|
||||
args = append(args, headerID)
|
||||
id := 2
|
||||
addrLen := len(storageFilter.Addresses)
|
||||
@@ -450,18 +494,18 @@ func (ecr *CIDRetriever) RetrieveStorageCIDs(tx *sqlx.Tx, storageFilter StorageF
|
||||
if !storageFilter.IntermediateNodes {
|
||||
pgStr += ` AND storage_cids.node_type = 2`
|
||||
}
|
||||
storageNodeCIDs := make([]eth.StorageNodeWithStateKeyModel, 0)
|
||||
storageNodeCIDs := make([]models.StorageNodeWithStateKeyModel, 0)
|
||||
return storageNodeCIDs, tx.Select(&storageNodeCIDs, pgStr, args...)
|
||||
}
|
||||
|
||||
// RetrieveBlockByHash returns all of the CIDs needed to compose an entire block, for a given block hash
|
||||
func (ecr *CIDRetriever) RetrieveBlockByHash(blockHash common.Hash) (eth.HeaderModel, []eth.UncleModel, []eth.TxModel, []eth.ReceiptModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveBlockByHash(blockHash common.Hash) (models.HeaderModel, []models.UncleModel, []models.TxModel, []models.ReceiptModel, error) {
|
||||
log.Debug("retrieving block cids for block hash ", blockHash.String())
|
||||
|
||||
// Begin new db tx
|
||||
tx, err := ecr.db.Beginx()
|
||||
if err != nil {
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
@@ -474,30 +518,34 @@ func (ecr *CIDRetriever) RetrieveBlockByHash(blockHash common.Hash) (eth.HeaderM
|
||||
}
|
||||
}()
|
||||
|
||||
var headerCID eth.HeaderModel
|
||||
var headerCID models.HeaderModel
|
||||
headerCID, err = ecr.RetrieveHeaderCIDByHash(tx, blockHash)
|
||||
if err != nil {
|
||||
log.Error("header cid retrieval error")
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
var uncleCIDs []eth.UncleModel
|
||||
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID.ID)
|
||||
blockNumber, err := strconv.ParseInt(headerCID.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
var uncleCIDs []models.UncleModel
|
||||
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID.BlockHash)
|
||||
if err != nil {
|
||||
log.Error("uncle cid retrieval error")
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
var txCIDs []eth.TxModel
|
||||
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.ID)
|
||||
var txCIDs []models.TxModel
|
||||
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.BlockHash, blockNumber)
|
||||
if err != nil {
|
||||
log.Error("tx cid retrieval error")
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
txIDs := make([]int64, len(txCIDs))
|
||||
txHashes := make([]string, len(txCIDs))
|
||||
for i, txCID := range txCIDs {
|
||||
txIDs[i] = txCID.ID
|
||||
txHashes[i] = txCID.TxHash
|
||||
}
|
||||
var rctCIDs []eth.ReceiptModel
|
||||
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txIDs)
|
||||
var rctCIDs []models.ReceiptModel
|
||||
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txHashes)
|
||||
if err != nil {
|
||||
log.Error("rct cid retrieval error")
|
||||
}
|
||||
@@ -505,13 +553,13 @@ func (ecr *CIDRetriever) RetrieveBlockByHash(blockHash common.Hash) (eth.HeaderM
|
||||
}
|
||||
|
||||
// RetrieveBlockByNumber returns all of the CIDs needed to compose an entire block, for a given block number
|
||||
func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (eth.HeaderModel, []eth.UncleModel, []eth.TxModel, []eth.ReceiptModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (models.HeaderModel, []models.UncleModel, []models.TxModel, []models.ReceiptModel, error) {
|
||||
log.Debug("retrieving block cids for block number ", blockNumber)
|
||||
|
||||
// Begin new db tx
|
||||
tx, err := ecr.db.Beginx()
|
||||
if err != nil {
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
defer func() {
|
||||
if p := recover(); p != nil {
|
||||
@@ -524,33 +572,33 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (eth.HeaderMod
|
||||
}
|
||||
}()
|
||||
|
||||
var headerCID []eth.HeaderModel
|
||||
var headerCID []models.HeaderModel
|
||||
headerCID, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
|
||||
if err != nil {
|
||||
log.Error("header cid retrieval error")
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
if len(headerCID) < 1 {
|
||||
return eth.HeaderModel{}, nil, nil, nil, fmt.Errorf("header cid retrieval error, no header CIDs found at block %d", blockNumber)
|
||||
return models.HeaderModel{}, nil, nil, nil, fmt.Errorf("header cid retrieval error, no header CIDs found at block %d", blockNumber)
|
||||
}
|
||||
var uncleCIDs []eth.UncleModel
|
||||
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID[0].ID)
|
||||
var uncleCIDs []models.UncleModel
|
||||
uncleCIDs, err = ecr.RetrieveUncleCIDsByHeaderID(tx, headerCID[0].BlockHash)
|
||||
if err != nil {
|
||||
log.Error("uncle cid retrieval error")
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
var txCIDs []eth.TxModel
|
||||
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID[0].ID)
|
||||
var txCIDs []models.TxModel
|
||||
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID[0].BlockHash, blockNumber)
|
||||
if err != nil {
|
||||
log.Error("tx cid retrieval error")
|
||||
return eth.HeaderModel{}, nil, nil, nil, err
|
||||
return models.HeaderModel{}, nil, nil, nil, err
|
||||
}
|
||||
txIDs := make([]int64, len(txCIDs))
|
||||
txHashes := make([]string, len(txCIDs))
|
||||
for i, txCID := range txCIDs {
|
||||
txIDs[i] = txCID.ID
|
||||
txHashes[i] = txCID.TxHash
|
||||
}
|
||||
var rctCIDs []eth.ReceiptModel
|
||||
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txIDs)
|
||||
var rctCIDs []models.ReceiptModel
|
||||
rctCIDs, err = ecr.RetrieveReceiptCIDsByTxIDs(tx, txHashes)
|
||||
if err != nil {
|
||||
log.Error("rct cid retrieval error")
|
||||
}
|
||||
@@ -558,34 +606,36 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (eth.HeaderMod
|
||||
}
|
||||
|
||||
// RetrieveHeaderCIDByHash returns the header for the given block hash
|
||||
func (ecr *CIDRetriever) RetrieveHeaderCIDByHash(tx *sqlx.Tx, blockHash common.Hash) (eth.HeaderModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveHeaderCIDByHash(tx *sqlx.Tx, blockHash common.Hash) (models.HeaderModel, error) {
|
||||
log.Debug("retrieving header cids for block hash ", blockHash.String())
|
||||
pgStr := `SELECT * FROM eth.header_cids
|
||||
pgStr := `SELECT block_hash, CAST(block_number as Text), cid, mh_key FROM eth.header_cids
|
||||
WHERE block_hash = $1`
|
||||
var headerCID eth.HeaderModel
|
||||
var headerCID models.HeaderModel
|
||||
return headerCID, tx.Get(&headerCID, pgStr, blockHash.String())
|
||||
}
|
||||
|
||||
// RetrieveTxCIDsByHeaderID retrieves all tx CIDs for the given header id
|
||||
func (ecr *CIDRetriever) RetrieveTxCIDsByHeaderID(tx *sqlx.Tx, headerID int64) ([]eth.TxModel, error) {
|
||||
func (ecr *CIDRetriever) RetrieveTxCIDsByHeaderID(tx *sqlx.Tx, headerID string, blockNumber int64) ([]models.TxModel, error) {
|
||||
log.Debug("retrieving tx cids for block id ", headerID)
|
||||
pgStr := `SELECT * FROM eth.transaction_cids
|
||||
WHERE header_id = $1
|
||||
pgStr := `SELECT CAST(block_number as Text), header_id, index, tx_hash, cid, mh_key,
|
||||
dst, src, tx_data, tx_type, value
|
||||
FROM eth.transaction_cids
|
||||
WHERE header_id = $1 AND block_number = $2
|
||||
ORDER BY index`
|
||||
var txCIDs []eth.TxModel
|
||||
return txCIDs, tx.Select(&txCIDs, pgStr, headerID)
|
||||
var txCIDs []models.TxModel
|
||||
return txCIDs, tx.Select(&txCIDs, pgStr, headerID, blockNumber)
|
||||
}
|
||||
|
||||
// RetrieveReceiptCIDsByTxIDs retrieves receipt CIDs by their associated tx IDs
|
||||
func (ecr *CIDRetriever) RetrieveReceiptCIDsByTxIDs(tx *sqlx.Tx, txIDs []int64) ([]eth.ReceiptModel, error) {
|
||||
log.Debugf("retrieving receipt cids for tx ids %v", txIDs)
|
||||
pgStr := `SELECT receipt_cids.id, receipt_cids.tx_id, receipt_cids.cid, receipt_cids.mh_key,
|
||||
receipt_cids.contract, receipt_cids.contract_hash, receipt_cids.topic0s, receipt_cids.topic1s,
|
||||
receipt_cids.topic2s, receipt_cids.topic3s, receipt_cids.log_contracts
|
||||
func (ecr *CIDRetriever) RetrieveReceiptCIDsByTxIDs(tx *sqlx.Tx, txHashes []string) ([]models.ReceiptModel, error) {
|
||||
log.Debugf("retrieving receipt cids for tx hashes %v", txHashes)
|
||||
pgStr := `SELECT CAST(receipt_cids.block_number as Text), receipt_cids.tx_id, receipt_cids.leaf_cid, receipt_cids.leaf_mh_key,
|
||||
receipt_cids.contract, receipt_cids.contract_hash
|
||||
FROM eth.receipt_cids, eth.transaction_cids
|
||||
WHERE tx_id = ANY($1::INTEGER[])
|
||||
AND receipt_cids.tx_id = transaction_cids.id
|
||||
WHERE tx_id = ANY($1)
|
||||
AND receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
ORDER BY transaction_cids.index`
|
||||
var rctCIDs []eth.ReceiptModel
|
||||
return rctCIDs, tx.Select(&rctCIDs, pgStr, pq.Array(txIDs))
|
||||
var rctCIDs []models.ReceiptModel
|
||||
return rctCIDs, tx.Select(&rctCIDs, pgStr, pq.Array(txHashes))
|
||||
}
|
||||
|
||||
+120
-59
@@ -19,19 +19,19 @@ package eth_test
|
||||
import (
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/interfaces"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -211,27 +211,45 @@ var (
|
||||
|
||||
var _ = Describe("Retriever", func() {
|
||||
var (
|
||||
db *postgres.DB
|
||||
repo *eth2.IPLDPublisher
|
||||
retriever *eth.CIDRetriever
|
||||
db *sqlx.DB
|
||||
diffIndexer interfaces.StateDiffIndexer
|
||||
retriever *eth.CIDRetriever
|
||||
)
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
db, err = shared.SetupDB()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
repo = eth2.NewIPLDPublisher(db)
|
||||
db = shared.SetupDB()
|
||||
diffIndexer = shared.SetupTestStateDiffIndexer(ctx, params.TestChainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
retriever = eth.NewCIDRetriever(db)
|
||||
})
|
||||
AfterEach(func() {
|
||||
eth.TearDownDB(db)
|
||||
shared.TearDownDB(db)
|
||||
})
|
||||
|
||||
Describe("Retrieve", func() {
|
||||
BeforeEach(func() {
|
||||
err := repo.Publish(test_helpers.MockConvertedPayload)
|
||||
tx, err := diffIndexer.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
for _, node := range test_helpers.MockStateNodes {
|
||||
err = diffIndexer.PushStateNode(tx, node, test_helpers.MockBlock.Hash().String())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
It("Retrieves all CIDs for the given blocknumber when provided an open filter", func() {
|
||||
type rctCIDAndMHKeyResult struct {
|
||||
LeafCID string `db:"leaf_cid"`
|
||||
LeafMhKey string `db:"leaf_mh_key"`
|
||||
}
|
||||
expectedRctCIDsAndLeafNodes := make([]rctCIDAndMHKeyResult, 0)
|
||||
pgStr := `SELECT receipt_cids.leaf_cid, receipt_cids.leaf_mh_key FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
||||
WHERE receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND transaction_cids.header_id = header_cids.block_hash
|
||||
AND header_cids.block_number = $1
|
||||
ORDER BY transaction_cids.index`
|
||||
err := db.Select(&expectedRctCIDsAndLeafNodes, pgStr, test_helpers.BlockNumber.Uint64())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cids, empty, err := retriever.Retrieve(openFilter, 1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
@@ -239,17 +257,17 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(cids[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
|
||||
expectedHeaderCID := test_helpers.MockCIDWrapper.Header
|
||||
expectedHeaderCID.ID = cids[0].Header.ID
|
||||
expectedHeaderCID.BlockHash = cids[0].Header.BlockHash
|
||||
expectedHeaderCID.NodeID = cids[0].Header.NodeID
|
||||
Expect(cids[0].Header).To(Equal(expectedHeaderCID))
|
||||
Expect(len(cids[0].Transactions)).To(Equal(3))
|
||||
Expect(len(cids[0].Transactions)).To(Equal(4))
|
||||
Expect(eth.TxModelsContainsCID(cids[0].Transactions, test_helpers.MockCIDWrapper.Transactions[0].CID)).To(BeTrue())
|
||||
Expect(eth.TxModelsContainsCID(cids[0].Transactions, test_helpers.MockCIDWrapper.Transactions[1].CID)).To(BeTrue())
|
||||
Expect(eth.TxModelsContainsCID(cids[0].Transactions, test_helpers.MockCIDWrapper.Transactions[2].CID)).To(BeTrue())
|
||||
Expect(len(cids[0].Receipts)).To(Equal(3))
|
||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, test_helpers.MockCIDWrapper.Receipts[0].CID)).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, test_helpers.MockCIDWrapper.Receipts[1].CID)).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, test_helpers.MockCIDWrapper.Receipts[2].CID)).To(BeTrue())
|
||||
Expect(len(cids[0].Receipts)).To(Equal(4))
|
||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, expectedRctCIDsAndLeafNodes[0].LeafCID)).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, expectedRctCIDsAndLeafNodes[1].LeafCID)).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids[0].Receipts, expectedRctCIDsAndLeafNodes[2].LeafCID)).To(BeTrue())
|
||||
Expect(len(cids[0].StateNodes)).To(Equal(2))
|
||||
|
||||
for _, stateNode := range cids[0].StateNodes {
|
||||
@@ -266,25 +284,37 @@ var _ = Describe("Retriever", func() {
|
||||
}
|
||||
Expect(len(cids[0].StorageNodes)).To(Equal(1))
|
||||
expectedStorageNodeCIDs := test_helpers.MockCIDWrapper.StorageNodes
|
||||
expectedStorageNodeCIDs[0].ID = cids[0].StorageNodes[0].ID
|
||||
expectedStorageNodeCIDs[0].StateID = cids[0].StorageNodes[0].StateID
|
||||
expectedStorageNodeCIDs[0].HeaderID = cids[0].StorageNodes[0].HeaderID
|
||||
expectedStorageNodeCIDs[0].StatePath = cids[0].StorageNodes[0].StatePath
|
||||
Expect(cids[0].StorageNodes).To(Equal(expectedStorageNodeCIDs))
|
||||
})
|
||||
|
||||
It("Applies filters from the provided config.Subscription", func() {
|
||||
type rctCIDAndMHKeyResult struct {
|
||||
LeafCID string `db:"leaf_cid"`
|
||||
LeafMhKey string `db:"leaf_mh_key"`
|
||||
}
|
||||
expectedRctCIDsAndLeafNodes := make([]rctCIDAndMHKeyResult, 0)
|
||||
pgStr := `SELECT receipt_cids.leaf_cid, receipt_cids.leaf_mh_key FROM eth.receipt_cids, eth.transaction_cids, eth.header_cids
|
||||
WHERE receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND transaction_cids.header_id = header_cids.block_hash
|
||||
AND header_cids.block_number = $1
|
||||
ORDER BY transaction_cids.index`
|
||||
err := db.Select(&expectedRctCIDsAndLeafNodes, pgStr, test_helpers.BlockNumber.Uint64())
|
||||
cids1, empty, err := retriever.Retrieve(rctAddressFilter, 1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids1)).To(Equal(1))
|
||||
Expect(cids1[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
Expect(cids1[0].Header).To(Equal(eth2.HeaderModel{}))
|
||||
Expect(cids1[0].Header).To(Equal(models.HeaderModel{}))
|
||||
Expect(len(cids1[0].Transactions)).To(Equal(0))
|
||||
Expect(len(cids1[0].StateNodes)).To(Equal(0))
|
||||
Expect(len(cids1[0].StorageNodes)).To(Equal(0))
|
||||
Expect(len(cids1[0].Receipts)).To(Equal(1))
|
||||
expectedReceiptCID := test_helpers.MockCIDWrapper.Receipts[0]
|
||||
expectedReceiptCID.ID = cids1[0].Receipts[0].ID
|
||||
expectedReceiptCID.TxID = cids1[0].Receipts[0].TxID
|
||||
expectedReceiptCID.LeafCID = expectedRctCIDsAndLeafNodes[0].LeafCID
|
||||
expectedReceiptCID.LeafMhKey = expectedRctCIDsAndLeafNodes[0].LeafMhKey
|
||||
Expect(cids1[0].Receipts[0]).To(Equal(expectedReceiptCID))
|
||||
|
||||
cids2, empty, err := retriever.Retrieve(rctTopicsFilter, 1)
|
||||
@@ -292,14 +322,15 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids2)).To(Equal(1))
|
||||
Expect(cids2[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
Expect(cids2[0].Header).To(Equal(eth2.HeaderModel{}))
|
||||
Expect(cids2[0].Header).To(Equal(models.HeaderModel{}))
|
||||
Expect(len(cids2[0].Transactions)).To(Equal(0))
|
||||
Expect(len(cids2[0].StateNodes)).To(Equal(0))
|
||||
Expect(len(cids2[0].StorageNodes)).To(Equal(0))
|
||||
Expect(len(cids2[0].Receipts)).To(Equal(1))
|
||||
expectedReceiptCID = test_helpers.MockCIDWrapper.Receipts[0]
|
||||
expectedReceiptCID.ID = cids2[0].Receipts[0].ID
|
||||
expectedReceiptCID.TxID = cids2[0].Receipts[0].TxID
|
||||
expectedReceiptCID.LeafCID = expectedRctCIDsAndLeafNodes[0].LeafCID
|
||||
expectedReceiptCID.LeafMhKey = expectedRctCIDsAndLeafNodes[0].LeafMhKey
|
||||
Expect(cids2[0].Receipts[0]).To(Equal(expectedReceiptCID))
|
||||
|
||||
cids3, empty, err := retriever.Retrieve(rctTopicsAndAddressFilter, 1)
|
||||
@@ -307,14 +338,15 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids3)).To(Equal(1))
|
||||
Expect(cids3[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
Expect(cids3[0].Header).To(Equal(eth2.HeaderModel{}))
|
||||
Expect(cids3[0].Header).To(Equal(models.HeaderModel{}))
|
||||
Expect(len(cids3[0].Transactions)).To(Equal(0))
|
||||
Expect(len(cids3[0].StateNodes)).To(Equal(0))
|
||||
Expect(len(cids3[0].StorageNodes)).To(Equal(0))
|
||||
Expect(len(cids3[0].Receipts)).To(Equal(1))
|
||||
expectedReceiptCID = test_helpers.MockCIDWrapper.Receipts[0]
|
||||
expectedReceiptCID.ID = cids3[0].Receipts[0].ID
|
||||
expectedReceiptCID.TxID = cids3[0].Receipts[0].TxID
|
||||
expectedReceiptCID.LeafCID = expectedRctCIDsAndLeafNodes[0].LeafCID
|
||||
expectedReceiptCID.LeafMhKey = expectedRctCIDsAndLeafNodes[0].LeafMhKey
|
||||
Expect(cids3[0].Receipts[0]).To(Equal(expectedReceiptCID))
|
||||
|
||||
cids4, empty, err := retriever.Retrieve(rctAddressesAndTopicFilter, 1)
|
||||
@@ -322,14 +354,15 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids4)).To(Equal(1))
|
||||
Expect(cids4[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
Expect(cids4[0].Header).To(Equal(eth2.HeaderModel{}))
|
||||
Expect(cids4[0].Header).To(Equal(models.HeaderModel{}))
|
||||
Expect(len(cids4[0].Transactions)).To(Equal(0))
|
||||
Expect(len(cids4[0].StateNodes)).To(Equal(0))
|
||||
Expect(len(cids4[0].StorageNodes)).To(Equal(0))
|
||||
Expect(len(cids4[0].Receipts)).To(Equal(1))
|
||||
expectedReceiptCID = test_helpers.MockCIDWrapper.Receipts[1]
|
||||
expectedReceiptCID.ID = cids4[0].Receipts[0].ID
|
||||
expectedReceiptCID.TxID = cids4[0].Receipts[0].TxID
|
||||
expectedReceiptCID.LeafCID = expectedRctCIDsAndLeafNodes[1].LeafCID
|
||||
expectedReceiptCID.LeafMhKey = expectedRctCIDsAndLeafNodes[1].LeafMhKey
|
||||
Expect(cids4[0].Receipts[0]).To(Equal(expectedReceiptCID))
|
||||
|
||||
cids5, empty, err := retriever.Retrieve(rctsForAllCollectedTrxs, 1)
|
||||
@@ -337,35 +370,36 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids5)).To(Equal(1))
|
||||
Expect(cids5[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
Expect(cids5[0].Header).To(Equal(eth2.HeaderModel{}))
|
||||
Expect(len(cids5[0].Transactions)).To(Equal(3))
|
||||
Expect(cids5[0].Header).To(Equal(models.HeaderModel{}))
|
||||
Expect(len(cids5[0].Transactions)).To(Equal(4))
|
||||
Expect(eth.TxModelsContainsCID(cids5[0].Transactions, test_helpers.Trx1CID.String())).To(BeTrue())
|
||||
Expect(eth.TxModelsContainsCID(cids5[0].Transactions, test_helpers.Trx2CID.String())).To(BeTrue())
|
||||
Expect(eth.TxModelsContainsCID(cids5[0].Transactions, test_helpers.Trx3CID.String())).To(BeTrue())
|
||||
Expect(len(cids5[0].StateNodes)).To(Equal(0))
|
||||
Expect(len(cids5[0].StorageNodes)).To(Equal(0))
|
||||
Expect(len(cids5[0].Receipts)).To(Equal(3))
|
||||
Expect(eth.ReceiptModelsContainsCID(cids5[0].Receipts, test_helpers.Rct1CID.String())).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids5[0].Receipts, test_helpers.Rct2CID.String())).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids5[0].Receipts, test_helpers.Rct3CID.String())).To(BeTrue())
|
||||
Expect(len(cids5[0].Receipts)).To(Equal(4))
|
||||
Expect(eth.ReceiptModelsContainsCID(cids5[0].Receipts, expectedRctCIDsAndLeafNodes[0].LeafCID)).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids5[0].Receipts, expectedRctCIDsAndLeafNodes[1].LeafCID)).To(BeTrue())
|
||||
Expect(eth.ReceiptModelsContainsCID(cids5[0].Receipts, expectedRctCIDsAndLeafNodes[2].LeafCID)).To(BeTrue())
|
||||
|
||||
cids6, empty, err := retriever.Retrieve(rctsForSelectCollectedTrxs, 1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids6)).To(Equal(1))
|
||||
Expect(cids6[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
Expect(cids6[0].Header).To(Equal(eth2.HeaderModel{}))
|
||||
Expect(cids6[0].Header).To(Equal(models.HeaderModel{}))
|
||||
Expect(len(cids6[0].Transactions)).To(Equal(1))
|
||||
expectedTxCID := test_helpers.MockCIDWrapper.Transactions[1]
|
||||
expectedTxCID.ID = cids6[0].Transactions[0].ID
|
||||
expectedTxCID.TxHash = cids6[0].Transactions[0].TxHash
|
||||
expectedTxCID.HeaderID = cids6[0].Transactions[0].HeaderID
|
||||
Expect(cids6[0].Transactions[0]).To(Equal(expectedTxCID))
|
||||
Expect(len(cids6[0].StateNodes)).To(Equal(0))
|
||||
Expect(len(cids6[0].StorageNodes)).To(Equal(0))
|
||||
Expect(len(cids6[0].Receipts)).To(Equal(1))
|
||||
expectedReceiptCID = test_helpers.MockCIDWrapper.Receipts[1]
|
||||
expectedReceiptCID.ID = cids6[0].Receipts[0].ID
|
||||
expectedReceiptCID.TxID = cids6[0].Receipts[0].TxID
|
||||
expectedReceiptCID.LeafCID = expectedRctCIDsAndLeafNodes[1].LeafCID
|
||||
expectedReceiptCID.LeafMhKey = expectedRctCIDsAndLeafNodes[1].LeafMhKey
|
||||
Expect(cids6[0].Receipts[0]).To(Equal(expectedReceiptCID))
|
||||
|
||||
cids7, empty, err := retriever.Retrieve(stateFilter, 1)
|
||||
@@ -373,19 +407,19 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
Expect(len(cids7)).To(Equal(1))
|
||||
Expect(cids7[0].BlockNumber).To(Equal(test_helpers.MockCIDWrapper.BlockNumber))
|
||||
Expect(cids7[0].Header).To(Equal(eth2.HeaderModel{}))
|
||||
Expect(cids7[0].Header).To(Equal(models.HeaderModel{}))
|
||||
Expect(len(cids7[0].Transactions)).To(Equal(0))
|
||||
Expect(len(cids7[0].Receipts)).To(Equal(0))
|
||||
Expect(len(cids7[0].StorageNodes)).To(Equal(0))
|
||||
Expect(len(cids7[0].StateNodes)).To(Equal(1))
|
||||
Expect(cids7[0].StateNodes[0]).To(Equal(eth2.StateNodeModel{
|
||||
ID: cids7[0].StateNodes[0].ID,
|
||||
HeaderID: cids7[0].StateNodes[0].HeaderID,
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(test_helpers.AccountLeafKey).Hex(),
|
||||
CID: test_helpers.State2CID.String(),
|
||||
MhKey: test_helpers.State2MhKey,
|
||||
Path: []byte{'\x0c'},
|
||||
Expect(cids7[0].StateNodes[0]).To(Equal(models.StateNodeModel{
|
||||
BlockNumber: "1",
|
||||
HeaderID: cids7[0].StateNodes[0].HeaderID,
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(test_helpers.AccountLeafKey).Hex(),
|
||||
CID: test_helpers.State2CID.String(),
|
||||
MhKey: test_helpers.State2MhKey,
|
||||
Path: []byte{'\x0c'},
|
||||
}))
|
||||
|
||||
_, empty, err = retriever.Retrieve(rctTopicsAndAddressFilterFail, 1)
|
||||
@@ -400,8 +434,12 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("Gets the number of the first block that has data in the database", func() {
|
||||
err := repo.Publish(test_helpers.MockConvertedPayload)
|
||||
tx, err := diffIndexer.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
num, err := retriever.RetrieveFirstBlockNumber()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(num).To(Equal(int64(1)))
|
||||
@@ -410,8 +448,12 @@ var _ = Describe("Retriever", func() {
|
||||
It("Gets the number of the first block that has data in the database", func() {
|
||||
payload := test_helpers.MockConvertedPayload
|
||||
payload.Block = newMockBlock(1010101)
|
||||
err := repo.Publish(payload)
|
||||
tx, err := diffIndexer.PushBlock(payload.Block, payload.Receipts, payload.Block.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
num, err := retriever.RetrieveFirstBlockNumber()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(num).To(Equal(int64(1010101)))
|
||||
@@ -422,10 +464,16 @@ var _ = Describe("Retriever", func() {
|
||||
payload1.Block = newMockBlock(1010101)
|
||||
payload2 := payload1
|
||||
payload2.Block = newMockBlock(5)
|
||||
err := repo.Publish(payload1)
|
||||
tx, err := diffIndexer.PushBlock(payload1.Block, payload1.Receipts, payload1.Block.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = repo.Publish(payload2)
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
tx, err = diffIndexer.PushBlock(payload2.Block, payload2.Receipts, payload2.Block.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
num, err := retriever.RetrieveFirstBlockNumber()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(num).To(Equal(int64(5)))
|
||||
@@ -438,8 +486,11 @@ var _ = Describe("Retriever", func() {
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("Gets the number of the latest block that has data in the database", func() {
|
||||
err := repo.Publish(test_helpers.MockConvertedPayload)
|
||||
tx, err := diffIndexer.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
num, err := retriever.RetrieveLastBlockNumber()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(num).To(Equal(int64(1)))
|
||||
@@ -448,8 +499,12 @@ var _ = Describe("Retriever", func() {
|
||||
It("Gets the number of the latest block that has data in the database", func() {
|
||||
payload := test_helpers.MockConvertedPayload
|
||||
payload.Block = newMockBlock(1010101)
|
||||
err := repo.Publish(payload)
|
||||
tx, err := diffIndexer.PushBlock(payload.Block, payload.Receipts, payload.Block.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
num, err := retriever.RetrieveLastBlockNumber()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(num).To(Equal(int64(1010101)))
|
||||
@@ -460,10 +515,16 @@ var _ = Describe("Retriever", func() {
|
||||
payload1.Block = newMockBlock(1010101)
|
||||
payload2 := payload1
|
||||
payload2.Block = newMockBlock(5)
|
||||
err := repo.Publish(payload1)
|
||||
tx, err := diffIndexer.PushBlock(payload1.Block, payload1.Receipts, payload1.Block.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = repo.Publish(payload2)
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
tx, err = diffIndexer.PushBlock(payload2.Block, payload2.Receipts, payload2.Block.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
num, err := retriever.RetrieveLastBlockNumber()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(num).To(Equal(int64(1010101)))
|
||||
|
||||
+52
-33
@@ -21,6 +21,7 @@ import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -29,17 +30,17 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
ethServerShared "github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -64,7 +65,7 @@ var _ = Describe("eth state reading tests", func() {
|
||||
blocks []*types.Block
|
||||
receipts []types.Receipts
|
||||
chain *core.BlockChain
|
||||
db *postgres.DB
|
||||
db *sqlx.DB
|
||||
api *eth.PublicEthAPI
|
||||
backend *eth.Backend
|
||||
chainConfig = params.TestChainConfig
|
||||
@@ -74,16 +75,24 @@ var _ = Describe("eth state reading tests", func() {
|
||||
It("test init", func() {
|
||||
// db and type initializations
|
||||
var err error
|
||||
db, err = shared.SetupDB()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
transformer := eth2.NewStateDiffTransformer(chainConfig, db)
|
||||
db = shared.SetupDB()
|
||||
transformer := shared.SetupTestStateDiffIndexer(ctx, chainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
backend, err = eth.NewEthBackend(db, ð.Config{
|
||||
ChainConfig: chainConfig,
|
||||
VmConfig: vm.Config{},
|
||||
VMConfig: vm.Config{},
|
||||
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||
GroupCacheConfig: ðServerShared.GroupCacheConfig{
|
||||
StateDB: ethServerShared.GroupConfig{
|
||||
Name: "eth_state_test",
|
||||
CacheSizeInMB: 8,
|
||||
CacheExpiryInMins: 60,
|
||||
LogStatsIntervalInSecs: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
api = eth.NewPublicEthAPI(backend, nil, false)
|
||||
api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false)
|
||||
|
||||
// make the test blockchain (and state)
|
||||
blocks, receipts, chain = test_helpers.MakeChain(chainLength, test_helpers.Genesis, test_helpers.TestChainGen)
|
||||
@@ -135,35 +144,45 @@ var _ = Describe("eth state reading tests", func() {
|
||||
}
|
||||
diff, err := builder.BuildStateDiffObject(args, params)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
diffRlp, err := rlp.EncodeToBytes(diff)
|
||||
tx, err := transformer.PushBlock(block, rcts, mockTD)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
blockRlp, err := rlp.EncodeToBytes(block)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
receiptsRlp, err := rlp.EncodeToBytes(rcts)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
payload := statediff.Payload{
|
||||
StateObjectRlp: diffRlp,
|
||||
BlockRlp: blockRlp,
|
||||
ReceiptsRlp: receiptsRlp,
|
||||
TotalDifficulty: mockTD,
|
||||
|
||||
for _, node := range diff.Nodes {
|
||||
err = transformer.PushStateNode(tx, node, block.Hash().String())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
_, err = transformer.Transform(0, payload)
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// Insert some non-canonical data into the database so that we test our ability to discern canonicity
|
||||
indexAndPublisher := eth2.NewIPLDPublisher(db)
|
||||
api = eth.NewPublicEthAPI(backend, nil, false)
|
||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
||||
indexAndPublisher := shared.SetupTestStateDiffIndexer(ctx, chainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
tx, err := indexAndPublisher.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// The non-canonical header has a child
|
||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayloadForChild)
|
||||
tx, err = indexAndPublisher.PushBlock(test_helpers.MockChild, test_helpers.MockReceipts, test_helpers.MockChild.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = publishCode(db, test_helpers.ContractCodeHash, test_helpers.ContractCode)
|
||||
|
||||
hash := sdtypes.CodeAndCodeHash{
|
||||
Hash: test_helpers.CodeHash,
|
||||
Code: test_helpers.ContractCode,
|
||||
}
|
||||
|
||||
err = indexAndPublisher.PushCodeAndCodeHash(tx, hash)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// wait for tx batch process to complete.
|
||||
time.Sleep(10000 * time.Millisecond)
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
defer It("test teardown", func() {
|
||||
eth.TearDownDB(db)
|
||||
shared.TearDownDB(db)
|
||||
chain.Stop()
|
||||
})
|
||||
|
||||
@@ -460,16 +479,16 @@ var _ = Describe("eth state reading tests", func() {
|
||||
It("Returns empty slice if it tries to access a contract which does not exist", func() {
|
||||
storage, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(0))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(storage).To(Equal(hexutil.Bytes(make([]byte, 32))))
|
||||
Expect(storage).To(Equal(hexutil.Bytes(eth.EmptyNodeValue)))
|
||||
|
||||
storage, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.ContractSlotKeyHash.Hex(), rpc.BlockNumberOrHashWithNumber(1))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(storage).To(Equal(hexutil.Bytes(make([]byte, 32))))
|
||||
Expect(storage).To(Equal(hexutil.Bytes(eth.EmptyNodeValue)))
|
||||
})
|
||||
It("Returns empty slice if it tries to access a contract slot which does not exist", func() {
|
||||
storage, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, randomHash.Hex(), rpc.BlockNumberOrHashWithNumber(2))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(storage).To(Equal(hexutil.Bytes(make([]byte, 32))))
|
||||
Expect(storage).To(Equal(hexutil.Bytes(eth.EmptyNodeValue)))
|
||||
})
|
||||
It("Retrieves the storage value at the provided contract address and storage leaf key at the block with the provided hash or number", func() {
|
||||
// After deployment
|
||||
@@ -490,7 +509,7 @@ var _ = Describe("eth state reading tests", func() {
|
||||
|
||||
val, err = api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithNumber(5))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(val).To(Equal(hexutil.Bytes{}))
|
||||
Expect(val).To(Equal(hexutil.Bytes(eth.EmptyNodeValue)))
|
||||
})
|
||||
It("Throws an error for a non-existing block hash", func() {
|
||||
_, err := api.GetStorageAt(ctx, test_helpers.ContractAddr, test_helpers.IndexOne, rpc.BlockNumberOrHashWithHash(randomHash, true))
|
||||
|
||||
+98
-53
@@ -19,22 +19,20 @@ package eth
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multihash"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs/ipld"
|
||||
)
|
||||
|
||||
// Filterer interface for substituing mocks in tests
|
||||
type Filterer interface {
|
||||
Filter(filter SubscriptionSettings, payload eth.ConvertedPayload) (*IPLDs, error)
|
||||
Filter(filter SubscriptionSettings, payload ConvertedPayload) (*IPLDs, error)
|
||||
}
|
||||
|
||||
// ResponseFilterer satisfies the ResponseFilterer interface for ethereum
|
||||
@@ -46,7 +44,7 @@ func NewResponseFilterer() *ResponseFilterer {
|
||||
}
|
||||
|
||||
// Filter is used to filter through eth data to extract and package requested data into a Payload
|
||||
func (s *ResponseFilterer) Filter(filter SubscriptionSettings, payload eth.ConvertedPayload) (*IPLDs, error) {
|
||||
func (s *ResponseFilterer) Filter(filter SubscriptionSettings, payload ConvertedPayload) (*IPLDs, error) {
|
||||
if checkRange(filter.Start.Int64(), filter.End.Int64(), payload.Block.Number().Int64()) {
|
||||
response := new(IPLDs)
|
||||
response.TotalDifficulty = payload.TotalDifficulty
|
||||
@@ -73,7 +71,7 @@ func (s *ResponseFilterer) Filter(filter SubscriptionSettings, payload eth.Conve
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (s *ResponseFilterer) filterHeaders(headerFilter HeaderFilter, response *IPLDs, payload eth.ConvertedPayload) error {
|
||||
func (s *ResponseFilterer) filterHeaders(headerFilter HeaderFilter, response *IPLDs, payload ConvertedPayload) error {
|
||||
if !headerFilter.Off {
|
||||
headerRLP, err := rlp.EncodeToBytes(payload.Block.Header())
|
||||
if err != nil {
|
||||
@@ -83,12 +81,13 @@ func (s *ResponseFilterer) filterHeaders(headerFilter HeaderFilter, response *IP
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response.Header = ipfs.BlockModel{
|
||||
Data: headerRLP,
|
||||
CID: cid.String(),
|
||||
response.Header = models.IPLDModel{
|
||||
BlockNumber: payload.Block.Number().String(),
|
||||
Data: headerRLP,
|
||||
Key: cid.String(),
|
||||
}
|
||||
if headerFilter.Uncles {
|
||||
response.Uncles = make([]ipfs.BlockModel, len(payload.Block.Body().Uncles))
|
||||
response.Uncles = make([]models.IPLDModel, len(payload.Block.Body().Uncles))
|
||||
for i, uncle := range payload.Block.Body().Uncles {
|
||||
uncleRlp, err := rlp.EncodeToBytes(uncle)
|
||||
if err != nil {
|
||||
@@ -98,9 +97,10 @@ func (s *ResponseFilterer) filterHeaders(headerFilter HeaderFilter, response *IP
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response.Uncles[i] = ipfs.BlockModel{
|
||||
Data: uncleRlp,
|
||||
CID: cid.String(),
|
||||
response.Uncles[i] = models.IPLDModel{
|
||||
BlockNumber: uncle.Number.String(),
|
||||
Data: uncleRlp,
|
||||
Key: cid.String(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,12 +115,12 @@ func checkRange(start, end, actual int64) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *ResponseFilterer) filterTransactions(trxFilter TxFilter, response *IPLDs, payload eth.ConvertedPayload) ([]common.Hash, error) {
|
||||
func (s *ResponseFilterer) filterTransactions(trxFilter TxFilter, response *IPLDs, payload ConvertedPayload) ([]common.Hash, error) {
|
||||
var trxHashes []common.Hash
|
||||
if !trxFilter.Off {
|
||||
trxLen := len(payload.Block.Body().Transactions)
|
||||
trxHashes = make([]common.Hash, 0, trxLen)
|
||||
response.Transactions = make([]ipfs.BlockModel, 0, trxLen)
|
||||
response.Transactions = make([]models.IPLDModel, 0, trxLen)
|
||||
for i, trx := range payload.Block.Body().Transactions {
|
||||
// TODO: check if want corresponding receipt and if we do we must include this transaction
|
||||
if checkTransactionAddrs(trxFilter.Src, trxFilter.Dst, payload.TxMetaData[i].Src, payload.TxMetaData[i].Dst) {
|
||||
@@ -133,9 +133,9 @@ func (s *ResponseFilterer) filterTransactions(trxFilter TxFilter, response *IPLD
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.Transactions = append(response.Transactions, ipfs.BlockModel{
|
||||
response.Transactions = append(response.Transactions, models.IPLDModel{
|
||||
Data: data,
|
||||
CID: cid.String(),
|
||||
Key: cid.String(),
|
||||
})
|
||||
trxHashes = append(trxHashes, trx.Hash())
|
||||
}
|
||||
@@ -163,25 +163,31 @@ func checkTransactionAddrs(wantedSrc, wantedDst []string, actualSrc, actualDst s
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *ResponseFilterer) filerReceipts(receiptFilter ReceiptFilter, response *IPLDs, payload eth.ConvertedPayload, trxHashes []common.Hash) error {
|
||||
func (s *ResponseFilterer) filerReceipts(receiptFilter ReceiptFilter, response *IPLDs, payload ConvertedPayload, trxHashes []common.Hash) error {
|
||||
if !receiptFilter.Off {
|
||||
response.Receipts = make([]ipfs.BlockModel, 0, len(payload.Receipts))
|
||||
for i, receipt := range payload.Receipts {
|
||||
response.Receipts = make([]models.IPLDModel, 0, len(payload.Receipts))
|
||||
rctLeafCID, rctIPLDData, err := GetRctLeafNodeData(payload.Receipts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for idx, receipt := range payload.Receipts {
|
||||
// topics is always length 4
|
||||
topics := [][]string{payload.ReceiptMetaData[i].Topic0s, payload.ReceiptMetaData[i].Topic1s, payload.ReceiptMetaData[i].Topic2s, payload.ReceiptMetaData[i].Topic3s}
|
||||
if checkReceipts(receipt, receiptFilter.Topics, topics, receiptFilter.LogAddresses, payload.ReceiptMetaData[i].LogContracts, trxHashes) {
|
||||
receiptBuffer := new(bytes.Buffer)
|
||||
if err := receipt.EncodeRLP(receiptBuffer); err != nil {
|
||||
return err
|
||||
topics := make([][]string, 4)
|
||||
contracts := make([]string, len(receipt.Logs))
|
||||
for _, l := range receipt.Logs {
|
||||
contracts = append(contracts, l.Address.String())
|
||||
for idx, t := range l.Topics {
|
||||
topics[idx] = append(topics[idx], t.String())
|
||||
}
|
||||
data := receiptBuffer.Bytes()
|
||||
cid, err := ipld.RawdataToCid(ipld.MEthTxReceipt, data, multihash.KECCAK_256)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response.Receipts = append(response.Receipts, ipfs.BlockModel{
|
||||
Data: data,
|
||||
CID: cid.String(),
|
||||
}
|
||||
|
||||
// TODO: Verify this filter logic.
|
||||
if checkReceipts(receipt, receiptFilter.Topics, topics, receiptFilter.LogAddresses, contracts, trxHashes) {
|
||||
response.Receipts = append(response.Receipts, models.IPLDModel{
|
||||
BlockNumber: payload.Block.Number().String(),
|
||||
Data: rctIPLDData[idx],
|
||||
Key: rctLeafCID[idx].String(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -253,7 +259,7 @@ func slicesShareString(slice1, slice2 []string) int {
|
||||
}
|
||||
|
||||
// filterStateAndStorage filters state and storage nodes into the response according to the provided filters
|
||||
func (s *ResponseFilterer) filterStateAndStorage(stateFilter StateFilter, storageFilter StorageFilter, response *IPLDs, payload eth.ConvertedPayload) error {
|
||||
func (s *ResponseFilterer) filterStateAndStorage(stateFilter StateFilter, storageFilter StorageFilter, response *IPLDs, payload ConvertedPayload) error {
|
||||
response.StateNodes = make([]StateNode, 0, len(payload.StateNodes))
|
||||
response.StorageNodes = make([]StorageNode, 0)
|
||||
stateAddressFilters := make([]common.Hash, len(stateFilter.Addresses))
|
||||
@@ -270,37 +276,39 @@ func (s *ResponseFilterer) filterStateAndStorage(stateFilter StateFilter, storag
|
||||
}
|
||||
for _, stateNode := range payload.StateNodes {
|
||||
if !stateFilter.Off && checkNodeKeys(stateAddressFilters, stateNode.LeafKey) {
|
||||
if stateNode.Type == sdtypes.Leaf || stateFilter.IntermediateNodes {
|
||||
cid, err := ipld.RawdataToCid(ipld.MEthStateTrie, stateNode.Value, multihash.KECCAK_256)
|
||||
if stateNode.NodeType == sdtypes.Leaf || stateFilter.IntermediateNodes {
|
||||
cid, err := ipld.RawdataToCid(ipld.MEthStateTrie, stateNode.NodeValue, multihash.KECCAK_256)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response.StateNodes = append(response.StateNodes, StateNode{
|
||||
StateLeafKey: stateNode.LeafKey,
|
||||
StateLeafKey: common.BytesToHash(stateNode.LeafKey),
|
||||
Path: stateNode.Path,
|
||||
IPLD: ipfs.BlockModel{
|
||||
Data: stateNode.Value,
|
||||
CID: cid.String(),
|
||||
IPLD: models.IPLDModel{
|
||||
BlockNumber: payload.Block.Number().String(),
|
||||
Data: stateNode.NodeValue,
|
||||
Key: cid.String(),
|
||||
},
|
||||
Type: stateNode.Type,
|
||||
Type: stateNode.NodeType,
|
||||
})
|
||||
}
|
||||
}
|
||||
if !storageFilter.Off && checkNodeKeys(storageAddressFilters, stateNode.LeafKey) {
|
||||
for _, storageNode := range payload.StorageNodes[common.Bytes2Hex(stateNode.Path)] {
|
||||
if checkNodeKeys(storageKeyFilters, storageNode.LeafKey) {
|
||||
cid, err := ipld.RawdataToCid(ipld.MEthStorageTrie, storageNode.Value, multihash.KECCAK_256)
|
||||
cid, err := ipld.RawdataToCid(ipld.MEthStorageTrie, storageNode.NodeValue, multihash.KECCAK_256)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
response.StorageNodes = append(response.StorageNodes, StorageNode{
|
||||
StateLeafKey: stateNode.LeafKey,
|
||||
StorageLeafKey: storageNode.LeafKey,
|
||||
IPLD: ipfs.BlockModel{
|
||||
Data: storageNode.Value,
|
||||
CID: cid.String(),
|
||||
StateLeafKey: common.BytesToHash(stateNode.LeafKey),
|
||||
StorageLeafKey: common.BytesToHash(storageNode.LeafKey),
|
||||
IPLD: models.IPLDModel{
|
||||
BlockNumber: payload.Block.Number().String(),
|
||||
Data: storageNode.NodeValue,
|
||||
Key: cid.String(),
|
||||
},
|
||||
Type: storageNode.Type,
|
||||
Type: storageNode.NodeType,
|
||||
Path: storageNode.Path,
|
||||
})
|
||||
}
|
||||
@@ -310,15 +318,52 @@ func (s *ResponseFilterer) filterStateAndStorage(stateFilter StateFilter, storag
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkNodeKeys(wantedKeys []common.Hash, actualKey common.Hash) bool {
|
||||
func checkNodeKeys(wantedKeys []common.Hash, actualKey []byte) bool {
|
||||
// If we aren't filtering for any specific keys, all nodes are a go
|
||||
if len(wantedKeys) == 0 {
|
||||
return true
|
||||
}
|
||||
for _, key := range wantedKeys {
|
||||
if bytes.Equal(key.Bytes(), actualKey.Bytes()) {
|
||||
if bytes.Equal(key.Bytes(), actualKey) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetRctLeafNodeData converts the receipts to receipt trie and returns the receipt leaf node IPLD data and
|
||||
// corresponding CIDs
|
||||
func GetRctLeafNodeData(rcts types.Receipts) ([]cid.Cid, [][]byte, error) {
|
||||
receiptTrie := ipld.NewRctTrie()
|
||||
for idx, rct := range rcts {
|
||||
ethRct, err := ipld.NewReceipt(rct)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
if err = receiptTrie.Add(idx, ethRct.RawData()); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
}
|
||||
|
||||
rctLeafNodes, keys, err := receiptTrie.GetLeafNodes()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ethRctleafNodeCids := make([]cid.Cid, len(rctLeafNodes))
|
||||
ethRctleafNodeData := make([][]byte, len(rctLeafNodes))
|
||||
for i, rln := range rctLeafNodes {
|
||||
var idx uint
|
||||
|
||||
r := bytes.NewReader(keys[i].TrieKey)
|
||||
err = rlp.Decode(r, &idx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ethRctleafNodeCids[idx] = rln.Cid()
|
||||
ethRctleafNodeData[idx] = rln.RawData()
|
||||
}
|
||||
|
||||
return ethRctleafNodeCids, ethRctleafNodeData, nil
|
||||
}
|
||||
|
||||
+55
-48
@@ -19,16 +19,15 @@ package eth_test
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -47,29 +46,31 @@ var _ = Describe("Filterer", func() {
|
||||
Expect(iplds).ToNot(BeNil())
|
||||
Expect(iplds.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds.Header).To(Equal(test_helpers.MockIPLDs.Header))
|
||||
var expectedEmptyUncles []ipfs.BlockModel
|
||||
var expectedEmptyUncles []models.IPLDModel
|
||||
Expect(iplds.Uncles).To(Equal(expectedEmptyUncles))
|
||||
Expect(len(iplds.Transactions)).To(Equal(3))
|
||||
Expect(len(iplds.Transactions)).To(Equal(4))
|
||||
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.Tx1)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.Tx2)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds.Transactions, test_helpers.Tx3)).To(BeTrue())
|
||||
Expect(len(iplds.Receipts)).To(Equal(3))
|
||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct1)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct2)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct3)).To(BeTrue())
|
||||
Expect(len(iplds.Receipts)).To(Equal(4))
|
||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct1IPLD)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct2IPLD)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds.Receipts, test_helpers.Rct3IPLD)).To(BeTrue())
|
||||
Expect(len(iplds.StateNodes)).To(Equal(2))
|
||||
for _, stateNode := range iplds.StateNodes {
|
||||
Expect(stateNode.Type).To(Equal(sdtypes.Leaf))
|
||||
if bytes.Equal(stateNode.StateLeafKey.Bytes(), test_helpers.AccountLeafKey) {
|
||||
Expect(stateNode.IPLD).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.State2IPLD.RawData(),
|
||||
CID: test_helpers.State2IPLD.Cid().String(),
|
||||
Expect(stateNode.IPLD).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.State2IPLD.RawData(),
|
||||
Key: test_helpers.State2IPLD.Cid().String(),
|
||||
}))
|
||||
}
|
||||
if bytes.Equal(stateNode.StateLeafKey.Bytes(), test_helpers.ContractLeafKey) {
|
||||
Expect(stateNode.IPLD).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.State1IPLD.RawData(),
|
||||
CID: test_helpers.State1IPLD.Cid().String(),
|
||||
Expect(stateNode.IPLD).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.State1IPLD.RawData(),
|
||||
Key: test_helpers.State1IPLD.Cid().String(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
@@ -81,116 +82,122 @@ var _ = Describe("Filterer", func() {
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds1).ToNot(BeNil())
|
||||
Expect(iplds1.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds1.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds1.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds1.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds1.Transactions)).To(Equal(0))
|
||||
Expect(len(iplds1.StorageNodes)).To(Equal(0))
|
||||
Expect(len(iplds1.StateNodes)).To(Equal(0))
|
||||
Expect(len(iplds1.Receipts)).To(Equal(1))
|
||||
Expect(iplds1.Receipts[0]).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.Rct1IPLD.RawData(),
|
||||
CID: test_helpers.Rct1IPLD.Cid().String(),
|
||||
Expect(iplds1.Receipts[0]).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.Rct1IPLD,
|
||||
Key: test_helpers.Rct1CID.String(),
|
||||
}))
|
||||
|
||||
iplds2, err := filterer.Filter(rctTopicsFilter, test_helpers.MockConvertedPayload)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds2).ToNot(BeNil())
|
||||
Expect(iplds2.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds2.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds2.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds2.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds2.Transactions)).To(Equal(0))
|
||||
Expect(len(iplds2.StorageNodes)).To(Equal(0))
|
||||
Expect(len(iplds2.StateNodes)).To(Equal(0))
|
||||
Expect(len(iplds2.Receipts)).To(Equal(1))
|
||||
Expect(iplds2.Receipts[0]).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.Rct1IPLD.RawData(),
|
||||
CID: test_helpers.Rct1IPLD.Cid().String(),
|
||||
Expect(iplds2.Receipts[0]).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.Rct1IPLD,
|
||||
Key: test_helpers.Rct1CID.String(),
|
||||
}))
|
||||
|
||||
iplds3, err := filterer.Filter(rctTopicsAndAddressFilter, test_helpers.MockConvertedPayload)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds3).ToNot(BeNil())
|
||||
Expect(iplds3.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds3.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds3.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds3.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds3.Transactions)).To(Equal(0))
|
||||
Expect(len(iplds3.StorageNodes)).To(Equal(0))
|
||||
Expect(len(iplds3.StateNodes)).To(Equal(0))
|
||||
Expect(len(iplds3.Receipts)).To(Equal(1))
|
||||
Expect(iplds3.Receipts[0]).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.Rct1IPLD.RawData(),
|
||||
CID: test_helpers.Rct1IPLD.Cid().String(),
|
||||
Expect(iplds3.Receipts[0]).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.Rct1IPLD,
|
||||
Key: test_helpers.Rct1CID.String(),
|
||||
}))
|
||||
|
||||
iplds4, err := filterer.Filter(rctAddressesAndTopicFilter, test_helpers.MockConvertedPayload)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds4).ToNot(BeNil())
|
||||
Expect(iplds4.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds4.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds4.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds4.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds4.Transactions)).To(Equal(0))
|
||||
Expect(len(iplds4.StorageNodes)).To(Equal(0))
|
||||
Expect(len(iplds4.StateNodes)).To(Equal(0))
|
||||
Expect(len(iplds4.Receipts)).To(Equal(1))
|
||||
Expect(iplds4.Receipts[0]).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.Rct2IPLD.RawData(),
|
||||
CID: test_helpers.Rct2IPLD.Cid().String(),
|
||||
Expect(iplds4.Receipts[0]).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.Rct2IPLD,
|
||||
Key: test_helpers.Rct2CID.String(),
|
||||
}))
|
||||
|
||||
iplds5, err := filterer.Filter(rctsForAllCollectedTrxs, test_helpers.MockConvertedPayload)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds5).ToNot(BeNil())
|
||||
Expect(iplds5.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds5.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds5.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds5.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds5.Transactions)).To(Equal(3))
|
||||
Expect(len(iplds5.Transactions)).To(Equal(4))
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx1)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx2)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx3)).To(BeTrue())
|
||||
Expect(len(iplds5.StorageNodes)).To(Equal(0))
|
||||
Expect(len(iplds5.StateNodes)).To(Equal(0))
|
||||
Expect(len(iplds5.Receipts)).To(Equal(3))
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct1)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct2)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct3)).To(BeTrue())
|
||||
Expect(len(iplds5.Receipts)).To(Equal(4))
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct1IPLD)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct2IPLD)).To(BeTrue())
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Receipts, test_helpers.Rct3IPLD)).To(BeTrue())
|
||||
|
||||
iplds6, err := filterer.Filter(rctsForSelectCollectedTrxs, test_helpers.MockConvertedPayload)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds6).ToNot(BeNil())
|
||||
Expect(iplds6.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds6.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds6.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds6.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds6.Transactions)).To(Equal(1))
|
||||
Expect(shared.IPLDsContainBytes(iplds5.Transactions, test_helpers.Tx2)).To(BeTrue())
|
||||
Expect(len(iplds6.StorageNodes)).To(Equal(0))
|
||||
Expect(len(iplds6.StateNodes)).To(Equal(0))
|
||||
Expect(len(iplds6.Receipts)).To(Equal(1))
|
||||
Expect(iplds4.Receipts[0]).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.Rct2IPLD.RawData(),
|
||||
CID: test_helpers.Rct2IPLD.Cid().String(),
|
||||
Expect(iplds4.Receipts[0]).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.Rct2IPLD,
|
||||
Key: test_helpers.Rct2CID.String(),
|
||||
}))
|
||||
|
||||
iplds7, err := filterer.Filter(stateFilter, test_helpers.MockConvertedPayload)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds7).ToNot(BeNil())
|
||||
Expect(iplds7.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds7.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds7.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds7.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds7.Transactions)).To(Equal(0))
|
||||
Expect(len(iplds7.StorageNodes)).To(Equal(0))
|
||||
Expect(len(iplds7.Receipts)).To(Equal(0))
|
||||
Expect(len(iplds7.StateNodes)).To(Equal(1))
|
||||
Expect(iplds7.StateNodes[0].StateLeafKey.Bytes()).To(Equal(test_helpers.AccountLeafKey))
|
||||
Expect(iplds7.StateNodes[0].IPLD).To(Equal(ipfs.BlockModel{
|
||||
Data: test_helpers.State2IPLD.RawData(),
|
||||
CID: test_helpers.State2IPLD.Cid().String(),
|
||||
Expect(iplds7.StateNodes[0].IPLD).To(Equal(models.IPLDModel{
|
||||
BlockNumber: test_helpers.BlockNumber.String(),
|
||||
Data: test_helpers.State2IPLD.RawData(),
|
||||
Key: test_helpers.State2IPLD.Cid().String(),
|
||||
}))
|
||||
|
||||
iplds8, err := filterer.Filter(rctTopicsAndAddressFilterFail, test_helpers.MockConvertedPayload)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(iplds8).ToNot(BeNil())
|
||||
Expect(iplds8.BlockNumber.Int64()).To(Equal(test_helpers.MockIPLDs.BlockNumber.Int64()))
|
||||
Expect(iplds8.Header).To(Equal(ipfs.BlockModel{}))
|
||||
Expect(iplds8.Header).To(Equal(models.IPLDModel{}))
|
||||
Expect(len(iplds8.Uncles)).To(Equal(0))
|
||||
Expect(len(iplds8.Transactions)).To(Equal(0))
|
||||
Expect(len(iplds8.StorageNodes)).To(Equal(0))
|
||||
|
||||
@@ -17,15 +17,7 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"os"
|
||||
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
func ResolveToNodeType(nodeType int) sdtypes.NodeType {
|
||||
@@ -42,41 +34,3 @@ func ResolveToNodeType(nodeType int) sdtypes.NodeType {
|
||||
return sdtypes.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
// LoadConfig loads chain config from json file
|
||||
func LoadConfig(chainConfigPath string) (*params.ChainConfig, error) {
|
||||
file, err := os.Open(chainConfigPath)
|
||||
if err != nil {
|
||||
utils.Fatalf("Failed to read chain config file: %v", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
chainConfig := new(params.ChainConfig)
|
||||
if err := json.NewDecoder(file).Decode(chainConfig); err != nil {
|
||||
utils.Fatalf("invalid chain config file: %v", err)
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Infof("Using chain config from %s file. Content %+v", chainConfigPath, chainConfig)
|
||||
|
||||
return chainConfig, nil
|
||||
}
|
||||
|
||||
// ChainConfig returns the appropriate ethereum chain config for the provided chain id
|
||||
func ChainConfig(chainID uint64) (*params.ChainConfig, error) {
|
||||
switch chainID {
|
||||
case 1:
|
||||
return params.MainnetChainConfig, nil
|
||||
case 3:
|
||||
return params.RopstenChainConfig, nil
|
||||
case 4:
|
||||
return params.RinkebyChainConfig, nil
|
||||
case 5:
|
||||
return params.GoerliChainConfig, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("chain config for chainid %d not available", chainID)
|
||||
}
|
||||
}
|
||||
|
||||
+71
-42
@@ -20,16 +20,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/shared"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
// Fetcher interface for substituting mocks in tests
|
||||
@@ -40,11 +37,11 @@ type Fetcher interface {
|
||||
// IPLDFetcher satisfies the IPLDFetcher interface for ethereum
|
||||
// It interfaces directly with PG-IPFS
|
||||
type IPLDFetcher struct {
|
||||
db *postgres.DB
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
// NewIPLDFetcher creates a pointer to a new IPLDFetcher
|
||||
func NewIPLDFetcher(db *postgres.DB) *IPLDFetcher {
|
||||
func NewIPLDFetcher(db *sqlx.DB) *IPLDFetcher {
|
||||
return &IPLDFetcher{
|
||||
db: db,
|
||||
}
|
||||
@@ -104,85 +101,112 @@ func (f *IPLDFetcher) Fetch(cids CIDWrapper) (*IPLDs, error) {
|
||||
}
|
||||
|
||||
// FetchHeaders fetches headers
|
||||
func (f *IPLDFetcher) FetchHeader(tx *sqlx.Tx, c eth.HeaderModel) (ipfs.BlockModel, error) {
|
||||
func (f *IPLDFetcher) FetchHeader(tx *sqlx.Tx, c models.HeaderModel) (models.IPLDModel, error) {
|
||||
log.Debug("fetching header ipld")
|
||||
headerBytes, err := shared.FetchIPLDByMhKey(tx, c.MhKey)
|
||||
blockNumber, err := strconv.ParseUint(c.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return ipfs.BlockModel{}, err
|
||||
return models.IPLDModel{}, err
|
||||
}
|
||||
return ipfs.BlockModel{
|
||||
Data: headerBytes,
|
||||
CID: c.CID,
|
||||
|
||||
headerBytes, err := shared.FetchIPLDByMhKeyAndBlockNumber(tx, c.MhKey, blockNumber)
|
||||
if err != nil {
|
||||
return models.IPLDModel{}, err
|
||||
}
|
||||
return models.IPLDModel{
|
||||
BlockNumber: c.BlockNumber,
|
||||
Data: headerBytes,
|
||||
Key: c.CID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// FetchUncles fetches uncles
|
||||
func (f *IPLDFetcher) FetchUncles(tx *sqlx.Tx, cids []eth.UncleModel) ([]ipfs.BlockModel, error) {
|
||||
func (f *IPLDFetcher) FetchUncles(tx *sqlx.Tx, cids []models.UncleModel) ([]models.IPLDModel, error) {
|
||||
log.Debug("fetching uncle iplds")
|
||||
uncleIPLDs := make([]ipfs.BlockModel, len(cids))
|
||||
uncleIPLDs := make([]models.IPLDModel, len(cids))
|
||||
for i, c := range cids {
|
||||
uncleBytes, err := shared.FetchIPLDByMhKey(tx, c.MhKey)
|
||||
blockNumber, err := strconv.ParseUint(c.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uncleIPLDs[i] = ipfs.BlockModel{
|
||||
Data: uncleBytes,
|
||||
CID: c.CID,
|
||||
uncleBytes, err := shared.FetchIPLDByMhKeyAndBlockNumber(tx, c.MhKey, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uncleIPLDs[i] = models.IPLDModel{
|
||||
BlockNumber: c.BlockNumber,
|
||||
Data: uncleBytes,
|
||||
Key: c.CID,
|
||||
}
|
||||
}
|
||||
return uncleIPLDs, nil
|
||||
}
|
||||
|
||||
// FetchTrxs fetches transactions
|
||||
func (f *IPLDFetcher) FetchTrxs(tx *sqlx.Tx, cids []eth.TxModel) ([]ipfs.BlockModel, error) {
|
||||
func (f *IPLDFetcher) FetchTrxs(tx *sqlx.Tx, cids []models.TxModel) ([]models.IPLDModel, error) {
|
||||
log.Debug("fetching transaction iplds")
|
||||
trxIPLDs := make([]ipfs.BlockModel, len(cids))
|
||||
trxIPLDs := make([]models.IPLDModel, len(cids))
|
||||
for i, c := range cids {
|
||||
txBytes, err := shared.FetchIPLDByMhKey(tx, c.MhKey)
|
||||
blockNumber, err := strconv.ParseUint(c.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trxIPLDs[i] = ipfs.BlockModel{
|
||||
Data: txBytes,
|
||||
CID: c.CID,
|
||||
txBytes, err := shared.FetchIPLDByMhKeyAndBlockNumber(tx, c.MhKey, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
trxIPLDs[i] = models.IPLDModel{
|
||||
BlockNumber: c.BlockNumber,
|
||||
Data: txBytes,
|
||||
Key: c.CID,
|
||||
}
|
||||
}
|
||||
return trxIPLDs, nil
|
||||
}
|
||||
|
||||
// FetchRcts fetches receipts
|
||||
func (f *IPLDFetcher) FetchRcts(tx *sqlx.Tx, cids []eth.ReceiptModel) ([]ipfs.BlockModel, error) {
|
||||
func (f *IPLDFetcher) FetchRcts(tx *sqlx.Tx, cids []models.ReceiptModel) ([]models.IPLDModel, error) {
|
||||
log.Debug("fetching receipt iplds")
|
||||
rctIPLDs := make([]ipfs.BlockModel, len(cids))
|
||||
rctIPLDs := make([]models.IPLDModel, len(cids))
|
||||
for i, c := range cids {
|
||||
rctBytes, err := shared.FetchIPLDByMhKey(tx, c.MhKey)
|
||||
blockNumber, err := strconv.ParseUint(c.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rctIPLDs[i] = ipfs.BlockModel{
|
||||
Data: rctBytes,
|
||||
CID: c.CID,
|
||||
rctBytes, err := shared.FetchIPLDByMhKeyAndBlockNumber(tx, c.LeafMhKey, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//nodeVal, err := DecodeLeafNode(rctBytes)
|
||||
rctIPLDs[i] = models.IPLDModel{
|
||||
BlockNumber: c.BlockNumber,
|
||||
Data: rctBytes,
|
||||
Key: c.LeafCID,
|
||||
}
|
||||
}
|
||||
return rctIPLDs, nil
|
||||
}
|
||||
|
||||
// FetchState fetches state nodes
|
||||
func (f *IPLDFetcher) FetchState(tx *sqlx.Tx, cids []eth.StateNodeModel) ([]StateNode, error) {
|
||||
func (f *IPLDFetcher) FetchState(tx *sqlx.Tx, cids []models.StateNodeModel) ([]StateNode, error) {
|
||||
log.Debug("fetching state iplds")
|
||||
stateNodes := make([]StateNode, 0, len(cids))
|
||||
for _, stateNode := range cids {
|
||||
if stateNode.CID == "" {
|
||||
continue
|
||||
}
|
||||
stateBytes, err := shared.FetchIPLDByMhKey(tx, stateNode.MhKey)
|
||||
blockNumber, err := strconv.ParseUint(stateNode.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stateBytes, err := shared.FetchIPLDByMhKeyAndBlockNumber(tx, stateNode.MhKey, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
stateNodes = append(stateNodes, StateNode{
|
||||
IPLD: ipfs.BlockModel{
|
||||
Data: stateBytes,
|
||||
CID: stateNode.CID,
|
||||
IPLD: models.IPLDModel{
|
||||
BlockNumber: stateNode.BlockNumber,
|
||||
Data: stateBytes,
|
||||
Key: stateNode.CID,
|
||||
},
|
||||
StateLeafKey: common.HexToHash(stateNode.StateKey),
|
||||
Type: ResolveToNodeType(stateNode.NodeType),
|
||||
@@ -193,21 +217,26 @@ func (f *IPLDFetcher) FetchState(tx *sqlx.Tx, cids []eth.StateNodeModel) ([]Stat
|
||||
}
|
||||
|
||||
// FetchStorage fetches storage nodes
|
||||
func (f *IPLDFetcher) FetchStorage(tx *sqlx.Tx, cids []eth.StorageNodeWithStateKeyModel) ([]StorageNode, error) {
|
||||
func (f *IPLDFetcher) FetchStorage(tx *sqlx.Tx, cids []models.StorageNodeWithStateKeyModel) ([]StorageNode, error) {
|
||||
log.Debug("fetching storage iplds")
|
||||
storageNodes := make([]StorageNode, 0, len(cids))
|
||||
for _, storageNode := range cids {
|
||||
if storageNode.CID == "" || storageNode.StateKey == "" {
|
||||
continue
|
||||
}
|
||||
storageBytes, err := shared.FetchIPLDByMhKey(tx, storageNode.MhKey)
|
||||
blockNumber, err := strconv.ParseUint(storageNode.BlockNumber, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storageBytes, err := shared.FetchIPLDByMhKeyAndBlockNumber(tx, storageNode.MhKey, blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storageNodes = append(storageNodes, StorageNode{
|
||||
IPLD: ipfs.BlockModel{
|
||||
Data: storageBytes,
|
||||
CID: storageNode.CID,
|
||||
IPLD: models.IPLDModel{
|
||||
BlockNumber: storageNode.BlockNumber,
|
||||
Data: storageBytes,
|
||||
Key: storageNode.CID,
|
||||
},
|
||||
StateLeafKey: common.HexToHash(storageNode.StateKey),
|
||||
StorageLeafKey: common.HexToHash(storageNode.StorageKey),
|
||||
|
||||
@@ -17,35 +17,45 @@
|
||||
package eth_test
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/interfaces"
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
|
||||
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var _ = Describe("IPLDFetcher", func() {
|
||||
var (
|
||||
db *postgres.DB
|
||||
pubAndIndexer *eth2.IPLDPublisher
|
||||
db *sqlx.DB
|
||||
pubAndIndexer interfaces.StateDiffIndexer
|
||||
fetcher *eth.IPLDFetcher
|
||||
)
|
||||
Describe("Fetch", func() {
|
||||
BeforeEach(func() {
|
||||
var err error
|
||||
db, err = shared.SetupDB()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
pubAndIndexer = eth2.NewIPLDPublisher(db)
|
||||
err = pubAndIndexer.Publish(test_helpers.MockConvertedPayload)
|
||||
var (
|
||||
err error
|
||||
tx interfaces.Batch
|
||||
)
|
||||
db = shared.SetupDB()
|
||||
pubAndIndexer = shared.SetupTestStateDiffIndexer(ctx, params.TestChainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
tx, err = pubAndIndexer.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
for _, node := range test_helpers.MockStateNodes {
|
||||
err = pubAndIndexer.PushStateNode(tx, node, test_helpers.MockBlock.Hash().String())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
fetcher = eth.NewIPLDFetcher(db)
|
||||
|
||||
})
|
||||
AfterEach(func() {
|
||||
eth.TearDownDB(db)
|
||||
shared.TearDownDB(db)
|
||||
})
|
||||
|
||||
It("Fetches and returns IPLDs for the CIDs provided in the CIDWrapper", func() {
|
||||
|
||||
+245
-92
@@ -19,147 +19,254 @@ package eth
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/statediff/trie_helpers"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/lib/pq"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
)
|
||||
|
||||
const (
|
||||
// node type removed value.
|
||||
// https://github.com/vulcanize/go-ethereum/blob/271f4d01e7e2767ffd8e0cd469bf545be96f2a84/statediff/indexer/helpers.go#L34
|
||||
removedNode = 3
|
||||
|
||||
RetrieveHeadersByHashesPgStr = `SELECT cid, data
|
||||
FROM eth.header_cids
|
||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||
INNER JOIN public.blocks ON (
|
||||
header_cids.mh_key = blocks.key
|
||||
AND header_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = ANY($1::VARCHAR(66)[])`
|
||||
RetrieveHeadersByBlockNumberPgStr = `SELECT cid, data
|
||||
FROM eth.header_cids
|
||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||
INNER JOIN public.blocks ON (
|
||||
header_cids.mh_key = blocks.key
|
||||
AND header_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_number = $1`
|
||||
RetrieveHeaderByHashPgStr = `SELECT cid, data
|
||||
FROM eth.header_cids
|
||||
INNER JOIN public.blocks ON (header_cids.mh_key = blocks.key)
|
||||
INNER JOIN public.blocks ON (
|
||||
header_cids.mh_key = blocks.key
|
||||
AND header_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = $1`
|
||||
RetrieveUnclesByHashesPgStr = `SELECT cid, data
|
||||
FROM eth.uncle_cids
|
||||
INNER JOIN public.blocks ON (uncle_cids.mh_key = blocks.key)
|
||||
INNER JOIN public.blocks ON (
|
||||
uncle_cids.mh_key = blocks.key
|
||||
AND uncle_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = ANY($1::VARCHAR(66)[])`
|
||||
RetrieveUnclesByBlockHashPgStr = `SELECT uncle_cids.cid, data
|
||||
FROM eth.uncle_cids
|
||||
INNER JOIN eth.header_cids ON (uncle_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (uncle_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
uncle_cids.header_id = header_cids.block_hash
|
||||
AND uncle_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
uncle_cids.mh_key = blocks.key
|
||||
AND uncle_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = $1`
|
||||
RetrieveUnclesByBlockNumberPgStr = `SELECT uncle_cids.cid, data
|
||||
FROM eth.uncle_cids
|
||||
INNER JOIN eth.header_cids ON (uncle_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (uncle_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
uncle_cids.header_id = header_cids.block_hash
|
||||
AND uncle_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
uncle_cids.mh_key = blocks.key
|
||||
AND uncle_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_number = $1`
|
||||
RetrieveUncleByHashPgStr = `SELECT cid, data
|
||||
FROM eth.uncle_cids
|
||||
INNER JOIN public.blocks ON (uncle_cids.mh_key = blocks.key)
|
||||
INNER JOIN public.blocks ON (
|
||||
uncle_cids.mh_key = blocks.key
|
||||
AND uncle_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = $1`
|
||||
RetrieveTransactionsByHashesPgStr = `SELECT cid, data
|
||||
FROM eth.transaction_cids
|
||||
INNER JOIN public.blocks ON (transaction_cids.mh_key = blocks.key)
|
||||
INNER JOIN public.blocks ON (
|
||||
transaction_cids.mh_key = blocks.key
|
||||
AND transaction_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE tx_hash = ANY($1::VARCHAR(66)[])`
|
||||
RetrieveTransactionsByBlockHashPgStr = `SELECT transaction_cids.cid, data
|
||||
FROM eth.transaction_cids
|
||||
INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (transaction_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
transaction_cids.mh_key = blocks.key
|
||||
AND transaction_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = $1
|
||||
ORDER BY eth.transaction_cids.index ASC`
|
||||
RetrieveTransactionsByBlockNumberPgStr = `SELECT transaction_cids.cid, data
|
||||
FROM eth.transaction_cids
|
||||
INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (transaction_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
transaction_cids.mh_key = blocks.key
|
||||
AND transaction_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_number = $1
|
||||
ORDER BY eth.transaction_cids.index ASC`
|
||||
RetrieveTransactionByHashPgStr = `SELECT cid, data
|
||||
FROM eth.transaction_cids
|
||||
INNER JOIN public.blocks ON (transaction_cids.mh_key = blocks.key)
|
||||
INNER JOIN public.blocks ON (
|
||||
transaction_cids.mh_key = blocks.key
|
||||
AND transaction_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE tx_hash = $1`
|
||||
RetrieveReceiptsByTxHashesPgStr = `SELECT receipt_cids.cid, data
|
||||
RetrieveReceiptsByTxHashesPgStr = `SELECT receipt_cids.leaf_cid, data
|
||||
FROM eth.receipt_cids
|
||||
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
||||
INNER JOIN public.blocks ON (receipt_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.transaction_cids ON (
|
||||
receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
receipt_cids.leaf_mh_key = blocks.key
|
||||
AND receipt_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE tx_hash = ANY($1::VARCHAR(66)[])`
|
||||
RetrieveReceiptsByBlockHashPgStr = `SELECT receipt_cids.cid, data, eth.transaction_cids.tx_hash
|
||||
RetrieveReceiptsByBlockHashPgStr = `SELECT receipt_cids.leaf_cid, data, eth.transaction_cids.tx_hash
|
||||
FROM eth.receipt_cids
|
||||
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
||||
INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (receipt_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.transaction_cids ON (
|
||||
receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
receipt_cids.leaf_mh_key = blocks.key
|
||||
AND receipt_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = $1
|
||||
ORDER BY eth.transaction_cids.index ASC`
|
||||
RetrieveReceiptsByBlockNumberPgStr = `SELECT receipt_cids.cid, data
|
||||
RetrieveReceiptsByBlockNumberPgStr = `SELECT receipt_cids.leaf_cid, data
|
||||
FROM eth.receipt_cids
|
||||
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
||||
INNER JOIN eth.header_cids ON (transaction_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (receipt_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.transaction_cids ON (
|
||||
receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
transaction_cids.header_id = header_cids.block_hash
|
||||
AND transaction_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
receipt_cids.leaf_mh_key = blocks.key
|
||||
AND receipt_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_number = $1
|
||||
ORDER BY eth.transaction_cids.index ASC`
|
||||
RetrieveReceiptByTxHashPgStr = `SELECT receipt_cids.cid, data
|
||||
RetrieveReceiptByTxHashPgStr = `SELECT receipt_cids.leaf_cid, data
|
||||
FROM eth.receipt_cids
|
||||
INNER JOIN eth.transaction_cids ON (receipt_cids.tx_id = transaction_cids.id)
|
||||
INNER JOIN public.blocks ON (receipt_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.transaction_cids ON (
|
||||
receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.block_number = transaction_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
receipt_cids.leaf_mh_key = blocks.key
|
||||
AND receipt_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE tx_hash = $1`
|
||||
RetrieveAccountByLeafKeyAndBlockHashPgStr = `SELECT state_cids.cid,
|
||||
data,
|
||||
was_state_removed(state_path, block_number, $2) AS removed
|
||||
RetrieveAccountByLeafKeyAndBlockHashPgStr = `SELECT state_cids.cid, data, state_cids.node_type
|
||||
FROM eth.state_cids
|
||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (state_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
state_cids.header_id = header_cids.block_hash
|
||||
AND state_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
state_cids.mh_key = blocks.key
|
||||
AND state_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE state_leaf_key = $1
|
||||
AND block_number <= (SELECT block_number
|
||||
AND header_cids.block_number <= (SELECT block_number
|
||||
FROM eth.header_cids
|
||||
WHERE block_hash = $2)
|
||||
AND header_cids.id = (SELECT canonical_header_id(block_number))
|
||||
ORDER BY block_number DESC
|
||||
AND header_cids.block_hash = (SELECT canonical_header_hash(header_cids.block_number))
|
||||
ORDER BY header_cids.block_number DESC
|
||||
LIMIT 1`
|
||||
RetrieveAccountByLeafKeyAndBlockNumberPgStr = `SELECT state_cids.cid,
|
||||
data,
|
||||
was_state_removed(state_path, block_number, (SELECT block_hash
|
||||
FROM eth.header_cids
|
||||
WHERE block_number = $2
|
||||
LIMIT 1)) AS removed
|
||||
RetrieveAccountByLeafKeyAndBlockNumberPgStr = `SELECT state_cids.cid, data, state_cids.node_type
|
||||
FROM eth.state_cids
|
||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (state_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
state_cids.header_id = header_cids.block_hash
|
||||
AND state_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
state_cids.mh_key = blocks.key
|
||||
AND state_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE state_leaf_key = $1
|
||||
AND block_number <= $2
|
||||
ORDER BY block_number DESC
|
||||
LIMIT 1`
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockNumberPgStr = `SELECT storage_cids.cid,
|
||||
data,
|
||||
was_storage_removed(storage_path, block_number, (SELECT block_hash
|
||||
FROM eth.header_cids
|
||||
WHERE block_number = $3
|
||||
LIMIT 1)) AS removed
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockNumberPgStr = `SELECT storage_cids.cid, data, storage_cids.node_type, was_state_leaf_removed($1, $3) AS state_leaf_removed
|
||||
FROM eth.storage_cids
|
||||
INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id)
|
||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (storage_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.state_cids ON (
|
||||
storage_cids.header_id = state_cids.header_id
|
||||
AND storage_cids.state_path = state_cids.state_path
|
||||
AND storage_cids.block_number = state_cids.block_number
|
||||
)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
state_cids.header_id = header_cids.block_hash
|
||||
AND state_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
storage_cids.mh_key = blocks.key
|
||||
AND storage_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE state_leaf_key = $1
|
||||
AND storage_leaf_key = $2
|
||||
AND block_number <= $3
|
||||
ORDER BY block_number DESC
|
||||
LIMIT 1`
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr = `SELECT storage_cids.cid,
|
||||
data,
|
||||
was_storage_removed(storage_path, block_number, $3) AS removed
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr = `SELECT storage_cids.cid, data, storage_cids.node_type, was_state_leaf_removed($1, $3) AS state_leaf_removed
|
||||
FROM eth.storage_cids
|
||||
INNER JOIN eth.state_cids ON (storage_cids.state_id = state_cids.id)
|
||||
INNER JOIN eth.header_cids ON (state_cids.header_id = header_cids.id)
|
||||
INNER JOIN public.blocks ON (storage_cids.mh_key = blocks.key)
|
||||
INNER JOIN eth.state_cids ON (
|
||||
storage_cids.header_id = state_cids.header_id
|
||||
AND storage_cids.state_path = state_cids.state_path
|
||||
AND storage_cids.block_number = state_cids.block_number
|
||||
)
|
||||
INNER JOIN eth.header_cids ON (
|
||||
state_cids.header_id = header_cids.block_hash
|
||||
AND state_cids.block_number = header_cids.block_number
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
storage_cids.mh_key = blocks.key
|
||||
AND storage_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE state_leaf_key = $1
|
||||
AND storage_leaf_key = $2
|
||||
AND block_number <= (SELECT block_number
|
||||
AND header_cids.block_number <= (SELECT block_number
|
||||
FROM eth.header_cids
|
||||
WHERE block_hash = $3)
|
||||
AND header_cids.id = (SELECT canonical_header_id(block_number))
|
||||
ORDER BY block_number DESC
|
||||
AND header_cids.block_hash = (SELECT canonical_header_hash(header_cids.block_number))
|
||||
ORDER BY header_cids.block_number DESC
|
||||
LIMIT 1`
|
||||
)
|
||||
|
||||
var EmptyNodeValue = make([]byte, common.HashLength)
|
||||
|
||||
type rctIpldResult struct {
|
||||
LeafCID string `db:"leaf_cid"`
|
||||
Data []byte `db:"data"`
|
||||
TxHash string `db:"tx_hash"`
|
||||
}
|
||||
|
||||
type ipldResult struct {
|
||||
CID string `db:"cid"`
|
||||
Data []byte `db:"data"`
|
||||
@@ -167,10 +274,10 @@ type ipldResult struct {
|
||||
}
|
||||
|
||||
type IPLDRetriever struct {
|
||||
db *postgres.DB
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func NewIPLDRetriever(db *postgres.DB) *IPLDRetriever {
|
||||
func NewIPLDRetriever(db *sqlx.DB) *IPLDRetriever {
|
||||
return &IPLDRetriever{
|
||||
db: db,
|
||||
}
|
||||
@@ -327,9 +434,26 @@ func (r *IPLDRetriever) RetrieveTransactionByTxHash(hash common.Hash) (string, [
|
||||
return txResult.CID, txResult.Data, r.db.Get(txResult, RetrieveTransactionByHashPgStr, hash.Hex())
|
||||
}
|
||||
|
||||
// DecodeLeafNode decodes the leaf node data
|
||||
func DecodeLeafNode(node []byte) ([]byte, error) {
|
||||
var nodeElements []interface{}
|
||||
if err := rlp.DecodeBytes(node, &nodeElements); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ty, err := trie_helpers.CheckKeyType(nodeElements)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if ty != sdtypes.Leaf {
|
||||
return nil, fmt.Errorf("expected leaf node but found %s", ty)
|
||||
}
|
||||
return nodeElements[1].([]byte), nil
|
||||
}
|
||||
|
||||
// RetrieveReceiptsByTxHashes returns the cids and rlp bytes for the receipts corresponding to the provided tx hashes
|
||||
func (r *IPLDRetriever) RetrieveReceiptsByTxHashes(hashes []common.Hash) ([]string, [][]byte, error) {
|
||||
rctResults := make([]ipldResult, 0)
|
||||
rctResults := make([]rctIpldResult, 0)
|
||||
hashStrs := make([]string, len(hashes))
|
||||
for i, hash := range hashes {
|
||||
hashStrs[i] = hash.Hex()
|
||||
@@ -340,15 +464,20 @@ func (r *IPLDRetriever) RetrieveReceiptsByTxHashes(hashes []common.Hash) ([]stri
|
||||
cids := make([]string, len(rctResults))
|
||||
rcts := make([][]byte, len(rctResults))
|
||||
for i, res := range rctResults {
|
||||
cids[i] = res.CID
|
||||
rcts[i] = res.Data
|
||||
cids[i] = res.LeafCID
|
||||
nodeVal, err := DecodeLeafNode(res.Data)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
rcts[i] = nodeVal
|
||||
}
|
||||
return cids, rcts, nil
|
||||
}
|
||||
|
||||
// RetrieveReceiptsByBlockHash returns the cids and rlp bytes for the receipts corresponding to the provided block hash
|
||||
// RetrieveReceiptsByBlockHash returns the cids and rlp bytes for the receipts corresponding to the provided block hash.
|
||||
// cid returned corresponds to the leaf node data which contains the receipt.
|
||||
func (r *IPLDRetriever) RetrieveReceiptsByBlockHash(hash common.Hash) ([]string, [][]byte, []common.Hash, error) {
|
||||
rctResults := make([]ipldResult, 0)
|
||||
rctResults := make([]rctIpldResult, 0)
|
||||
if err := r.db.Select(&rctResults, RetrieveReceiptsByBlockHashPgStr, hash.Hex()); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@@ -357,39 +486,58 @@ func (r *IPLDRetriever) RetrieveReceiptsByBlockHash(hash common.Hash) ([]string,
|
||||
txs := make([]common.Hash, len(rctResults))
|
||||
|
||||
for i, res := range rctResults {
|
||||
cids[i] = res.CID
|
||||
rcts[i] = res.Data
|
||||
cids[i] = res.LeafCID
|
||||
nodeVal, err := DecodeLeafNode(res.Data)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
rcts[i] = nodeVal
|
||||
txs[i] = common.HexToHash(res.TxHash)
|
||||
}
|
||||
|
||||
return cids, rcts, txs, nil
|
||||
}
|
||||
|
||||
// RetrieveReceiptsByBlockNumber returns the cids and rlp bytes for the receipts corresponding to the provided block hash
|
||||
// RetrieveReceiptsByBlockNumber returns the cids and rlp bytes for the receipts corresponding to the provided block hash.
|
||||
// cid returned corresponds to the leaf node data which contains the receipt.
|
||||
func (r *IPLDRetriever) RetrieveReceiptsByBlockNumber(number uint64) ([]string, [][]byte, error) {
|
||||
rctResults := make([]ipldResult, 0)
|
||||
rctResults := make([]rctIpldResult, 0)
|
||||
if err := r.db.Select(&rctResults, RetrieveReceiptsByBlockNumberPgStr, number); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cids := make([]string, len(rctResults))
|
||||
rcts := make([][]byte, len(rctResults))
|
||||
for i, res := range rctResults {
|
||||
cids[i] = res.CID
|
||||
rcts[i] = res.Data
|
||||
cids[i] = res.LeafCID
|
||||
nodeVal, err := DecodeLeafNode(res.Data)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
rcts[i] = nodeVal
|
||||
}
|
||||
return cids, rcts, nil
|
||||
}
|
||||
|
||||
// RetrieveReceiptByHash returns the cid and rlp bytes for the receipt corresponding to the provided tx hash
|
||||
// RetrieveReceiptByHash returns the cid and rlp bytes for the receipt corresponding to the provided tx hash.
|
||||
// cid returned corresponds to the leaf node data which contains the receipt.
|
||||
func (r *IPLDRetriever) RetrieveReceiptByHash(hash common.Hash) (string, []byte, error) {
|
||||
rctResult := new(ipldResult)
|
||||
return rctResult.CID, rctResult.Data, r.db.Get(rctResult, RetrieveReceiptByTxHashPgStr, hash.Hex())
|
||||
rctResult := new(rctIpldResult)
|
||||
if err := r.db.Select(&rctResult, RetrieveReceiptByTxHashPgStr, hash.Hex()); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
nodeVal, err := DecodeLeafNode(rctResult.Data)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
return rctResult.LeafCID, nodeVal, nil
|
||||
}
|
||||
|
||||
type nodeInfo struct {
|
||||
CID string `db:"cid"`
|
||||
Data []byte `db:"data"`
|
||||
Removed bool `db:"removed"`
|
||||
CID string `db:"cid"`
|
||||
Data []byte `db:"data"`
|
||||
NodeType int `db:"node_type"`
|
||||
StateLeafRemoved bool `db:"state_leaf_removed"`
|
||||
}
|
||||
|
||||
// RetrieveAccountByAddressAndBlockHash returns the cid and rlp bytes for the account corresponding to the provided address and block hash
|
||||
@@ -400,9 +548,11 @@ func (r *IPLDRetriever) RetrieveAccountByAddressAndBlockHash(address common.Addr
|
||||
if err := r.db.Get(accountResult, RetrieveAccountByLeafKeyAndBlockHashPgStr, leafKey.Hex(), hash.Hex()); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if accountResult.Removed {
|
||||
return "", []byte{}, nil
|
||||
|
||||
if accountResult.NodeType == removedNode {
|
||||
return "", EmptyNodeValue, nil
|
||||
}
|
||||
|
||||
var i []interface{}
|
||||
if err := rlp.DecodeBytes(accountResult.Data, &i); err != nil {
|
||||
return "", nil, fmt.Errorf("error decoding state leaf node rlp: %s", err.Error())
|
||||
@@ -421,9 +571,11 @@ func (r *IPLDRetriever) RetrieveAccountByAddressAndBlockNumber(address common.Ad
|
||||
if err := r.db.Get(accountResult, RetrieveAccountByLeafKeyAndBlockNumberPgStr, leafKey.Hex(), number); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if accountResult.Removed {
|
||||
return "", []byte{}, nil
|
||||
|
||||
if accountResult.NodeType == removedNode {
|
||||
return "", EmptyNodeValue, nil
|
||||
}
|
||||
|
||||
var i []interface{}
|
||||
if err := rlp.DecodeBytes(accountResult.Data, &i); err != nil {
|
||||
return "", nil, fmt.Errorf("error decoding state leaf node rlp: %s", err.Error())
|
||||
@@ -442,8 +594,8 @@ func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageSlotAndBlockHash(add
|
||||
if err := r.db.Get(storageResult, RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr, stateLeafKey.Hex(), storageHash.Hex(), hash.Hex()); err != nil {
|
||||
return "", nil, nil, err
|
||||
}
|
||||
if storageResult.Removed {
|
||||
return "", []byte{}, []byte{}, nil
|
||||
if storageResult.StateLeafRemoved || storageResult.NodeType == removedNode {
|
||||
return "", EmptyNodeValue, EmptyNodeValue, nil
|
||||
}
|
||||
var i []interface{}
|
||||
if err := rlp.DecodeBytes(storageResult.Data, &i); err != nil {
|
||||
@@ -464,8 +616,9 @@ func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageKeyAndBlockNumber(ad
|
||||
if err := r.db.Get(storageResult, RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockNumberPgStr, stateLeafKey.Hex(), storageLeafKey.Hex(), number); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if storageResult.Removed {
|
||||
return "", []byte{}, nil
|
||||
|
||||
if storageResult.StateLeafRemoved || storageResult.NodeType == removedNode {
|
||||
return "", EmptyNodeValue, nil
|
||||
}
|
||||
var i []interface{}
|
||||
if err := rlp.DecodeBytes(storageResult.Data, &i); err != nil {
|
||||
|
||||
+5
-30
@@ -17,36 +17,11 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
)
|
||||
|
||||
// TearDownDB is used to tear down the watcher dbs after tests
|
||||
func TearDownDB(db *postgres.DB) {
|
||||
tx, err := db.Beginx()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
_, err = tx.Exec(`DELETE FROM eth.header_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.transaction_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.receipt_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.state_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.storage_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM blocks`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = tx.Commit()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
// TxModelsContainsCID used to check if a list of TxModels contains a specific cid string
|
||||
func TxModelsContainsCID(txs []eth.TxModel, cid string) bool {
|
||||
func TxModelsContainsCID(txs []models.TxModel, cid string) bool {
|
||||
for _, tx := range txs {
|
||||
if tx.CID == cid {
|
||||
return true
|
||||
@@ -55,10 +30,10 @@ func TxModelsContainsCID(txs []eth.TxModel, cid string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ListContainsBytes used to check if a list of byte arrays contains a particular byte array
|
||||
func ReceiptModelsContainsCID(rcts []eth.ReceiptModel, cid string) bool {
|
||||
// ReceiptModelsContainsCID used to check if a list of ReceiptModel contains a specific cid string
|
||||
func ReceiptModelsContainsCID(rcts []models.ReceiptModel, cid string) bool {
|
||||
for _, rct := range rcts {
|
||||
if rct.CID == cid {
|
||||
if rct.LeafCID == cid {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
+285
-239
@@ -23,27 +23,22 @@ import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/statediff/testhelpers"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/ipld"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/shared"
|
||||
testhelpers "github.com/ethereum/go-ethereum/statediff/test_helpers"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
blocks "github.com/ipfs/go-block-format"
|
||||
"github.com/multiformats/go-multihash"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs/ipld"
|
||||
|
||||
eth2 "github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
)
|
||||
|
||||
// Test variables
|
||||
@@ -97,6 +92,8 @@ var (
|
||||
MockChildRlp, _ = rlp.EncodeToBytes(MockChild.Header())
|
||||
Address = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476592")
|
||||
AnotherAddress = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476593")
|
||||
AnotherAddress1 = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476594")
|
||||
AnotherAddress2 = common.HexToAddress("0xaE9BEa628c4Ce503DcFD7E305CaB4e29E7476596")
|
||||
ContractAddress = crypto.CreateAddress(SenderAddr, MockTransactions[2].Nonce())
|
||||
ContractHash = crypto.Keccak256Hash(ContractAddress.Bytes()).String()
|
||||
MockContractByteCode = []byte{0, 1, 2, 3, 4, 5}
|
||||
@@ -104,6 +101,12 @@ var (
|
||||
mockTopic12 = common.HexToHash("0x06")
|
||||
mockTopic21 = common.HexToHash("0x05")
|
||||
mockTopic22 = common.HexToHash("0x07")
|
||||
mockTopic31 = common.HexToHash("0x08")
|
||||
mockTopic41 = common.HexToHash("0x09")
|
||||
mockTopic42 = common.HexToHash("0x0a")
|
||||
mockTopic43 = common.HexToHash("0x0b")
|
||||
mockTopic51 = common.HexToHash("0x0c")
|
||||
mockTopic61 = common.HexToHash("0x0d")
|
||||
MockLog1 = &types.Log{
|
||||
Address: Address,
|
||||
Topics: []common.Hash{mockTopic11, mockTopic12},
|
||||
@@ -120,36 +123,75 @@ var (
|
||||
TxIndex: 1,
|
||||
Index: 1,
|
||||
}
|
||||
MockLog3 = &types.Log{
|
||||
Address: AnotherAddress1,
|
||||
Topics: []common.Hash{mockTopic31},
|
||||
Data: []byte{},
|
||||
BlockNumber: BlockNumber.Uint64(),
|
||||
TxIndex: 2,
|
||||
Index: 2,
|
||||
}
|
||||
|
||||
MockLog4 = &types.Log{
|
||||
Address: AnotherAddress1,
|
||||
Topics: []common.Hash{mockTopic41, mockTopic42, mockTopic43},
|
||||
Data: []byte{},
|
||||
BlockNumber: BlockNumber.Uint64(),
|
||||
TxIndex: 2,
|
||||
Index: 3,
|
||||
}
|
||||
MockLog5 = &types.Log{
|
||||
Address: AnotherAddress1,
|
||||
Topics: []common.Hash{mockTopic51},
|
||||
Data: []byte{},
|
||||
BlockNumber: BlockNumber.Uint64(),
|
||||
TxIndex: 2,
|
||||
Index: 4,
|
||||
}
|
||||
MockLog6 = &types.Log{
|
||||
Address: AnotherAddress2,
|
||||
Topics: []common.Hash{mockTopic61},
|
||||
Data: []byte{},
|
||||
BlockNumber: BlockNumber.Uint64(),
|
||||
TxIndex: 3,
|
||||
Index: 5,
|
||||
}
|
||||
|
||||
Tx1 = GetTxnRlp(0, MockTransactions)
|
||||
Tx2 = GetTxnRlp(1, MockTransactions)
|
||||
Tx3 = GetTxnRlp(2, MockTransactions)
|
||||
Tx4 = GetTxnRlp(3, MockTransactions)
|
||||
|
||||
Rct1 = GetRctRlp(0, MockReceipts)
|
||||
Rct2 = GetRctRlp(1, MockReceipts)
|
||||
Rct3 = GetRctRlp(2, MockReceipts)
|
||||
|
||||
HeaderCID, _ = ipld.RawdataToCid(ipld.MEthHeader, MockHeaderRlp, multihash.KECCAK_256)
|
||||
HeaderMhKey = shared.MultihashKeyFromCID(HeaderCID)
|
||||
Trx1CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx1, multihash.KECCAK_256)
|
||||
Trx1MhKey = shared.MultihashKeyFromCID(Trx1CID)
|
||||
Trx2CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx2, multihash.KECCAK_256)
|
||||
Trx2MhKey = shared.MultihashKeyFromCID(Trx2CID)
|
||||
Trx3CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx3, multihash.KECCAK_256)
|
||||
Trx3MhKey = shared.MultihashKeyFromCID(Trx3CID)
|
||||
Rct1CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, Rct1, multihash.KECCAK_256)
|
||||
Rct1MhKey = shared.MultihashKeyFromCID(Rct1CID)
|
||||
Rct2CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, Rct2, multihash.KECCAK_256)
|
||||
Rct2MhKey = shared.MultihashKeyFromCID(Rct2CID)
|
||||
Rct3CID, _ = ipld.RawdataToCid(ipld.MEthTxReceipt, Rct3, multihash.KECCAK_256)
|
||||
Rct3MhKey = shared.MultihashKeyFromCID(Rct3CID)
|
||||
State1CID, _ = ipld.RawdataToCid(ipld.MEthStateTrie, ContractLeafNode, multihash.KECCAK_256)
|
||||
State1MhKey = shared.MultihashKeyFromCID(State1CID)
|
||||
State2CID, _ = ipld.RawdataToCid(ipld.MEthStateTrie, AccountLeafNode, multihash.KECCAK_256)
|
||||
State2MhKey = shared.MultihashKeyFromCID(State2CID)
|
||||
StorageCID, _ = ipld.RawdataToCid(ipld.MEthStorageTrie, StorageLeafNode, multihash.KECCAK_256)
|
||||
StorageMhKey = shared.MultihashKeyFromCID(StorageCID)
|
||||
MockTrxMeta = []eth.TxModel{
|
||||
rctCIDs, rctIPLDData, _ = eth.GetRctLeafNodeData(MockReceipts)
|
||||
HeaderCID, _ = ipld.RawdataToCid(ipld.MEthHeader, MockHeaderRlp, multihash.KECCAK_256)
|
||||
HeaderMhKey = shared.MultihashKeyFromCID(HeaderCID)
|
||||
Trx1CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx1, multihash.KECCAK_256)
|
||||
Trx1MhKey = shared.MultihashKeyFromCID(Trx1CID)
|
||||
Trx2CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx2, multihash.KECCAK_256)
|
||||
Trx2MhKey = shared.MultihashKeyFromCID(Trx2CID)
|
||||
Trx3CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx3, multihash.KECCAK_256)
|
||||
Trx3MhKey = shared.MultihashKeyFromCID(Trx3CID)
|
||||
Trx4CID, _ = ipld.RawdataToCid(ipld.MEthTx, Tx4, multihash.KECCAK_256)
|
||||
Trx4MhKey = shared.MultihashKeyFromCID(Trx4CID)
|
||||
Rct1CID = rctCIDs[0]
|
||||
Rct1MhKey = shared.MultihashKeyFromCID(Rct1CID)
|
||||
Rct2CID = rctCIDs[1]
|
||||
Rct2MhKey = shared.MultihashKeyFromCID(Rct2CID)
|
||||
Rct3CID = rctCIDs[2]
|
||||
Rct3MhKey = shared.MultihashKeyFromCID(Rct3CID)
|
||||
Rct4CID = rctCIDs[3]
|
||||
Rct4MhKey = shared.MultihashKeyFromCID(Rct4CID)
|
||||
State1CID, _ = ipld.RawdataToCid(ipld.MEthStateTrie, ContractLeafNode, multihash.KECCAK_256)
|
||||
State1MhKey = shared.MultihashKeyFromCID(State1CID)
|
||||
State2CID, _ = ipld.RawdataToCid(ipld.MEthStateTrie, AccountLeafNode, multihash.KECCAK_256)
|
||||
State2MhKey = shared.MultihashKeyFromCID(State2CID)
|
||||
StorageCID, _ = ipld.RawdataToCid(ipld.MEthStorageTrie, StorageLeafNode, multihash.KECCAK_256)
|
||||
StorageMhKey = shared.MultihashKeyFromCID(StorageCID)
|
||||
Rct1IPLD = rctIPLDData[0]
|
||||
Rct2IPLD = rctIPLDData[1]
|
||||
Rct3IPLD = rctIPLDData[2]
|
||||
Rct4IPLD = rctIPLDData[3]
|
||||
MockTrxMeta = []models.TxModel{
|
||||
{
|
||||
CID: "", // This is empty until we go to publish to ipfs
|
||||
MhKey: "",
|
||||
@@ -177,112 +219,113 @@ var (
|
||||
TxHash: MockTransactions[2].Hash().String(),
|
||||
Data: MockContractByteCode,
|
||||
},
|
||||
}
|
||||
MockTrxMetaPostPublsh = []eth.TxModel{
|
||||
{
|
||||
CID: Trx1CID.String(), // This is empty until we go to publish to ipfs
|
||||
MhKey: Trx1MhKey,
|
||||
Src: SenderAddr.Hex(),
|
||||
Dst: Address.String(),
|
||||
Index: 0,
|
||||
TxHash: MockTransactions[0].Hash().String(),
|
||||
Data: []byte{},
|
||||
},
|
||||
{
|
||||
CID: Trx2CID.String(),
|
||||
MhKey: Trx2MhKey,
|
||||
Src: SenderAddr.Hex(),
|
||||
Dst: AnotherAddress.String(),
|
||||
Index: 1,
|
||||
TxHash: MockTransactions[1].Hash().String(),
|
||||
Data: []byte{},
|
||||
},
|
||||
{
|
||||
CID: Trx3CID.String(),
|
||||
MhKey: Trx3MhKey,
|
||||
CID: "",
|
||||
MhKey: "",
|
||||
Src: SenderAddr.Hex(),
|
||||
Dst: "",
|
||||
Index: 2,
|
||||
TxHash: MockTransactions[2].Hash().String(),
|
||||
Data: MockContractByteCode,
|
||||
Index: 3,
|
||||
TxHash: MockTransactions[3].Hash().String(),
|
||||
Data: []byte{},
|
||||
},
|
||||
}
|
||||
MockRctMeta = []eth.ReceiptModel{
|
||||
MockTrxMetaPostPublsh = []models.TxModel{
|
||||
{
|
||||
CID: "",
|
||||
MhKey: "",
|
||||
Topic0s: []string{
|
||||
mockTopic11.String(),
|
||||
},
|
||||
Topic1s: []string{
|
||||
mockTopic12.String(),
|
||||
},
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
LogContracts: []string{
|
||||
Address.String(),
|
||||
},
|
||||
BlockNumber: "1",
|
||||
CID: Trx1CID.String(), // This is empty until we go to publish to ipfs
|
||||
MhKey: Trx1MhKey,
|
||||
Src: SenderAddr.Hex(),
|
||||
Dst: Address.String(),
|
||||
Index: 0,
|
||||
TxHash: MockTransactions[0].Hash().String(),
|
||||
Data: []byte{},
|
||||
},
|
||||
{
|
||||
CID: "",
|
||||
MhKey: "",
|
||||
Topic0s: []string{
|
||||
mockTopic21.String(),
|
||||
},
|
||||
Topic1s: []string{
|
||||
mockTopic22.String(),
|
||||
},
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
LogContracts: []string{
|
||||
AnotherAddress.String(),
|
||||
},
|
||||
BlockNumber: "1",
|
||||
CID: Trx2CID.String(),
|
||||
MhKey: Trx2MhKey,
|
||||
Src: SenderAddr.Hex(),
|
||||
Dst: AnotherAddress.String(),
|
||||
Index: 1,
|
||||
TxHash: MockTransactions[1].Hash().String(),
|
||||
Data: []byte{},
|
||||
},
|
||||
{
|
||||
CID: "",
|
||||
MhKey: "",
|
||||
Contract: ContractAddress.String(),
|
||||
ContractHash: ContractHash,
|
||||
LogContracts: []string{},
|
||||
BlockNumber: "1",
|
||||
CID: Trx3CID.String(),
|
||||
MhKey: Trx3MhKey,
|
||||
Src: SenderAddr.Hex(),
|
||||
Dst: "",
|
||||
Index: 2,
|
||||
TxHash: MockTransactions[2].Hash().String(),
|
||||
Data: MockContractByteCode,
|
||||
},
|
||||
{
|
||||
BlockNumber: "1",
|
||||
CID: Trx4CID.String(),
|
||||
MhKey: Trx4MhKey,
|
||||
Src: SenderAddr.Hex(),
|
||||
Dst: AnotherAddress1.String(),
|
||||
Index: 3,
|
||||
TxHash: MockTransactions[3].Hash().String(),
|
||||
Data: []byte{},
|
||||
},
|
||||
}
|
||||
MockRctMetaPostPublish = []eth.ReceiptModel{
|
||||
MockRctMeta = []models.ReceiptModel{
|
||||
{
|
||||
CID: Rct1CID.String(),
|
||||
MhKey: Rct1MhKey,
|
||||
Topic0s: []string{
|
||||
mockTopic11.String(),
|
||||
},
|
||||
Topic1s: []string{
|
||||
mockTopic12.String(),
|
||||
},
|
||||
LeafCID: "",
|
||||
LeafMhKey: "",
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
LogContracts: []string{
|
||||
Address.String(),
|
||||
},
|
||||
},
|
||||
{
|
||||
CID: Rct2CID.String(),
|
||||
MhKey: Rct2MhKey,
|
||||
Topic0s: []string{
|
||||
mockTopic21.String(),
|
||||
},
|
||||
Topic1s: []string{
|
||||
mockTopic22.String(),
|
||||
},
|
||||
LeafCID: "",
|
||||
LeafMhKey: "",
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
LogContracts: []string{
|
||||
AnotherAddress.String(),
|
||||
},
|
||||
},
|
||||
{
|
||||
CID: Rct3CID.String(),
|
||||
MhKey: Rct3MhKey,
|
||||
LeafCID: "",
|
||||
LeafMhKey: "",
|
||||
Contract: ContractAddress.String(),
|
||||
ContractHash: ContractHash,
|
||||
LogContracts: []string{},
|
||||
},
|
||||
{
|
||||
LeafCID: "",
|
||||
LeafMhKey: "",
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
},
|
||||
}
|
||||
|
||||
MockRctMetaPostPublish = []models.ReceiptModel{
|
||||
{
|
||||
BlockNumber: "1",
|
||||
LeafCID: Rct1CID.String(),
|
||||
LeafMhKey: Rct1MhKey,
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
},
|
||||
{
|
||||
BlockNumber: "1",
|
||||
LeafCID: Rct2CID.String(),
|
||||
LeafMhKey: Rct2MhKey,
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
},
|
||||
{
|
||||
BlockNumber: "1",
|
||||
LeafCID: Rct3CID.String(),
|
||||
LeafMhKey: Rct3MhKey,
|
||||
Contract: ContractAddress.String(),
|
||||
ContractHash: ContractHash,
|
||||
},
|
||||
{
|
||||
BlockNumber: "1",
|
||||
LeafCID: Rct4CID.String(),
|
||||
LeafMhKey: Rct4MhKey,
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -291,7 +334,7 @@ var (
|
||||
StorageLeafKey = crypto.Keccak256Hash(storageLocation[:]).Bytes()
|
||||
StorageValue = crypto.Keccak256([]byte{1, 2, 3, 4, 5})
|
||||
StoragePartialPath = common.Hex2Bytes("20290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
|
||||
StorageLeafNode, _ = rlp.EncodeToBytes([]interface{}{
|
||||
StorageLeafNode, _ = rlp.EncodeToBytes(&[]interface{}{
|
||||
StoragePartialPath,
|
||||
StorageValue,
|
||||
})
|
||||
@@ -301,14 +344,14 @@ var (
|
||||
ContractCodeHash = crypto.Keccak256Hash(MockContractByteCode)
|
||||
contractPath = common.Bytes2Hex([]byte{'\x06'})
|
||||
ContractLeafKey = testhelpers.AddressToLeafKey(ContractAddress)
|
||||
ContractAccount, _ = rlp.EncodeToBytes(state.Account{
|
||||
ContractAccount, _ = rlp.EncodeToBytes(&types.StateAccount{
|
||||
Nonce: nonce1,
|
||||
Balance: big.NewInt(0),
|
||||
CodeHash: ContractCodeHash.Bytes(),
|
||||
Root: common.HexToHash(ContractRoot),
|
||||
})
|
||||
ContractPartialPath = common.Hex2Bytes("3114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45")
|
||||
ContractLeafNode, _ = rlp.EncodeToBytes([]interface{}{
|
||||
ContractLeafNode, _ = rlp.EncodeToBytes(&[]interface{}{
|
||||
ContractPartialPath,
|
||||
ContractAccount,
|
||||
})
|
||||
@@ -319,55 +362,66 @@ var (
|
||||
AccountCodeHash = common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
|
||||
AccountAddresss = common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e")
|
||||
AccountLeafKey = testhelpers.Account2LeafKey
|
||||
Account, _ = rlp.EncodeToBytes(state.Account{
|
||||
Account, _ = rlp.EncodeToBytes(&types.StateAccount{
|
||||
Nonce: nonce0,
|
||||
Balance: AccountBalance,
|
||||
CodeHash: AccountCodeHash.Bytes(),
|
||||
Root: common.HexToHash(AccountRoot),
|
||||
})
|
||||
AccountPartialPath = common.Hex2Bytes("3957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45")
|
||||
AccountLeafNode, _ = rlp.EncodeToBytes([]interface{}{
|
||||
AccountLeafNode, _ = rlp.EncodeToBytes(&[]interface{}{
|
||||
AccountPartialPath,
|
||||
Account,
|
||||
})
|
||||
|
||||
MockStateNodes = []eth.TrieNode{
|
||||
MockStateNodes = []sdtypes.StateNode{
|
||||
{
|
||||
LeafKey: common.BytesToHash(ContractLeafKey),
|
||||
Path: []byte{'\x06'},
|
||||
Value: ContractLeafNode,
|
||||
Type: sdtypes.Leaf,
|
||||
LeafKey: ContractLeafKey,
|
||||
Path: []byte{'\x06'},
|
||||
NodeValue: ContractLeafNode,
|
||||
NodeType: sdtypes.Leaf,
|
||||
StorageNodes: []sdtypes.StorageNode{
|
||||
{
|
||||
Path: []byte{},
|
||||
NodeType: sdtypes.Leaf,
|
||||
LeafKey: StorageLeafKey,
|
||||
NodeValue: StorageLeafNode,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
LeafKey: common.BytesToHash(AccountLeafKey),
|
||||
Path: []byte{'\x0c'},
|
||||
Value: AccountLeafNode,
|
||||
Type: sdtypes.Leaf,
|
||||
LeafKey: AccountLeafKey,
|
||||
Path: []byte{'\x0c'},
|
||||
NodeValue: AccountLeafNode,
|
||||
NodeType: sdtypes.Leaf,
|
||||
StorageNodes: []sdtypes.StorageNode{},
|
||||
},
|
||||
}
|
||||
MockStateMetaPostPublish = []eth.StateNodeModel{
|
||||
MockStateMetaPostPublish = []models.StateNodeModel{
|
||||
{
|
||||
CID: State1CID.String(),
|
||||
MhKey: State1MhKey,
|
||||
Path: []byte{'\x06'},
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(ContractLeafKey).Hex(),
|
||||
BlockNumber: "1",
|
||||
CID: State1CID.String(),
|
||||
MhKey: State1MhKey,
|
||||
Path: []byte{'\x06'},
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(ContractLeafKey).Hex(),
|
||||
},
|
||||
{
|
||||
CID: State2CID.String(),
|
||||
MhKey: State2MhKey,
|
||||
Path: []byte{'\x0c'},
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(AccountLeafKey).Hex(),
|
||||
BlockNumber: "1",
|
||||
CID: State2CID.String(),
|
||||
MhKey: State2MhKey,
|
||||
Path: []byte{'\x0c'},
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(AccountLeafKey).Hex(),
|
||||
},
|
||||
}
|
||||
MockStorageNodes = map[string][]eth.TrieNode{
|
||||
MockStorageNodes = map[string][]sdtypes.StorageNode{
|
||||
contractPath: {
|
||||
{
|
||||
LeafKey: common.BytesToHash(StorageLeafKey),
|
||||
Value: StorageLeafNode,
|
||||
Type: sdtypes.Leaf,
|
||||
Path: []byte{},
|
||||
LeafKey: StorageLeafKey,
|
||||
NodeValue: StorageLeafNode,
|
||||
NodeType: sdtypes.Leaf,
|
||||
Path: []byte{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -391,11 +445,10 @@ var (
|
||||
StateNodes: MockStateNodes,
|
||||
}
|
||||
|
||||
Reward = eth.CalcEthBlockReward(MockBlock.Header(), MockBlock.Uncles(), MockBlock.Transactions(), MockReceipts)
|
||||
|
||||
MockCIDWrapper = ð2.CIDWrapper{
|
||||
Reward = shared.CalcEthBlockReward(MockBlock.Header(), MockBlock.Uncles(), MockBlock.Transactions(), MockReceipts)
|
||||
MockCIDWrapper = ð.CIDWrapper{
|
||||
BlockNumber: new(big.Int).Set(BlockNumber),
|
||||
Header: eth.HeaderModel{
|
||||
Header: models.HeaderModel{
|
||||
BlockNumber: "1",
|
||||
BlockHash: MockBlock.Hash().String(),
|
||||
ParentHash: "0x0000000000000000000000000000000000000000000000000000000000000000",
|
||||
@@ -410,19 +463,21 @@ var (
|
||||
Bloom: MockBlock.Bloom().Bytes(),
|
||||
Timestamp: MockBlock.Time(),
|
||||
TimesValidated: 1,
|
||||
Coinbase: "0x0000000000000000000000000000000000000000",
|
||||
},
|
||||
Transactions: MockTrxMetaPostPublsh,
|
||||
Receipts: MockRctMetaPostPublish,
|
||||
Uncles: []eth.UncleModel{},
|
||||
Uncles: []models.UncleModel{},
|
||||
StateNodes: MockStateMetaPostPublish,
|
||||
StorageNodes: []eth.StorageNodeWithStateKeyModel{
|
||||
StorageNodes: []models.StorageNodeWithStateKeyModel{
|
||||
{
|
||||
Path: []byte{},
|
||||
CID: StorageCID.String(),
|
||||
MhKey: StorageMhKey,
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(ContractLeafKey).Hex(),
|
||||
StorageKey: common.BytesToHash(StorageLeafKey).Hex(),
|
||||
BlockNumber: "1",
|
||||
Path: []byte{},
|
||||
CID: StorageCID.String(),
|
||||
MhKey: StorageMhKey,
|
||||
NodeType: 2,
|
||||
StateKey: common.BytesToHash(ContractLeafKey).Hex(),
|
||||
StorageKey: common.BytesToHash(StorageLeafKey).Hex(),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -431,75 +486,93 @@ var (
|
||||
Trx1IPLD, _ = blocks.NewBlockWithCid(Tx1, Trx1CID)
|
||||
Trx2IPLD, _ = blocks.NewBlockWithCid(Tx2, Trx2CID)
|
||||
Trx3IPLD, _ = blocks.NewBlockWithCid(Tx3, Trx3CID)
|
||||
Rct1IPLD, _ = blocks.NewBlockWithCid(Rct1, Rct1CID)
|
||||
Rct2IPLD, _ = blocks.NewBlockWithCid(Rct2, Rct2CID)
|
||||
Rct3IPLD, _ = blocks.NewBlockWithCid(Rct3, Rct3CID)
|
||||
Trx4IPLD, _ = blocks.NewBlockWithCid(Tx4, Trx4CID)
|
||||
State1IPLD, _ = blocks.NewBlockWithCid(ContractLeafNode, State1CID)
|
||||
State2IPLD, _ = blocks.NewBlockWithCid(AccountLeafNode, State2CID)
|
||||
StorageIPLD, _ = blocks.NewBlockWithCid(StorageLeafNode, StorageCID)
|
||||
|
||||
MockIPLDs = eth2.IPLDs{
|
||||
MockIPLDs = eth.IPLDs{
|
||||
BlockNumber: new(big.Int).Set(BlockNumber),
|
||||
Header: ipfs.BlockModel{
|
||||
Data: HeaderIPLD.RawData(),
|
||||
CID: HeaderIPLD.Cid().String(),
|
||||
Header: models.IPLDModel{
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: HeaderIPLD.RawData(),
|
||||
Key: HeaderIPLD.Cid().String(),
|
||||
},
|
||||
Transactions: []ipfs.BlockModel{
|
||||
Transactions: []models.IPLDModel{
|
||||
{
|
||||
Data: Trx1IPLD.RawData(),
|
||||
CID: Trx1IPLD.Cid().String(),
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Trx1IPLD.RawData(),
|
||||
Key: Trx1IPLD.Cid().String(),
|
||||
},
|
||||
{
|
||||
Data: Trx2IPLD.RawData(),
|
||||
CID: Trx2IPLD.Cid().String(),
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Trx2IPLD.RawData(),
|
||||
Key: Trx2IPLD.Cid().String(),
|
||||
},
|
||||
{
|
||||
Data: Trx3IPLD.RawData(),
|
||||
CID: Trx3IPLD.Cid().String(),
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Trx3IPLD.RawData(),
|
||||
Key: Trx3IPLD.Cid().String(),
|
||||
},
|
||||
{
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Trx4IPLD.RawData(),
|
||||
Key: Trx4IPLD.Cid().String(),
|
||||
},
|
||||
},
|
||||
Receipts: []ipfs.BlockModel{
|
||||
Receipts: []models.IPLDModel{
|
||||
{
|
||||
Data: Rct1IPLD.RawData(),
|
||||
CID: Rct1IPLD.Cid().String(),
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Rct1IPLD,
|
||||
Key: Rct1CID.String(),
|
||||
},
|
||||
{
|
||||
Data: Rct2IPLD.RawData(),
|
||||
CID: Rct2IPLD.Cid().String(),
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Rct2IPLD,
|
||||
Key: Rct2CID.String(),
|
||||
},
|
||||
{
|
||||
Data: Rct3IPLD.RawData(),
|
||||
CID: Rct3IPLD.Cid().String(),
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Rct3IPLD,
|
||||
Key: Rct3CID.String(),
|
||||
},
|
||||
{
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: Rct4IPLD,
|
||||
Key: Rct4CID.String(),
|
||||
},
|
||||
},
|
||||
StateNodes: []eth2.StateNode{
|
||||
StateNodes: []eth.StateNode{
|
||||
{
|
||||
StateLeafKey: common.BytesToHash(ContractLeafKey),
|
||||
Type: sdtypes.Leaf,
|
||||
IPLD: ipfs.BlockModel{
|
||||
Data: State1IPLD.RawData(),
|
||||
CID: State1IPLD.Cid().String(),
|
||||
IPLD: models.IPLDModel{
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: State1IPLD.RawData(),
|
||||
Key: State1IPLD.Cid().String(),
|
||||
},
|
||||
Path: []byte{'\x06'},
|
||||
},
|
||||
{
|
||||
StateLeafKey: common.BytesToHash(AccountLeafKey),
|
||||
Type: sdtypes.Leaf,
|
||||
IPLD: ipfs.BlockModel{
|
||||
Data: State2IPLD.RawData(),
|
||||
CID: State2IPLD.Cid().String(),
|
||||
IPLD: models.IPLDModel{
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: State2IPLD.RawData(),
|
||||
Key: State2IPLD.Cid().String(),
|
||||
},
|
||||
Path: []byte{'\x0c'},
|
||||
},
|
||||
},
|
||||
StorageNodes: []eth2.StorageNode{
|
||||
StorageNodes: []eth.StorageNode{
|
||||
{
|
||||
StateLeafKey: common.BytesToHash(ContractLeafKey),
|
||||
StorageLeafKey: common.BytesToHash(StorageLeafKey),
|
||||
Type: sdtypes.Leaf,
|
||||
IPLD: ipfs.BlockModel{
|
||||
Data: StorageIPLD.RawData(),
|
||||
CID: StorageIPLD.Cid().String(),
|
||||
IPLD: models.IPLDModel{
|
||||
BlockNumber: BlockNumber.String(),
|
||||
Data: StorageIPLD.RawData(),
|
||||
Key: StorageIPLD.Cid().String(),
|
||||
},
|
||||
Path: []byte{},
|
||||
},
|
||||
@@ -516,46 +589,8 @@ var (
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
|
||||
MockLondonTransactions, MockLondonReceipts, SenderAdd = createDynamicTransactionsAndReceipts(LondonBlockNum)
|
||||
MockLondonBlock = createNewBlock(&MockLondonHeader, MockLondonTransactions, nil, MockLondonReceipts, new(trie.Trie))
|
||||
MockLondonTrxMeta = []eth.TxModel{
|
||||
{
|
||||
CID: "", // This is empty until we go to publish to ipfs
|
||||
MhKey: "",
|
||||
Src: SenderAdd.Hex(),
|
||||
Dst: Address.String(),
|
||||
Index: 0,
|
||||
TxHash: MockLondonTransactions[0].Hash().String(),
|
||||
Data: []byte{},
|
||||
},
|
||||
}
|
||||
MockLondonRctMeta = []eth.ReceiptModel{
|
||||
{
|
||||
CID: "",
|
||||
MhKey: "",
|
||||
Topic0s: []string{
|
||||
mockTopic11.String(),
|
||||
},
|
||||
Topic1s: []string{
|
||||
mockTopic12.String(),
|
||||
},
|
||||
Contract: "",
|
||||
ContractHash: "",
|
||||
LogContracts: []string{
|
||||
Address.String(),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
MockConvertedLondonPayload = eth.ConvertedPayload{
|
||||
TotalDifficulty: MockLondonBlock.Difficulty(),
|
||||
Block: MockLondonBlock,
|
||||
Receipts: MockLondonReceipts,
|
||||
TxMetaData: MockLondonTrxMeta,
|
||||
ReceiptMetaData: MockLondonRctMeta,
|
||||
StorageNodes: MockStorageNodes,
|
||||
StateNodes: MockStateNodes,
|
||||
}
|
||||
MockLondonTransactions, MockLondonReceipts, _ = createDynamicTransactionsAndReceipts(LondonBlockNum)
|
||||
MockLondonBlock = createNewBlock(&MockLondonHeader, MockLondonTransactions, nil, MockLondonReceipts, new(trie.Trie))
|
||||
)
|
||||
|
||||
func createNewBlock(header *types.Header, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, hasher types.TrieHasher) *types.Block {
|
||||
@@ -605,8 +640,8 @@ func createDynamicTransactionsAndReceipts(blockNumber *big.Int) (types.Transacti
|
||||
// TODO: Change the receipt type to DynamicFeeTxType once this PR is merged.
|
||||
// https://github.com/ethereum/go-ethereum/pull/22806
|
||||
mockReceipt1 := &types.Receipt{
|
||||
Type: types.AccessListTxType,
|
||||
PostState: common.HexToHash("0x1").Bytes(),
|
||||
Type: types.DynamicFeeTxType,
|
||||
PostState: common.HexToHash("0x0").Bytes(),
|
||||
Status: types.ReceiptStatusSuccessful,
|
||||
CumulativeGasUsed: 50,
|
||||
Logs: []*types.Log{},
|
||||
@@ -622,6 +657,7 @@ func createLegacyTransactionsAndReceipts() (types.Transactions, types.Receipts,
|
||||
trx1 := types.NewTransaction(0, Address, big.NewInt(1000), 50, big.NewInt(100), []byte{})
|
||||
trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{})
|
||||
trx3 := types.NewContractCreation(2, big.NewInt(1500), 75, big.NewInt(150), MockContractByteCode)
|
||||
trx4 := types.NewTransaction(3, AnotherAddress1, big.NewInt(2000), 100, big.NewInt(200), []byte{})
|
||||
transactionSigner := types.MakeSigner(params.MainnetChainConfig, new(big.Int).Set(BlockNumber))
|
||||
mockCurve := elliptic.P256()
|
||||
mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader)
|
||||
@@ -640,12 +676,16 @@ func createLegacyTransactionsAndReceipts() (types.Transactions, types.Receipts,
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
signedTrx4, err := types.SignTx(trx4, transactionSigner, mockPrvKey)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
SenderAddr, err := types.Sender(transactionSigner, signedTrx1) // same for both trx
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// make receipts
|
||||
mockReceipt1 := types.NewReceipt(common.HexToHash("0x0").Bytes(), false, 50)
|
||||
mockReceipt1 := types.NewReceipt(nil, false, 50)
|
||||
|
||||
hash1 := signedTrx1.Hash()
|
||||
MockLog1.TxHash = hash1
|
||||
@@ -663,11 +703,17 @@ func createLegacyTransactionsAndReceipts() (types.Transactions, types.Receipts,
|
||||
mockReceipt2.GasUsed = mockReceipt2.CumulativeGasUsed - mockReceipt1.CumulativeGasUsed
|
||||
|
||||
mockReceipt3 := types.NewReceipt(common.HexToHash("0x2").Bytes(), false, 175)
|
||||
mockReceipt3.Logs = []*types.Log{}
|
||||
mockReceipt3.Logs = []*types.Log{MockLog3, MockLog4, MockLog5}
|
||||
mockReceipt3.TxHash = signedTrx3.Hash()
|
||||
mockReceipt3.GasUsed = mockReceipt3.CumulativeGasUsed - mockReceipt2.CumulativeGasUsed
|
||||
|
||||
return types.Transactions{signedTrx1, signedTrx2, signedTrx3}, types.Receipts{mockReceipt1, mockReceipt2, mockReceipt3}, SenderAddr
|
||||
// Receipt with failed status.
|
||||
mockReceipt4 := types.NewReceipt(nil, true, 250)
|
||||
mockReceipt4.Logs = []*types.Log{MockLog6}
|
||||
mockReceipt4.TxHash = signedTrx4.Hash()
|
||||
mockReceipt4.GasUsed = mockReceipt4.CumulativeGasUsed - mockReceipt3.CumulativeGasUsed
|
||||
|
||||
return types.Transactions{signedTrx1, signedTrx2, signedTrx3, signedTrx4}, types.Receipts{mockReceipt1, mockReceipt2, mockReceipt3, mockReceipt4}, SenderAddr
|
||||
}
|
||||
|
||||
func GetTxnRlp(num int, txs types.Transactions) []byte {
|
||||
|
||||
+137
-26
@@ -17,14 +17,16 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
||||
@@ -99,18 +101,94 @@ type CallArgs struct {
|
||||
Input *hexutil.Bytes `json:"input"`
|
||||
}
|
||||
|
||||
// account indicates the overriding fields of account during the execution of
|
||||
// a message call.
|
||||
// Note, state and stateDiff can't be specified at the same time. If state is
|
||||
// set, message execution will only use the data in the given state. Otherwise
|
||||
// if statDiff is set, all diff will be applied first and then execute the call
|
||||
// message.
|
||||
type account struct {
|
||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||
Code *hexutil.Bytes `json:"code"`
|
||||
Balance **hexutil.Big `json:"balance"`
|
||||
State *map[common.Hash]common.Hash `json:"state"`
|
||||
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
|
||||
// from retrieves the transaction sender address.
|
||||
func (arg *CallArgs) from() common.Address {
|
||||
if arg.From == nil {
|
||||
return common.Address{}
|
||||
}
|
||||
return *arg.From
|
||||
}
|
||||
|
||||
// data retrieves the transaction calldata. Input field is preferred.
|
||||
func (arg *CallArgs) data() []byte {
|
||||
if arg.Input != nil {
|
||||
return *arg.Input
|
||||
}
|
||||
if arg.Data != nil {
|
||||
return *arg.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToMessage converts the transaction arguments to the Message type used by the
|
||||
// core evm. This method is used in calls and traces that do not require a real
|
||||
// live transaction.
|
||||
func (arg *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) {
|
||||
// Reject invalid combinations of pre- and post-1559 fee styles
|
||||
if arg.GasPrice != nil && (arg.MaxFeePerGas != nil || arg.MaxPriorityFeePerGas != nil) {
|
||||
return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||
}
|
||||
// Set sender address or use zero address if none specified.
|
||||
addr := arg.from()
|
||||
|
||||
// Set default gas & gas price if none were set
|
||||
gas := globalGasCap
|
||||
if gas == 0 {
|
||||
gas = uint64(math.MaxUint64 / 2)
|
||||
}
|
||||
if arg.Gas != nil {
|
||||
gas = uint64(*arg.Gas)
|
||||
}
|
||||
if globalGasCap != 0 && globalGasCap < gas {
|
||||
logrus.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
|
||||
gas = globalGasCap
|
||||
}
|
||||
var (
|
||||
gasPrice *big.Int
|
||||
gasFeeCap *big.Int
|
||||
gasTipCap *big.Int
|
||||
)
|
||||
if baseFee == nil {
|
||||
// If there's no basefee, then it must be a non-1559 execution
|
||||
gasPrice = new(big.Int)
|
||||
if arg.GasPrice != nil {
|
||||
gasPrice = arg.GasPrice.ToInt()
|
||||
}
|
||||
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||
} else {
|
||||
// A basefee is provided, necessitating 1559-type execution
|
||||
if arg.GasPrice != nil {
|
||||
// User specified the legacy gas field, convert to 1559 gas typing
|
||||
gasPrice = arg.GasPrice.ToInt()
|
||||
gasFeeCap, gasTipCap = gasPrice, gasPrice
|
||||
} else {
|
||||
// User specified 1559 gas feilds (or none), use those
|
||||
gasFeeCap = new(big.Int)
|
||||
if arg.MaxFeePerGas != nil {
|
||||
gasFeeCap = arg.MaxFeePerGas.ToInt()
|
||||
}
|
||||
gasTipCap = new(big.Int)
|
||||
if arg.MaxPriorityFeePerGas != nil {
|
||||
gasTipCap = arg.MaxPriorityFeePerGas.ToInt()
|
||||
}
|
||||
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
|
||||
gasPrice = new(big.Int)
|
||||
if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
|
||||
gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap)
|
||||
}
|
||||
}
|
||||
}
|
||||
value := new(big.Int)
|
||||
if arg.Value != nil {
|
||||
value = arg.Value.ToInt()
|
||||
}
|
||||
data := arg.data()
|
||||
var accessList types.AccessList
|
||||
if arg.AccessList != nil {
|
||||
accessList = *arg.AccessList
|
||||
}
|
||||
msg := types.NewMessage(addr, arg.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true)
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// IPLDs is used to package raw IPLD block data fetched from IPFS and returned by the server
|
||||
@@ -118,10 +196,10 @@ type account struct {
|
||||
type IPLDs struct {
|
||||
BlockNumber *big.Int
|
||||
TotalDifficulty *big.Int
|
||||
Header ipfs.BlockModel
|
||||
Uncles []ipfs.BlockModel
|
||||
Transactions []ipfs.BlockModel
|
||||
Receipts []ipfs.BlockModel
|
||||
Header models.IPLDModel
|
||||
Uncles []models.IPLDModel
|
||||
Transactions []models.IPLDModel
|
||||
Receipts []models.IPLDModel
|
||||
StateNodes []StateNode
|
||||
StorageNodes []StorageNode
|
||||
}
|
||||
@@ -130,7 +208,7 @@ type StateNode struct {
|
||||
Type sdtypes.NodeType
|
||||
StateLeafKey common.Hash
|
||||
Path []byte
|
||||
IPLD ipfs.BlockModel
|
||||
IPLD models.IPLDModel
|
||||
}
|
||||
|
||||
type StorageNode struct {
|
||||
@@ -138,7 +216,7 @@ type StorageNode struct {
|
||||
StateLeafKey common.Hash
|
||||
StorageLeafKey common.Hash
|
||||
Path []byte
|
||||
IPLD ipfs.BlockModel
|
||||
IPLD models.IPLDModel
|
||||
}
|
||||
|
||||
// CIDWrapper is used to direct fetching of IPLDs from IPFS
|
||||
@@ -146,10 +224,43 @@ type StorageNode struct {
|
||||
// Passed to IPLDFetcher
|
||||
type CIDWrapper struct {
|
||||
BlockNumber *big.Int
|
||||
Header eth.HeaderModel
|
||||
Uncles []eth.UncleModel
|
||||
Transactions []eth.TxModel
|
||||
Receipts []eth.ReceiptModel
|
||||
StateNodes []eth.StateNodeModel
|
||||
StorageNodes []eth.StorageNodeWithStateKeyModel
|
||||
Header models.HeaderModel
|
||||
Uncles []models.UncleModel
|
||||
Transactions []models.TxModel
|
||||
Receipts []models.ReceiptModel
|
||||
StateNodes []models.StateNodeModel
|
||||
StorageNodes []models.StorageNodeWithStateKeyModel
|
||||
}
|
||||
|
||||
// ConvertedPayload is a custom type which packages raw ETH data for publishing to IPFS and filtering to subscribers
|
||||
// Returned by PayloadConverter
|
||||
// Passed to IPLDPublisher and ResponseFilterer
|
||||
type ConvertedPayload struct {
|
||||
TotalDifficulty *big.Int
|
||||
Block *types.Block
|
||||
TxMetaData []models.TxModel
|
||||
Receipts types.Receipts
|
||||
ReceiptMetaData []models.ReceiptModel
|
||||
StateNodes []sdtypes.StateNode
|
||||
StorageNodes map[string][]sdtypes.StorageNode
|
||||
}
|
||||
|
||||
// LogResult represent a log.
|
||||
type LogResult struct {
|
||||
LeafCID string `db:"leaf_cid"`
|
||||
ReceiptID string `db:"rct_id"`
|
||||
Address string `db:"address"`
|
||||
Index int64 `db:"index"`
|
||||
Data []byte `db:"log_data"`
|
||||
Topic0 string `db:"topic0"`
|
||||
Topic1 string `db:"topic1"`
|
||||
Topic2 string `db:"topic2"`
|
||||
Topic3 string `db:"topic3"`
|
||||
LogLeafData []byte `db:"data"`
|
||||
RctCID string `db:"cid"`
|
||||
RctStatus uint64 `db:"post_status"`
|
||||
BlockNumber string `db:"block_number"`
|
||||
BlockHash string `db:"block_hash"`
|
||||
TxnIndex int64 `db:"txn_index"`
|
||||
TxHash string `db:"tx_hash"`
|
||||
}
|
||||
|
||||
+13
-6
@@ -24,6 +24,8 @@ type LogResponse struct {
|
||||
Topics []common.Hash `json:"topics"`
|
||||
Data hexutil.Bytes `json:"data"`
|
||||
Transaction TransactionResp `json:"transaction"`
|
||||
ReceiptCID string `json:"receiptCID"`
|
||||
Status int32 `json:"status"`
|
||||
}
|
||||
|
||||
type TransactionResp struct {
|
||||
@@ -43,18 +45,23 @@ func NewClient(endpoint string) *Client {
|
||||
return &Client{client: client}
|
||||
}
|
||||
|
||||
func (c *Client) GetLogs(ctx context.Context, hash common.Hash, address common.Address) ([]LogResponse, error) {
|
||||
getLogsQuery := fmt.Sprintf(`
|
||||
query{
|
||||
getLogs(blockHash: "%s", contract: "%s") {
|
||||
func (c *Client) GetLogs(ctx context.Context, hash common.Hash, address *common.Address) ([]LogResponse, error) {
|
||||
params := fmt.Sprintf(`blockHash: "%s"`, hash.String())
|
||||
if address != nil {
|
||||
params += fmt.Sprintf(`, contract: "%s"`, address.String())
|
||||
}
|
||||
|
||||
getLogsQuery := fmt.Sprintf(`query{
|
||||
getLogs(%s) {
|
||||
data
|
||||
topics
|
||||
transaction {
|
||||
hash
|
||||
}
|
||||
status
|
||||
receiptCID
|
||||
}
|
||||
}
|
||||
`, hash.String(), address.String())
|
||||
}`, params)
|
||||
|
||||
req := gqlclient.NewRequest(getLogsQuery)
|
||||
req.Header.Set("Cache-Control", "no-cache")
|
||||
|
||||
+120
-42
@@ -18,6 +18,7 @@
|
||||
package graphql
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
@@ -32,7 +33,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -94,14 +95,18 @@ type Log struct {
|
||||
transaction *Transaction
|
||||
log *types.Log
|
||||
cid string
|
||||
ipldBlock []byte
|
||||
receiptCID string
|
||||
ipldBlock []byte // log leaf node IPLD block data
|
||||
status uint64
|
||||
}
|
||||
|
||||
func (l *Log) Transaction(ctx context.Context) *Transaction {
|
||||
// Transaction returns transaction that generated this log entry.
|
||||
func (l *Log) Transaction(_ context.Context) *Transaction {
|
||||
return l.transaction
|
||||
}
|
||||
|
||||
func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account {
|
||||
// Account returns the contract account which generated this log.
|
||||
func (l *Log) Account(_ context.Context, args BlockNumberArgs) *Account {
|
||||
return &Account{
|
||||
backend: l.backend,
|
||||
address: l.log.Address,
|
||||
@@ -109,24 +114,39 @@ func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Log) Index(ctx context.Context) int32 {
|
||||
// Index returns the index of this log in the block
|
||||
func (l *Log) Index(_ context.Context) int32 {
|
||||
return int32(l.log.Index)
|
||||
}
|
||||
|
||||
func (l *Log) Topics(ctx context.Context) []common.Hash {
|
||||
// Topics returns the list of 0-4 indexed topics for the log.
|
||||
func (l *Log) Topics(_ context.Context) []common.Hash {
|
||||
return l.log.Topics
|
||||
}
|
||||
|
||||
func (l *Log) Data(ctx context.Context) hexutil.Bytes {
|
||||
return hexutil.Bytes(l.log.Data)
|
||||
// Data returns data of this log.
|
||||
func (l *Log) Data(_ context.Context) hexutil.Bytes {
|
||||
return l.log.Data
|
||||
}
|
||||
|
||||
func (l *Log) Cid(ctx context.Context) string {
|
||||
// Cid returns cid of the leaf node of this log.
|
||||
func (l *Log) Cid(_ context.Context) string {
|
||||
return l.cid
|
||||
}
|
||||
|
||||
func (l *Log) IpldBlock(ctx context.Context) hexutil.Bytes {
|
||||
return hexutil.Bytes(l.ipldBlock)
|
||||
// IpldBlock returns IPLD block of the leaf node of this log.
|
||||
func (l *Log) IpldBlock(_ context.Context) hexutil.Bytes {
|
||||
return l.ipldBlock
|
||||
}
|
||||
|
||||
// Status returns the status of the receipt IPLD block this Log exists in.
|
||||
func (l *Log) Status(_ context.Context) int32 {
|
||||
return int32(l.status)
|
||||
}
|
||||
|
||||
// ReceiptCID returns the receipt CID of the receipt IPLD block this Log exists in.
|
||||
func (l *Log) ReceiptCID(_ context.Context) string {
|
||||
return l.receiptCID
|
||||
}
|
||||
|
||||
// Transaction represents an Ethereum transaction.
|
||||
@@ -815,16 +835,20 @@ func (b *Block) Call(ctx context.Context, args struct {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
result, gas, failed, err := eth.DoCall(ctx, b.backend, args.Data, *b.numberOrHash, nil, 5*time.Second, b.backend.RPCGasCap())
|
||||
result, err := eth.DoCall(ctx, b.backend, args.Data, *b.numberOrHash, nil, 5*time.Second, b.backend.RPCGasCap().Uint64())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
status := hexutil.Uint64(1)
|
||||
if failed {
|
||||
if result.Failed() {
|
||||
status = 0
|
||||
}
|
||||
|
||||
return &CallResult{
|
||||
data: hexutil.Bytes(result),
|
||||
gasUsed: hexutil.Uint64(gas),
|
||||
data: result.ReturnData,
|
||||
gasUsed: hexutil.Uint64(result.UsedGas),
|
||||
status: status,
|
||||
}, err
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Resolver is the top-level object in the GraphQL hierarchy.
|
||||
@@ -993,6 +1017,10 @@ func (r *Resolver) GetStorageAt(ctx context.Context, args struct {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if bytes.Compare(rlpValue, eth.EmptyNodeValue) == 0 {
|
||||
return &StorageResult{value: eth.EmptyNodeValue, cid: cid, ipldBlock: ipldBlock}, nil
|
||||
}
|
||||
|
||||
var value interface{}
|
||||
err = rlp.DecodeBytes(rlpValue, &value)
|
||||
if err != nil {
|
||||
@@ -1007,40 +1035,90 @@ func (r *Resolver) GetLogs(ctx context.Context, args struct {
|
||||
BlockHash common.Hash
|
||||
Contract *common.Address
|
||||
}) (*[]*Log, error) {
|
||||
ret := make([]*Log, 0, 10)
|
||||
|
||||
receiptCIDs, receiptsBytes, txs, err := r.backend.IPLDRetriever.RetrieveReceiptsByBlockHash(args.BlockHash)
|
||||
var filter eth.ReceiptFilter
|
||||
if args.Contract != nil {
|
||||
filter.LogAddresses = []string{args.Contract.String()}
|
||||
}
|
||||
|
||||
// Begin tx
|
||||
tx, err := r.backend.DB.Beginx()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var logIndexInBlock uint = 0
|
||||
receipts := make(types.Receipts, len(receiptsBytes))
|
||||
for index, receiptBytes := range receiptsBytes {
|
||||
receiptCID := receiptCIDs[index]
|
||||
receipt := new(types.Receipt)
|
||||
if err := rlp.DecodeBytes(receiptBytes, receipt); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
filteredLogs, err := r.backend.Retriever.RetrieveFilteredGQLLogs(tx, filter, &args.BlockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
receipts[index] = receipt
|
||||
for _, log := range receipt.Logs {
|
||||
log.Index = logIndexInBlock
|
||||
logIndexInBlock++
|
||||
if err = tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if args.Contract == nil || *args.Contract == log.Address {
|
||||
ret = append(ret, &Log{
|
||||
backend: r.backend,
|
||||
log: log,
|
||||
cid: receiptCID,
|
||||
ipldBlock: receiptBytes,
|
||||
transaction: &Transaction{
|
||||
hash: txs[index],
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
rctLog := decomposeGQLLogs(filteredLogs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ret := make([]*Log, 0, 10)
|
||||
for _, l := range rctLog {
|
||||
ret = append(ret, &Log{
|
||||
backend: r.backend,
|
||||
log: l.Log,
|
||||
cid: l.CID,
|
||||
receiptCID: l.RctCID,
|
||||
ipldBlock: l.LogLeafData,
|
||||
transaction: &Transaction{
|
||||
hash: l.Log.TxHash,
|
||||
},
|
||||
status: l.RctStatus,
|
||||
})
|
||||
}
|
||||
|
||||
return &ret, nil
|
||||
}
|
||||
|
||||
type logsCID struct {
|
||||
Log *types.Log
|
||||
CID string
|
||||
RctCID string
|
||||
LogLeafData []byte
|
||||
RctStatus uint64
|
||||
}
|
||||
|
||||
// decomposeGQLLogs return logs for graphql.
|
||||
func decomposeGQLLogs(logCIDs []eth.LogResult) []logsCID {
|
||||
logs := make([]logsCID, len(logCIDs))
|
||||
for i, l := range logCIDs {
|
||||
topics := make([]common.Hash, 0)
|
||||
if l.Topic0 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic0))
|
||||
}
|
||||
if l.Topic1 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic1))
|
||||
}
|
||||
if l.Topic2 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic2))
|
||||
}
|
||||
if l.Topic3 != "" {
|
||||
topics = append(topics, common.HexToHash(l.Topic3))
|
||||
}
|
||||
|
||||
logs[i] = logsCID{
|
||||
Log: &types.Log{
|
||||
Address: common.HexToAddress(l.Address),
|
||||
Topics: topics,
|
||||
Data: l.Data,
|
||||
Index: uint(l.Index),
|
||||
TxHash: common.HexToHash(l.TxHash),
|
||||
},
|
||||
CID: l.LeafCID,
|
||||
RctCID: l.RctCID,
|
||||
LogLeafData: l.LogLeafData,
|
||||
RctStatus: l.RctStatus,
|
||||
}
|
||||
}
|
||||
|
||||
return logs
|
||||
}
|
||||
|
||||
+74
-51
@@ -28,18 +28,18 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/graphql"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/graphql"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
ethServerShared "github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var _ = Describe("GraphQL", func() {
|
||||
@@ -52,7 +52,7 @@ var _ = Describe("GraphQL", func() {
|
||||
blocks []*types.Block
|
||||
receipts []types.Receipts
|
||||
chain *core.BlockChain
|
||||
db *postgres.DB
|
||||
db *sqlx.DB
|
||||
blockHashes []common.Hash
|
||||
backend *eth.Backend
|
||||
graphQLServer *graphql.Service
|
||||
@@ -66,13 +66,21 @@ var _ = Describe("GraphQL", func() {
|
||||
|
||||
It("test init", func() {
|
||||
var err error
|
||||
db, err = shared.SetupDB()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
transformer := eth2.NewStateDiffTransformer(chainConfig, db)
|
||||
db = shared.SetupDB()
|
||||
transformer := shared.SetupTestStateDiffIndexer(ctx, chainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
backend, err = eth.NewEthBackend(db, ð.Config{
|
||||
ChainConfig: chainConfig,
|
||||
VmConfig: vm.Config{},
|
||||
VMConfig: vm.Config{},
|
||||
RPCGasCap: big.NewInt(10000000000),
|
||||
GroupCacheConfig: ðServerShared.GroupCacheConfig{
|
||||
StateDB: ethServerShared.GroupConfig{
|
||||
Name: "graphql_test",
|
||||
CacheSizeInMB: 8,
|
||||
CacheExpiryInMins: 60,
|
||||
LogStatsIntervalInSecs: 0,
|
||||
},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
@@ -106,38 +114,47 @@ var _ = Describe("GraphQL", func() {
|
||||
rcts = receipts[i-1]
|
||||
}
|
||||
|
||||
var diff statediff.StateObject
|
||||
var diff sdtypes.StateObject
|
||||
diff, err = builder.BuildStateDiffObject(args, params)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
diffRlp, err := rlp.EncodeToBytes(diff)
|
||||
|
||||
tx, err := transformer.PushBlock(block, rcts, mockTD)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
blockRlp, err := rlp.EncodeToBytes(block)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
receiptsRlp, err := rlp.EncodeToBytes(rcts)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
payload := statediff.Payload{
|
||||
StateObjectRlp: diffRlp,
|
||||
BlockRlp: blockRlp,
|
||||
ReceiptsRlp: receiptsRlp,
|
||||
TotalDifficulty: mockTD,
|
||||
|
||||
for _, node := range diff.Nodes {
|
||||
err = transformer.PushStateNode(tx, node, block.Hash().String())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
_, err = transformer.Transform(0, payload)
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
}
|
||||
|
||||
// Insert some non-canonical data into the database so that we test our ability to discern canonicity
|
||||
indexAndPublisher := eth2.NewIPLDPublisher(db)
|
||||
indexAndPublisher := shared.SetupTestStateDiffIndexer(ctx, chainConfig, test_helpers.Genesis.Hash())
|
||||
|
||||
blockHash = test_helpers.MockBlock.Hash()
|
||||
contractAddress = test_helpers.ContractAddr
|
||||
|
||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayload)
|
||||
tx, err := indexAndPublisher.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// The non-canonical header has a child
|
||||
err = indexAndPublisher.Publish(test_helpers.MockConvertedPayloadForChild)
|
||||
tx, err = indexAndPublisher.PushBlock(test_helpers.MockChild, test_helpers.MockReceipts, test_helpers.MockChild.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
err = publishCode(db, test_helpers.ContractCodeHash, test_helpers.ContractCode)
|
||||
|
||||
ccHash := sdtypes.CodeAndCodeHash{
|
||||
Hash: test_helpers.CodeHash,
|
||||
Code: test_helpers.ContractCode,
|
||||
}
|
||||
|
||||
err = indexAndPublisher.PushCodeAndCodeHash(tx, ccHash)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
err = tx.Submit(err)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
graphQLServer, err = graphql.New(backend, gqlEndPoint, nil, []string{"*"}, rpc.HTTPTimeouts{})
|
||||
@@ -150,13 +167,13 @@ var _ = Describe("GraphQL", func() {
|
||||
defer It("test teardown", func() {
|
||||
err := graphQLServer.Stop()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
eth.TearDownDB(db)
|
||||
shared.TearDownDB(db)
|
||||
chain.Stop()
|
||||
})
|
||||
|
||||
Describe("eth_getLogs", func() {
|
||||
It("Retrieves logs that matches the provided blockHash and contract address", func() {
|
||||
logs, err := client.GetLogs(ctx, blockHash, contractAddress)
|
||||
logs, err := client.GetLogs(ctx, blockHash, &contractAddress)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedLogs := []graphql.LogResponse{
|
||||
@@ -164,13 +181,39 @@ var _ = Describe("GraphQL", func() {
|
||||
Topics: test_helpers.MockLog1.Topics,
|
||||
Data: hexutil.Bytes(test_helpers.MockLog1.Data),
|
||||
Transaction: graphql.TransactionResp{Hash: test_helpers.MockTransactions[0].Hash()},
|
||||
ReceiptCID: test_helpers.Rct1CID.String(),
|
||||
Status: int32(test_helpers.MockReceipts[0].Status),
|
||||
},
|
||||
}
|
||||
|
||||
Expect(logs).To(Equal(expectedLogs))
|
||||
})
|
||||
|
||||
It("Retrieves logs for the failed receipt status that matches the provided blockHash and another contract address", func() {
|
||||
logs, err := client.GetLogs(ctx, blockHash, &test_helpers.AnotherAddress2)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedLogs := []graphql.LogResponse{
|
||||
{
|
||||
Topics: test_helpers.MockLog6.Topics,
|
||||
Data: hexutil.Bytes(test_helpers.MockLog6.Data),
|
||||
Transaction: graphql.TransactionResp{Hash: test_helpers.MockTransactions[3].Hash()},
|
||||
ReceiptCID: test_helpers.Rct4CID.String(),
|
||||
Status: int32(test_helpers.MockReceipts[3].Status),
|
||||
},
|
||||
}
|
||||
|
||||
Expect(logs).To(Equal(expectedLogs))
|
||||
})
|
||||
|
||||
It("Retrieves all the logs for the receipt that matches the provided blockHash and nil contract address", func() {
|
||||
logs, err := client.GetLogs(ctx, blockHash, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(6))
|
||||
})
|
||||
|
||||
It("Retrieves logs with random hash", func() {
|
||||
logs, err := client.GetLogs(ctx, randomHash, contractAddress)
|
||||
logs, err := client.GetLogs(ctx, randomHash, &contractAddress)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(0))
|
||||
})
|
||||
@@ -208,23 +251,3 @@ var _ = Describe("GraphQL", func() {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
func publishCode(db *postgres.DB, codeHash common.Hash, code []byte) error {
|
||||
tx, err := db.Beginx()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
mhKey, err := shared.MultihashKeyFromKeccak256(codeHash)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := shared.PublishDirect(tx, mhKey, code); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
@@ -67,11 +67,17 @@ const schema string = `
|
||||
# Transaction is the transaction that generated this log entry.
|
||||
transaction: Transaction
|
||||
|
||||
# CID for the Receipt IPLD block this Log exists in.
|
||||
# CID for the leaf node IPLD block of the log.
|
||||
cid: String!
|
||||
|
||||
# IPLD block data for the Receipt this Log exists in.
|
||||
# ReceiptCID for the Receipt IPLD block this Log exists in.
|
||||
receiptCID: String!
|
||||
|
||||
# IPLD block data for the Log Leaf node.
|
||||
ipldBlock: Bytes!
|
||||
|
||||
# Status of the Receipt IPLD block this Log exists in.
|
||||
status: Int!
|
||||
}
|
||||
|
||||
# Transaction is an Ethereum transaction.
|
||||
|
||||
@@ -29,7 +29,7 @@ import (
|
||||
"github.com/graph-gophers/graphql-go/relay"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
)
|
||||
|
||||
// Service encapsulates a GraphQL service.
|
||||
@@ -69,7 +69,7 @@ func (s *Service) Start(server *p2p.Server) error {
|
||||
return err
|
||||
}
|
||||
|
||||
handler := node.NewHTTPHandlerStack(s.handler, s.cors, s.vhosts)
|
||||
handler := node.NewHTTPHandlerStack(s.handler, s.cors, s.vhosts, nil)
|
||||
|
||||
// start http server
|
||||
_, addr, err := node.StartHTTPEndpoint(s.endpoint, rpc.DefaultHTTPTimeouts, handler)
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ import (
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/net"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/net"
|
||||
)
|
||||
|
||||
var _ = Describe("API", func() {
|
||||
|
||||
+2
-2
@@ -29,11 +29,11 @@ import (
|
||||
func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors []string, vhosts []string, timeouts rpc.HTTPTimeouts) (*rpc.Server, error) {
|
||||
|
||||
srv := rpc.NewServer()
|
||||
err := node.RegisterApisFromWhitelist(apis, modules, srv, false)
|
||||
err := node.RegisterApis(apis, modules, srv, false)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not register HTTP API: %w", err)
|
||||
}
|
||||
handler := node.NewHTTPHandlerStack(srv, cors, vhosts)
|
||||
handler := node.NewHTTPHandlerStack(srv, cors, vhosts, nil)
|
||||
|
||||
// start http server
|
||||
_, addr, err := node.StartHTTPEndpoint(endpoint, rpc.DefaultHTTPTimeouts, handler)
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/prom"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/prom"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/prom"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/prom"
|
||||
)
|
||||
|
||||
// StartWSEndpoint starts a websocket endpoint.
|
||||
@@ -37,7 +37,7 @@ func StartWSEndpoint(endpoint string, apis []rpc.API, modules []string, wsOrigin
|
||||
|
||||
// Register all the APIs exposed by the services
|
||||
handler := rpc.NewServer()
|
||||
err = node.RegisterApisFromWhitelist(apis, modules, handler, exposeAll)
|
||||
err = node.RegisterApis(apis, modules, handler, exposeAll)
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not register WS API: %w", err)
|
||||
}
|
||||
|
||||
+15
-9
@@ -20,11 +20,10 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
)
|
||||
|
||||
// APIName is the namespace used for the state diffing service API
|
||||
@@ -35,13 +34,15 @@ const APIVersion = "0.0.1"
|
||||
|
||||
// PublicServerAPI is the public api for the watcher
|
||||
type PublicServerAPI struct {
|
||||
w Server
|
||||
w Server
|
||||
rpc *rpc.Client
|
||||
}
|
||||
|
||||
// NewPublicServerAPI creates a new PublicServerAPI with the provided underlying Server process
|
||||
func NewPublicServerAPI(w Server) *PublicServerAPI {
|
||||
func NewPublicServerAPI(w Server, client *rpc.Client) *PublicServerAPI {
|
||||
return &PublicServerAPI{
|
||||
w: w,
|
||||
w: w,
|
||||
rpc: client,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,7 +85,12 @@ func (api *PublicServerAPI) Stream(ctx context.Context, params eth.SubscriptionS
|
||||
return rpcSub, nil
|
||||
}
|
||||
|
||||
// Chain returns the chain type that this watcher instance supports
|
||||
func (api *PublicServerAPI) Chain() shared.ChainType {
|
||||
return shared.Ethereum
|
||||
// WatchAddress makes a geth WatchAddress API call with the given operation and args
|
||||
func (api *PublicServerAPI) WatchAddress(operation types.OperationType, args []types.WatchAddressArg) error {
|
||||
err := api.rpc.Call(nil, "statediff_watchAddress", operation, args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+97
-20
@@ -22,19 +22,18 @@ import (
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/shared"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
"github.com/vulcanize/ipld-eth-indexer/utils"
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/prom"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/prom"
|
||||
ethServerShared "github.com/vulcanize/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
// Env variables
|
||||
@@ -51,11 +50,16 @@ const (
|
||||
ETH_RPC_GAS_CAP = "ETH_RPC_GAS_CAP"
|
||||
ETH_CHAIN_CONFIG = "ETH_CHAIN_CONFIG"
|
||||
ETH_SUPPORTS_STATEDIFF = "ETH_SUPPORTS_STATEDIFF"
|
||||
ETH_FORWARD_ETH_CALLS = "ETH_FORWARD_ETH_CALLS"
|
||||
ETH_PROXY_ON_ERROR = "ETH_PROXY_ON_ERROR"
|
||||
|
||||
VALIDATOR_ENABLED = "VALIDATOR_ENABLED"
|
||||
VALIDATOR_EVERY_NTH_BLOCK = "VALIDATOR_EVERY_NTH_BLOCK"
|
||||
)
|
||||
|
||||
// Config struct
|
||||
type Config struct {
|
||||
DB *postgres.DB
|
||||
DB *sqlx.DB
|
||||
DBConfig postgres.Config
|
||||
|
||||
WSEnabled bool
|
||||
@@ -82,6 +86,15 @@ type Config struct {
|
||||
EthHttpEndpoint string
|
||||
Client *rpc.Client
|
||||
SupportStateDiff bool
|
||||
ForwardEthCalls bool
|
||||
ProxyOnError bool
|
||||
NodeNetworkID string
|
||||
|
||||
// Cache configuration.
|
||||
GroupCache *ethServerShared.GroupCacheConfig
|
||||
|
||||
StateValidationEnabled bool
|
||||
StateValidationEveryNthBlock uint64
|
||||
}
|
||||
|
||||
// NewConfig is used to initialize a watcher config from a .toml file
|
||||
@@ -89,22 +102,26 @@ type Config struct {
|
||||
func NewConfig() (*Config, error) {
|
||||
c := new(Config)
|
||||
|
||||
viper.BindEnv("ethereum.httpPath", shared.ETH_HTTP_PATH)
|
||||
viper.BindEnv("ethereum.httpPath", ETH_HTTP_PATH)
|
||||
viper.BindEnv("ethereum.defaultSender", ETH_DEFAULT_SENDER_ADDR)
|
||||
viper.BindEnv("ethereum.rpcGasCap", ETH_RPC_GAS_CAP)
|
||||
viper.BindEnv("ethereum.chainConfig", ETH_CHAIN_CONFIG)
|
||||
viper.BindEnv("ethereum.supportsStateDiff", ETH_SUPPORTS_STATEDIFF)
|
||||
viper.BindEnv("ethereum.forwardEthCalls", ETH_FORWARD_ETH_CALLS)
|
||||
viper.BindEnv("ethereum.proxyOnError", ETH_PROXY_ON_ERROR)
|
||||
|
||||
c.DBConfig.Init()
|
||||
|
||||
c.dbInit()
|
||||
ethHTTP := viper.GetString("ethereum.httpPath")
|
||||
ethHTTPEndpoint := fmt.Sprintf("http://%s", ethHTTP)
|
||||
nodeInfo, cli, err := shared.GetEthNodeAndClient(ethHTTPEndpoint)
|
||||
nodeInfo, cli, err := getEthNodeAndClient(ethHTTPEndpoint)
|
||||
c.NodeNetworkID = nodeInfo.NetworkID
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c.Client = cli
|
||||
c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff")
|
||||
c.ForwardEthCalls = viper.GetBool("ethereum.forwardEthCalls")
|
||||
c.ProxyOnError = viper.GetBool("ethereum.proxyOnError")
|
||||
c.EthHttpEndpoint = ethHTTPEndpoint
|
||||
|
||||
// websocket server
|
||||
@@ -184,9 +201,13 @@ func NewConfig() (*Config, error) {
|
||||
c.IpldGraphqlEnabled = ipldGraphqlEnabled
|
||||
|
||||
overrideDBConnConfig(&c.DBConfig)
|
||||
serveDB := utils.LoadPostgres(c.DBConfig, nodeInfo, false)
|
||||
prom.RegisterDBCollector(c.DBConfig.Name, serveDB.DB)
|
||||
c.DB = &serveDB
|
||||
serveDB, err := ethServerShared.NewDB(c.DBConfig.DbConnectionString(), c.DBConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prom.RegisterDBCollector(c.DBConfig.DatabaseName, serveDB)
|
||||
c.DB = serveDB
|
||||
|
||||
defaultSenderStr := viper.GetString("ethereum.defaultSender")
|
||||
if defaultSenderStr != "" {
|
||||
@@ -201,10 +222,15 @@ func NewConfig() (*Config, error) {
|
||||
}
|
||||
chainConfigPath := viper.GetString("ethereum.chainConfig")
|
||||
if chainConfigPath != "" {
|
||||
c.ChainConfig, err = eth.LoadConfig(chainConfigPath)
|
||||
c.ChainConfig, err = statediff.LoadConfig(chainConfigPath)
|
||||
} else {
|
||||
c.ChainConfig, err = eth.ChainConfig(nodeInfo.ChainID)
|
||||
c.ChainConfig, err = statediff.ChainConfig(nodeInfo.ChainID)
|
||||
}
|
||||
|
||||
c.loadGroupCacheConfig()
|
||||
|
||||
c.loadValidatorConfig()
|
||||
|
||||
return c, err
|
||||
}
|
||||
|
||||
@@ -213,6 +239,57 @@ func overrideDBConnConfig(con *postgres.Config) {
|
||||
viper.BindEnv("database.server.maxOpen", SERVER_MAX_OPEN_CONNECTIONS)
|
||||
viper.BindEnv("database.server.maxLifetime", SERVER_MAX_CONN_LIFETIME)
|
||||
con.MaxIdle = viper.GetInt("database.server.maxIdle")
|
||||
con.MaxOpen = viper.GetInt("database.server.maxOpen")
|
||||
con.MaxLifetime = viper.GetInt("database.server.maxLifetime")
|
||||
con.MaxConns = viper.GetInt("database.server.maxOpen")
|
||||
con.MaxConnLifetime = time.Duration(viper.GetInt("database.server.maxLifetime"))
|
||||
}
|
||||
|
||||
func (c *Config) dbInit() {
|
||||
viper.BindEnv("database.name", DATABASE_NAME)
|
||||
viper.BindEnv("database.hostname", DATABASE_HOSTNAME)
|
||||
viper.BindEnv("database.port", DATABASE_PORT)
|
||||
viper.BindEnv("database.user", DATABASE_USER)
|
||||
viper.BindEnv("database.password", DATABASE_PASSWORD)
|
||||
viper.BindEnv("database.maxIdle", DATABASE_MAX_IDLE_CONNECTIONS)
|
||||
viper.BindEnv("database.maxOpen", DATABASE_MAX_OPEN_CONNECTIONS)
|
||||
viper.BindEnv("database.maxLifetime", DATABASE_MAX_CONN_LIFETIME)
|
||||
|
||||
c.DBConfig.DatabaseName = viper.GetString("database.name")
|
||||
c.DBConfig.Hostname = viper.GetString("database.hostname")
|
||||
c.DBConfig.Port = viper.GetInt("database.port")
|
||||
c.DBConfig.Username = viper.GetString("database.user")
|
||||
c.DBConfig.Password = viper.GetString("database.password")
|
||||
c.DBConfig.MaxIdle = viper.GetInt("database.maxIdle")
|
||||
c.DBConfig.MaxConns = viper.GetInt("database.maxOpen")
|
||||
c.DBConfig.MaxConnLifetime = time.Duration(viper.GetInt("database.maxLifetime"))
|
||||
}
|
||||
|
||||
func (c *Config) loadGroupCacheConfig() {
|
||||
viper.BindEnv("groupcache.pool.enabled", ethServerShared.GcachePoolEnabled)
|
||||
viper.BindEnv("groupcache.pool.httpEndpoint", ethServerShared.GcachePoolHttpPath)
|
||||
viper.BindEnv("groupcache.pool.peerHttpEndpoints", ethServerShared.GcachePoolHttpPeers)
|
||||
viper.BindEnv("groupcache.statedb.cacheSizeInMB", ethServerShared.GcacheStatedbCacheSize)
|
||||
viper.BindEnv("groupcache.statedb.cacheExpiryInMins", ethServerShared.GcacheStatedbCacheExpiry)
|
||||
viper.BindEnv("groupcache.statedb.logStatsIntervalInSecs", ethServerShared.GcacheStatedbLogStatsInterval)
|
||||
|
||||
gcc := ethServerShared.GroupCacheConfig{}
|
||||
gcc.Pool.Enabled = viper.GetBool("groupcache.pool.enabled")
|
||||
if gcc.Pool.Enabled {
|
||||
gcc.Pool.HttpEndpoint = viper.GetString("groupcache.pool.httpEndpoint")
|
||||
gcc.Pool.PeerHttpEndpoints = viper.GetStringSlice("groupcache.pool.peerHttpEndpoints")
|
||||
}
|
||||
|
||||
// Irrespective of whether the pool is enabled, we always use the hot/local cache.
|
||||
gcc.StateDB.CacheSizeInMB = viper.GetInt("groupcache.statedb.cacheSizeInMB")
|
||||
gcc.StateDB.CacheExpiryInMins = viper.GetInt("groupcache.statedb.cacheExpiryInMins")
|
||||
gcc.StateDB.LogStatsIntervalInSecs = viper.GetInt("groupcache.statedb.logStatsIntervalInSecs")
|
||||
|
||||
c.GroupCache = &gcc
|
||||
}
|
||||
|
||||
func (c *Config) loadValidatorConfig() {
|
||||
viper.BindEnv("validator.enabled", VALIDATOR_ENABLED)
|
||||
viper.BindEnv("validator.everyNthBlock", VALIDATOR_EVERY_NTH_BLOCK)
|
||||
|
||||
c.StateValidationEnabled = viper.GetBool("validator.enabled")
|
||||
c.StateValidationEveryNthBlock = viper.GetUint64("validator.everyNthBlock")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package serve
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/node"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Env variables
|
||||
const (
|
||||
HTTP_TIMEOUT = "HTTP_TIMEOUT"
|
||||
|
||||
ETH_WS_PATH = "ETH_WS_PATH"
|
||||
ETH_HTTP_PATH = "ETH_HTTP_PATH"
|
||||
ETH_NODE_ID = "ETH_NODE_ID"
|
||||
ETH_CLIENT_NAME = "ETH_CLIENT_NAME"
|
||||
ETH_GENESIS_BLOCK = "ETH_GENESIS_BLOCK"
|
||||
ETH_NETWORK_ID = "ETH_NETWORK_ID"
|
||||
ETH_CHAIN_ID = "ETH_CHAIN_ID"
|
||||
|
||||
DATABASE_NAME = "DATABASE_NAME"
|
||||
DATABASE_HOSTNAME = "DATABASE_HOSTNAME"
|
||||
DATABASE_PORT = "DATABASE_PORT"
|
||||
DATABASE_USER = "DATABASE_USER"
|
||||
DATABASE_PASSWORD = "DATABASE_PASSWORD"
|
||||
DATABASE_MAX_IDLE_CONNECTIONS = "DATABASE_MAX_IDLE_CONNECTIONS"
|
||||
DATABASE_MAX_OPEN_CONNECTIONS = "DATABASE_MAX_OPEN_CONNECTIONS"
|
||||
DATABASE_MAX_CONN_LIFETIME = "DATABASE_MAX_CONN_LIFETIME"
|
||||
)
|
||||
|
||||
// GetEthNodeAndClient returns eth node info and client from path url
|
||||
func getEthNodeAndClient(path string) (node.Info, *rpc.Client, error) {
|
||||
viper.BindEnv("ethereum.nodeID", ETH_NODE_ID)
|
||||
viper.BindEnv("ethereum.clientName", ETH_CLIENT_NAME)
|
||||
viper.BindEnv("ethereum.genesisBlock", ETH_GENESIS_BLOCK)
|
||||
viper.BindEnv("ethereum.networkID", ETH_NETWORK_ID)
|
||||
viper.BindEnv("ethereum.chainID", ETH_CHAIN_ID)
|
||||
|
||||
rpcClient, err := rpc.Dial(path)
|
||||
if err != nil {
|
||||
return node.Info{}, nil, err
|
||||
}
|
||||
return node.Info{
|
||||
ID: viper.GetString("ethereum.nodeID"),
|
||||
ClientName: viper.GetString("ethereum.clientName"),
|
||||
GenesisBlock: viper.GetString("ethereum.genesisBlock"),
|
||||
NetworkID: viper.GetString("ethereum.networkID"),
|
||||
ChainID: viper.GetUint64("ethereum.chainID"),
|
||||
}, rpcClient, nil
|
||||
}
|
||||
+30
-20
@@ -21,22 +21,18 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/net"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
ethnode "github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/p2p"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
eth2 "github.com/vulcanize/ipld-eth-indexer/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/net"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -52,7 +48,7 @@ type Server interface {
|
||||
APIs() []rpc.API
|
||||
Protocols() []p2p.Protocol
|
||||
// Pub-Sub handling event loop
|
||||
Serve(wg *sync.WaitGroup, screenAndServePayload <-chan eth2.ConvertedPayload)
|
||||
Serve(wg *sync.WaitGroup, screenAndServePayload <-chan eth.ConvertedPayload)
|
||||
// Method to subscribe to the service
|
||||
Subscribe(id rpc.ID, sub chan<- SubscriptionPayload, quitChan chan<- bool, params eth.SubscriptionSettings)
|
||||
// Method to unsubscribe from the service
|
||||
@@ -78,7 +74,7 @@ type Service struct {
|
||||
// A mapping of subscription params hash to the corresponding subscription params
|
||||
SubscriptionTypes map[common.Hash]eth.SubscriptionSettings
|
||||
// Underlying db
|
||||
db *postgres.DB
|
||||
db *sqlx.DB
|
||||
// wg for syncing serve processes
|
||||
serveWg *sync.WaitGroup
|
||||
// rpc client for forwarding cache misses
|
||||
@@ -87,6 +83,12 @@ type Service struct {
|
||||
supportsStateDiffing bool
|
||||
// backend for the server
|
||||
backend *eth.Backend
|
||||
// whether to forward eth_calls directly to proxy node
|
||||
forwardEthCalls bool
|
||||
// whether to forward all calls to proxy node if they throw an error locally
|
||||
proxyOnError bool
|
||||
// eth node network id
|
||||
nodeNetworkId string
|
||||
}
|
||||
|
||||
// NewServer creates a new Server using an underlying Service struct
|
||||
@@ -101,12 +103,16 @@ func NewServer(settings *Config) (Server, error) {
|
||||
sap.SubscriptionTypes = make(map[common.Hash]eth.SubscriptionSettings)
|
||||
sap.client = settings.Client
|
||||
sap.supportsStateDiffing = settings.SupportStateDiff
|
||||
sap.forwardEthCalls = settings.ForwardEthCalls
|
||||
sap.proxyOnError = settings.ProxyOnError
|
||||
sap.nodeNetworkId = settings.NodeNetworkID
|
||||
var err error
|
||||
sap.backend, err = eth.NewEthBackend(sap.db, ð.Config{
|
||||
ChainConfig: settings.ChainConfig,
|
||||
VmConfig: vm.Config{},
|
||||
DefaultSender: settings.DefaultSender,
|
||||
RPCGasCap: settings.RPCGasCap,
|
||||
ChainConfig: settings.ChainConfig,
|
||||
VMConfig: vm.Config{NoBaseFee: true},
|
||||
DefaultSender: settings.DefaultSender,
|
||||
RPCGasCap: settings.RPCGasCap,
|
||||
GroupCacheConfig: settings.GroupCache,
|
||||
})
|
||||
return sap, err
|
||||
}
|
||||
@@ -118,12 +124,12 @@ func (sap *Service) Protocols() []p2p.Protocol {
|
||||
|
||||
// APIs returns the RPC descriptors the watcher service offers
|
||||
func (sap *Service) APIs() []rpc.API {
|
||||
networkID, _ := strconv.ParseUint(sap.db.Node.NetworkID, 10, 64)
|
||||
networkID, _ := strconv.ParseUint(sap.nodeNetworkId, 10, 64)
|
||||
apis := []rpc.API{
|
||||
{
|
||||
Namespace: APIName,
|
||||
Version: APIVersion,
|
||||
Service: NewPublicServerAPI(sap),
|
||||
Service: NewPublicServerAPI(sap, sap.client),
|
||||
Public: true,
|
||||
},
|
||||
{
|
||||
@@ -133,10 +139,14 @@ func (sap *Service) APIs() []rpc.API {
|
||||
Public: true,
|
||||
},
|
||||
}
|
||||
ethAPI, err := eth.NewPublicEthAPI(sap.backend, sap.client, sap.supportsStateDiffing, sap.forwardEthCalls, sap.proxyOnError)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create public eth api: %v", err)
|
||||
}
|
||||
return append(apis, rpc.API{
|
||||
Namespace: eth.APIName,
|
||||
Version: eth.APIVersion,
|
||||
Service: eth.NewPublicEthAPI(sap.backend, sap.client, sap.supportsStateDiffing),
|
||||
Service: ethAPI,
|
||||
Public: true,
|
||||
})
|
||||
}
|
||||
@@ -145,7 +155,7 @@ func (sap *Service) APIs() []rpc.API {
|
||||
// It filters and sends this data to any subscribers to the service
|
||||
// This process can also be stood up alone, without an screenAndServePayload attached to a Sync process
|
||||
// and it will hang on the WaitGroup indefinitely, allowing the Service to serve historical data requests only
|
||||
func (sap *Service) Serve(wg *sync.WaitGroup, screenAndServePayload <-chan eth2.ConvertedPayload) {
|
||||
func (sap *Service) Serve(wg *sync.WaitGroup, screenAndServePayload <-chan eth.ConvertedPayload) {
|
||||
sap.serveWg = wg
|
||||
go func() {
|
||||
wg.Add(1)
|
||||
@@ -164,7 +174,7 @@ func (sap *Service) Serve(wg *sync.WaitGroup, screenAndServePayload <-chan eth2.
|
||||
}
|
||||
|
||||
// filterAndServe filters the payload according to each subscription type and sends to the subscriptions
|
||||
func (sap *Service) filterAndServe(payload eth2.ConvertedPayload) {
|
||||
func (sap *Service) filterAndServe(payload eth.ConvertedPayload) {
|
||||
log.Debug("sending eth ipld payload to subscriptions")
|
||||
sap.Lock()
|
||||
sap.serveWg.Add(1)
|
||||
@@ -337,7 +347,7 @@ func (sap *Service) Unsubscribe(id rpc.ID) {
|
||||
func (sap *Service) Start() error {
|
||||
log.Info("starting eth ipld server")
|
||||
wg := new(sync.WaitGroup)
|
||||
payloadChan := make(chan eth2.ConvertedPayload, PayloadChanBufferSize)
|
||||
payloadChan := make(chan eth.ConvertedPayload, PayloadChanBufferSize)
|
||||
sap.Serve(wg, payloadChan)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -19,4 +19,11 @@ package shared
|
||||
const (
|
||||
DefaultMaxBatchSize uint64 = 100
|
||||
DefaultMaxBatchNumber int64 = 50
|
||||
|
||||
GcachePoolEnabled = "GCACHE_POOL_ENABLED"
|
||||
GcachePoolHttpPath = "GCACHE_POOL_HTTP_PATH"
|
||||
GcachePoolHttpPeers = "GCACHE_POOL_HTTP_PEERS"
|
||||
GcacheStatedbCacheSize = "GCACHE_STATEDB_CACHE_SIZE"
|
||||
GcacheStatedbCacheExpiry = "GCACHE_STATEDB_CACHE_EXPIRY"
|
||||
GcacheStatedbLogStatsInterval = "GCACHE_STATEDB_LOG_STATS_INTERVAL"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2022 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// NewDB creates a new db connection and initializes the connection pool
|
||||
func NewDB(connectString string, config postgres.Config) (*sqlx.DB, error) {
|
||||
db, connectErr := sqlx.Connect("postgres", connectString)
|
||||
if connectErr != nil {
|
||||
return nil, postgres.ErrDBConnectionFailed(connectErr)
|
||||
}
|
||||
if config.MaxConns > 0 {
|
||||
db.SetMaxOpenConns(config.MaxConns)
|
||||
}
|
||||
if config.MaxIdle > 0 {
|
||||
db.SetMaxIdleConns(config.MaxIdle)
|
||||
}
|
||||
if config.MaxConnLifetime > 0 {
|
||||
db.SetConnMaxLifetime(config.MaxConnLifetime)
|
||||
}
|
||||
|
||||
return db, nil
|
||||
}
|
||||
+6
-40
@@ -19,12 +19,10 @@ package shared
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/ipfs/go-ipfs-blockstore"
|
||||
"github.com/ipfs/go-ipfs-ds-help"
|
||||
node "github.com/ipfs/go-ipld-format"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
dshelp "github.com/ipfs/go-ipfs-ds-help"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs/ipld"
|
||||
)
|
||||
|
||||
// HandleZeroAddrPointer will return an emtpy string for a nil address pointer
|
||||
@@ -50,31 +48,11 @@ func Rollback(tx *sqlx.Tx) {
|
||||
}
|
||||
}
|
||||
|
||||
// PublishIPLD is used to insert an ipld into Postgres blockstore with the provided tx
|
||||
func PublishIPLD(tx *sqlx.Tx, i node.Node) error {
|
||||
dbKey := dshelp.MultihashToDsKey(i.Cid().Hash())
|
||||
prefixedKey := blockstore.BlockPrefix.String() + dbKey.String()
|
||||
raw := i.RawData()
|
||||
_, err := tx.Exec(`INSERT INTO public.blocks (key, data) VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`, prefixedKey, raw)
|
||||
return err
|
||||
}
|
||||
|
||||
// FetchIPLD is used to retrieve an ipld from Postgres blockstore with the provided tx and cid string
|
||||
func FetchIPLD(tx *sqlx.Tx, cid string) ([]byte, error) {
|
||||
mhKey, err := MultihashKeyFromCIDString(cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
pgStr := `SELECT data FROM public.blocks WHERE key = $1`
|
||||
// FetchIPLDByMhKeyAndBlockNumber is used to retrieve an ipld from Postgres blockstore with the provided tx, mhkey string and blockNumber
|
||||
func FetchIPLDByMhKeyAndBlockNumber(tx *sqlx.Tx, mhKey string, blockNumber uint64) ([]byte, error) {
|
||||
pgStr := `SELECT data FROM public.blocks WHERE key = $1 AND block_number = $2`
|
||||
var block []byte
|
||||
return block, tx.Get(&block, pgStr, mhKey)
|
||||
}
|
||||
|
||||
// FetchIPLDByMhKey is used to retrieve an ipld from Postgres blockstore with the provided tx and mhkey string
|
||||
func FetchIPLDByMhKey(tx *sqlx.Tx, mhKey string) ([]byte, error) {
|
||||
pgStr := `SELECT data FROM public.blocks WHERE key = $1`
|
||||
var block []byte
|
||||
return block, tx.Get(&block, pgStr, mhKey)
|
||||
return block, tx.Get(&block, pgStr, mhKey, blockNumber)
|
||||
}
|
||||
|
||||
// MultihashKeyFromCID converts a cid into a blockstore-prefixed multihash db key string
|
||||
@@ -92,15 +70,3 @@ func MultihashKeyFromCIDString(c string) (string, error) {
|
||||
dbKey := dshelp.MultihashToDsKey(dc.Hash())
|
||||
return blockstore.BlockPrefix.String() + dbKey.String(), nil
|
||||
}
|
||||
|
||||
// PublishRaw derives a cid from raw bytes and provided codec and multihash type, and writes it to the db tx
|
||||
func PublishRaw(tx *sqlx.Tx, codec, mh uint64, raw []byte) (string, error) {
|
||||
c, err := ipld.RawdataToCid(codec, raw, mh)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
dbKey := dshelp.MultihashToDsKey(c.Hash())
|
||||
prefixedKey := blockstore.BlockPrefix.String() + dbKey.String()
|
||||
_, err = tx.Exec(`INSERT INTO public.blocks (key, data) VALUES ($1, $2) ON CONFLICT (key) DO NOTHING`, prefixedKey, raw)
|
||||
return c.String(), err
|
||||
}
|
||||
|
||||
@@ -18,12 +18,24 @@ package shared
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/ipfs"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/interfaces"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/node"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
// IPLDsContainBytes used to check if a list of strings contains a particular string
|
||||
func IPLDsContainBytes(iplds []ipfs.BlockModel, b []byte) bool {
|
||||
func IPLDsContainBytes(iplds []models.IPLDModel, b []byte) bool {
|
||||
for _, ipld := range iplds {
|
||||
if bytes.Equal(ipld.Data, b) {
|
||||
return true
|
||||
@@ -31,3 +43,73 @@ func IPLDsContainBytes(iplds []ipfs.BlockModel, b []byte) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetupDB is use to setup a db for watcher tests
|
||||
func SetupDB() *sqlx.DB {
|
||||
config := getTestDBConfig()
|
||||
|
||||
db, err := NewDB(config.DbConnectionString(), config)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return db
|
||||
}
|
||||
|
||||
// TearDownDB is used to tear down the watcher dbs after tests
|
||||
func TearDownDB(db *sqlx.DB) {
|
||||
tx, err := db.Beginx()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM nodes`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.header_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.uncle_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.transaction_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.receipt_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.state_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.storage_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.state_accounts`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.access_list_elements`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM blocks`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth.log_cids`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
_, err = tx.Exec(`DELETE FROM eth_meta.watched_addresses`)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
err = tx.Commit()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
}
|
||||
|
||||
func SetupTestStateDiffIndexer(ctx context.Context, chainConfig *params.ChainConfig, genHash common.Hash) interfaces.StateDiffIndexer {
|
||||
testInfo := node.Info{
|
||||
GenesisBlock: genHash.String(),
|
||||
NetworkID: "1",
|
||||
ID: "1",
|
||||
ClientName: "geth",
|
||||
ChainID: params.TestChainConfig.ChainID.Uint64(),
|
||||
}
|
||||
|
||||
_, stateDiffIndexer, err := indexer.NewStateDiffIndexer(ctx, chainConfig, testInfo, getTestDBConfig())
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
return stateDiffIndexer
|
||||
}
|
||||
|
||||
func getTestDBConfig() postgres.Config {
|
||||
port, _ := strconv.Atoi(os.Getenv("DATABASE_PORT"))
|
||||
return postgres.Config{
|
||||
Hostname: os.Getenv("DATABASE_HOSTNAME"),
|
||||
DatabaseName: os.Getenv("DATABASE_NAME"),
|
||||
Username: os.Getenv("DATABASE_USER"),
|
||||
Password: os.Getenv("DATABASE_PASSWORD"),
|
||||
Port: port,
|
||||
Driver: postgres.SQLX,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// VulcanizeDB
|
||||
// Copyright © 2021 Vulcanize
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package shared
|
||||
|
||||
type PoolConfig struct {
|
||||
Enabled bool
|
||||
HttpEndpoint string
|
||||
PeerHttpEndpoints []string
|
||||
}
|
||||
|
||||
type GroupConfig struct {
|
||||
CacheSizeInMB int
|
||||
CacheExpiryInMins int
|
||||
LogStatsIntervalInSecs int
|
||||
|
||||
// Used in tests to override the cache name, to work around
|
||||
// the "duplicate registration of group" error from groupcache
|
||||
Name string
|
||||
}
|
||||
|
||||
type GroupCacheConfig struct {
|
||||
Pool PoolConfig
|
||||
StateDB GroupConfig
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
# Clear up existing docker images and volume.
|
||||
docker-compose down --remove-orphans --volumes
|
||||
|
||||
# Build and start the containers.
|
||||
# Note: Build only if `ipld-eth-server` code is modified. Otherwise comment this line.
|
||||
docker build -t ipld-eth-server_eth-server:latest .
|
||||
docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server
|
||||
export ETH_FORWARD_ETH_CALLS=false
|
||||
export DB_WRITE=true
|
||||
export ETH_PROXY_ON_ERROR=false
|
||||
|
||||
export PGPASSWORD=password
|
||||
export DATABASE_USER=vdbm
|
||||
@@ -18,4 +14,4 @@ export DATABASE_HOSTNAME=127.0.0.1
|
||||
# Wait for containers to be up and execute the integration test.
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8081)" != "200" ]; do echo "waiting for ipld-eth-server..." && sleep 5; done && \
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8545)" != "200" ]; do echo "waiting for geth-statediff..." && sleep 5; done && \
|
||||
make integrationtest
|
||||
make integrationtest
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
set -e
|
||||
set -o xtrace
|
||||
|
||||
export ETH_FORWARD_ETH_CALLS=true
|
||||
export DB_WRITE=false
|
||||
export ETH_PROXY_ON_ERROR=false
|
||||
|
||||
export PGPASSWORD=password
|
||||
export DATABASE_USER=vdbm
|
||||
export DATABASE_PORT=8077
|
||||
export DATABASE_PASSWORD=password
|
||||
export DATABASE_HOSTNAME=127.0.0.1
|
||||
|
||||
# Wait for containers to be up and execute the integration test.
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8081)" != "200" ]; do echo "waiting for ipld-eth-server..." && sleep 5; done && \
|
||||
while [ "$(curl -s -o /dev/null -w ''%{http_code}'' localhost:8545)" != "200" ]; do echo "waiting for geth-statediff..." && sleep 5; done && \
|
||||
make integrationtest
|
||||
@@ -1,2 +1,26 @@
|
||||
docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db
|
||||
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8077 DATABASE_PASSWORD=password DATABASE_HOSTNAME=127.0.0.1 make test
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
mkdir -p out
|
||||
|
||||
# Remove existing docker-tsdb directory
|
||||
rm -rf out/docker-tsdb/
|
||||
|
||||
# Copy over files to setup TimescaleDB
|
||||
ID=$(docker create vulcanize/ipld-eth-db:v4.1.1-alpha)
|
||||
docker cp $ID:/app/docker-tsdb out/docker-tsdb/
|
||||
docker rm -v $ID
|
||||
|
||||
# Spin up TimescaleDB
|
||||
docker-compose -f out/docker-tsdb/docker-compose.test.yml -f docker-compose.yml up ipld-eth-db
|
||||
trap "docker-compose -f out/docker-tsdb/docker-compose.test.yml -f docker-compose.yml down --remove-orphans --volumes; rm -rf out/" SIGINT SIGTERM ERR
|
||||
sleep 45
|
||||
|
||||
# Run unit tests
|
||||
go clean -testcache
|
||||
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8066 DATABASE_PASSWORD=password DATABASE_HOSTNAME=127.0.0.1 DATABASE_NAME=vulcanize_testing_v4 make test
|
||||
|
||||
# Clean up
|
||||
docker-compose -f out/docker-tsdb/docker-compose.test.yml -f docker-compose.yml down --remove-orphans --volumes
|
||||
rm -rf out/
|
||||
|
||||
+121
-12
@@ -1,15 +1,124 @@
|
||||
# Test Insructions
|
||||
|
||||
Spin up services:
|
||||
```
|
||||
docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d db dapptools contract eth-server
|
||||
```
|
||||
## Setup
|
||||
|
||||
Running unit tests:
|
||||
```bash
|
||||
make test_local
|
||||
```
|
||||
- Clone [stack-orchestrator](https://github.com/vulcanize/stack-orchestrator), [ipld-eth-db](https://github.com/vulcanize/ipld-eth-db) [go-ethereum](https://github.com/vulcanize/go-ethereum) repositories.
|
||||
|
||||
Running integration test:
|
||||
```bash
|
||||
make integrationtest_local
|
||||
```
|
||||
- Checkout [v4 release](https://github.com/vulcanize/ipld-eth-db/releases/tag/v4.1.1-alpha) in ipld-eth-db repo.
|
||||
```bash
|
||||
# In ipld-eth-db repo.
|
||||
git checkout v4.1.1-alpha
|
||||
```
|
||||
|
||||
- Checkout [v4 release](https://github.com/vulcanize/go-ethereum/releases/tag/v1.10.18-statediff-4.0.2-alpha) in go-ethereum repo.
|
||||
```bash
|
||||
# In go-ethereum repo.
|
||||
git checkout v1.10.18-statediff-4.0.2-alpha
|
||||
```
|
||||
|
||||
- Checkout working commit in stack-orchestrator repo.
|
||||
```bash
|
||||
# In stack-orchestrator repo.
|
||||
git checkout 418957a1f745c921b21286c13bb033f922a91ae9
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
- Run unit tests:
|
||||
|
||||
```bash
|
||||
# In ipld-eth-server root directory.
|
||||
./scripts/run_unit_test.sh
|
||||
```
|
||||
|
||||
- Run integration tests:
|
||||
|
||||
- In stack-orchestrator repo, create config file:
|
||||
|
||||
```bash
|
||||
cd helper-scripts
|
||||
|
||||
./create-config.sh
|
||||
```
|
||||
|
||||
A `config.sh` will be created in the root directory.
|
||||
|
||||
- Update/Edit the generated config file with:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Path to ipld-eth-server repo.
|
||||
vulcanize_ipld_eth_db=~/ipld-eth-db/
|
||||
|
||||
# Path to go-ethereum repo.
|
||||
vulcanize_go_ethereum=~/go-ethereum/
|
||||
|
||||
# Path to ipld-eth-server repo.
|
||||
vulcanize_ipld_eth_server=~/ipld-eth-server/
|
||||
|
||||
# Path to test contract.
|
||||
vulcanize_test_contract=~/ipld-eth-server/test/contract
|
||||
|
||||
db_write=true
|
||||
eth_forward_eth_calls=false
|
||||
eth_proxy_on_error=false
|
||||
eth_http_path="go-ethereum:8545"
|
||||
ipld_eth_server_db_dependency=access-node
|
||||
go_ethereum_db_dependency=access-node
|
||||
connecting_db_name=vulcanize_testing_v4
|
||||
```
|
||||
|
||||
- Run stack-orchestrator:
|
||||
|
||||
```bash
|
||||
# In stack-orchestrator root directory.
|
||||
cd helper-scripts
|
||||
|
||||
./wrapper.sh \
|
||||
-e docker \
|
||||
-d ../docker/latest/docker-compose-timescale-db.yml \
|
||||
-d ../docker/local/docker-compose-db-migration.yml \
|
||||
-d ../docker/local/docker-compose-go-ethereum.yml \
|
||||
-d ../docker/local/docker-compose-ipld-eth-server.yml \
|
||||
-d ../docker/local/docker-compose-contract.yml \
|
||||
-v remove \
|
||||
-p ../config.sh
|
||||
```
|
||||
|
||||
- Run test:
|
||||
|
||||
```bash
|
||||
# In ipld-eth-server root directory.
|
||||
./scripts/run_integration_test.sh
|
||||
```
|
||||
|
||||
- Update stack-orchestrator `config.sh` file:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Path to go-ethereum repo.
|
||||
vulcanize_go_ethereum=~/go-ethereum/
|
||||
|
||||
# Path to ipld-eth-server repo.
|
||||
vulcanize_ipld_eth_server=~/ipld-eth-server/
|
||||
|
||||
# Path to test contract.
|
||||
vulcanize_test_contract=~/ipld-eth-server/test/contract
|
||||
|
||||
db_write=false
|
||||
eth_forward_eth_calls=true
|
||||
eth_proxy_on_error=false
|
||||
eth_http_path="go-ethereum:8545"
|
||||
ipld_eth_server_db_dependency=access-node
|
||||
go_ethereum_db_dependency=access-node
|
||||
connecting_db_name=vulcanize_testing_v4
|
||||
```
|
||||
|
||||
- Stop the stack-orchestrator and start again using the same command
|
||||
|
||||
- Run integration tests for direct proxy fall-through of eth_calls:
|
||||
```bash
|
||||
./scripts/run_integration_test_forward_eth_calls.sh
|
||||
```
|
||||
|
||||
@@ -4,4 +4,7 @@ contract GLDToken is ERC20 {
|
||||
constructor() ERC20("Gold", "GLD") {
|
||||
_mint(msg.sender, 1000000000000000000000);
|
||||
}
|
||||
function destroy() public {
|
||||
selfdestruct(payable(msg.sender));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0
|
||||
pragma solidity ^0.8.0;
|
||||
|
||||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
||||
|
||||
contract SLVToken is ERC20 {
|
||||
uint256 private countA;
|
||||
uint256 private countB;
|
||||
|
||||
constructor() ERC20("Silver", "SLV") {}
|
||||
|
||||
function incrementCountA() public {
|
||||
countA = countA + 1;
|
||||
}
|
||||
|
||||
function incrementCountB() public {
|
||||
countB = countB + 1;
|
||||
}
|
||||
|
||||
receive() external payable {}
|
||||
|
||||
function destroy() public {
|
||||
selfdestruct(payable(msg.sender));
|
||||
}
|
||||
}
|
||||
@@ -17,15 +17,26 @@ task("accounts", "Prints the list of accounts", async () => {
|
||||
* @type import('hardhat/config').HardhatUserConfig
|
||||
*/
|
||||
module.exports = {
|
||||
solidity: "0.8.0",
|
||||
solidity: {
|
||||
version: "0.8.0",
|
||||
settings: {
|
||||
outputSelection: {
|
||||
'*': {
|
||||
'*': [
|
||||
'abi', 'storageLayout',
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
networks: {
|
||||
local: {
|
||||
url: 'http://127.0.0.1:8545',
|
||||
chainId: 4
|
||||
chainId: 99
|
||||
},
|
||||
docker: {
|
||||
url: process.env.ETH_ADDR,
|
||||
chainId: 4
|
||||
chainId: 99
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Generated
+46
-95
@@ -5,12 +5,14 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "contract",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^4.0.0",
|
||||
"fastify": "^3.14.2",
|
||||
"hardhat": "^2.2.0"
|
||||
"hardhat": "^2.2.0",
|
||||
"solidity-create2-deployer": "^0.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||
@@ -254,10 +256,10 @@
|
||||
"@resolver-engine/imports-fs": "^0.3.3",
|
||||
"@typechain/ethers-v5": "^2.0.0",
|
||||
"@types/mkdirp": "^0.5.2",
|
||||
"@types/node-fetch": "^2.5.5",
|
||||
"@types/node-fetch": "^2.6.7",
|
||||
"ethers": "^5.0.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"solc": "^0.6.3",
|
||||
"ts-generator": "^0.1.1",
|
||||
"typechain": "^3.0.0"
|
||||
@@ -468,7 +470,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.1.0.tgz",
|
||||
"integrity": "sha512-N/W9Sbn1/C6Kh2kuHRjf/hX6euMK4+9zdJRBB8sDWmihVntjUAfxbusGZKzDQD8i3szAHhTz8K7XADV5iFNfJw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -495,7 +496,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.1.0.tgz",
|
||||
"integrity": "sha512-8dJUnT8VNvPwWhYIau4dwp7qe1g+KgdRm4XTWvjkI9gAT2zZa90WF5ApdZ3vl1r6NDmnn6vUVvyphClRZRteTQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -520,7 +520,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.1.0.tgz",
|
||||
"integrity": "sha512-qQDMkjGZSSJSKl6AnfTgmz9FSnzq3iEoEbHTYwjDlEAv+LNP7zd4ixCcVWlWyk+2siud856M5CRhAmPdupeN9w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -543,7 +542,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.1.0.tgz",
|
||||
"integrity": "sha512-rfWQR12eHn2cpstCFS4RF7oGjfbkZb0oqep+BfrT+gWEGWG2IowJvIsacPOvzyS1jhNF4MQ4BS59B04Mbovteg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -566,7 +564,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.1.0.tgz",
|
||||
"integrity": "sha512-npD1bLvK4Bcxz+m4EMkx+F8Rd7CnqS9DYnhNu0/GlQBXhWjvfoAZzk5HJ0f1qeyp8d+A86PTuzLOGOXf4/CN8g==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -585,7 +582,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.1.0.tgz",
|
||||
"integrity": "sha512-vBKr39bum7DDbOvkr1Sj19bRMEPA4FnST6Utt6xhDzI7o7L6QNkDn2yrCfP+hnvJGhZFKtLygWwqlTBZoBXYLg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -605,7 +601,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.1.0.tgz",
|
||||
"integrity": "sha512-wUvQlhTjPjFXIdLPOuTrFeQmSa6Wvls1bGXQNQWvB/SEn1NsTCE8PmumIEZxmOPjSHl1eV2uyHP5jBm5Cgj92Q==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -626,7 +621,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.1.0.tgz",
|
||||
"integrity": "sha512-sGTxb+LVjFxJcJeUswAIK6ncgOrh3D8c192iEJd7mLr95V6du119rRfYT/b87WPkZ5I3gRBUYIYXtdgCWACe8g==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -645,7 +639,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.1.0.tgz",
|
||||
"integrity": "sha512-0/SuHrxc8R8k+JiLmJymxHJbojUDWBQqO+b+XFdwaP0jGzqC09YDy/CAlSZB6qHsBifY8X3I89HcK/oMqxRdBw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -664,7 +657,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.1.0.tgz",
|
||||
"integrity": "sha512-dvTMs/4XGSc57cYOW0KjgX1NdTujUu7mNb6PQdJWg08m9ULzPyGZuBkFJnijBcp6vTOCQ59RwjboWgNWw393og==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -692,7 +684,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.1.0.tgz",
|
||||
"integrity": "sha512-fNwry20yLLPpnRRwm3fBL+2ksgO+KMadxM44WJmRIoTKzy4269+rbq9KFoe2LTqq2CXJM2CE70beGaNrpuqflQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -718,7 +709,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.1.0.tgz",
|
||||
"integrity": "sha512-obIWdlujloExPHWJGmhJO/sETOOo7SEb6qemV4f8kyFoXg+cJK+Ta9SvBrj7hsUK85n3LZeZJZRjjM7oez3Clg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -748,7 +738,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.1.0.tgz",
|
||||
"integrity": "sha512-00n2iBy27w8zrGZSiU762UOVuzCQZxUZxopsZC47++js6xUFuI74DHcJ5K/2pddlF1YBskvmMuboEu1geK8mnA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -779,7 +768,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.1.0.tgz",
|
||||
"integrity": "sha512-vrTB1W6AEYoadww5c9UyVJ2YcSiyIUTNDRccZIgwTmFFoSHwBtcvG1hqy9RzJ1T0bMdATbM9Hfx2mJ6H0i7Hig==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -798,14 +786,12 @@
|
||||
"node_modules/@ethersproject/keccak256/node_modules/js-sha3": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz",
|
||||
"integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc="
|
||||
},
|
||||
"node_modules/@ethersproject/logger": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.1.0.tgz",
|
||||
"integrity": "sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -821,7 +807,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.1.0.tgz",
|
||||
"integrity": "sha512-A/NIrIED/G/IgU1XUukOA3WcFRxn2I4O5GxsYGA5nFlIi+UZWdGojs85I1VXkR1gX9eFnDXzjE6OtbgZHjFhIA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -840,7 +825,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.1.0.tgz",
|
||||
"integrity": "sha512-B8cUbHHTgs8OtgJIafrRcz/YPDobVd5Ru8gTnShOiM9EBuFpYHQpq3+8iQJ6pyczDu6HP/oc/njAsIBhwFZYew==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -860,7 +844,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.1.0.tgz",
|
||||
"integrity": "sha512-519KKTwgmH42AQL3+GFV3SX6khYEfHsvI6v8HYejlkigSDuqttdgVygFTDsGlofNFchhDwuclrxQnD5B0YLNMg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -879,7 +862,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.1.0.tgz",
|
||||
"integrity": "sha512-FjpZL2lSXrYpQDg2fMjugZ0HjQD9a+2fOOoRhhihh+Z+qi/xZ8vIlPoumrEP1DzIG4DBV6liUqLNqnX2C6FIAA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -916,7 +898,6 @@
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
|
||||
"integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
@@ -937,7 +918,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.1.0.tgz",
|
||||
"integrity": "sha512-+uuczLQZ4+no9cP6TCoCktXx0u2YbNaRT7lRkSt12d8263e702f0u+4JnnRO8Qmv5nylWJebnqCHzyxP+6mLqw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -957,7 +937,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.1.0.tgz",
|
||||
"integrity": "sha512-vDTyHIwNPrecy55gKGZ47eJZhBm8LLBxihzi5ou+zrSvYTpkSTWRcKUlXFDFQVwfWB+P5PGyERAdiDEI76clxw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -977,7 +956,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.1.0.tgz",
|
||||
"integrity": "sha512-+fNSeZRstOpdRJpdGUkRONFCaiAqWkc91zXgg76Nlp5ndBQE25Kk5yK8gCPG1aGnCrbariiPr5j9DmrYH78JCA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -998,7 +976,6 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
|
||||
"integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"minimalistic-assert": "^1.0.0"
|
||||
@@ -1008,7 +985,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.1.0.tgz",
|
||||
"integrity": "sha512-tE5LFlbmdObG8bY04NpuwPWSRPgEswfxweAI1sH7TbP0ml1elNfqcq7ii/3AvIN05i5U0Pkm3Tf8bramt8MmLw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1031,7 +1007,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.1.0.tgz",
|
||||
"integrity": "sha512-kPodsGyo9zg1g9XSXp1lGhFaezBAUUsAUB1Vf6OkppE5Wksg4Et+x3kG4m7J/uShDMP2upkJtHNsIBK2XkVpKQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1054,7 +1029,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.1.0.tgz",
|
||||
"integrity": "sha512-perBZy0RrmmL0ejiFGUOlBVjMsUceqLut3OBP3zP96LhiJWWbS8u1NqQVgN4/Gyrbziuda66DxiQocXhsvx+Sw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1075,7 +1049,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.1.0.tgz",
|
||||
"integrity": "sha512-s10crRLZEA0Bgv6FGEl/AKkTw9f+RVUrlWDX1rHnD4ZncPFeiV2AJr4nT7QSUhxJdFPvjyKRDb3nEH27dIqcPQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1102,7 +1075,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.1.0.tgz",
|
||||
"integrity": "sha512-isvJrx6qG0nKWfxsGORNjmOq/nh175fStfvRTA2xEKrGqx8JNJY83fswu4GkILowfriEM/eYpretfJnfzi7YhA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1123,7 +1095,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.1.0.tgz",
|
||||
"integrity": "sha512-ULmUtiYQLTUS+y3DgkLzRhFEK10zMwmjOthnjiZxee3Q/MVwr3rnmuAnXIUZrPjna6hvUPnyRIdW5XuF0Ld0YQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1156,7 +1127,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.1.0.tgz",
|
||||
"integrity": "sha512-LTeluWgTq04+RNqAkVhpydPcRZK/kKxD2Vy7PYGrAD27ABO9kTqTBKwiOuzTyAHKUQHfnvZbXmxBXJAGViSDcA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1179,7 +1149,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.1.0.tgz",
|
||||
"integrity": "sha512-NsUCi/TpBb+oTFvMSccUkJGtp5o/84eOyqp5q5aBeiNBSLkYyw21znRn9mAmxZgySpxgruVgKbaapnYPgvctPQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -1506,7 +1475,7 @@
|
||||
"integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g=="
|
||||
},
|
||||
"node_modules/@types/node-fetch": {
|
||||
"version": "2.5.10",
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz",
|
||||
"integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==",
|
||||
"dev": true,
|
||||
@@ -1629,8 +1598,7 @@
|
||||
"node_modules/aes-js": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
|
||||
"integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0="
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
@@ -1869,8 +1837,7 @@
|
||||
"node_modules/bech32": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
|
||||
"integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
@@ -2773,7 +2740,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ethers/-/ethers-5.1.0.tgz",
|
||||
"integrity": "sha512-2L6Ge6wMBw02FlRoCLg4E0Elt3khMNlW6ULawa10mMeeZToYJ5+uCfiuTuB+XZ6om1Y7wuO9ZzezP8FsU2M/+g==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -3093,7 +3059,7 @@
|
||||
"integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw=="
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.13.3",
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
|
||||
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA==",
|
||||
"funding": [
|
||||
@@ -12519,7 +12485,7 @@
|
||||
"merkle-patricia-tree": "^4.1.0",
|
||||
"mnemonist": "^0.38.0",
|
||||
"mocha": "^7.1.2",
|
||||
"node-fetch": "^2.6.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"qs": "^6.7.0",
|
||||
"raw-body": "^2.4.1",
|
||||
"resolve": "1.17.0",
|
||||
@@ -13722,7 +13688,7 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||
"engines": {
|
||||
@@ -14696,7 +14662,7 @@
|
||||
"dependencies": {
|
||||
"command-exists": "^1.2.8",
|
||||
"commander": "3.0.2",
|
||||
"follow-redirects": "^1.12.1",
|
||||
"follow-redirects": "^1.14.7",
|
||||
"fs-extra": "^0.30.0",
|
||||
"js-sha3": "0.8.0",
|
||||
"memorystream": "^0.3.1",
|
||||
@@ -14739,6 +14705,17 @@
|
||||
"semver": "bin/semver"
|
||||
}
|
||||
},
|
||||
"node_modules/solidity-create2-deployer": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/solidity-create2-deployer/-/solidity-create2-deployer-0.4.0.tgz",
|
||||
"integrity": "sha512-bB5d8fPt4dWsOoRodrsyfWKcjiv77IFl84+e6EckMMGYlfL2ZFqUoMz6tnqqiUFrM9abF1p6dWFOgJ/3zVc8yQ==",
|
||||
"dependencies": {
|
||||
"ethers": "^5.0.14"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/sonic-boom": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
|
||||
@@ -15856,10 +15833,10 @@
|
||||
"@resolver-engine/imports-fs": "^0.3.3",
|
||||
"@typechain/ethers-v5": "^2.0.0",
|
||||
"@types/mkdirp": "^0.5.2",
|
||||
"@types/node-fetch": "^2.5.5",
|
||||
"@types/node-fetch": "^2.6.7",
|
||||
"ethers": "^5.0.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"solc": "^0.6.3",
|
||||
"ts-generator": "^0.1.1",
|
||||
"typechain": "^3.0.0"
|
||||
@@ -16055,7 +16032,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.1.0.tgz",
|
||||
"integrity": "sha512-N/W9Sbn1/C6Kh2kuHRjf/hX6euMK4+9zdJRBB8sDWmihVntjUAfxbusGZKzDQD8i3szAHhTz8K7XADV5iFNfJw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/address": "^5.1.0",
|
||||
"@ethersproject/bignumber": "^5.1.0",
|
||||
@@ -16072,7 +16048,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.1.0.tgz",
|
||||
"integrity": "sha512-8dJUnT8VNvPwWhYIau4dwp7qe1g+KgdRm4XTWvjkI9gAT2zZa90WF5ApdZ3vl1r6NDmnn6vUVvyphClRZRteTQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bignumber": "^5.1.0",
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
@@ -16087,7 +16062,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.1.0.tgz",
|
||||
"integrity": "sha512-qQDMkjGZSSJSKl6AnfTgmz9FSnzq3iEoEbHTYwjDlEAv+LNP7zd4ixCcVWlWyk+2siud856M5CRhAmPdupeN9w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abstract-provider": "^5.1.0",
|
||||
"@ethersproject/bignumber": "^5.1.0",
|
||||
@@ -16100,7 +16074,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.1.0.tgz",
|
||||
"integrity": "sha512-rfWQR12eHn2cpstCFS4RF7oGjfbkZb0oqep+BfrT+gWEGWG2IowJvIsacPOvzyS1jhNF4MQ4BS59B04Mbovteg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bignumber": "^5.1.0",
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
@@ -16113,7 +16086,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.1.0.tgz",
|
||||
"integrity": "sha512-npD1bLvK4Bcxz+m4EMkx+F8Rd7CnqS9DYnhNu0/GlQBXhWjvfoAZzk5HJ0f1qeyp8d+A86PTuzLOGOXf4/CN8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0"
|
||||
}
|
||||
@@ -16122,7 +16094,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.1.0.tgz",
|
||||
"integrity": "sha512-vBKr39bum7DDbOvkr1Sj19bRMEPA4FnST6Utt6xhDzI7o7L6QNkDn2yrCfP+hnvJGhZFKtLygWwqlTBZoBXYLg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/properties": "^5.1.0"
|
||||
@@ -16132,7 +16103,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.1.0.tgz",
|
||||
"integrity": "sha512-wUvQlhTjPjFXIdLPOuTrFeQmSa6Wvls1bGXQNQWvB/SEn1NsTCE8PmumIEZxmOPjSHl1eV2uyHP5jBm5Cgj92Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/logger": "^5.1.0",
|
||||
@@ -16143,7 +16113,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.1.0.tgz",
|
||||
"integrity": "sha512-sGTxb+LVjFxJcJeUswAIK6ncgOrh3D8c192iEJd7mLr95V6du119rRfYT/b87WPkZ5I3gRBUYIYXtdgCWACe8g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/logger": "^5.1.0"
|
||||
}
|
||||
@@ -16152,7 +16121,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.1.0.tgz",
|
||||
"integrity": "sha512-0/SuHrxc8R8k+JiLmJymxHJbojUDWBQqO+b+XFdwaP0jGzqC09YDy/CAlSZB6qHsBifY8X3I89HcK/oMqxRdBw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bignumber": "^5.1.0"
|
||||
}
|
||||
@@ -16161,7 +16129,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.1.0.tgz",
|
||||
"integrity": "sha512-dvTMs/4XGSc57cYOW0KjgX1NdTujUu7mNb6PQdJWg08m9ULzPyGZuBkFJnijBcp6vTOCQ59RwjboWgNWw393og==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abi": "^5.1.0",
|
||||
"@ethersproject/abstract-provider": "^5.1.0",
|
||||
@@ -16179,7 +16146,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.1.0.tgz",
|
||||
"integrity": "sha512-fNwry20yLLPpnRRwm3fBL+2ksgO+KMadxM44WJmRIoTKzy4269+rbq9KFoe2LTqq2CXJM2CE70beGaNrpuqflQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abstract-signer": "^5.1.0",
|
||||
"@ethersproject/address": "^5.1.0",
|
||||
@@ -16195,7 +16161,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.1.0.tgz",
|
||||
"integrity": "sha512-obIWdlujloExPHWJGmhJO/sETOOo7SEb6qemV4f8kyFoXg+cJK+Ta9SvBrj7hsUK85n3LZeZJZRjjM7oez3Clg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abstract-signer": "^5.1.0",
|
||||
"@ethersproject/basex": "^5.1.0",
|
||||
@@ -16215,7 +16180,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.1.0.tgz",
|
||||
"integrity": "sha512-00n2iBy27w8zrGZSiU762UOVuzCQZxUZxopsZC47++js6xUFuI74DHcJ5K/2pddlF1YBskvmMuboEu1geK8mnA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abstract-signer": "^5.1.0",
|
||||
"@ethersproject/address": "^5.1.0",
|
||||
@@ -16236,7 +16200,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.1.0.tgz",
|
||||
"integrity": "sha512-vrTB1W6AEYoadww5c9UyVJ2YcSiyIUTNDRccZIgwTmFFoSHwBtcvG1hqy9RzJ1T0bMdATbM9Hfx2mJ6H0i7Hig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"js-sha3": "0.5.7"
|
||||
@@ -16245,22 +16208,19 @@
|
||||
"js-sha3": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.5.7.tgz",
|
||||
"integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc=",
|
||||
"dev": true
|
||||
"integrity": "sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc="
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ethersproject/logger": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.1.0.tgz",
|
||||
"integrity": "sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-wtUaD1lBX10HBXjjKV9VHCBnTdUaKQnQ2XSET1ezglqLdPdllNOIlLfhyCRqXm5xwcjExVI5ETokOYfjPtaAlw=="
|
||||
},
|
||||
"@ethersproject/networks": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.1.0.tgz",
|
||||
"integrity": "sha512-A/NIrIED/G/IgU1XUukOA3WcFRxn2I4O5GxsYGA5nFlIi+UZWdGojs85I1VXkR1gX9eFnDXzjE6OtbgZHjFhIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/logger": "^5.1.0"
|
||||
}
|
||||
@@ -16269,7 +16229,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.1.0.tgz",
|
||||
"integrity": "sha512-B8cUbHHTgs8OtgJIafrRcz/YPDobVd5Ru8gTnShOiM9EBuFpYHQpq3+8iQJ6pyczDu6HP/oc/njAsIBhwFZYew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/sha2": "^5.1.0"
|
||||
@@ -16279,7 +16238,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.1.0.tgz",
|
||||
"integrity": "sha512-519KKTwgmH42AQL3+GFV3SX6khYEfHsvI6v8HYejlkigSDuqttdgVygFTDsGlofNFchhDwuclrxQnD5B0YLNMg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/logger": "^5.1.0"
|
||||
}
|
||||
@@ -16288,7 +16246,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.1.0.tgz",
|
||||
"integrity": "sha512-FjpZL2lSXrYpQDg2fMjugZ0HjQD9a+2fOOoRhhihh+Z+qi/xZ8vIlPoumrEP1DzIG4DBV6liUqLNqnX2C6FIAA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abstract-provider": "^5.1.0",
|
||||
"@ethersproject/abstract-signer": "^5.1.0",
|
||||
@@ -16315,7 +16272,6 @@
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.2.3.tgz",
|
||||
"integrity": "sha512-HTDl9G9hbkNDk98naoR/cHDws7+EyYMOdL1BmjsZXRUjf7d+MficC4B7HLUPlSiho0vg+CWKrGIt/VJBd1xunQ==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
@@ -16324,7 +16280,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.1.0.tgz",
|
||||
"integrity": "sha512-+uuczLQZ4+no9cP6TCoCktXx0u2YbNaRT7lRkSt12d8263e702f0u+4JnnRO8Qmv5nylWJebnqCHzyxP+6mLqw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/logger": "^5.1.0"
|
||||
@@ -16334,7 +16289,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.1.0.tgz",
|
||||
"integrity": "sha512-vDTyHIwNPrecy55gKGZ47eJZhBm8LLBxihzi5ou+zrSvYTpkSTWRcKUlXFDFQVwfWB+P5PGyERAdiDEI76clxw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/logger": "^5.1.0"
|
||||
@@ -16344,7 +16298,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.1.0.tgz",
|
||||
"integrity": "sha512-+fNSeZRstOpdRJpdGUkRONFCaiAqWkc91zXgg76Nlp5ndBQE25Kk5yK8gCPG1aGnCrbariiPr5j9DmrYH78JCA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/logger": "^5.1.0",
|
||||
@@ -16355,7 +16308,6 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
|
||||
"integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"minimalistic-assert": "^1.0.0"
|
||||
@@ -16367,7 +16319,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.1.0.tgz",
|
||||
"integrity": "sha512-tE5LFlbmdObG8bY04NpuwPWSRPgEswfxweAI1sH7TbP0ml1elNfqcq7ii/3AvIN05i5U0Pkm3Tf8bramt8MmLw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/logger": "^5.1.0",
|
||||
@@ -16380,7 +16331,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.1.0.tgz",
|
||||
"integrity": "sha512-kPodsGyo9zg1g9XSXp1lGhFaezBAUUsAUB1Vf6OkppE5Wksg4Et+x3kG4m7J/uShDMP2upkJtHNsIBK2XkVpKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bignumber": "^5.1.0",
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
@@ -16393,7 +16343,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.1.0.tgz",
|
||||
"integrity": "sha512-perBZy0RrmmL0ejiFGUOlBVjMsUceqLut3OBP3zP96LhiJWWbS8u1NqQVgN4/Gyrbziuda66DxiQocXhsvx+Sw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/constants": "^5.1.0",
|
||||
@@ -16404,7 +16353,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.1.0.tgz",
|
||||
"integrity": "sha512-s10crRLZEA0Bgv6FGEl/AKkTw9f+RVUrlWDX1rHnD4ZncPFeiV2AJr4nT7QSUhxJdFPvjyKRDb3nEH27dIqcPQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/address": "^5.1.0",
|
||||
"@ethersproject/bignumber": "^5.1.0",
|
||||
@@ -16421,7 +16369,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.1.0.tgz",
|
||||
"integrity": "sha512-isvJrx6qG0nKWfxsGORNjmOq/nh175fStfvRTA2xEKrGqx8JNJY83fswu4GkILowfriEM/eYpretfJnfzi7YhA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bignumber": "^5.1.0",
|
||||
"@ethersproject/constants": "^5.1.0",
|
||||
@@ -16432,7 +16379,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.1.0.tgz",
|
||||
"integrity": "sha512-ULmUtiYQLTUS+y3DgkLzRhFEK10zMwmjOthnjiZxee3Q/MVwr3rnmuAnXIUZrPjna6hvUPnyRIdW5XuF0Ld0YQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abstract-provider": "^5.1.0",
|
||||
"@ethersproject/abstract-signer": "^5.1.0",
|
||||
@@ -16455,7 +16401,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.1.0.tgz",
|
||||
"integrity": "sha512-LTeluWgTq04+RNqAkVhpydPcRZK/kKxD2Vy7PYGrAD27ABO9kTqTBKwiOuzTyAHKUQHfnvZbXmxBXJAGViSDcA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/base64": "^5.1.0",
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
@@ -16468,7 +16413,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.1.0.tgz",
|
||||
"integrity": "sha512-NsUCi/TpBb+oTFvMSccUkJGtp5o/84eOyqp5q5aBeiNBSLkYyw21znRn9mAmxZgySpxgruVgKbaapnYPgvctPQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/bytes": "^5.1.0",
|
||||
"@ethersproject/hash": "^5.1.0",
|
||||
@@ -16704,7 +16648,9 @@
|
||||
"resolved": "https://registry.npmjs.org/@typechain/ethers-v5/-/ethers-v5-2.0.0.tgz",
|
||||
"integrity": "sha512-0xdCkyGOzdqh4h5JSf+zoWx85IusEjDcPIwNEHP8mrWSnCae4rvrqB+/gtpdNfX7zjlFlZiMeePn2r63EI3Lrw==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
"requires": {
|
||||
"ethers": "^5.0.2"
|
||||
}
|
||||
},
|
||||
"@types/abstract-leveldown": {
|
||||
"version": "5.0.1",
|
||||
@@ -16754,7 +16700,7 @@
|
||||
"integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g=="
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
"version": "2.5.10",
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz",
|
||||
"integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==",
|
||||
"dev": true,
|
||||
@@ -16868,8 +16814,7 @@
|
||||
"aes-js": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz",
|
||||
"integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0="
|
||||
},
|
||||
"agent-base": {
|
||||
"version": "6.0.2",
|
||||
@@ -17056,8 +17001,7 @@
|
||||
"bech32": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz",
|
||||
"integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ=="
|
||||
},
|
||||
"binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
@@ -17804,7 +17748,6 @@
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ethers/-/ethers-5.1.0.tgz",
|
||||
"integrity": "sha512-2L6Ge6wMBw02FlRoCLg4E0Elt3khMNlW6ULawa10mMeeZToYJ5+uCfiuTuB+XZ6om1Y7wuO9ZzezP8FsU2M/+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@ethersproject/abi": "5.1.0",
|
||||
"@ethersproject/abstract-provider": "5.1.0",
|
||||
@@ -18067,7 +18010,7 @@
|
||||
"integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw=="
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.13.3",
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.3.tgz",
|
||||
"integrity": "sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA=="
|
||||
},
|
||||
@@ -25307,7 +25250,7 @@
|
||||
"merkle-patricia-tree": "^4.1.0",
|
||||
"mnemonist": "^0.38.0",
|
||||
"mocha": "^7.1.2",
|
||||
"node-fetch": "^2.6.0",
|
||||
"node-fetch": "^2.6.7",
|
||||
"qs": "^6.7.0",
|
||||
"raw-body": "^2.4.1",
|
||||
"resolve": "1.17.0",
|
||||
@@ -26211,7 +26154,7 @@
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
@@ -26930,7 +26873,7 @@
|
||||
"requires": {
|
||||
"command-exists": "^1.2.8",
|
||||
"commander": "3.0.2",
|
||||
"follow-redirects": "^1.12.1",
|
||||
"follow-redirects": "^1.14.7",
|
||||
"fs-extra": "^0.30.0",
|
||||
"js-sha3": "0.8.0",
|
||||
"memorystream": "^0.3.1",
|
||||
@@ -26966,6 +26909,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"solidity-create2-deployer": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/solidity-create2-deployer/-/solidity-create2-deployer-0.4.0.tgz",
|
||||
"integrity": "sha512-bB5d8fPt4dWsOoRodrsyfWKcjiv77IFl84+e6EckMMGYlfL2ZFqUoMz6tnqqiUFrM9abF1p6dWFOgJ/3zVc8yQ==",
|
||||
"requires": {
|
||||
"ethers": "^5.0.14"
|
||||
}
|
||||
},
|
||||
"sonic-boom": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
"dependencies": {
|
||||
"@openzeppelin/contracts": "^4.0.0",
|
||||
"fastify": "^3.14.2",
|
||||
"hardhat": "^2.2.0"
|
||||
"hardhat": "^2.2.0",
|
||||
"solidity-create2-deployer": "^0.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.2",
|
||||
|
||||
+127
-1
@@ -1,6 +1,15 @@
|
||||
const fastify = require('fastify')({ logger: true });
|
||||
const hre = require("hardhat");
|
||||
|
||||
const {
|
||||
deployContract,
|
||||
isDeployed
|
||||
} = require("solidity-create2-deployer");
|
||||
|
||||
const { getStorageSlotKey, deployCreate2Factory } = require('./utils');
|
||||
|
||||
const CREATE2_FACTORY_ADDRESS = '0x4a27c059FD7E383854Ea7DE6Be9c390a795f6eE3'
|
||||
|
||||
// readiness check
|
||||
fastify.get('/v1/healthz', async (req, reply) => {
|
||||
reply
|
||||
@@ -22,6 +31,20 @@ fastify.get('/v1/deployContract', async (req, reply) => {
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/v1/destroyContract', async (req, reply) => {
|
||||
const addr = req.query.addr;
|
||||
|
||||
const Token = await hre.ethers.getContractFactory("GLDToken");
|
||||
const token = await Token.attach(addr);
|
||||
|
||||
await token.destroy();
|
||||
const blockNum = await hre.ethers.provider.getBlockNumber()
|
||||
|
||||
return {
|
||||
blockNumber: blockNum,
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/v1/sendEth', async (req, reply) => {
|
||||
const to = req.query.to;
|
||||
const value = req.query.value;
|
||||
@@ -48,6 +71,109 @@ fastify.get('/v1/sendEth', async (req, reply) => {
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/v1/deploySLVContract', async (req, reply) => {
|
||||
const SLVToken = await hre.ethers.getContractFactory("SLVToken");
|
||||
const token = await SLVToken.deploy();
|
||||
const receipt = await token.deployTransaction.wait();
|
||||
|
||||
return {
|
||||
address: token.address,
|
||||
txHash: token.deployTransaction.hash,
|
||||
blockNumber: receipt.blockNumber,
|
||||
blockHash: receipt.blockHash,
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/v1/destroySLVContract', async (req, reply) => {
|
||||
const addr = req.query.addr;
|
||||
|
||||
const SLVToken = await hre.ethers.getContractFactory("SLVToken");
|
||||
const token = SLVToken.attach(addr);
|
||||
|
||||
const tx = await token.destroy();
|
||||
const receipt = await tx.wait();
|
||||
|
||||
return {
|
||||
blockNumber: receipt.blockNumber,
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/v1/incrementCountA', async (req, reply) => {
|
||||
const addr = req.query.addr;
|
||||
|
||||
const SLVToken = await hre.ethers.getContractFactory("SLVToken");
|
||||
const token = await SLVToken.attach(addr);
|
||||
|
||||
const tx = await token.incrementCountA();
|
||||
const receipt = await tx.wait();
|
||||
|
||||
return {
|
||||
blockNumber: receipt.blockNumber,
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/v1/incrementCountB', async (req, reply) => {
|
||||
const addr = req.query.addr;
|
||||
|
||||
const SLVToken = await hre.ethers.getContractFactory("SLVToken");
|
||||
const token = await SLVToken.attach(addr);
|
||||
|
||||
const tx = await token.incrementCountB();
|
||||
const receipt = await tx.wait();
|
||||
|
||||
return {
|
||||
blockNumber: receipt.blockNumber,
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/v1/getStorageKey', async (req, reply) => {
|
||||
const contract = req.query.contract;
|
||||
const label = req.query.label;
|
||||
|
||||
const key = await getStorageSlotKey(contract, label)
|
||||
|
||||
return {
|
||||
key
|
||||
}
|
||||
});
|
||||
|
||||
fastify.get('/v1/create2Contract', async (req, reply) => {
|
||||
const contract = req.query.contract;
|
||||
const salt = req.query.salt;
|
||||
|
||||
const provider = hre.ethers.provider;
|
||||
const signer = await hre.ethers.getSigner();
|
||||
const isFactoryDeployed = await isDeployed(CREATE2_FACTORY_ADDRESS, provider);
|
||||
|
||||
if (!isFactoryDeployed) {
|
||||
await deployCreate2Factory(provider, signer)
|
||||
}
|
||||
|
||||
const contractFactory = await hre.ethers.getContractFactory(contract);
|
||||
const bytecode = contractFactory.bytecode;
|
||||
const constructorTypes = [];
|
||||
const constructorArgs = [];
|
||||
|
||||
const { txHash, address, receipt } = await deployContract({
|
||||
salt,
|
||||
contractBytecode: bytecode,
|
||||
constructorTypes: constructorTypes,
|
||||
constructorArgs: constructorArgs,
|
||||
signer
|
||||
});
|
||||
|
||||
const success = await isDeployed(address, provider);
|
||||
|
||||
if (success) {
|
||||
return {
|
||||
address,
|
||||
txHash,
|
||||
blockNumber: receipt.blockNumber,
|
||||
blockHash: receipt.blockHash,
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
async function main() {
|
||||
try {
|
||||
await fastify.listen(3000, '0.0.0.0');
|
||||
@@ -57,4 +183,4 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
main();
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
const { artifacts } = require("hardhat")
|
||||
const { utils, BigNumber } = require("ethers")
|
||||
const { deployFactory } = require("solidity-create2-deployer");
|
||||
|
||||
const CREATE2_FACTORY_ACCOUNT = '0x2287Fa6efdEc6d8c3E0f4612ce551dEcf89A357A';
|
||||
|
||||
async function getStorageLayout(contractName) {
|
||||
const artifact = await artifacts.readArtifact(contractName);
|
||||
const buildInfo = await artifacts.getBuildInfo(`${artifact.sourceName}:${artifact.contractName}`);
|
||||
|
||||
if (!buildInfo) {
|
||||
throw new Error('storageLayout not present in compiler output.');
|
||||
}
|
||||
|
||||
const output = buildInfo.output;
|
||||
const { storageLayout } = output.contracts[artifact.sourceName][artifact.contractName];
|
||||
|
||||
if (!storageLayout) {
|
||||
throw new Error('Contract hasn\'t been compiled.');
|
||||
}
|
||||
|
||||
return storageLayout;
|
||||
};
|
||||
|
||||
async function getStorageSlotKey(contractName, variableName) {
|
||||
storageLayout = await getStorageLayout(contractName)
|
||||
|
||||
const { storage } = storageLayout;
|
||||
const targetState = storage.find((state) => state.label === variableName);
|
||||
|
||||
// Throw if state variable could not be found in storage layout.
|
||||
if (!targetState) {
|
||||
throw new Error('Variable not present in storage layout.');
|
||||
}
|
||||
|
||||
key = utils.hexlify(BigNumber.from(targetState.slot));
|
||||
return key
|
||||
};
|
||||
|
||||
async function deployCreate2Factory(provider, signer) {
|
||||
// Send eth to account as required to deploy create2 factory contract.
|
||||
let tx = {
|
||||
to: CREATE2_FACTORY_ACCOUNT,
|
||||
value: utils.parseEther('0.01')
|
||||
}
|
||||
|
||||
const txResponse = await signer.sendTransaction(tx);
|
||||
await txResponse.wait()
|
||||
|
||||
// Deploy create2 factory contract.
|
||||
await deployFactory(provider)
|
||||
}
|
||||
|
||||
module.exports = { getStorageSlotKey, deployCreate2Factory }
|
||||
@@ -0,0 +1,437 @@
|
||||
package integration_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
integration "github.com/vulcanize/ipld-eth-server/v4/test"
|
||||
)
|
||||
|
||||
var _ = Describe("Integration test", func() {
|
||||
directProxyEthCalls, err := strconv.ParseBool(os.Getenv("ETH_FORWARD_ETH_CALLS"))
|
||||
Expect(err).To(BeNil())
|
||||
gethHttpPath := "http://127.0.0.1:8545"
|
||||
gethClient, err := ethclient.Dial(gethHttpPath)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldEthHttpPath := "http://127.0.0.1:8081"
|
||||
ipldClient, err := ethclient.Dial(ipldEthHttpPath)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
var contract *integration.ContractDeployed
|
||||
var erc20TotalSupply *big.Int
|
||||
var tx *integration.Tx
|
||||
var bigIntResult bool
|
||||
var contractErr error
|
||||
var txErr error
|
||||
sleepInterval := 2 * time.Second
|
||||
|
||||
BeforeEach(func() {
|
||||
if !directProxyEthCalls {
|
||||
Skip("skipping direct-proxy-forwarding integration tests")
|
||||
}
|
||||
})
|
||||
|
||||
Describe("get Block", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("get not existing block by number", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
blockNum := contract.BlockNumber + 100
|
||||
|
||||
gethBlock, err := gethClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||
Expect(err).To(MatchError(ethereum.NotFound))
|
||||
Expect(gethBlock).To(BeZero())
|
||||
|
||||
ipldBlock, err := ipldClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||
Expect(err).To(MatchError(ethereum.NotFound))
|
||||
Expect(ipldBlock).To(BeZero())
|
||||
})
|
||||
|
||||
It("get not existing block by hash", func() {
|
||||
gethBlock, err := gethClient.BlockByHash(ctx, common.HexToHash(nonExistingBlockHash))
|
||||
Expect(err).To(MatchError(ethereum.NotFound))
|
||||
Expect(gethBlock).To(BeZero())
|
||||
|
||||
ipldBlock, err := ipldClient.BlockByHash(ctx, common.HexToHash(nonExistingBlockHash))
|
||||
Expect(err).To(MatchError(ethereum.NotFound))
|
||||
Expect(ipldBlock).To(BeZero())
|
||||
})
|
||||
|
||||
It("get block by number", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
blockNum := contract.BlockNumber
|
||||
|
||||
_, err := gethClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.BlockByNumber(ctx, big.NewInt(int64(blockNum)))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("get block by hash", func() {
|
||||
_, err := gethClient.BlockByHash(ctx, common.HexToHash(contract.BlockHash))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.BlockByHash(ctx, common.HexToHash(contract.BlockHash))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Transaction", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("Get tx by hash", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
_, _, err := gethClient.TransactionByHash(ctx, common.HexToHash(contract.TransactionHash))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, _, err = ipldClient.TransactionByHash(ctx, common.HexToHash(contract.TransactionHash))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Get tx by block hash and index", func() {
|
||||
_, err := gethClient.TransactionInBlock(ctx, common.HexToHash(contract.BlockHash), 0)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.TransactionInBlock(ctx, common.HexToHash(contract.BlockHash), 0)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Receipt", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("Get tx receipt", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
_, err := gethClient.TransactionReceipt(ctx, common.HexToHash(contract.TransactionHash))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.TransactionReceipt(ctx, common.HexToHash(contract.TransactionHash))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("FilterLogs", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("with blockhash", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
blockHash := common.HexToHash(contract.BlockHash)
|
||||
filterQuery := ethereum.FilterQuery{
|
||||
//Addresses: addresses,
|
||||
BlockHash: &blockHash,
|
||||
Topics: [][]common.Hash{},
|
||||
}
|
||||
|
||||
gethLogs, err := gethClient.FilterLogs(ctx, filterQuery)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldLogs, err := ipldClient.FilterLogs(ctx, filterQuery)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// not empty list
|
||||
Expect(gethLogs).ToNot(BeEmpty())
|
||||
// empty list
|
||||
Expect(ipldLogs).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("CodeAt", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("gets code at non-existing address without block number", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
gethCode, err := gethClient.CodeAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(gethCode).To(BeEmpty())
|
||||
Expect(gethCode).To(Equal(ipldCode))
|
||||
})
|
||||
It("gets code of deployed contract without block number", func() {
|
||||
_, err := gethClient.CodeAt(ctx, common.HexToAddress(contract.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(contract.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ipldCode).To(BeEmpty())
|
||||
})
|
||||
It("gets code of deployed contract with block number", func() {
|
||||
_, err := gethClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ipldCode).To(BeEmpty())
|
||||
})
|
||||
It("gets code of contract that doesn't exist at this height", func() {
|
||||
gethCode, err := gethClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber-1)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldCode, err := ipldClient.CodeAt(ctx, common.HexToAddress(contract.Address), big.NewInt(int64(contract.BlockNumber-1)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(gethCode).To(BeEmpty())
|
||||
Expect(gethCode).To(Equal(ipldCode))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Get balance", func() {
|
||||
address := "0x1111111111111111111111111111111111111112"
|
||||
BeforeEach(func() {
|
||||
tx, txErr = integration.SendEth(address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("gets balance for an account with eth without block number", func() {
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
|
||||
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gethBalance.String()).To(Equal(big.NewInt(10000000000000000).String()))
|
||||
|
||||
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ipldBalance.String()).To(Equal(big.NewInt(0).String()))
|
||||
})
|
||||
It("gets balance for an account with eth with block number", func() {
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
|
||||
_, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber)))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("gets historical balance for an account with eth with block number", func() {
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
|
||||
_, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber-1)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber-1)))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("gets balance for a non-existing account without block number", func() {
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
|
||||
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(nonExistingAddress), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(gethBalance).To(Equal(ipldBalance))
|
||||
})
|
||||
It("gets balance for an non-existing block number", func() {
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
|
||||
gethBalance, err := gethClient.BalanceAt(ctx, common.HexToAddress(address), big.NewInt(int64(tx.BlockNumber+3)))
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
|
||||
ipldBalance, err := ipldClient.BalanceAt(ctx, common.HexToAddress(nonExistingAddress), big.NewInt(int64(tx.BlockNumber+3)))
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
|
||||
Expect(gethBalance).To(Equal(ipldBalance))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Get Storage", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10)
|
||||
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("gets ERC20 total supply (without block number)", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
Expect(bigIntResult).To(Equal(true))
|
||||
|
||||
totalSupplyIndex := "0x2"
|
||||
|
||||
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
gethTotalSupply := new(big.Int).SetBytes(gethStorage)
|
||||
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||
|
||||
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ipldStorage).To(Equal(make([]byte, 32)))
|
||||
})
|
||||
|
||||
It("gets ERC20 total supply (with block number)", func() {
|
||||
totalSupplyIndex := "0x2"
|
||||
|
||||
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
gethTotalSupply := new(big.Int).SetBytes(gethStorage)
|
||||
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||
|
||||
_, err = ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
It("gets storage for non-existing account", func() {
|
||||
totalSupplyIndex := "0x2"
|
||||
|
||||
_, err := gethClient.StorageAt(ctx, common.HexToAddress(nonExistingAddress), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.StorageAt(ctx, common.HexToAddress(nonExistingAddress), common.HexToHash(totalSupplyIndex), big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
})
|
||||
It("gets storage for non-existing contract slot", func() {
|
||||
_, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), randomHash, big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), randomHash, big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
})
|
||||
It("gets storage for non-existing contract", func() {
|
||||
totalSupplyIndex := "0x2"
|
||||
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(0))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gethStorage).To(Equal(ipldStorage))
|
||||
})
|
||||
It("gets storage for non-existing block number", func() {
|
||||
blockNum := contract.BlockNumber + 100
|
||||
totalSupplyIndex := "0x2"
|
||||
|
||||
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(blockNum)))
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
|
||||
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(int64(blockNum)))
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
Expect(gethStorage).To(Equal(ipldStorage))
|
||||
})
|
||||
|
||||
It("get storage after self destruct", func() {
|
||||
totalSupplyIndex := "0x2"
|
||||
|
||||
tx, err := integration.DestroyContract(contract.Address)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
time.Sleep(sleepInterval)
|
||||
|
||||
gethStorage1, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber-1))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
gethStorage2, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(gethStorage1).NotTo(Equal(gethStorage2))
|
||||
Expect(gethStorage2).To(Equal(eth.EmptyNodeValue))
|
||||
|
||||
_, err = ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber-1))
|
||||
Expect(err).To(HaveOccurred())
|
||||
_, err = ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber))
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
|
||||
// Query the current block
|
||||
ipldStorage3, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(eth.EmptyNodeValue).To(Equal(ipldStorage3))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("eth call", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10)
|
||||
|
||||
time.Sleep(sleepInterval)
|
||||
})
|
||||
|
||||
It("calls totalSupply() without block number", func() {
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
Expect(bigIntResult).To(Equal(true))
|
||||
|
||||
contractAddress := common.HexToAddress(contract.Address)
|
||||
|
||||
msg := ethereum.CallMsg{
|
||||
To: &contractAddress,
|
||||
Data: common.Hex2Bytes("18160ddd"), // totalSupply()
|
||||
}
|
||||
gethResult, err := gethClient.CallContract(ctx, msg, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
gethTotalSupply := new(big.Int).SetBytes(gethResult)
|
||||
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||
|
||||
ipldResult, err := ipldClient.CallContract(ctx, msg, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(gethResult).To(Equal(ipldResult))
|
||||
})
|
||||
|
||||
It("calls totalSupply() with block number", func() {
|
||||
contractAddress := common.HexToAddress(contract.Address)
|
||||
|
||||
msg := ethereum.CallMsg{
|
||||
To: &contractAddress,
|
||||
Data: common.Hex2Bytes("18160ddd"), // totalSupply()
|
||||
}
|
||||
gethResult, err := gethClient.CallContract(ctx, msg, big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
gethTotalSupply := new(big.Int).SetBytes(gethResult)
|
||||
Expect(gethTotalSupply).To(Equal(erc20TotalSupply))
|
||||
|
||||
ipldResult, err := ipldClient.CallContract(ctx, msg, big.NewInt(int64(contract.BlockNumber)))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(gethResult).To(Equal(ipldResult))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Chain ID", func() {
|
||||
It("Check chain id", func() {
|
||||
_, err := gethClient.ChainID(ctx)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
_, err = ipldClient.ChainID(ctx)
|
||||
Expect(err).To(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
||||
+125
@@ -5,6 +5,9 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"net/http"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff/types"
|
||||
)
|
||||
|
||||
type ContractDeployed struct {
|
||||
@@ -14,6 +17,10 @@ type ContractDeployed struct {
|
||||
BlockHash string `json:"blockHash"`
|
||||
}
|
||||
|
||||
type ContractDestroyed struct {
|
||||
BlockNumber int64 `json:"blockNumber"`
|
||||
}
|
||||
|
||||
type Tx struct {
|
||||
From string `json:"from"`
|
||||
To string `json:"to"`
|
||||
@@ -23,6 +30,14 @@ type Tx struct {
|
||||
BlockHash string `json:"blockHash"`
|
||||
}
|
||||
|
||||
type StorageKey struct {
|
||||
Key string `json:"key"`
|
||||
}
|
||||
|
||||
type CountIncremented struct {
|
||||
BlockNumber int64 `json:"blockNumber"`
|
||||
}
|
||||
|
||||
const srvUrl = "http://localhost:3000"
|
||||
|
||||
func DeployContract() (*ContractDeployed, error) {
|
||||
@@ -43,6 +58,19 @@ func DeployContract() (*ContractDeployed, error) {
|
||||
return &contract, nil
|
||||
}
|
||||
|
||||
func DestroyContract(addr string) (*ContractDestroyed, error) {
|
||||
res, err := http.Get(fmt.Sprintf("%s/v1/destroyContract?addr=%s", srvUrl, addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data ContractDestroyed
|
||||
decoder := json.NewDecoder(res.Body)
|
||||
|
||||
return &data, decoder.Decode(&data)
|
||||
}
|
||||
|
||||
func SendEth(to string, value string) (*Tx, error) {
|
||||
res, err := http.Get(fmt.Sprintf("%s/v1/sendEth?to=%s&value=%s", srvUrl, to, value))
|
||||
if err != nil {
|
||||
@@ -60,3 +88,100 @@ func SendEth(to string, value string) (*Tx, error) {
|
||||
|
||||
return &tx, nil
|
||||
}
|
||||
|
||||
func DeploySLVContract() (*ContractDeployed, error) {
|
||||
res, err := http.Get(fmt.Sprintf("%s/v1/deploySLVContract", srvUrl))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var contract ContractDeployed
|
||||
|
||||
decoder := json.NewDecoder(res.Body)
|
||||
err = decoder.Decode(&contract)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &contract, nil
|
||||
}
|
||||
|
||||
func DestroySLVContract(addr string) (*ContractDestroyed, error) {
|
||||
res, err := http.Get(fmt.Sprintf("%s/v1/destroySLVContract?addr=%s", srvUrl, addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var data ContractDestroyed
|
||||
decoder := json.NewDecoder(res.Body)
|
||||
|
||||
return &data, decoder.Decode(&data)
|
||||
}
|
||||
|
||||
func IncrementCount(addr string, count string) (*CountIncremented, error) {
|
||||
res, err := http.Get(fmt.Sprintf("%s/v1/incrementCount%s?addr=%s", srvUrl, count, addr))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var blockNumber CountIncremented
|
||||
|
||||
decoder := json.NewDecoder(res.Body)
|
||||
err = decoder.Decode(&blockNumber)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &blockNumber, nil
|
||||
}
|
||||
|
||||
func GetStorageSlotKey(contract string, label string) (*StorageKey, error) {
|
||||
res, err := http.Get(fmt.Sprintf("%s/v1/getStorageKey?contract=%s&label=%s", srvUrl, contract, label))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var key StorageKey
|
||||
|
||||
decoder := json.NewDecoder(res.Body)
|
||||
err = decoder.Decode(&key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &key, nil
|
||||
}
|
||||
|
||||
func ClearWatchedAddresses(gethRPCClient *rpc.Client) error {
|
||||
gethMethod := "statediff_watchAddress"
|
||||
args := []types.WatchAddressArg{}
|
||||
|
||||
// Clear watched addresses
|
||||
gethErr := gethRPCClient.Call(nil, gethMethod, types.Clear, args)
|
||||
if gethErr != nil {
|
||||
return gethErr
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Create2Contract(contractName string, salt string) (*ContractDeployed, error) {
|
||||
res, err := http.Get(fmt.Sprintf("%s/v1/create2Contract?contract=%s&salt=%s", srvUrl, contractName, salt))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
var contract ContractDeployed
|
||||
|
||||
decoder := json.NewDecoder(res.Body)
|
||||
err = decoder.Decode(&contract)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &contract, nil
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package integration_test
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
|
||||
+119
-3
@@ -3,18 +3,21 @@ package integration_test
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
integration "github.com/vulcanize/ipld-eth-server/test"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/vulcanize/ipld-eth-server/v4/pkg/eth"
|
||||
integration "github.com/vulcanize/ipld-eth-server/v4/test"
|
||||
)
|
||||
|
||||
const nonExistingBlockHash = "0x111111111111111111111111111111111111111111111111111111111111111"
|
||||
@@ -26,6 +29,8 @@ var (
|
||||
)
|
||||
|
||||
var _ = Describe("Integration test", func() {
|
||||
directProxyEthCalls, err := strconv.ParseBool(os.Getenv("ETH_FORWARD_ETH_CALLS"))
|
||||
Expect(err).To(BeNil())
|
||||
gethHttpPath := "http://127.0.0.1:8545"
|
||||
gethClient, err := ethclient.Dial(gethHttpPath)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
@@ -44,6 +49,12 @@ var _ = Describe("Integration test", func() {
|
||||
var txErr error
|
||||
sleepInterval := 2 * time.Second
|
||||
|
||||
BeforeEach(func() {
|
||||
if directProxyEthCalls {
|
||||
Skip("skipping no-direct-proxy-forwarding integration tests")
|
||||
}
|
||||
})
|
||||
|
||||
Describe("get Block", func() {
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
@@ -312,6 +323,11 @@ var _ = Describe("Integration test", func() {
|
||||
})
|
||||
|
||||
Describe("Get Storage", func() {
|
||||
var slvContract *integration.ContractDeployed
|
||||
var slvCountA *big.Int
|
||||
|
||||
contractSalt := "SLVContractSalt"
|
||||
|
||||
BeforeEach(func() {
|
||||
contract, contractErr = integration.DeployContract()
|
||||
erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10)
|
||||
@@ -391,6 +407,106 @@ var _ = Describe("Integration test", func() {
|
||||
Expect(err).To(MatchError("header not found"))
|
||||
Expect(gethStorage).To(Equal(ipldStorage))
|
||||
})
|
||||
|
||||
It("get storage for SLV countA after tx", func() {
|
||||
slvContract, contractErr = integration.Create2Contract("SLVToken", contractSalt)
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
countAIndex := "0x5"
|
||||
|
||||
time.Sleep(sleepInterval)
|
||||
|
||||
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(slvContract.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
gethCountA := new(big.Int).SetBytes(gethStorage)
|
||||
slvCountA = gethCountA
|
||||
|
||||
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(slvContract.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldCountA := new(big.Int).SetBytes(ipldStorage)
|
||||
Expect(ipldCountA.String()).To(Equal(slvCountA.String()))
|
||||
|
||||
_, txErr = integration.IncrementCount(slvContract.Address, "A")
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
slvCountA.Add(slvCountA, big.NewInt(1))
|
||||
|
||||
time.Sleep(sleepInterval)
|
||||
|
||||
ipldStorage, err = ipldClient.StorageAt(ctx, common.HexToAddress(slvContract.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldCountA = new(big.Int).SetBytes(ipldStorage)
|
||||
Expect(ipldCountA.String()).To(Equal(slvCountA.String()))
|
||||
})
|
||||
|
||||
It("get storage after self destruct", func() {
|
||||
totalSupplyIndex := "0x2"
|
||||
countAIndex := "0x5"
|
||||
|
||||
tx, err := integration.DestroyContract(contract.Address)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
slvTx, err := integration.DestroyContract(slvContract.Address)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
time.Sleep(sleepInterval)
|
||||
|
||||
gethStorage1, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber-1))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
gethStorage2, err := gethClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(gethStorage1).NotTo(Equal(gethStorage2))
|
||||
Expect(gethStorage2).To(Equal(eth.EmptyNodeValue))
|
||||
|
||||
ipldStorage1, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber-1))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ipldStorage2, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), big.NewInt(tx.BlockNumber))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(ipldStorage1).To(Equal(gethStorage1))
|
||||
Expect(ipldStorage2).To(Equal(gethStorage2))
|
||||
|
||||
// Query the current block
|
||||
ipldStorage3, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract.Address), common.HexToHash(totalSupplyIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(ipldStorage2).To(Equal(ipldStorage3))
|
||||
|
||||
// Check for SLV contract
|
||||
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(slvContract.Address), common.HexToHash(countAIndex), big.NewInt(slvTx.BlockNumber))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(gethStorage).To(Equal(eth.EmptyNodeValue))
|
||||
|
||||
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(slvContract.Address), common.HexToHash(countAIndex), big.NewInt(slvTx.BlockNumber))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(ipldStorage).To(Equal(gethStorage))
|
||||
|
||||
slvCountA.Set(big.NewInt(0))
|
||||
})
|
||||
|
||||
It("get storage after redeploying", func() {
|
||||
slvContract, contractErr = integration.Create2Contract("SLVToken", contractSalt)
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
time.Sleep(sleepInterval)
|
||||
|
||||
countAIndex := "0x5"
|
||||
|
||||
gethStorage, err := gethClient.StorageAt(ctx, common.HexToAddress(slvContract.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
gethCountA := new(big.Int).SetBytes(gethStorage)
|
||||
Expect(gethCountA.String()).To(Equal(slvCountA.String()))
|
||||
|
||||
ipldStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(slvContract.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldCountA := new(big.Int).SetBytes(ipldStorage)
|
||||
Expect(ipldCountA.String()).To(Equal(slvCountA.String()))
|
||||
|
||||
Expect(gethStorage).To(Equal(ipldStorage))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("eth call", func() {
|
||||
@@ -474,7 +590,7 @@ func compareTxs(tx1 *types.Transaction, tx2 *types.Transaction) {
|
||||
Expect(tx1.Hash()).To(Equal(tx2.Hash()))
|
||||
Expect(tx1.Size()).To(Equal(tx2.Size()))
|
||||
|
||||
signer := types.NewEIP155Signer(big.NewInt(4))
|
||||
signer := types.NewEIP155Signer(big.NewInt(99))
|
||||
|
||||
gethSender, err := types.Sender(signer, tx1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
@@ -0,0 +1,670 @@
|
||||
package integration_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"os"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
integration "github.com/vulcanize/ipld-eth-server/v4/test"
|
||||
)
|
||||
|
||||
var (
|
||||
gethMethod = "statediff_watchAddress"
|
||||
ipldMethod = "vdb_watchAddress"
|
||||
|
||||
sleepInterval = 2 * time.Second
|
||||
)
|
||||
|
||||
var _ = Describe("WatchAddress integration test", func() {
|
||||
dbWrite, err := strconv.ParseBool(os.Getenv("DB_WRITE"))
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
gethHttpPath := "http://127.0.0.1:8545"
|
||||
gethRPCClient, err := rpc.Dial(gethHttpPath)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
ipldEthHttpPath := "http://127.0.0.1:8081"
|
||||
ipldClient, err := ethclient.Dial(ipldEthHttpPath)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ipldRPCClient, err := rpc.Dial(ipldEthHttpPath)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
var (
|
||||
ctx = context.Background()
|
||||
|
||||
txErr error
|
||||
contractErr error
|
||||
incErr error
|
||||
|
||||
contract1 *integration.ContractDeployed
|
||||
contract2 *integration.ContractDeployed
|
||||
contract3 *integration.ContractDeployed
|
||||
|
||||
countAIndex string
|
||||
|
||||
prevBalance1 *big.Int
|
||||
prevBalance2 *big.Int
|
||||
prevBalance3 *big.Int
|
||||
|
||||
actualBalance1 *big.Int
|
||||
actualBalance2 *big.Int
|
||||
actualBalance3 *big.Int
|
||||
|
||||
prevCountA1 *big.Int
|
||||
prevCountA2 *big.Int
|
||||
prevCountA3 *big.Int
|
||||
|
||||
actualCountA1 *big.Int
|
||||
actualCountA2 *big.Int
|
||||
actualCountA3 *big.Int
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
if !dbWrite {
|
||||
Skip("skipping WatchAddress API integration tests")
|
||||
}
|
||||
})
|
||||
|
||||
It("test init", func() {
|
||||
// Deploy three contracts
|
||||
contract1, contractErr = integration.DeploySLVContract()
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
contract2, contractErr = integration.DeploySLVContract()
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
contract3, contractErr = integration.DeploySLVContract()
|
||||
Expect(contractErr).ToNot(HaveOccurred())
|
||||
|
||||
// Get the storage slot key
|
||||
storageSlotAKey, err := integration.GetStorageSlotKey("SLVToken", "countA")
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countAIndex = storageSlotAKey.Key
|
||||
|
||||
// Clear out watched addresses
|
||||
err = integration.ClearWatchedAddresses(gethRPCClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Get initial balances for all the contracts
|
||||
// Contract 1
|
||||
actualBalance1 = big.NewInt(0)
|
||||
initBalance1, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract1.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(initBalance1.String()).To(Equal(actualBalance1.String()))
|
||||
prevBalance1 = big.NewInt(0)
|
||||
|
||||
// Contract 2
|
||||
actualBalance2 = big.NewInt(0)
|
||||
initBalance2, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract2.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(initBalance2.String()).To(Equal(actualBalance2.String()))
|
||||
prevBalance2 = big.NewInt(0)
|
||||
|
||||
// Contract 3
|
||||
actualBalance3 = big.NewInt(0)
|
||||
initBalance3, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract3.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(initBalance3.String()).To(Equal(actualBalance3.String()))
|
||||
prevBalance3 = big.NewInt(0)
|
||||
|
||||
// Get initial storage values for the contracts
|
||||
// Contract 1, countA
|
||||
actualCountA1 = big.NewInt(0)
|
||||
ipldCountA1Storage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract1.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ipldCountA1 := new(big.Int).SetBytes(ipldCountA1Storage)
|
||||
Expect(ipldCountA1.String()).To(Equal(actualCountA1.String()))
|
||||
prevCountA1 = big.NewInt(0)
|
||||
|
||||
// Contract 2, countA
|
||||
actualCountA2 = big.NewInt(0)
|
||||
ipldCountA2Storage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract2.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ipldCountA2 := new(big.Int).SetBytes(ipldCountA2Storage)
|
||||
Expect(ipldCountA2.String()).To(Equal(actualCountA2.String()))
|
||||
prevCountA2 = big.NewInt(0)
|
||||
|
||||
// Contract 3, countA
|
||||
actualCountA3 = big.NewInt(0)
|
||||
ipldCountA3Storage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract3.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
ipldCountA3 := new(big.Int).SetBytes(ipldCountA3Storage)
|
||||
Expect(ipldCountA3.String()).To(Equal(actualCountA2.String()))
|
||||
prevCountA3 = big.NewInt(0)
|
||||
})
|
||||
|
||||
defer It("test cleanup", func() {
|
||||
// Clear out watched addresses
|
||||
err := integration.ClearWatchedAddresses(gethRPCClient)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
})
|
||||
|
||||
Context("no contracts being watched", func() {
|
||||
It("indexes state for all the contracts", func() {
|
||||
// WatchedAddresses = []
|
||||
// Send eth to all three contract accounts
|
||||
// Contract 1
|
||||
_, txErr = integration.SendEth(contract1.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance1.Add(actualBalance1, big.NewInt(10000000000000000))
|
||||
|
||||
balance1AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract1.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance1AfterTransfer.String()).To(Equal(actualBalance1.String()))
|
||||
prevBalance1.Set(actualBalance1)
|
||||
|
||||
// Contract 2
|
||||
_, txErr = integration.SendEth(contract2.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance2.Add(actualBalance2, big.NewInt(10000000000000000))
|
||||
|
||||
balance2AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract2.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance2AfterTransfer.String()).To(Equal(actualBalance2.String()))
|
||||
prevBalance2.Set(actualBalance2)
|
||||
|
||||
// Contract 3
|
||||
_, txErr = integration.SendEth(contract3.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance3.Add(actualBalance3, big.NewInt(10000000000000000))
|
||||
|
||||
balance3AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract3.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance3AfterTransfer.String()).To(Equal(actualBalance3.String()))
|
||||
prevBalance3.Set(actualBalance3)
|
||||
|
||||
// Increment counts
|
||||
// Contract 1, countA
|
||||
_, incErr = integration.IncrementCount(contract1.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA1.Add(actualCountA1, big.NewInt(1))
|
||||
|
||||
countA1AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract1.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA1AfterIncrement := new(big.Int).SetBytes(countA1AfterIncrementStorage)
|
||||
Expect(countA1AfterIncrement.String()).To(Equal(actualCountA1.String()))
|
||||
prevCountA1.Set(actualCountA1)
|
||||
|
||||
// Contract 2, countA
|
||||
_, incErr = integration.IncrementCount(contract2.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA2.Add(actualCountA2, big.NewInt(1))
|
||||
|
||||
countA2AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract2.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA2AfterIncrement := new(big.Int).SetBytes(countA2AfterIncrementStorage)
|
||||
Expect(countA2AfterIncrement.String()).To(Equal(actualCountA2.String()))
|
||||
prevCountA2.Set(actualCountA2)
|
||||
|
||||
// Contract 3, countA
|
||||
_, incErr = integration.IncrementCount(contract3.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA3.Add(actualCountA3, big.NewInt(1))
|
||||
|
||||
countA3AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract3.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA3AfterIncrement := new(big.Int).SetBytes(countA3AfterIncrementStorage)
|
||||
Expect(countA3AfterIncrement.String()).To(Equal(actualCountA3.String()))
|
||||
prevCountA3.Set(actualCountA3)
|
||||
})
|
||||
})
|
||||
|
||||
Context("one contract being watched", func() {
|
||||
It("indexes state only for the watched contract", func() {
|
||||
operation := sdtypes.Add
|
||||
args := []sdtypes.WatchAddressArg{
|
||||
{
|
||||
Address: contract1.Address,
|
||||
CreatedAt: uint64(contract1.BlockNumber),
|
||||
},
|
||||
}
|
||||
ipldErr := ipldRPCClient.Call(nil, ipldMethod, operation, args)
|
||||
Expect(ipldErr).ToNot(HaveOccurred())
|
||||
|
||||
// WatchedAddresses = [Contract1]
|
||||
// Send eth to all three contract accounts
|
||||
// Contract 1
|
||||
_, txErr = integration.SendEth(contract1.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance1.Add(actualBalance1, big.NewInt(10000000000000000))
|
||||
|
||||
balance1AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract1.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance1AfterTransfer.String()).To(Equal(actualBalance1.String()))
|
||||
prevBalance1.Set(actualBalance1)
|
||||
|
||||
// Contract 2
|
||||
_, txErr = integration.SendEth(contract2.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance2.Add(actualBalance2, big.NewInt(10000000000000000))
|
||||
|
||||
balance2AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract2.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance2AfterTransfer.String()).To(Equal(prevBalance2.String()))
|
||||
|
||||
// Contract 3
|
||||
_, txErr = integration.SendEth(contract3.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance3.Add(actualBalance3, big.NewInt(10000000000000000))
|
||||
|
||||
balance3AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract3.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance3AfterTransfer.String()).To(Equal(prevBalance3.String()))
|
||||
|
||||
// Increment counts
|
||||
// Contract 1, countA
|
||||
_, incErr = integration.IncrementCount(contract1.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA1.Add(actualCountA1, big.NewInt(1))
|
||||
|
||||
countA1AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract1.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA1AfterIncrement := new(big.Int).SetBytes(countA1AfterIncrementStorage)
|
||||
Expect(countA1AfterIncrement.String()).To(Equal(actualCountA1.String()))
|
||||
prevCountA1.Set(actualCountA1)
|
||||
|
||||
// Contract 2, countA
|
||||
_, incErr = integration.IncrementCount(contract2.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA2.Add(actualCountA2, big.NewInt(1))
|
||||
|
||||
countA2AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract2.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA2AfterIncrement := new(big.Int).SetBytes(countA2AfterIncrementStorage)
|
||||
Expect(countA2AfterIncrement.String()).To(Equal(prevCountA2.String()))
|
||||
|
||||
// Contract 3, countA
|
||||
_, incErr = integration.IncrementCount(contract3.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA3.Add(actualCountA3, big.NewInt(1))
|
||||
|
||||
countA3AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract3.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA3AfterIncrement := new(big.Int).SetBytes(countA3AfterIncrementStorage)
|
||||
Expect(countA3AfterIncrement.String()).To(Equal(prevCountA3.String()))
|
||||
})
|
||||
})
|
||||
|
||||
Context("contract added to a non-empty watch-list", func() {
|
||||
It("indexes state only for the watched contracts", func() {
|
||||
operation := sdtypes.Add
|
||||
args := []sdtypes.WatchAddressArg{
|
||||
{
|
||||
Address: contract2.Address,
|
||||
CreatedAt: uint64(contract2.BlockNumber),
|
||||
},
|
||||
}
|
||||
ipldErr := ipldRPCClient.Call(nil, ipldMethod, operation, args)
|
||||
Expect(ipldErr).ToNot(HaveOccurred())
|
||||
|
||||
// WatchedAddresses = [Contract1, Contract2]
|
||||
// Send eth to all three contract accounts
|
||||
// Contract 1
|
||||
_, txErr = integration.SendEth(contract1.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance1.Add(actualBalance1, big.NewInt(10000000000000000))
|
||||
|
||||
balance1AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract1.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance1AfterTransfer.String()).To(Equal(actualBalance1.String()))
|
||||
prevBalance1.Set(actualBalance1)
|
||||
|
||||
// Contract 2
|
||||
_, txErr = integration.SendEth(contract2.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance2.Add(actualBalance2, big.NewInt(10000000000000000))
|
||||
|
||||
balance2AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract2.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance2AfterTransfer.String()).To(Equal(actualBalance2.String()))
|
||||
prevBalance2.Set(actualBalance2)
|
||||
|
||||
// Contract 3
|
||||
_, txErr = integration.SendEth(contract3.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance3.Add(actualBalance3, big.NewInt(10000000000000000))
|
||||
|
||||
balance3AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract3.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance3AfterTransfer.String()).To(Equal(prevBalance3.String()))
|
||||
|
||||
// Increment counts
|
||||
// Contract 1, countA
|
||||
_, incErr = integration.IncrementCount(contract1.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA1.Add(actualCountA1, big.NewInt(1))
|
||||
|
||||
countA1AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract1.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA1AfterIncrement := new(big.Int).SetBytes(countA1AfterIncrementStorage)
|
||||
Expect(countA1AfterIncrement.String()).To(Equal(actualCountA1.String()))
|
||||
prevCountA1.Set(actualCountA1)
|
||||
|
||||
// Contract 2, countA
|
||||
_, incErr = integration.IncrementCount(contract2.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA2.Add(actualCountA2, big.NewInt(1))
|
||||
|
||||
countA2AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract2.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA2AfterIncrement := new(big.Int).SetBytes(countA2AfterIncrementStorage)
|
||||
Expect(countA2AfterIncrement.String()).To(Equal(actualCountA2.String()))
|
||||
prevCountA2.Set(actualCountA2)
|
||||
|
||||
// Contract 3, countA
|
||||
_, incErr = integration.IncrementCount(contract3.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA3.Add(actualCountA3, big.NewInt(1))
|
||||
|
||||
countA3AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract3.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA3AfterIncrement := new(big.Int).SetBytes(countA3AfterIncrementStorage)
|
||||
Expect(countA3AfterIncrement.String()).To(Equal(prevCountA3.String()))
|
||||
})
|
||||
})
|
||||
|
||||
Context("contract removed from the watch-list", func() {
|
||||
It("indexes state only for the watched contract", func() {
|
||||
operation := sdtypes.Remove
|
||||
args := []sdtypes.WatchAddressArg{
|
||||
{
|
||||
Address: contract1.Address,
|
||||
CreatedAt: uint64(contract1.BlockNumber),
|
||||
},
|
||||
}
|
||||
ipldErr := ipldRPCClient.Call(nil, ipldMethod, operation, args)
|
||||
Expect(ipldErr).ToNot(HaveOccurred())
|
||||
|
||||
// WatchedAddresses = [Contract2]
|
||||
// Send eth to all three contract accounts
|
||||
// Contract 1
|
||||
_, txErr = integration.SendEth(contract1.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance1.Add(actualBalance1, big.NewInt(10000000000000000))
|
||||
|
||||
balance1AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract1.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance1AfterTransfer.String()).To(Equal(prevBalance1.String()))
|
||||
|
||||
// Contract 2
|
||||
_, txErr = integration.SendEth(contract2.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance2.Add(actualBalance2, big.NewInt(10000000000000000))
|
||||
|
||||
balance2AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract2.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance2AfterTransfer.String()).To(Equal(actualBalance2.String()))
|
||||
prevBalance2.Set(actualBalance2)
|
||||
|
||||
// Contract 3
|
||||
_, txErr = integration.SendEth(contract3.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance3.Add(actualBalance3, big.NewInt(10000000000000000))
|
||||
|
||||
balance3AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract3.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance3AfterTransfer.String()).To(Equal(prevBalance3.String()))
|
||||
|
||||
// Increment counts
|
||||
// Contract 1, countA
|
||||
_, incErr = integration.IncrementCount(contract1.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA1.Add(actualCountA1, big.NewInt(1))
|
||||
|
||||
countA1AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract1.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA1AfterIncrement := new(big.Int).SetBytes(countA1AfterIncrementStorage)
|
||||
Expect(countA1AfterIncrement.String()).To(Equal(prevCountA1.String()))
|
||||
|
||||
// Contract 2, countA
|
||||
_, incErr = integration.IncrementCount(contract2.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA2.Add(actualCountA2, big.NewInt(1))
|
||||
|
||||
countA2AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract2.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA2AfterIncrement := new(big.Int).SetBytes(countA2AfterIncrementStorage)
|
||||
Expect(countA2AfterIncrement.String()).To(Equal(actualCountA2.String()))
|
||||
prevCountA2.Set(actualCountA2)
|
||||
|
||||
// Contract 3, countA
|
||||
_, incErr = integration.IncrementCount(contract3.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA3.Add(actualCountA3, big.NewInt(1))
|
||||
|
||||
countA3AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract3.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA3AfterIncrement := new(big.Int).SetBytes(countA3AfterIncrementStorage)
|
||||
Expect(countA3AfterIncrement.String()).To(Equal(prevCountA3.String()))
|
||||
})
|
||||
})
|
||||
|
||||
Context("list of watched addresses set", func() {
|
||||
It("indexes state only for the watched contracts", func() {
|
||||
operation := sdtypes.Set
|
||||
args := []sdtypes.WatchAddressArg{
|
||||
{
|
||||
Address: contract1.Address,
|
||||
CreatedAt: uint64(contract1.BlockNumber),
|
||||
},
|
||||
{
|
||||
Address: contract3.Address,
|
||||
CreatedAt: uint64(contract3.BlockNumber),
|
||||
},
|
||||
}
|
||||
ipldErr := ipldRPCClient.Call(nil, ipldMethod, operation, args)
|
||||
Expect(ipldErr).ToNot(HaveOccurred())
|
||||
|
||||
// WatchedAddresses = [Contract1, Contract3]
|
||||
// Send eth to all three contract accounts
|
||||
// Contract 1
|
||||
_, txErr = integration.SendEth(contract1.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance1.Add(actualBalance1, big.NewInt(10000000000000000))
|
||||
|
||||
balance1AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract1.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance1AfterTransfer.String()).To(Equal(actualBalance1.String()))
|
||||
prevBalance1.Set(actualBalance1)
|
||||
|
||||
// Contract 2
|
||||
_, txErr = integration.SendEth(contract2.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance2.Add(actualBalance2, big.NewInt(10000000000000000))
|
||||
|
||||
balance2AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract2.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance2AfterTransfer.String()).To(Equal(prevBalance2.String()))
|
||||
|
||||
// Contract 3
|
||||
_, txErr = integration.SendEth(contract3.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance3.Add(actualBalance3, big.NewInt(10000000000000000))
|
||||
|
||||
balance3AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract3.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance3AfterTransfer.String()).To(Equal(actualBalance3.String()))
|
||||
prevBalance3.Set(actualBalance3)
|
||||
|
||||
// Increment counts
|
||||
// Contract 1, countA
|
||||
_, incErr = integration.IncrementCount(contract1.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA1.Add(actualCountA1, big.NewInt(1))
|
||||
|
||||
countA1AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract1.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA1AfterIncrement := new(big.Int).SetBytes(countA1AfterIncrementStorage)
|
||||
Expect(countA1AfterIncrement.String()).To(Equal(actualCountA1.String()))
|
||||
prevCountA1.Set(actualCountA1)
|
||||
|
||||
// Contract 2, countA
|
||||
_, incErr = integration.IncrementCount(contract2.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA2.Add(actualCountA2, big.NewInt(1))
|
||||
|
||||
countA2AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract2.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA2AfterIncrement := new(big.Int).SetBytes(countA2AfterIncrementStorage)
|
||||
Expect(countA2AfterIncrement.String()).To(Equal(prevCountA2.String()))
|
||||
|
||||
// Contract 3, countA
|
||||
_, incErr = integration.IncrementCount(contract3.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA3.Add(actualCountA3, big.NewInt(1))
|
||||
|
||||
countA3AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract3.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA3AfterIncrement := new(big.Int).SetBytes(countA3AfterIncrementStorage)
|
||||
Expect(countA3AfterIncrement.String()).To(Equal(actualCountA3.String()))
|
||||
prevCountA3.Set(actualCountA3)
|
||||
})
|
||||
})
|
||||
|
||||
Context("list of watched addresses cleared", func() {
|
||||
It("indexes state for all the contracts", func() {
|
||||
operation := sdtypes.Clear
|
||||
args := []sdtypes.WatchAddressArg{}
|
||||
ipldErr := ipldRPCClient.Call(nil, ipldMethod, operation, args)
|
||||
Expect(ipldErr).ToNot(HaveOccurred())
|
||||
|
||||
// WatchedAddresses = []
|
||||
// Send eth to all three contract accounts
|
||||
// Contract 1
|
||||
_, txErr = integration.SendEth(contract1.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance1.Add(actualBalance1, big.NewInt(10000000000000000))
|
||||
|
||||
balance1AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract1.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance1AfterTransfer.String()).To(Equal(actualBalance1.String()))
|
||||
prevBalance1.Set(actualBalance1)
|
||||
|
||||
// Contract 2
|
||||
_, txErr = integration.SendEth(contract2.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance2.Add(actualBalance2, big.NewInt(10000000000000000))
|
||||
|
||||
balance2AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract2.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance2AfterTransfer.String()).To(Equal(actualBalance2.String()))
|
||||
prevBalance2.Set(actualBalance2)
|
||||
|
||||
// Contract 3
|
||||
_, txErr = integration.SendEth(contract3.Address, "0.01")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(txErr).ToNot(HaveOccurred())
|
||||
actualBalance3.Add(actualBalance3, big.NewInt(10000000000000000))
|
||||
|
||||
balance3AfterTransfer, err := ipldClient.BalanceAt(ctx, common.HexToAddress(contract3.Address), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(balance3AfterTransfer.String()).To(Equal(actualBalance3.String()))
|
||||
prevBalance3.Set(actualBalance3)
|
||||
|
||||
// Increment counts
|
||||
// Contract 1, countA
|
||||
_, incErr = integration.IncrementCount(contract1.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA1.Add(actualCountA1, big.NewInt(1))
|
||||
|
||||
countA1AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract1.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA1AfterIncrement := new(big.Int).SetBytes(countA1AfterIncrementStorage)
|
||||
Expect(countA1AfterIncrement.String()).To(Equal(actualCountA1.String()))
|
||||
prevCountA1.Set(actualCountA1)
|
||||
|
||||
// Contract 2, countA
|
||||
_, incErr = integration.IncrementCount(contract2.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA2.Add(actualCountA2, big.NewInt(1))
|
||||
|
||||
countA2AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract2.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA2AfterIncrement := new(big.Int).SetBytes(countA2AfterIncrementStorage)
|
||||
Expect(countA2AfterIncrement.String()).To(Equal(actualCountA2.String()))
|
||||
prevCountA2.Set(actualCountA2)
|
||||
|
||||
// Contract 3, countA
|
||||
_, incErr = integration.IncrementCount(contract3.Address, "A")
|
||||
time.Sleep(sleepInterval)
|
||||
Expect(incErr).ToNot(HaveOccurred())
|
||||
actualCountA3.Add(actualCountA3, big.NewInt(1))
|
||||
|
||||
countA3AfterIncrementStorage, err := ipldClient.StorageAt(ctx, common.HexToAddress(contract3.Address), common.HexToHash(countAIndex), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
countA3AfterIncrement := new(big.Int).SetBytes(countA3AfterIncrementStorage)
|
||||
Expect(countA3AfterIncrement.String()).To(Equal(actualCountA3.String()))
|
||||
prevCountA3.Set(actualCountA3)
|
||||
})
|
||||
})
|
||||
|
||||
Context("with invalid args", func() {
|
||||
It("returns an error on invalid operation arg", func() {
|
||||
operation := "WrongOp"
|
||||
args := []sdtypes.WatchAddressArg{}
|
||||
|
||||
gethErr := gethRPCClient.Call(nil, gethMethod, operation, args)
|
||||
Expect(gethErr).To(HaveOccurred())
|
||||
|
||||
ipldErr := ipldRPCClient.Call(nil, ipldMethod, operation, args)
|
||||
Expect(ipldErr).To(HaveOccurred())
|
||||
|
||||
Expect(ipldErr).To(Equal(gethErr))
|
||||
})
|
||||
|
||||
It("returns an error on args of invalid type", func() {
|
||||
operation := sdtypes.Add
|
||||
args := []string{"WrongArg"}
|
||||
|
||||
gethErr := gethRPCClient.Call(nil, gethMethod, operation, args)
|
||||
Expect(gethErr).To(HaveOccurred())
|
||||
|
||||
ipldErr := ipldRPCClient.Call(nil, ipldMethod, operation, args)
|
||||
Expect(ipldErr).To(HaveOccurred())
|
||||
|
||||
Expect(ipldErr).To(Equal(gethErr))
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -19,10 +19,9 @@ package test_config
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/vulcanize/ipld-eth-indexer/pkg/postgres"
|
||||
)
|
||||
|
||||
var DBConfig postgres.Config
|
||||
@@ -54,8 +53,8 @@ func setTestConfig() {
|
||||
name := vip.GetString("database.name")
|
||||
|
||||
DBConfig = postgres.Config{
|
||||
Hostname: hn,
|
||||
Name: name,
|
||||
Port: port,
|
||||
Hostname: hn,
|
||||
DatabaseName: name,
|
||||
Port: port,
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -19,10 +19,10 @@ package version
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
Major = 0 // Major version component of the current release
|
||||
Minor = 3 // Minor version component of the current release
|
||||
Patch = 6 // Patch version component of the current release
|
||||
Meta = "alpha" // Version metadata to append to the version string
|
||||
Major = 2 // Major version component of the current release
|
||||
Minor = 0 // Minor version component of the current release
|
||||
Patch = 0 // Patch version component of the current release
|
||||
Meta = "" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
// Version holds the textual version string.
|
||||
|
||||
Reference in New Issue
Block a user