diff --git a/.github/workflows/on-pr.yaml b/.github/workflows/on-pr.yaml index d33adc7a..0770355a 100644 --- a/.github/workflows/on-pr.yaml +++ b/.github/workflows/on-pr.yaml @@ -38,6 +38,10 @@ jobs: name: Run integration tests env: GOPATH: /tmp/go + DB_WRITE: true + ETH_FORWARD_ETH_CALLS: false + ETH_PROXY_ON_ERROR: false + ETH_HTTP_PATH: "" strategy: matrix: go-version: [1.16.x] @@ -58,3 +62,32 @@ jobs: 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: + GOPATH: /tmp/go + DB_WRITE: false + ETH_FORWARD_ETH_CALLS: true + ETH_PROXY_ON_ERROR: false + ETH_HTTP_PATH: "dapptools:8545" + strategy: + matrix: + go-version: [ 1.16.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 ipld-eth-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 diff --git a/Makefile b/Makefile index 3da04bf9..6cecdaa5 100644 --- a/Makefile +++ b/Makefile @@ -75,7 +75,8 @@ test_local: | $(GINKGO) $(GOOSE) integrationtest_local: | $(GINKGO) $(GOOSE) go vet ./... go fmt ./... - ./scripts/run_intregration_test.sh + ./scripts/run_integration_test.sh + ./scripts/run_integration_test_forward_eth_calls.sh build: go fmt ./... @@ -144,4 +145,4 @@ import: ## Build docker image .PHONY: docker-build docker-build: - docker build -t vulcanize/ipld-eth-server . \ No newline at end of file + docker build -t vulcanize/ipld-eth-server . diff --git a/cmd/serve.go b/cmd/serve.go index e050c281..11330ad6 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -344,7 +344,9 @@ 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") @@ -392,6 +394,8 @@ 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")) diff --git a/cmd/validate.go b/cmd/validate.go index c91fb918..1fcd5a82 100644 --- a/cmd/validate.go +++ b/cmd/validate.go @@ -63,12 +63,12 @@ func validate() { ExpiryDuration: time.Minute * time.Duration(CacheExpiryInMins), }) - validator := validator.NewValidator(nil, ethDB) - if err = validator.ValidateTrie(stateRoot); err != nil { + val := validator.NewValidator(nil, ethDB) + if err = val.ValidateTrie(stateRoot); err != nil { log.Fatalln("Error validating state root") } - stats := ethDB.GetCacheStats() + stats := ethDB.(*ipfsethdb.Database).GetCacheStats() log.Debugf("groupcache stats %+v", stats) log.Infoln("Successfully validated state root") diff --git a/docker-compose.yml b/docker-compose.yml index cbd0070e..fe0baff1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -5,13 +5,14 @@ services: restart: unless-stopped depends_on: - ipld-eth-db - image: vulcanize/dapptools:v0.30.0-v1.10.11-statediff-0.0.27 + image: vulcanize/dapptools:v0.30.0-v1.10.14-statediff-0.0.29 environment: DB_USER: vdbm DB_NAME: vulcanize_testing DB_HOST: ipld-eth-db DB_PORT: 5432 DB_PASSWORD: password + DB_WRITE: $DB_WRITE ports: - "127.0.0.1:8545:8545" - "127.0.0.1:8546:8546" @@ -50,6 +51,9 @@ services: 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 diff --git a/environments/example.toml b/environments/example.toml index 7ba9a6e6..102a592c 100644 --- a/environments/example.toml +++ b/environments/example.toml @@ -21,7 +21,9 @@ 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 \ No newline at end of file + networkID = "1" # $ETH_NETWORK_ID diff --git a/go.mod b/go.mod index 8f21e5ef..9fcc2576 100644 --- a/go.mod +++ b/go.mod @@ -1,23 +1,25 @@ module github.com/vulcanize/ipld-eth-server -go 1.13 +go 1.15 require ( - github.com/ethereum/go-ethereum v1.10.11 + github.com/ethereum/go-ethereum v1.10.14 github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/graph-gophers/graphql-go v0.0.0-20201113091052-beb923fada29 github.com/ipfs/go-block-format v0.0.3 + github.com/ipfs/go-blockservice v0.1.7 github.com/ipfs/go-cid v0.0.7 + github.com/ipfs/go-ipfs v0.10.0 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/lib/pq v1.10.4 github.com/machinebox/graphql v0.2.2 github.com/mailgun/groupcache/v2 v2.2.1 github.com/matryer/is v1.4.0 // indirect github.com/multiformats/go-multihash v0.0.15 - github.com/onsi/ginkgo v1.16.4 + github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.13.0 github.com/prometheus/client_golang v1.11.0 github.com/shirou/gopsutil v3.21.5+incompatible // indirect @@ -25,11 +27,12 @@ require ( 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/vulcanize/eth-ipfs-state-validator v0.0.2 + github.com/vulcanize/eth-ipfs-state-validator v0.1.0 github.com/vulcanize/gap-filler v0.3.1 - github.com/vulcanize/ipfs-ethdb v0.0.5 - golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac // indirect - golang.org/x/tools v0.1.7 // indirect + github.com/vulcanize/ipfs-ethdb v0.0.6 + golang.org/x/crypto v0.0.0-20211202192323-5770296d904e // indirect + golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect + golang.org/x/tools v0.1.8 // indirect ) -replace github.com/ethereum/go-ethereum v1.10.11 => github.com/vulcanize/go-ethereum v1.10.11-statediff-0.0.27 +replace github.com/ethereum/go-ethereum v1.10.14 => github.com/vulcanize/go-ethereum v1.10.14-statediff-0.0.29 diff --git a/go.sum b/go.sum index 56c2d6dd..1c0fce9f 100644 --- a/go.sum +++ b/go.sum @@ -245,7 +245,6 @@ github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwu github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf h1:sh8rkQZavChcmakYiSlqu2425CHyFXLZZnvm7PDpU8M= github.com/docker/docker v1.4.2-0.20180625184442-8e610b2b55bf/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/dop251/goja v0.0.0-20200106141417-aaec0e7bde29/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= -github.com/dop251/goja v0.0.0-20200721192441-a695b0cdd498/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA= github.com/dop251/goja v0.0.0-20211011172007-d99e4b8cbf48/go.mod h1:R9ET47fwRVRPZnOGvHxxhuZcbrMCuiqOz3Rlrh4KSnk= github.com/dop251/goja_nodejs v0.0.0-20210225215109-d91c329300e7/go.mod h1:hn7BA7c8pLvoGndExHudxTDKZ84Pyvv+90pbBjbTz0Y= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -268,7 +267,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ethereum/go-ethereum v1.9.11/go.mod h1:7oC0Ni6dosMv5pxMigm6s0hN8g4haJMBnqmmo0D9YfQ= -github.com/ethereum/go-ethereum v1.10.9/go.mod h1:CaTMQrv51WaAlD2eULQ3f03KiahDRO28fleQcKjWrrg= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 h1:BBso6MBKW8ncyZLv37o+KNyy0HrrHgfnOaGQC2qvN+A= github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5/go.mod h1:JpoxHjuQauoxiFMl1ie8Xc/7TfLuMZ5eOCONd1sUBHg= github.com/fatih/color v1.3.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -818,8 +816,9 @@ github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.5.2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= +github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libp2p/go-addr-util v0.0.1/go.mod h1:4ac6O7n9rIAKB1dnd+s8IbbMXkt+oBpzX4/+RACcnlQ= github.com/libp2p/go-addr-util v0.0.2/go.mod h1:Ecd6Fb3yIuLzq4bD7VcywcVSBtefcAwnUISBM3WG15E= github.com/libp2p/go-addr-util v0.1.0 h1:acKsntI33w2bTU7tC9a0SaPimJGfSI0bFKC18ChxeVI= @@ -1349,8 +1348,9 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E= -github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -1597,14 +1597,14 @@ github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPU github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/vulcanize/eth-ipfs-state-validator v0.0.2 h1:d1RUwdIbRAVaCTxrVZ2z4oitlbH8HlcosPWDKJKkWA0= -github.com/vulcanize/eth-ipfs-state-validator v0.0.2/go.mod h1:gBnqe4oycf5Frm/pNrXICJ/p49Wssn+Asu4fnM/stVI= +github.com/vulcanize/eth-ipfs-state-validator v0.1.0 h1:ZB54GOUrxQeSYvOmqk8jMgtGzG+Oyh7YeSCio9vCEPE= +github.com/vulcanize/eth-ipfs-state-validator v0.1.0/go.mod h1:QtmfhqDjN29UHHk2Fb+ouzO4j/lbhM7GuiEmxHIKdzk= github.com/vulcanize/gap-filler v0.3.1 h1:N5d+jCJo/VTWFvBSbTD7biRhK/OqDZzi1tgA85SIBKs= github.com/vulcanize/gap-filler v0.3.1/go.mod h1:qowG1cgshVpBqMokiWro/1xhh0uypw7oAu8FQ42JMy4= -github.com/vulcanize/go-ethereum v1.10.11-statediff-0.0.27 h1:ldAVLlKll2WHHKLNu8oKbkYRUVRs9T45z12KiSrRW24= -github.com/vulcanize/go-ethereum v1.10.11-statediff-0.0.27/go.mod h1:9L+QY31AnWnX2/2HDOySCjQoYUdWNGBRMezFJVfH73E= -github.com/vulcanize/ipfs-ethdb v0.0.5 h1:8hTTIP+fj8hXM6gVt/JoV7l0lVabnJUreXCEhc3Srq8= -github.com/vulcanize/ipfs-ethdb v0.0.5/go.mod h1:dITNR40SaglTI6EbIFiMpTs1bCnHj4yG9uR8l920+WU= +github.com/vulcanize/go-ethereum v1.10.14-statediff-0.0.29 h1:kjZjteD/6vh9DcixPkrg27XtxKW7ZoV5++1EYAi6FAw= +github.com/vulcanize/go-ethereum v1.10.14-statediff-0.0.29/go.mod h1:9L+QY31AnWnX2/2HDOySCjQoYUdWNGBRMezFJVfH73E= +github.com/vulcanize/ipfs-ethdb v0.0.6 h1:Jl+YHtee5Zd8jD9wix2aJLYXwX/WpPt37QBzoz8pVwM= +github.com/vulcanize/ipfs-ethdb v0.0.6/go.mod h1:DvZpevG89N5ST26WeaErQ+31Q1lQwGBEhn/s9wgGo3g= github.com/wangjia184/sortedset v0.0.0-20160527075905-f5d03557ba30/go.mod h1:YkocrP2K2tcw938x9gCOmT5G5eCD6jsTz0SZuyAqwIE= github.com/warpfork/go-testmark v0.3.0 h1:Q81c4u7hT+BR5kNfNQhEF0VT2pmL7+Kk0wD+ORYl7iA= github.com/warpfork/go-testmark v0.3.0/go.mod h1:jhEf8FVxd+F17juRubpmut64NEG6I2rgkUhlcqqXwE0= @@ -1645,7 +1645,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= @@ -1737,8 +1737,9 @@ golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWP golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210506145944-38f3c27a63bf/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e h1:VvfwVmMH40bpMeizC9/K7ipM5Qjucuu16RWfneFPyhQ= golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -1777,8 +1778,9 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= +golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1835,9 +1837,10 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d h1:LO7XpTYMwTqxjLcGWPijK3vRXg1aWdlNOVOHRq45d7c= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -1948,10 +1951,10 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= +golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2035,8 +2038,8 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1-0.20210225150353-54dc8c5edb56/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= +golang.org/x/tools v0.1.8 h1:P1HhGGuLW4aAclzjtmJdf0mJOjVUZUzOTqkAkWL+l6w= +golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2171,7 +2174,6 @@ gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU= gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20190213234257-ec84240a7772/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= -gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0= gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= diff --git a/pkg/eth/api.go b/pkg/eth/api.go index 15d6ea17..340d1ec2 100644 --- a/pkg/eth/api.go +++ b/pkg/eth/api.go @@ -57,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) @@ -73,7 +81,9 @@ func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff bool) *Pu supportsStateDiff: supportsStateDiff, rpc: client, ethClient: ethClient, - } + forwardEthCalls: forwardEthCalls, + proxyOnError: proxyOnError, + }, nil } /* @@ -90,7 +100,7 @@ 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) @@ -109,7 +119,7 @@ func (pea *PublicEthAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) } } - 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 { @@ -151,7 +161,7 @@ func (pea *PublicEthAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockN 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) @@ -169,7 +179,7 @@ func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, f 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) @@ -180,20 +190,21 @@ func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, f } // 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()) - - return 0 + if pea.proxyOnError { + if id, err := pea.ethClient.ChainID(context.Background()); err == nil { + return (*hexutil.Big)(id), nil + } + } + return nil, err } 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") } /* @@ -216,7 +227,7 @@ func (pea *PublicEthAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, bloc 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) @@ -240,7 +251,7 @@ func (pea *PublicEthAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockH 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) @@ -257,7 +268,7 @@ func (pea *PublicEthAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr 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()) @@ -275,7 +286,7 @@ func (pea *PublicEthAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash 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) @@ -299,7 +310,7 @@ func (pea *PublicEthAPI) GetTransactionCount(ctx context.Context, address common 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) @@ -327,7 +338,7 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByNumber(ctx context.Context, b 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()) @@ -345,7 +356,7 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByHash(ctx context.Context, blo 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) @@ -362,7 +373,7 @@ func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context 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()) @@ -379,7 +390,7 @@ func (pea *PublicEthAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, 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) @@ -395,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()) @@ -410,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) @@ -432,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) @@ -449,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) @@ -471,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 @@ -569,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) @@ -683,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) @@ -723,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) @@ -742,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) @@ -762,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) @@ -910,6 +921,12 @@ func (diff *StateOverride) Apply(state *state.StateDB) error { // 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 + } + result, err := DoCall(ctx, pea.B, args, blockNrOrHash, overrides, 5*time.Second, pea.B.Config.RPCGasCap.Uint64()) // If the result contains a revert reason, try to unpack and return it. @@ -921,7 +938,7 @@ func (pea *PublicEthAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash } } - if err != nil && pea.rpc != nil { + 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) diff --git a/pkg/eth/api_test.go b/pkg/eth/api_test.go index 13a6336b..203a7572 100644 --- a/pkg/eth/api_test.go +++ b/pkg/eth/api_test.go @@ -229,7 +229,7 @@ var _ = Describe("API", func() { }, }) Expect(err).ToNot(HaveOccurred()) - api = eth.NewPublicEthAPI(backend, nil, false) + 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()) diff --git a/pkg/eth/backend.go b/pkg/eth/backend.go index 1e1445f3..3d9485a4 100644 --- a/pkg/eth/backend.go +++ b/pkg/eth/backend.go @@ -130,7 +130,7 @@ func NewEthBackend(db *postgres.DB, c *Config) (*Backend, error) { ExpiryDuration: time.Minute * time.Duration(gcc.StateDB.CacheExpiryInMins), }) - logStateDBStatsOnTimer(ethDB, gcc) + logStateDBStatsOnTimer(ethDB.(*ipfsethdb.Database), gcc) return &Backend{ DB: db, @@ -825,6 +825,7 @@ 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) } diff --git a/pkg/eth/eth_state_test.go b/pkg/eth/eth_state_test.go index f7dccc31..581c0628 100644 --- a/pkg/eth/eth_state_test.go +++ b/pkg/eth/eth_state_test.go @@ -94,7 +94,7 @@ var _ = Describe("eth state reading tests", func() { }, }) 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) diff --git a/pkg/eth/helpers.go b/pkg/eth/helpers.go index fc09d13c..b4d4f679 100644 --- a/pkg/eth/helpers.go +++ b/pkg/eth/helpers.go @@ -19,9 +19,10 @@ package eth import ( "encoding/json" "fmt" + "os" + "github.com/ethereum/go-ethereum/cmd/utils" log "github.com/sirupsen/logrus" - "os" sdtypes "github.com/ethereum/go-ethereum/statediff/types" diff --git a/pkg/serve/config.go b/pkg/serve/config.go index 6fb31039..b378bf31 100644 --- a/pkg/serve/config.go +++ b/pkg/serve/config.go @@ -36,21 +36,23 @@ import ( // Env variables const ( - serverWsPath = "SERVER_WS_PATH" - serverIpcPath = "SERVER_IPC_PATH" - serverHTTPPath = "SERVER_HTTP_PATH" + SERVER_WS_PATH = "SERVER_WS_PATH" + SERVER_IPC_PATH = "SERVER_IPC_PATH" + SERVER_HTTP_PATH = "SERVER_HTTP_PATH" - serverMaxIdleConnections = "SERVER_MAX_IDLE_CONNECTIONS" - serverMaxOpenConnections = "SERVER_MAX_OPEN_CONNECTIONS" - serverMaxConnLifetime = "SERVER_MAX_CONN_LIFETIME" + SERVER_MAX_IDLE_CONNECTIONS = "SERVER_MAX_IDLE_CONNECTIONS" + SERVER_MAX_OPEN_CONNECTIONS = "SERVER_MAX_OPEN_CONNECTIONS" + SERVER_MAX_CONN_LIFETIME = "SERVER_MAX_CONN_LIFETIME" - ethDefaultSenderAddr = "ETH_DEFAULT_SENDER_ADDR" - ethRPCGasCap = "ETH_RPC_GAS_CAP" - ethChainConfig = "ETH_CHAIN_CONFIG" - ethSupportsStatediff = "ETH_SUPPORTS_STATEDIFF" + ETH_DEFAULT_SENDER_ADDR = "ETH_DEFAULT_SENDER_ADDR" + 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" - ValidatorEnabled = "VALIDATOR_ENABLED" - ValidatorEveryNthBlock = "VALIDATOR_EVERY_NTH_BLOCK" + VALIDATOR_ENABLED = "VALIDATOR_ENABLED" + VALIDATOR_EVERY_NTH_BLOCK = "VALIDATOR_EVERY_NTH_BLOCK" ) // Config struct @@ -83,6 +85,8 @@ type Config struct { EthHttpEndpoint string Client *rpc.Client SupportStateDiff bool + ForwardEthCalls bool + ProxyOnError bool // Cache configuration. GroupCache *ethServerShared.GroupCacheConfig @@ -96,11 +100,13 @@ type Config struct { func NewConfig() (*Config, error) { c := new(Config) - viper.BindEnv("ethereum.httpPath", ethHTTPPath) - viper.BindEnv("ethereum.defaultSender", ethDefaultSenderAddr) - viper.BindEnv("ethereum.rpcGasCap", ethRPCGasCap) - viper.BindEnv("ethereum.chainConfig", ethChainConfig) - viper.BindEnv("ethereum.supportsStateDiff", ethSupportsStatediff) + 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.dbInit() ethHTTP := viper.GetString("ethereum.httpPath") @@ -111,6 +117,8 @@ func NewConfig() (*Config, error) { } 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 @@ -224,23 +232,23 @@ func NewConfig() (*Config, error) { } func overrideDBConnConfig(con *postgres.ConnectionConfig) { - viper.BindEnv("database.server.maxIdle", serverMaxIdleConnections) - viper.BindEnv("database.server.maxOpen", serverMaxOpenConnections) - viper.BindEnv("database.server.maxLifetime", serverMaxConnLifetime) + viper.BindEnv("database.server.maxIdle", SERVER_MAX_IDLE_CONNECTIONS) + 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") } func (c *Config) dbInit() { - viper.BindEnv("database.name", databaseName) - viper.BindEnv("database.hostname", databaseHostname) - viper.BindEnv("database.port", databasePort) - viper.BindEnv("database.user", databaseUser) - viper.BindEnv("database.password", databasePassword) - viper.BindEnv("database.maxIdle", databaseMaxIdleConnections) - viper.BindEnv("database.maxOpen", databaseMaxOpenConnections) - viper.BindEnv("database.maxLifetime", databaseMaxOpenConnLifetime) + 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.DBParams.Name = viper.GetString("database.name") c.DBParams.Hostname = viper.GetString("database.hostname") @@ -276,8 +284,8 @@ func (c *Config) loadGroupCacheConfig() { } func (c *Config) loadValidatorConfig() { - viper.BindEnv("validator.enabled", ValidatorEnabled) - viper.BindEnv("validator.everyNthBlock", ValidatorEveryNthBlock) + 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") diff --git a/pkg/serve/env.go b/pkg/serve/env.go index ebcce07a..ec9bc4d1 100644 --- a/pkg/serve/env.go +++ b/pkg/serve/env.go @@ -8,33 +8,33 @@ import ( // Env variables const ( - HTTPTimeout = "HTTP_TIMEOUT" + HTTP_TIMEOUT = "HTTP_TIMEOUT" - EthWsPath = "ETH_WS_PATH" - ethHTTPPath = "ETH_HTTP_PATH" - ethNodeID = "ETH_NODE_ID" - ethClientName = "ETH_CLIENT_NAME" - ethGenesisBlock = "ETH_GENESIS_BLOCK" - ethNetworkID = "ETH_NETWORK_ID" - ethChainID = "ETH_CHAIN_ID" + 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" - databaseName = "DATABASE_NAME" - databaseHostname = "DATABASE_HOSTNAME" - databasePort = "DATABASE_PORT" - databaseUser = "DATABASE_USER" - databasePassword = "DATABASE_PASSWORD" - databaseMaxIdleConnections = "DATABASE_MAX_IDLE_CONNECTIONS" - databaseMaxOpenConnections = "DATABASE_MAX_OPEN_CONNECTIONS" - databaseMaxOpenConnLifetime = "DATABASE_MAX_CONN_LIFETIME" + 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", ethNodeID) - viper.BindEnv("ethereum.clientName", ethClientName) - viper.BindEnv("ethereum.genesisBlock", ethGenesisBlock) - viper.BindEnv("ethereum.networkID", ethNetworkID) - viper.BindEnv("ethereum.chainID", ethChainID) + 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 { diff --git a/pkg/serve/service.go b/pkg/serve/service.go index 82ab4bf1..b1c295f2 100644 --- a/pkg/serve/service.go +++ b/pkg/serve/service.go @@ -83,6 +83,10 @@ 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 } // NewServer creates a new Server using an underlying Service struct @@ -97,6 +101,8 @@ 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 var err error sap.backend, err = eth.NewEthBackend(sap.db, ð.Config{ ChainConfig: settings.ChainConfig, @@ -130,10 +136,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, }) } diff --git a/pkg/shared/functions.go b/pkg/shared/functions.go index aa9c4bd9..aaa72234 100644 --- a/pkg/shared/functions.go +++ b/pkg/shared/functions.go @@ -20,8 +20,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/statediff/indexer/ipfs/ipld" "github.com/ipfs/go-cid" - "github.com/ipfs/go-ipfs-blockstore" - "github.com/ipfs/go-ipfs-ds-help" + blockstore "github.com/ipfs/go-ipfs-blockstore" + dshelp "github.com/ipfs/go-ipfs-ds-help" node "github.com/ipfs/go-ipld-format" "github.com/jmoiron/sqlx" "github.com/sirupsen/logrus" diff --git a/scripts/run_intregration_test.sh b/scripts/run_integration_test.sh similarity index 86% rename from scripts/run_intregration_test.sh rename to scripts/run_integration_test.sh index 211df86e..09bffcef 100755 --- a/scripts/run_intregration_test.sh +++ b/scripts/run_integration_test.sh @@ -1,6 +1,11 @@ set -e set -o xtrace +export ETH_FORWARD_ETH_CALLS=false +export DB_WRITE=true +export ETH_HTTP_PATH="" +export ETH_PROXY_ON_ERROR=false + # Clear up existing docker images and volume. docker-compose down --remove-orphans --volumes @@ -18,4 +23,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 \ No newline at end of file + make integrationtest diff --git a/scripts/run_integration_test_forward_eth_calls.sh b/scripts/run_integration_test_forward_eth_calls.sh new file mode 100644 index 00000000..0b7ab672 --- /dev/null +++ b/scripts/run_integration_test_forward_eth_calls.sh @@ -0,0 +1,26 @@ +set -e +set -o xtrace + +export ETH_FORWARD_ETH_CALLS=true +export DB_WRITE=false +export ETH_HTTP_PATH="dapptools:8545" +export ETH_PROXY_ON_ERROR=false + +# 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` or other container code is modified. Otherwise comment this line. +docker-compose -f docker-compose.test.yml -f docker-compose.yml build eth-server +docker-compose -f docker-compose.test.yml -f docker-compose.yml up -d ipld-eth-db dapptools contract eth-server + +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 diff --git a/test/direct_proxy_integration_test.go b/test/direct_proxy_integration_test.go new file mode 100644 index 00000000..4256c18d --- /dev/null +++ b/test/direct_proxy_integration_test.go @@ -0,0 +1,458 @@ +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/pkg/eth" + integration "github.com/vulcanize/ipld-eth-server/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 + + Describe("get Block", func() { + BeforeEach(func() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + 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() { + if !directProxyEthCalls { + Skip("skipping direct-proxy-forwarding integration tests") + } + _, err := gethClient.ChainID(ctx) + Expect(err).ToNot(HaveOccurred()) + + _, err = ipldClient.ChainID(ctx) + Expect(err).To(HaveOccurred()) + }) + }) +}) diff --git a/test/integration_test.go b/test/integration_test.go index d250fcce..9abaaaff 100644 --- a/test/integration_test.go +++ b/test/integration_test.go @@ -3,6 +3,8 @@ package integration_test import ( "context" "math/big" + "os" + "strconv" "time" "github.com/ethereum/go-ethereum" @@ -27,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()) @@ -47,6 +51,9 @@ var _ = Describe("Integration test", func() { Describe("get Block", func() { BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } contract, contractErr = integration.DeployContract() time.Sleep(sleepInterval) }) @@ -116,6 +123,9 @@ var _ = Describe("Integration test", func() { Describe("Transaction", func() { BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } contract, contractErr = integration.DeployContract() time.Sleep(sleepInterval) }) @@ -147,6 +157,9 @@ var _ = Describe("Integration test", func() { Describe("Receipt", func() { BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } contract, contractErr = integration.DeployContract() time.Sleep(sleepInterval) }) @@ -174,6 +187,9 @@ var _ = Describe("Integration test", func() { Describe("FilterLogs", func() { BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } contract, contractErr = integration.DeployContract() time.Sleep(sleepInterval) }) @@ -204,6 +220,9 @@ var _ = Describe("Integration test", func() { Describe("CodeAt", func() { BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } contract, contractErr = integration.DeployContract() time.Sleep(sleepInterval) }) @@ -251,6 +270,9 @@ var _ = Describe("Integration test", func() { Describe("Get balance", func() { address := "0x1111111111111111111111111111111111111112" BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } tx, txErr = integration.SendEth(address, "0.01") time.Sleep(sleepInterval) }) @@ -314,6 +336,9 @@ var _ = Describe("Integration test", func() { Describe("Get Storage", func() { BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } contract, contractErr = integration.DeployContract() erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10) @@ -427,6 +452,9 @@ var _ = Describe("Integration test", func() { Describe("eth call", func() { BeforeEach(func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } contract, contractErr = integration.DeployContract() erc20TotalSupply, bigIntResult = new(big.Int).SetString("1000000000000000000000", 10) @@ -477,6 +505,9 @@ var _ = Describe("Integration test", func() { Describe("Chain ID", func() { It("Check chain id", func() { + if directProxyEthCalls { + Skip("skipping no-direct-proxy-forwarding integration tests") + } gethChainId, err := gethClient.ChainID(ctx) Expect(err).ToNot(HaveOccurred()) diff --git a/version/version.go b/version/version.go index 29ac8ff1..c6afda00 100644 --- a/version/version.go +++ b/version/version.go @@ -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 = 0 // Major version component of the current release + Minor = 3 // Minor version component of the current release + Patch = 9 // Patch version component of the current release + Meta = "" // Version metadata to append to the version string ) // Version holds the textual version string.