(CI dev) debug unit test Go version #237
No files matched your search
@@ -29,7 +29,7 @@ jobs:
|
||||
BUILD_KEY: ${{ secrets.BUILD_KEY }}
|
||||
with:
|
||||
STACK_ORCHESTRATOR_REF: "f2fd766f5400fcb9eb47b50675d2e3b1f2753702"
|
||||
GO_ETHEREUM_REF: "0c1e451c9865d8d47797b35526c4875f0d224772"
|
||||
GO_ETHEREUM_REF: "c339429ff6550d8012d65977fc79f73bba2616e3"
|
||||
IPLD_ETH_DB_REF: "be345e0733d2c025e4082c5154e441317ae94cf7"
|
||||
build:
|
||||
name: Run docker build
|
||||
@@ -41,39 +41,20 @@ jobs:
|
||||
github.event_name == 'release'
|
||||
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 cerc-io/ipld-eth-server git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Login
|
||||
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login https://git.vdb.to -u cerccicd --password-stdin
|
||||
- name: Docker Push
|
||||
run: docker push git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
|
||||
push_to_registries:
|
||||
name: Push Docker image to Docker Hub
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
always() &&
|
||||
(needs.build.result == 'success') &&
|
||||
github.event_name == 'release'
|
||||
needs: build
|
||||
steps:
|
||||
- name: Get the version
|
||||
id: vars
|
||||
run: |
|
||||
echo ::set-output name=sha::$(echo ${GITHUB_SHA:0:7})
|
||||
echo ::set-output name=tag::$(echo ${GITHUB_REF#refs/tags/})
|
||||
- name: Docker Login to Github Registry
|
||||
run: echo ${{ secrets.GITHUB_TOKEN }} | docker login https://git.vdb.to -u cerccicd --password-stdin
|
||||
- name: Docker Pull
|
||||
run: docker pull git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Login to Docker Registry
|
||||
run: echo ${{ secrets.VULCANIZEJENKINS_PAT }} | docker login -u vulcanizejenkins --password-stdin
|
||||
- name: Tag docker image
|
||||
run: docker tag git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}} cerc-io/ipld-eth-server:${{steps.vars.outputs.tag}}
|
||||
- name: Docker Push to Docker Hub
|
||||
run: docker push cerc-io/ipld-eth-server:${{steps.vars.outputs.tag}}
|
||||
- name: Run docker build
|
||||
run: make docker-build
|
||||
- name: Tag docker image SHA
|
||||
run: docker tag cerc-io/ipld-eth-server git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
- name: Tag docker image TAG
|
||||
run: docker tag git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}} git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.tag}}
|
||||
- name: Docker Login
|
||||
run: echo ${{ secrets.GITEA_TOKEN }} | docker login https://git.vdb.to -u cerccicd --password-stdin
|
||||
- name: Docker Push SHA
|
||||
run: docker push git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.sha}}
|
||||
- name: Docker Push TAG
|
||||
run: docker push git.vdb.to/cerc-io/ipld-eth-server/ipld-eth-server:${{steps.vars.outputs.tag}}
|
||||
@@ -1,11 +1,13 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# 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
|
||||
|
||||
@@ -16,11 +18,11 @@ rm -f /tmp/git_head_ref /tmp/git_repository
|
||||
echo 'docker-compose up -d migrations ipld-eth-db'
|
||||
docker-compose up -d migrations ipld-eth-db
|
||||
trap "docker-compose down -v --remove-orphans; cd $start_dir ; rm -r $temp_dir" SIGINT SIGTERM ERR
|
||||
sleep 30
|
||||
sleep 60
|
||||
|
||||
# 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=8077 DATABASE_PASSWORD=password DATABASE_HOSTNAME=localhost DATABASE_NAME=vulcanize_testing make test > /tmp/test.log
|
||||
PGPASSWORD=password DATABASE_USER=vdbm DATABASE_PORT=8077 DATABASE_PASSWORD=password DATABASE_HOSTNAME=localhost DATABASE_NAME=vulcanize_testing make test | tee /tmp/test.log
|
||||
echo $? > /tmp/return_test.txt
|
||||
|
||||
# Clean up
|
||||
|
||||
@@ -35,13 +35,16 @@ jobs:
|
||||
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, 1.18.x]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.19.7
|
||||
|
||||
# Passed experience with GHA has taught me to store variables in files instead of passing them as variables.
|
||||
- name: Output variables to files
|
||||
run: |
|
||||
@@ -62,6 +65,7 @@ jobs:
|
||||
|
||||
- name: Trigger Unit Test
|
||||
run: |
|
||||
echo BUILD_USERNAME=${{ env.BUILD_USERNAME }} BUILD_HOSTNAME=${{ env.BUILD_HOSTNAME }}
|
||||
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
|
||||
|
||||
@@ -85,12 +89,13 @@ jobs:
|
||||
ETH_HTTP_PATH: "go-ethereum:8545"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.19.7
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.18.x"
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-server"
|
||||
@@ -153,12 +158,13 @@ jobs:
|
||||
ETH_HTTP_PATH: "go-ethereum:8545"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: 1.19.7
|
||||
- name: Create GOPATH
|
||||
run: mkdir -p /tmp/go
|
||||
- uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: "1.18.x"
|
||||
check-latest: true
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
path: "./ipld-eth-server"
|
||||
|
||||
+7
-1
@@ -1,9 +1,12 @@
|
||||
FROM golang:1.18-alpine as builder
|
||||
FROM golang:1.19-alpine as builder
|
||||
|
||||
RUN apk --update --no-cache add make git g++ linux-headers
|
||||
# DEBUG
|
||||
RUN apk add busybox-extras
|
||||
|
||||
# Include dlv
|
||||
RUN go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
|
||||
# Build ipld-eth-server
|
||||
WORKDIR /go/src/github.com/cerc-io/ipld-eth-server
|
||||
|
||||
@@ -46,4 +49,7 @@ COPY --from=builder /go/src/github.com/cerc-io/ipld-eth-server/ipld-eth-server i
|
||||
COPY --from=builder /goose goose
|
||||
COPY --from=builder /go/src/github.com/cerc-io/ipld-eth-server/environments environments
|
||||
|
||||
# Allow for debugging
|
||||
COPY --from=builder /go/bin/dlv /usr/local/bin/
|
||||
|
||||
ENTRYPOINT ["/app/entrypoint.sh"]
|
||||
@@ -52,9 +52,11 @@ TEST_CONNECT_STRING_LOCAL = postgresql://$(USER)@$(HOST_NAME):$(PORT)/$(TEST_DB)
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
echo "GO VERSION:"
|
||||
go version
|
||||
go vet ./...
|
||||
go fmt ./...
|
||||
go run github.com/onsi/ginkgo/ginkgo -r --skipPackage=test
|
||||
go run github.com/onsi/ginkgo/ginkgo -r --skipPackage=test
|
||||
|
||||
.PHONY: integrationtest
|
||||
integrationtest:
|
||||
|
||||
@@ -22,7 +22,7 @@ Additional, unique endpoints are exposed which utilize the new indexes and state
|
||||
|
||||
## Dependencies
|
||||
Minimal build dependencies
|
||||
* Go (1.18)
|
||||
* Go (1.19)
|
||||
* Git
|
||||
* GCC compiler
|
||||
* This repository
|
||||
|
||||
+2
-34
@@ -18,15 +18,14 @@ 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/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/prom"
|
||||
)
|
||||
|
||||
@@ -50,24 +49,7 @@ func Execute() {
|
||||
}
|
||||
|
||||
func initFuncs(cmd *cobra.Command, args []string) {
|
||||
viper.BindEnv("log.file", "LOGRUS_FILE")
|
||||
logfile := viper.GetString("log.file")
|
||||
if logfile != "" {
|
||||
file, err := os.OpenFile(logfile,
|
||||
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||
if err == nil {
|
||||
log.Infof("Directing output to %s", logfile)
|
||||
log.SetOutput(file)
|
||||
} else {
|
||||
log.SetOutput(os.Stdout)
|
||||
log.Info("Failed to log to file, using default stdout")
|
||||
}
|
||||
} else {
|
||||
log.SetOutput(os.Stdout)
|
||||
}
|
||||
if err := logLevel(); err != nil {
|
||||
log.Fatal("Could not set log level: ", err)
|
||||
}
|
||||
log.Init()
|
||||
|
||||
if viper.GetBool("metrics") {
|
||||
prom.Init()
|
||||
@@ -83,20 +65,6 @@ func initFuncs(cmd *cobra.Command, args []string) {
|
||||
}
|
||||
}
|
||||
|
||||
func logLevel() error {
|
||||
viper.BindEnv("log.level", "LOGRUS_LEVEL")
|
||||
lvl, err := log.ParseLevel(viper.GetString("log.level"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.SetLevel(lvl)
|
||||
if lvl > log.InfoLevel {
|
||||
log.SetReportCaller(true)
|
||||
}
|
||||
log.Info("Log level set to ", lvl.String())
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
cobra.OnInitialize(initConfig)
|
||||
viper.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
|
||||
|
||||
+5
-3
@@ -17,7 +17,6 @@ package cmd
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/mailgun/groupcache/v2"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -26,8 +25,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/mailgun/groupcache/v2"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/vulcanize/gap-filler/pkg/mux"
|
||||
@@ -255,7 +256,7 @@ func startStateTrieValidator(config *s.Config, server s.Server) {
|
||||
|
||||
block, err := backend.CurrentBlock()
|
||||
if err != nil {
|
||||
log.Errorln("Error fetching current block for state trie validator")
|
||||
log.Error("Error fetching current block for state trie validator")
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -395,6 +396,7 @@ func init() {
|
||||
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.forwardGetStorageAt", serveCmd.PersistentFlags().Lookup("eth-forward-get-storage-at"))
|
||||
viper.BindPFlag("ethereum.proxyOnError", serveCmd.PersistentFlags().Lookup("eth-proxy-on-error"))
|
||||
|
||||
// groupcache flags
|
||||
|
||||
+1
-1
@@ -19,11 +19,11 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
|
||||
+3
-3
@@ -20,8 +20,8 @@ import (
|
||||
|
||||
validator "github.com/cerc-io/eth-ipfs-state-validator/v4/pkg"
|
||||
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v4/postgres"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
@@ -65,13 +65,13 @@ func validate() {
|
||||
|
||||
val := validator.NewValidator(nil, ethDB)
|
||||
if err = val.ValidateTrie(stateRoot); err != nil {
|
||||
log.Fatalln("Error validating state root")
|
||||
log.Fatal("Error validating state root")
|
||||
}
|
||||
|
||||
stats := ethDB.(*ipfsethdb.Database).GetCacheStats()
|
||||
log.Debugf("groupcache stats %+v", stats)
|
||||
|
||||
log.Infoln("Successfully validated state root")
|
||||
log.Info("Successfully validated state root")
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
v "github.com/cerc-io/ipld-eth-server/v4/version"
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ services:
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
- ipld-eth-db
|
||||
image: git.vdb.to/cerc-io/ipld-eth-db/ipld-eth-db:v4.2.1-alpha-unstable
|
||||
image: git.vdb.to/cerc-io/ipld-eth-db/ipld-eth-db:v4.2.3-alpha
|
||||
environment:
|
||||
DATABASE_USER: "vdbm"
|
||||
DATABASE_NAME: "vulcanize_testing"
|
||||
|
||||
+7
-2
@@ -2,8 +2,13 @@
|
||||
|
||||
echo "Beginning the ipld-eth-server process"
|
||||
|
||||
echo running: ./ipld-eth-server ${VDB_COMMAND} --config=config.toml
|
||||
./ipld-eth-server ${VDB_COMMAND} --config=config.toml
|
||||
START_CMD="./ipld-eth-server"
|
||||
if [ "true" == "$CERC_REMOTE_DEBUG" ] && [ -x "/usr/local/bin/dlv" ]; then
|
||||
START_CMD="/usr/local/bin/dlv --listen=:40000 --headless=true --api-version=2 --accept-multiclient exec `pwd`/ipld-eth-server --continue --"
|
||||
fi
|
||||
|
||||
echo running: $START_CMD ${VDB_COMMAND} --config=`pwd`/config.toml
|
||||
$START_CMD ${VDB_COMMAND} --config=`pwd`/config.toml
|
||||
rv=$?
|
||||
|
||||
if [ $rv != 0 ]; then
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
rpcGasCap = "1000000000000" # $ETH_RPC_GAS_CAP
|
||||
httpPath = "127.0.0.1:8545" # $ETH_HTTP_PATH
|
||||
supportsStateDiff = true # $ETH_SUPPORTS_STATEDIFF
|
||||
stateDiffTimeout = "4m" # $ETH_STATEDIFF_TIMEOUT
|
||||
forwardEthCalls = false # $ETH_FORWARD_ETH_CALLS
|
||||
proxyOnError = true # $ETH_PROXY_ON_ERROR
|
||||
nodeID = "arch1" # $ETH_NODE_ID
|
||||
|
||||
@@ -1,84 +1,91 @@
|
||||
module github.com/cerc-io/ipld-eth-server/v4
|
||||
|
||||
go 1.18
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/cerc-io/eth-ipfs-state-validator/v4 v4.0.8-alpha
|
||||
github.com/cerc-io/ipfs-ethdb/v4 v4.0.8-alpha
|
||||
github.com/ethereum/go-ethereum v1.10.23
|
||||
github.com/cerc-io/eth-ipfs-state-validator/v4 v4.0.15-alpha
|
||||
github.com/cerc-io/ipfs-ethdb/v4 v4.0.13-alpha
|
||||
github.com/ethereum/go-ethereum v1.11.5
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/graph-gophers/graphql-go v1.3.0
|
||||
github.com/ipfs/go-block-format v0.0.3
|
||||
github.com/ipfs/go-cid v0.2.0
|
||||
github.com/ipfs/go-cid v0.3.2
|
||||
github.com/ipfs/go-ipfs-blockstore v1.2.0
|
||||
github.com/ipfs/go-ipfs-ds-help v1.1.0
|
||||
github.com/jmoiron/sqlx v1.3.5
|
||||
github.com/joho/godotenv v1.4.0
|
||||
github.com/lib/pq v1.10.6
|
||||
github.com/lib/pq v1.10.7
|
||||
github.com/machinebox/graphql v0.2.2
|
||||
github.com/mailgun/groupcache/v2 v2.3.0
|
||||
github.com/multiformats/go-multihash v0.2.0
|
||||
github.com/multiformats/go-multihash v0.2.1
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.19.0
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/onsi/gomega v1.24.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/sirupsen/logrus v1.9.0
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/spf13/viper v1.11.0
|
||||
github.com/vulcanize/gap-filler v0.4.0
|
||||
github.com/vulcanize/gap-filler v0.4.2
|
||||
gorm.io/driver/postgres v1.3.7
|
||||
gorm.io/gorm v1.23.5
|
||||
)
|
||||
|
||||
require (
|
||||
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect
|
||||
github.com/Stebalien/go-bitfield v0.0.1 // indirect
|
||||
github.com/DataDog/zstd v1.5.2 // indirect
|
||||
github.com/VictoriaMetrics/fastcache v1.6.0 // indirect
|
||||
github.com/alecthomas/units v0.0.0-20210927113745-59d0afb8317a // indirect
|
||||
github.com/benbjohnson/clock v1.3.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/btcsuite/btcd/chaincfg/chainhash v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
|
||||
github.com/cerc-io/go-eth-state-node-iterator v1.1.7 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cheekybits/genny v1.0.0 // indirect
|
||||
github.com/containerd/cgroups v1.0.3 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cockroachdb/errors v1.9.1 // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811 // indirect
|
||||
github.com/cockroachdb/redact v1.1.3 // indirect
|
||||
github.com/containerd/cgroups v1.0.4 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // 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/deckarep/golang-set/v2 v2.1.0 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/deepmap/oapi-codegen v1.8.2 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.5.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/edsrzf/mmap-go v1.0.0 // indirect
|
||||
github.com/elastic/gosigar v0.14.2 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // 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.4 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
|
||||
github.com/georgysavva/scany v0.2.9 // indirect
|
||||
github.com/georgysavva/scany v1.2.1 // indirect
|
||||
github.com/getsentry/sentry-go v0.17.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/go-stack/stack v1.8.0 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/gofrs/flock v0.8.1 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0 // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/gopacket v1.1.19 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190812055157-5d271430af9f // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/graphql-go/graphql v0.7.9 // indirect
|
||||
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
|
||||
@@ -96,48 +103,48 @@ require (
|
||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||
github.com/ipfs/bbloom v0.0.4 // indirect
|
||||
github.com/ipfs/go-bitfield v1.0.0 // indirect
|
||||
github.com/ipfs/go-bitswap v0.8.0 // indirect
|
||||
github.com/ipfs/go-blockservice v0.4.0 // indirect
|
||||
github.com/ipfs/go-bitswap v0.11.0 // indirect
|
||||
github.com/ipfs/go-blockservice v0.5.0 // indirect
|
||||
github.com/ipfs/go-cidutil v0.1.0 // indirect
|
||||
github.com/ipfs/go-datastore v0.5.1 // indirect
|
||||
github.com/ipfs/go-delegated-routing v0.3.0 // indirect
|
||||
github.com/ipfs/go-datastore v0.6.0 // indirect
|
||||
github.com/ipfs/go-delegated-routing v0.7.0 // indirect
|
||||
github.com/ipfs/go-ds-measure v0.2.0 // indirect
|
||||
github.com/ipfs/go-fetcher v1.6.1 // indirect
|
||||
github.com/ipfs/go-filestore v1.2.0 // indirect
|
||||
github.com/ipfs/go-fs-lock v0.0.7 // indirect
|
||||
github.com/ipfs/go-graphsync v0.13.1 // indirect
|
||||
github.com/ipfs/go-graphsync v0.14.1 // indirect
|
||||
github.com/ipfs/go-ipfs-chunker v0.0.5 // indirect
|
||||
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
|
||||
github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect
|
||||
github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect
|
||||
github.com/ipfs/go-ipfs-files v0.1.1 // indirect
|
||||
github.com/ipfs/go-ipfs-keystore v0.0.2 // indirect
|
||||
github.com/ipfs/go-ipfs-keystore v0.1.0 // indirect
|
||||
github.com/ipfs/go-ipfs-pinner v0.2.1 // 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.7.1 // indirect
|
||||
github.com/ipfs/go-ipfs-routing v0.2.1 // indirect
|
||||
github.com/ipfs/go-ipfs-provider v0.8.1 // indirect
|
||||
github.com/ipfs/go-ipfs-routing v0.3.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-cbor v0.0.6 // indirect
|
||||
github.com/ipfs/go-ipld-format v0.4.0 // indirect
|
||||
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
|
||||
github.com/ipfs/go-ipns v0.1.2 // indirect
|
||||
github.com/ipfs/go-ipns v0.3.0 // indirect
|
||||
github.com/ipfs/go-libipfs v0.2.0 // indirect
|
||||
github.com/ipfs/go-log v1.0.5 // indirect
|
||||
github.com/ipfs/go-log/v2 v2.5.1 // indirect
|
||||
github.com/ipfs/go-merkledag v0.6.0 // indirect
|
||||
github.com/ipfs/go-merkledag v0.9.0 // indirect
|
||||
github.com/ipfs/go-metrics-interface v0.0.1 // indirect
|
||||
github.com/ipfs/go-mfs v0.2.1 // indirect
|
||||
github.com/ipfs/go-namesys v0.5.0 // indirect
|
||||
github.com/ipfs/go-namesys v0.6.0 // indirect
|
||||
github.com/ipfs/go-path v0.3.0 // indirect
|
||||
github.com/ipfs/go-peertaskqueue v0.7.1 // indirect
|
||||
github.com/ipfs/go-unixfs v0.4.0 // indirect
|
||||
github.com/ipfs/go-unixfsnode v1.4.0 // indirect
|
||||
github.com/ipfs/go-verifcid v0.0.1 // indirect
|
||||
github.com/ipfs/interface-go-ipfs-core v0.7.0 // indirect
|
||||
github.com/ipfs/kubo v0.14.0 // indirect
|
||||
github.com/ipld/edelweiss v0.1.4 // indirect
|
||||
github.com/ipld/go-codec-dagpb v1.4.0 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.17.0 // indirect
|
||||
github.com/ipfs/go-peertaskqueue v0.8.0 // indirect
|
||||
github.com/ipfs/go-unixfs v0.4.2 // indirect
|
||||
github.com/ipfs/go-unixfsnode v1.5.1 // indirect
|
||||
github.com/ipfs/go-verifcid v0.0.2 // indirect
|
||||
github.com/ipfs/interface-go-ipfs-core v0.8.2 // indirect
|
||||
github.com/ipfs/kubo v0.18.1 // indirect
|
||||
github.com/ipld/edelweiss v0.2.0 // indirect
|
||||
github.com/ipld/go-codec-dagpb v1.5.0 // indirect
|
||||
github.com/ipld/go-ipld-prime v0.19.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.12.1 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
@@ -153,50 +160,47 @@ require (
|
||||
github.com/jinzhu/copier v0.2.4 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.4 // indirect
|
||||
github.com/klauspost/compress v1.15.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.12 // indirect
|
||||
github.com/koron/go-ssdp v0.0.2 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.0.2 // indirect
|
||||
github.com/klauspost/compress v1.15.15 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.1 // indirect
|
||||
github.com/koron/go-ssdp v0.0.3 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/libp2p/go-buffer-pool v0.1.0 // indirect
|
||||
github.com/libp2p/go-cidranger v1.1.0 // indirect
|
||||
github.com/libp2p/go-doh-resolver v0.4.0 // 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.20.3 // indirect
|
||||
github.com/libp2p/go-flow-metrics v0.1.0 // indirect
|
||||
github.com/libp2p/go-libp2p v0.24.2 // indirect
|
||||
github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-core v0.16.1 // indirect
|
||||
github.com/libp2p/go-libp2p-discovery v0.7.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.16.0 // 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-peerstore v0.6.0 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub v0.6.1 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect
|
||||
github.com/libp2p/go-libp2p-record v0.1.3 // indirect
|
||||
github.com/libp2p/go-libp2p-resource-manager v0.3.0 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect
|
||||
github.com/libp2p/go-libp2p-swarm v0.11.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kad-dht v0.20.0 // indirect
|
||||
github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub v0.8.3 // indirect
|
||||
github.com/libp2p/go-libp2p-pubsub-router v0.6.0 // indirect
|
||||
github.com/libp2p/go-libp2p-record v0.2.0 // indirect
|
||||
github.com/libp2p/go-libp2p-routing-helpers v0.6.0 // indirect
|
||||
github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
|
||||
github.com/libp2p/go-mplex v0.7.0 // indirect
|
||||
github.com/libp2p/go-msgio v0.2.0 // indirect
|
||||
github.com/libp2p/go-nat v0.1.0 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.0 // indirect
|
||||
github.com/libp2p/go-openssl v0.0.7 // indirect
|
||||
github.com/libp2p/go-netroute v0.2.1 // indirect
|
||||
github.com/libp2p/go-openssl v0.1.0 // indirect
|
||||
github.com/libp2p/go-reuseport v0.2.0 // indirect
|
||||
github.com/libp2p/go-yamux/v3 v3.1.2 // indirect
|
||||
github.com/libp2p/zeroconf/v2 v2.1.1 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.27.1 // indirect
|
||||
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
|
||||
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
|
||||
github.com/lucas-clemente/quic-go v0.31.1 // 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/qpack v0.3.0 // indirect
|
||||
github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect
|
||||
github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect
|
||||
github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
|
||||
github.com/marten-seemann/webtransport-go v0.4.3 // 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-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-pointer v0.0.1 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/miekg/dns v1.1.48 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/miekg/dns v1.1.50 // indirect
|
||||
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
|
||||
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
@@ -204,36 +208,35 @@ require (
|
||||
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.4 // indirect
|
||||
github.com/multiformats/go-base36 v0.1.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.5.0 // indirect
|
||||
github.com/multiformats/go-base32 v0.1.0 // indirect
|
||||
github.com/multiformats/go-base36 v0.2.0 // indirect
|
||||
github.com/multiformats/go-multiaddr v0.8.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.1.0 // indirect
|
||||
github.com/multiformats/go-multicodec v0.5.0 // indirect
|
||||
github.com/multiformats/go-multibase v0.1.1 // indirect
|
||||
github.com/multiformats/go-multicodec v0.7.0 // indirect
|
||||
github.com/multiformats/go-multistream v0.3.3 // indirect
|
||||
github.com/multiformats/go-varint v0.0.6 // indirect
|
||||
github.com/multiformats/go-varint v0.0.7 // indirect
|
||||
github.com/nxadm/tail v1.4.8 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/onsi/ginkgo/v2 v2.5.1 // indirect
|
||||
github.com/opencontainers/runtime-spec v1.0.2 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.0-beta.8 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.5 // 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/pganalyze/pg_query_go/v2 v2.2.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.33.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/prometheus/tsdb v0.10.0 // indirect
|
||||
github.com/raulk/clock v1.1.0 // indirect
|
||||
github.com/raulk/go-watchdog v1.2.0 // indirect
|
||||
github.com/rjeczalik/notify v0.9.1 // indirect
|
||||
github.com/prometheus/client_model v0.3.0 // indirect
|
||||
github.com/prometheus/common v0.37.1 // indirect
|
||||
github.com/prometheus/procfs v0.9.0 // indirect
|
||||
github.com/raulk/go-watchdog v1.3.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
github.com/rs/cors v1.7.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/samber/lo v1.36.0 // indirect
|
||||
github.com/segmentio/fasthash v1.0.3 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||
github.com/smartystreets/assertions v1.0.1 // indirect
|
||||
@@ -243,49 +246,43 @@ require (
|
||||
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.2 // indirect
|
||||
github.com/status-im/keycard-go v0.2.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
|
||||
github.com/thoas/go-funk v0.9.2 // indirect
|
||||
github.com/tidwall/gjson v1.14.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // 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/urfave/cli/v2 v2.10.2 // indirect
|
||||
github.com/thoas/go-funk v0.9.3 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.11 // indirect
|
||||
github.com/tklauser/numcpus v0.6.0 // indirect
|
||||
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
|
||||
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect
|
||||
github.com/valyala/fastjson v1.6.3 // indirect
|
||||
github.com/wI2L/jsondiff v0.2.0 // 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/cbor-gen v0.0.0-20221220214510-0333c149dec0 // 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/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
|
||||
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee // indirect
|
||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||
go.opencensus.io v0.23.0 // indirect
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
go.opentelemetry.io/otel v1.7.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.7.0 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/dig v1.14.0 // indirect
|
||||
go.uber.org/fx v1.16.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
go.uber.org/atomic v1.10.0 // indirect
|
||||
go.uber.org/dig v1.15.0 // indirect
|
||||
go.uber.org/fx v1.18.2 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
go.uber.org/zap v1.24.0 // indirect
|
||||
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
|
||||
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d // indirect
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // 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.10 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/ini.v1 v1.66.4 // indirect
|
||||
golang.org/x/crypto v0.6.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230206171751-46f607a40771 // indirect
|
||||
golang.org/x/mod v0.7.0 // indirect
|
||||
golang.org/x/net v0.6.0 // indirect
|
||||
golang.org/x/sync v0.1.0 // indirect
|
||||
golang.org/x/sys v0.5.0 // indirect
|
||||
golang.org/x/text v0.7.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af // indirect
|
||||
golang.org/x/tools v0.3.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
@@ -293,4 +290,4 @@ require (
|
||||
lukechampine.com/blake3 v1.1.7 // indirect
|
||||
)
|
||||
|
||||
replace github.com/ethereum/go-ethereum v1.10.23 => github.com/cerc-io/go-ethereum v1.10.23-statediff-4.2.0-alpha
|
||||
replace github.com/ethereum/go-ethereum v1.11.5 => github.com/cerc-io/go-ethereum v1.11.5-statediff-4.3.9-alpha
|
||||
@@ -16,14 +16,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/cmd"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logrus.SetFormatter(&logrus.TextFormatter{
|
||||
FullTimestamp: true,
|
||||
})
|
||||
cmd.Execute()
|
||||
}
|
||||
@@ -42,13 +42,13 @@ type Backend struct {
|
||||
}
|
||||
|
||||
// StateAtBlock retrieves the state database associated with a certain block
|
||||
func (b *Backend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, error) {
|
||||
func (b *Backend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
rpcBlockNumber := rpc.BlockNumber(block.NumberU64())
|
||||
statedb, _, err := b.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpcBlockNumber))
|
||||
return statedb, err
|
||||
return statedb, func() {}, err
|
||||
}
|
||||
|
||||
// StateAtTransaction returns the execution environment of a certain transaction
|
||||
func (b *Backend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (core.Message, vm.BlockContext, *state.StateDB, error) {
|
||||
return nil, vm.BlockContext{}, nil, errMethodNotSupported
|
||||
func (b *Backend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
return nil, vm.BlockContext{}, nil, func() {}, errMethodNotSupported
|
||||
}
|
||||
+166
-85
@@ -27,6 +27,8 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -40,14 +42,12 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultEVMTimeout = 30 * time.Second
|
||||
defaultStateDiffTimeout = 240 * time.Second
|
||||
defaultEVMTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
// APIName is the namespace for the watcher's eth api
|
||||
@@ -56,28 +56,37 @@ const APIName = "eth"
|
||||
// APIVersion is the version of the watcher's eth api
|
||||
const APIVersion = "0.0.1"
|
||||
|
||||
type APIConfig struct {
|
||||
// Proxy node for forwarding cache misses
|
||||
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
|
||||
ForwardEthCalls bool // if true, forward eth_call calls directly to the configured proxy node
|
||||
ForwardGetStorageAt bool // if true, forward eth_getStorageAt 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
|
||||
|
||||
StateDiffTimeout time.Duration
|
||||
}
|
||||
|
||||
// PublicEthAPI is the eth namespace API
|
||||
type PublicEthAPI struct {
|
||||
// Local db backend
|
||||
B *Backend
|
||||
|
||||
// Proxy node for forwarding cache misses
|
||||
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
|
||||
B *Backend
|
||||
rpc *rpc.Client
|
||||
ethClient *ethclient.Client
|
||||
config APIConfig
|
||||
}
|
||||
|
||||
// NewPublicEthAPI creates a new PublicEthAPI with the provided underlying Backend
|
||||
func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff, forwardEthCalls, proxyOnError bool) (*PublicEthAPI, error) {
|
||||
func NewPublicEthAPI(b *Backend, client *rpc.Client, config APIConfig) (*PublicEthAPI, error) {
|
||||
if b == nil {
|
||||
return nil, errors.New("ipld-eth-server must be configured with an ethereum backend")
|
||||
}
|
||||
if forwardEthCalls && client == nil {
|
||||
if config.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 {
|
||||
if config.ForwardGetStorageAt && client == nil {
|
||||
return nil, errors.New("ipld-eth-server is configured to forward eth_getStorageAt to proxy node but no proxy node is configured")
|
||||
}
|
||||
if config.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
|
||||
@@ -85,12 +94,10 @@ func NewPublicEthAPI(b *Backend, client *rpc.Client, supportsStateDiff, forwardE
|
||||
ethClient = ethclient.NewClient(client)
|
||||
}
|
||||
return &PublicEthAPI{
|
||||
B: b,
|
||||
supportsStateDiff: supportsStateDiff,
|
||||
rpc: client,
|
||||
ethClient: ethClient,
|
||||
forwardEthCalls: forwardEthCalls,
|
||||
proxyOnError: proxyOnError,
|
||||
B: b,
|
||||
rpc: client,
|
||||
ethClient: ethClient,
|
||||
config: config,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -108,7 +115,7 @@ func (pea *PublicEthAPI) GetHeaderByNumber(ctx context.Context, number rpc.Block
|
||||
if header != nil && err == nil {
|
||||
return pea.rpcMarshalHeader(header)
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.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)
|
||||
@@ -127,7 +134,7 @@ func (pea *PublicEthAPI) GetHeaderByHash(ctx context.Context, hash common.Hash)
|
||||
}
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var result map[string]interface{}
|
||||
if err := pea.rpc.CallContext(ctx, &result, "eth_getHeaderByHash", hash); result != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
@@ -163,13 +170,12 @@ func (pea *PublicEthAPI) BlockNumber() hexutil.Uint64 {
|
||||
// * When fullTx is true all transactions in the block are returned, otherwise
|
||||
// only the transaction hash is returned.
|
||||
func (pea *PublicEthAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
|
||||
logrus.Debug("Received getBlockByNumber request for number ", number.Int64())
|
||||
block, err := pea.B.BlockByNumber(ctx, number)
|
||||
if block != nil && err == nil {
|
||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.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)
|
||||
@@ -182,13 +188,12 @@ func (pea *PublicEthAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockN
|
||||
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
||||
// detail, otherwise only the transaction hash is returned.
|
||||
func (pea *PublicEthAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||
logrus.Debug("Received getBlockByHash request for hash ", hash.Hex())
|
||||
block, err := pea.B.BlockByHash(ctx, hash)
|
||||
if block != nil && err == nil {
|
||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
if block, err := pea.ethClient.BlockByHash(ctx, hash); block != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
return pea.rpcMarshalBlock(block, true, fullTx)
|
||||
@@ -201,7 +206,7 @@ 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.Big {
|
||||
if pea.B.Config.ChainConfig.ChainID == nil || pea.B.Config.ChainConfig.ChainID.Cmp(big.NewInt(0)) <= 0 {
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
if id, err := pea.ethClient.ChainID(context.Background()); err == nil {
|
||||
return (*hexutil.Big)(id)
|
||||
}
|
||||
@@ -225,14 +230,14 @@ func (pea *PublicEthAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, bloc
|
||||
if block != nil && err == nil {
|
||||
uncles := block.Uncles()
|
||||
if index >= hexutil.Uint(len(uncles)) {
|
||||
logrus.Debugf("uncle with index %s request at block number %d was not found", index.String(), blockNr.Int64())
|
||||
log.Debugxf(ctx, "uncle with index %s request at block number %d was not found", index.String(), blockNr.Int64())
|
||||
return nil, nil
|
||||
}
|
||||
block = types.NewBlockWithHeader(uncles[index])
|
||||
return pea.rpcMarshalBlock(block, false, false)
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.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)
|
||||
@@ -249,14 +254,14 @@ func (pea *PublicEthAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockH
|
||||
if block != nil {
|
||||
uncles := block.Uncles()
|
||||
if index >= hexutil.Uint(len(uncles)) {
|
||||
logrus.Debugf("uncle with index %s request at block hash %s was not found", index.String(), blockHash.Hex())
|
||||
log.Debugxf(ctx, "uncle with index %s request at block hash %s was not found", index.String(), blockHash.Hex())
|
||||
return nil, nil
|
||||
}
|
||||
block = types.NewBlockWithHeader(uncles[index])
|
||||
return pea.rpcMarshalBlock(block, false, false)
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.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)
|
||||
@@ -273,7 +278,7 @@ func (pea *PublicEthAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr
|
||||
return &n
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getUncleCountByBlockNumber", blockNr); num != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
@@ -291,7 +296,7 @@ func (pea *PublicEthAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash
|
||||
return &n
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getUncleCountByBlockHash", blockHash); num != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
@@ -315,7 +320,7 @@ func (pea *PublicEthAPI) GetTransactionCount(ctx context.Context, address common
|
||||
return count, nil
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var num *hexutil.Uint64
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getTransactionCount", address, blockNrOrHash); num != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
@@ -343,7 +348,7 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByNumber(ctx context.Context, b
|
||||
return &n
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getBlockTransactionCountByNumber", blockNr); num != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
@@ -361,7 +366,7 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByHash(ctx context.Context, blo
|
||||
return &n
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var num *hexutil.Uint
|
||||
if err := pea.rpc.CallContext(ctx, &num, "eth_getBlockTransactionCountByHash", blockHash); num != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
@@ -378,7 +383,7 @@ func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context
|
||||
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var tx *RPCTransaction
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByBlockNumberAndIndex", blockNr, index); tx != nil && err == nil {
|
||||
go pea.writeStateDiffAt(blockNr.Int64())
|
||||
@@ -395,7 +400,7 @@ func (pea *PublicEthAPI) GetTransactionByBlockHashAndIndex(ctx context.Context,
|
||||
return newRPCTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var tx *RPCTransaction
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
@@ -411,7 +416,7 @@ func (pea *PublicEthAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Cont
|
||||
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
|
||||
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.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())
|
||||
@@ -426,7 +431,7 @@ func (pea *PublicEthAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Contex
|
||||
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
|
||||
return newRPCRawTransactionFromBlockIndex(block, uint64(index))
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var tx hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getRawTransactionByBlockHashAndIndex", blockHash, index); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(blockHash)
|
||||
@@ -448,7 +453,7 @@ func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.H
|
||||
|
||||
return NewRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee), nil
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var tx *RPCTransaction
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getTransactionByHash", hash); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
@@ -465,7 +470,7 @@ func (pea *PublicEthAPI) GetRawTransactionByHash(ctx context.Context, hash commo
|
||||
if tx != nil && err == nil {
|
||||
return rlp.EncodeToBytes(tx)
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var tx hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &tx, "eth_getRawTransactionByHash", hash); tx != nil && err == nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
@@ -475,6 +480,84 @@ func (pea *PublicEthAPI) GetRawTransactionByHash(ctx context.Context, hash commo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// accessListResult returns an optional accesslist
|
||||
// Its the result of the `debug_createAccessList` RPC call.
|
||||
// It contains an error if the transaction itself failed.
|
||||
type accessListResult struct {
|
||||
Accesslist *types.AccessList `json:"accessList"`
|
||||
Error string `json:"error,omitempty"`
|
||||
GasUsed hexutil.Uint64 `json:"gasUsed"`
|
||||
}
|
||||
|
||||
// CreateAccessList creates a EIP-2930 type AccessList for the given transaction.
|
||||
// Reexec and BlockNrOrHash can be specified to create the accessList on top of a certain state.
|
||||
func (pea *PublicEthAPI) CreateAccessList(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (*accessListResult, error) {
|
||||
if pea.rpc != nil {
|
||||
var res *accessListResult
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_createAccessList", args, blockNrOrHash); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
return nil, RequiresProxyError{method: "eth_createAccessList"}
|
||||
}
|
||||
|
||||
type feeHistoryResult struct {
|
||||
OldestBlock *hexutil.Big `json:"oldestBlock"`
|
||||
Reward [][]*hexutil.Big `json:"reward,omitempty"`
|
||||
BaseFee []*hexutil.Big `json:"baseFeePerGas,omitempty"`
|
||||
GasUsedRatio []float64 `json:"gasUsedRatio"`
|
||||
}
|
||||
|
||||
// FeeHistory returns the fee market history.
|
||||
func (pea *PublicEthAPI) FeeHistory(ctx context.Context, blockCount int, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*feeHistoryResult, error) {
|
||||
if pea.rpc != nil {
|
||||
var res *feeHistoryResult
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_feeHistory", blockCount, lastBlock, rewardPercentiles); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
return nil, RequiresProxyError{method: "eth_feeHistory"}
|
||||
}
|
||||
|
||||
// EstimateGas returns an estimate of the amount of gas needed to execute the
|
||||
// given transaction against the current pending block.
|
||||
func (pea *PublicEthAPI) EstimateGas(ctx context.Context, args TransactionArgs, blockNrOrHash *rpc.BlockNumberOrHash) (hexutil.Uint64, error) {
|
||||
if pea.rpc != nil {
|
||||
var res hexutil.Uint64
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_estimateGas", args, blockNrOrHash); err != nil {
|
||||
return hexutil.Uint64(0), err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
return hexutil.Uint64(0), RequiresProxyError{method: "eth_estimateGas"}
|
||||
}
|
||||
|
||||
// GasPrice returns a suggestion for a gas price for legacy transactions.
|
||||
func (pea *PublicEthAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
|
||||
if pea.rpc != nil {
|
||||
var res *hexutil.Big
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_gasPrice"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
return nil, RequiresProxyError{method: "eth_gasPrice"}
|
||||
}
|
||||
|
||||
// MaxPriorityFeePerGas returns a suggestion for a gas tip cap for dynamic fee transactions.
|
||||
func (pea *PublicEthAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, error) {
|
||||
if pea.rpc != nil {
|
||||
var res *hexutil.Big
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_maxPriorityFeePerGas"); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
return nil, RequiresProxyError{method: "eth_maxPriorityFeePerGas"}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Receipts and Logs
|
||||
@@ -487,7 +570,7 @@ func (pea *PublicEthAPI) GetTransactionReceipt(ctx context.Context, hash common.
|
||||
if receipt != nil && err == nil {
|
||||
return receipt, nil
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
if receipt := pea.remoteGetTransactionReceipt(ctx, hash); receipt != nil {
|
||||
go pea.writeStateDiffFor(hash)
|
||||
return receipt, nil
|
||||
@@ -513,7 +596,7 @@ func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash co
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = receipts.DeriveFields(pea.B.Config.ChainConfig, blockHash, blockNumber, block.Transactions())
|
||||
err = receipts.DeriveFields(pea.B.Config.ChainConfig, blockHash, blockNumber, block.BaseFee(), block.Transactions())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -585,7 +668,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.proxyOnError {
|
||||
if err != nil && pea.config.ProxyOnError {
|
||||
var res []*types.Log
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getLogs", crit); err == nil {
|
||||
go pea.writeStateDiffWithCriteria(crit)
|
||||
@@ -699,10 +782,9 @@ func (pea *PublicEthAPI) GetBalance(ctx context.Context, address common.Address,
|
||||
if bal != nil && err == nil {
|
||||
return bal, nil
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var res *hexutil.Big
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getBalance", address, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
@@ -725,6 +807,13 @@ func (pea *PublicEthAPI) localGetBalance(ctx context.Context, address common.Add
|
||||
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
||||
// numbers are also allowed.
|
||||
func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNrOrHash rpc.BlockNumberOrHash) (hexutil.Bytes, error) {
|
||||
if pea.config.ForwardGetStorageAt {
|
||||
var res hexutil.Bytes
|
||||
// If forwarding all getStorageAt calls, don't request statediffing.
|
||||
err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash)
|
||||
return res, err
|
||||
}
|
||||
|
||||
storageVal, err := pea.B.GetStorageByNumberOrHash(ctx, address, common.HexToHash(key), blockNrOrHash)
|
||||
if storageVal != nil && err == nil {
|
||||
var value common.Hash
|
||||
@@ -739,10 +828,10 @@ func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Addres
|
||||
|
||||
return value[:], nil
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
log.Warnxf(ctx, "Missing eth_getStorageAt(%s, %s, %s)", address.Hash().String(), key, blockNrOrHash.String())
|
||||
var res hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
@@ -758,10 +847,9 @@ func (pea *PublicEthAPI) GetCode(ctx context.Context, address common.Address, bl
|
||||
if code != nil && err == nil {
|
||||
return code, nil
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var res hexutil.Bytes
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getCode", address, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
@@ -778,10 +866,9 @@ func (pea *PublicEthAPI) GetProof(ctx context.Context, address common.Address, s
|
||||
if proof != nil && err == nil {
|
||||
return proof, nil
|
||||
}
|
||||
if pea.proxyOnError {
|
||||
if pea.config.ProxyOnError {
|
||||
var res *AccountResult
|
||||
if err := pea.rpc.CallContext(ctx, &res, "eth_getProof", address, storageKeys, blockNrOrHash); res != nil && err == nil {
|
||||
go pea.writeStateDiffAtOrFor(blockNrOrHash)
|
||||
return res, nil
|
||||
}
|
||||
}
|
||||
@@ -794,7 +881,10 @@ func (pea *PublicEthAPI) localGetProof(ctx context.Context, address common.Addre
|
||||
return nil, err
|
||||
}
|
||||
|
||||
storageTrie := state.StorageTrie(address)
|
||||
storageTrie, err := state.StorageTrie(address)
|
||||
if storageTrie == nil || err != nil {
|
||||
return nil, err
|
||||
}
|
||||
storageHash := types.EmptyRootHash
|
||||
codeHash := state.GetCodeHash(address)
|
||||
storageProof := make([]StorageResult, len(storageKeys))
|
||||
@@ -837,6 +927,11 @@ func (pea *PublicEthAPI) localGetProof(ctx context.Context, address common.Addre
|
||||
}, state.Error()
|
||||
}
|
||||
|
||||
// GetSlice returns a slice of state or storage nodes from a provided root to a provided path and past it to a certain depth
|
||||
func (pea *PublicEthAPI) GetSlice(ctx context.Context, path string, depth int, root common.Hash, storage bool) (*GetSliceResponse, error) {
|
||||
return pea.B.GetSlice(path, depth, root, storage)
|
||||
}
|
||||
|
||||
// revertError is an API error that encompassas an EVM revertal with JSON error
|
||||
// code and a binary data blob.
|
||||
type revertError struct {
|
||||
@@ -926,7 +1021,7 @@ 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 {
|
||||
if pea.config.ForwardEthCalls {
|
||||
var hex hexutil.Bytes
|
||||
err := pea.rpc.CallContext(ctx, &hex, "eth_call", args, blockNrOrHash, overrides)
|
||||
return hex, err
|
||||
@@ -943,10 +1038,9 @@ func (pea *PublicEthAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil && pea.proxyOnError {
|
||||
if err != nil && pea.config.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
|
||||
}
|
||||
}
|
||||
@@ -960,7 +1054,7 @@ func (pea *PublicEthAPI) Call(ctx context.Context, args CallArgs, blockNrOrHash
|
||||
|
||||
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())
|
||||
log.Debugxf(ctx, "Executing EVM call finished %s runtime %s", time.Now().String(), time.Since(start).String())
|
||||
}(time.Now())
|
||||
|
||||
state, header, err := b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
@@ -1014,7 +1108,7 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
||||
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
|
||||
}
|
||||
if err != nil {
|
||||
return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
|
||||
return result, fmt.Errorf("err: %w (supplied gas %d)", err, args.Gas)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -1022,7 +1116,7 @@ func DoCall(ctx context.Context, b *Backend, args CallArgs, blockNrOrHash rpc.Bl
|
||||
// writeStateDiffAtOrFor calls out to the proxy statediffing geth client to fill in a gap in the index
|
||||
func (pea *PublicEthAPI) writeStateDiffAtOrFor(blockNrOrHash rpc.BlockNumberOrHash) {
|
||||
// short circuit right away if the proxy doesn't support diffing
|
||||
if !pea.supportsStateDiff {
|
||||
if !pea.config.SupportsStateDiff {
|
||||
return
|
||||
}
|
||||
if blockNr, ok := blockNrOrHash.Number(); ok {
|
||||
@@ -1037,34 +1131,19 @@ func (pea *PublicEthAPI) writeStateDiffAtOrFor(blockNrOrHash rpc.BlockNumberOrHa
|
||||
// writeStateDiffWithCriteria calls out to the proxy statediffing geth client to fill in a gap in the index
|
||||
func (pea *PublicEthAPI) writeStateDiffWithCriteria(crit filters.FilterCriteria) {
|
||||
// short circuit right away if the proxy doesn't support diffing
|
||||
if !pea.supportsStateDiff {
|
||||
if !pea.config.SupportsStateDiff || crit.BlockHash == nil {
|
||||
return
|
||||
}
|
||||
if crit.BlockHash != nil {
|
||||
pea.writeStateDiffFor(*crit.BlockHash)
|
||||
return
|
||||
}
|
||||
var start, end int64
|
||||
if crit.FromBlock != nil {
|
||||
start = crit.FromBlock.Int64()
|
||||
}
|
||||
if crit.ToBlock != nil {
|
||||
end = crit.ToBlock.Int64()
|
||||
} else {
|
||||
end = start
|
||||
}
|
||||
for i := start; i <= end; i++ {
|
||||
pea.writeStateDiffAt(i)
|
||||
}
|
||||
pea.writeStateDiffFor(*crit.BlockHash)
|
||||
}
|
||||
|
||||
// writeStateDiffAt calls out to the proxy statediffing geth client to fill in a gap in the index
|
||||
func (pea *PublicEthAPI) writeStateDiffAt(height int64) {
|
||||
if !pea.supportsStateDiff {
|
||||
if !pea.config.SupportsStateDiff {
|
||||
return
|
||||
}
|
||||
// we use a separate context than the one provided by the client
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultStateDiffTimeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), pea.config.StateDiffTimeout)
|
||||
defer cancel()
|
||||
var data json.RawMessage
|
||||
params := statediff.Params{
|
||||
@@ -1075,18 +1154,19 @@ func (pea *PublicEthAPI) writeStateDiffAt(height int64) {
|
||||
IncludeTD: true,
|
||||
IncludeCode: true,
|
||||
}
|
||||
log.Debugf("Calling statediff_writeStateDiffAt(%d)", height)
|
||||
if err := pea.rpc.CallContext(ctx, &data, "statediff_writeStateDiffAt", uint64(height), params); err != nil {
|
||||
logrus.Errorf("writeStateDiffAt %d faild with err %s", height, err.Error())
|
||||
log.Errorf("writeStateDiffAt %d failed with err %s", height, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// writeStateDiffFor calls out to the proxy statediffing geth client to fill in a gap in the index
|
||||
func (pea *PublicEthAPI) writeStateDiffFor(blockHash common.Hash) {
|
||||
if !pea.supportsStateDiff {
|
||||
if !pea.config.SupportsStateDiff {
|
||||
return
|
||||
}
|
||||
// we use a separate context than the one provided by the client
|
||||
ctx, cancel := context.WithTimeout(context.Background(), defaultStateDiffTimeout)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), pea.config.StateDiffTimeout)
|
||||
defer cancel()
|
||||
var data json.RawMessage
|
||||
params := statediff.Params{
|
||||
@@ -1097,8 +1177,9 @@ func (pea *PublicEthAPI) writeStateDiffFor(blockHash common.Hash) {
|
||||
IncludeTD: true,
|
||||
IncludeCode: true,
|
||||
}
|
||||
log.Debugf("Calling statediff_writeStateDiffFor(%s)", blockHash.Hex())
|
||||
if err := pea.rpc.CallContext(ctx, &data, "statediff_writeStateDiffFor", blockHash, params); err != nil {
|
||||
logrus.Errorf("writeStateDiffFor %s faild with err %s", blockHash.Hex(), err.Error())
|
||||
log.Errorf("writeStateDiffFor %s failed with err %s", blockHash.Hex(), err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1106,13 +1187,13 @@ func (pea *PublicEthAPI) writeStateDiffFor(blockHash common.Hash) {
|
||||
func (pea *PublicEthAPI) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
|
||||
fields, err := RPCMarshalBlock(b, inclTx, fullTx)
|
||||
if err != nil {
|
||||
logrus.Errorf("error RPC marshalling block with hash %s: %s", b.Hash().String(), err)
|
||||
log.Errorf("error RPC marshalling block with hash %s: %s", b.Hash().String(), err)
|
||||
return nil, err
|
||||
}
|
||||
if inclTx {
|
||||
td, err := pea.B.GetTd(b.Hash())
|
||||
if err != nil {
|
||||
logrus.Errorf("error getting td for block with hash and number %s, %s: %s", b.Hash().String(), b.Number().String(), err)
|
||||
log.Errorf("error getting td for block with hash and number %s, %s: %s", b.Hash().String(), b.Number().String(), err)
|
||||
return nil, err
|
||||
}
|
||||
fields["totalDifficulty"] = (*hexutil.Big)(td)
|
||||
|
||||
+7
-7
@@ -21,10 +21,6 @@ import (
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
ethServerShared "github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
@@ -39,6 +35,10 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -202,8 +202,8 @@ var _ = Describe("API", func() {
|
||||
ChainConfig: chainConfig,
|
||||
VMConfig: vm.Config{},
|
||||
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||
GroupCacheConfig: ðServerShared.GroupCacheConfig{
|
||||
StateDB: ethServerShared.GroupConfig{
|
||||
GroupCacheConfig: &shared.GroupCacheConfig{
|
||||
StateDB: shared.GroupConfig{
|
||||
Name: "api_test",
|
||||
CacheSizeInMB: 8,
|
||||
CacheExpiryInMins: 60,
|
||||
@@ -212,7 +212,7 @@ var _ = Describe("API", func() {
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false)
|
||||
api, _ = eth.NewPublicEthAPI(backend, nil, eth.APIConfig{false, false, false, false, shared.DefaultStateDiffTimeout})
|
||||
tx, err = indexAndPublisher.PushBlock(test_helpers.MockBlock, test_helpers.MockReceipts, test_helpers.MockBlock.Difficulty())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
|
||||
+285
-21
@@ -17,15 +17,18 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
validator "github.com/cerc-io/eth-ipfs-state-validator/v4/pkg"
|
||||
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v4/postgres"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
@@ -41,11 +44,11 @@ import (
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
ethServerShared "github.com/ethereum/go-ethereum/statediff/indexer/shared"
|
||||
sdtrie "github.com/ethereum/go-ethereum/statediff/trie_helpers"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
ethServerShared "github.com/ethereum/go-ethereum/statediff/indexer/shared"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
@@ -364,8 +367,10 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blockNumber := header.Number.Uint64()
|
||||
|
||||
// Fetch uncles
|
||||
uncles, err := b.GetUnclesByBlockHash(tx, hash)
|
||||
uncles, err := b.GetUnclesByBlockHashAndNumber(tx, hash, blockNumber)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
log.Error("error fetching uncles: ", err)
|
||||
return nil, err
|
||||
@@ -389,14 +394,14 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
|
||||
}
|
||||
|
||||
// Fetch transactions
|
||||
transactions, err := b.GetTransactionsByBlockHash(tx, hash)
|
||||
transactions, err := b.GetTransactionsByBlockHashAndNumber(tx, hash, blockNumber)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
log.Error("error fetching transactions: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Fetch receipts
|
||||
receipts, err := b.GetReceiptsByBlockHash(tx, hash)
|
||||
receipts, err := b.GetReceiptsByBlockHashAndNumber(tx, hash, blockNumber)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
log.Error("error fetching receipts: ", err)
|
||||
return nil, err
|
||||
@@ -417,6 +422,27 @@ func (b *Backend) GetHeaderByBlockHash(tx *sqlx.Tx, hash common.Hash) (*types.He
|
||||
return header, rlp.DecodeBytes(headerRLP, header)
|
||||
}
|
||||
|
||||
// CurrentHeader returns the current block's header
|
||||
func (b *Backend) CurrentHeader() *types.Header {
|
||||
block, err := b.BlockByNumber(context.Background(), rpc.LatestBlockNumber)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return block.Header()
|
||||
}
|
||||
|
||||
// GetBody returns the the body for the provided block hash and number
|
||||
func (b *Backend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
|
||||
if number < 0 || hash == (common.Hash{}) {
|
||||
return nil, errors.New("invalid arguments; expect hash and no special block numbers")
|
||||
}
|
||||
block, bErr := b.BlockByHash(ctx, hash)
|
||||
if block != nil && bErr == nil {
|
||||
return block.Body(), nil
|
||||
}
|
||||
return nil, errors.New("block body not found")
|
||||
}
|
||||
|
||||
// GetUnclesByBlockHash retrieves uncles for a provided block hash
|
||||
func (b *Backend) GetUnclesByBlockHash(tx *sqlx.Tx, hash common.Hash) ([]*types.Header, error) {
|
||||
_, uncleBytes, err := b.IPLDRetriever.RetrieveUnclesByBlockHash(tx, hash)
|
||||
@@ -438,6 +464,27 @@ func (b *Backend) GetUnclesByBlockHash(tx *sqlx.Tx, hash common.Hash) ([]*types.
|
||||
return uncles, nil
|
||||
}
|
||||
|
||||
// GetUnclesByBlockHashAndNumber retrieves uncles for a provided block hash and number
|
||||
func (b *Backend) GetUnclesByBlockHashAndNumber(tx *sqlx.Tx, hash common.Hash, number uint64) ([]*types.Header, error) {
|
||||
_, uncleBytes, err := b.IPLDRetriever.RetrieveUncles(tx, hash, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uncles := make([]*types.Header, len(uncleBytes))
|
||||
for i, bytes := range uncleBytes {
|
||||
var uncle types.Header
|
||||
err = rlp.DecodeBytes(bytes, &uncle)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
uncles[i] = &uncle
|
||||
}
|
||||
|
||||
return uncles, nil
|
||||
}
|
||||
|
||||
// GetTransactionsByBlockHash retrieves transactions for a provided block hash
|
||||
func (b *Backend) GetTransactionsByBlockHash(tx *sqlx.Tx, hash common.Hash) (types.Transactions, error) {
|
||||
_, transactionBytes, err := b.IPLDRetriever.RetrieveTransactionsByBlockHash(tx, hash)
|
||||
@@ -458,6 +505,26 @@ func (b *Backend) GetTransactionsByBlockHash(tx *sqlx.Tx, hash common.Hash) (typ
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
// GetTransactionsByBlockHashAndNumber retrieves transactions for a provided block hash and number
|
||||
func (b *Backend) GetTransactionsByBlockHashAndNumber(tx *sqlx.Tx, hash common.Hash, number uint64) (types.Transactions, error) {
|
||||
_, transactionBytes, err := b.IPLDRetriever.RetrieveTransactions(tx, hash, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txs := make(types.Transactions, len(transactionBytes))
|
||||
for i, txBytes := range transactionBytes {
|
||||
var tx types.Transaction
|
||||
if err := tx.UnmarshalBinary(txBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txs[i] = &tx
|
||||
}
|
||||
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
// GetReceiptsByBlockHash retrieves receipts for a provided block hash
|
||||
func (b *Backend) GetReceiptsByBlockHash(tx *sqlx.Tx, hash common.Hash) (types.Receipts, error) {
|
||||
_, receiptBytes, txs, err := b.IPLDRetriever.RetrieveReceiptsByBlockHash(tx, hash)
|
||||
@@ -476,6 +543,24 @@ func (b *Backend) GetReceiptsByBlockHash(tx *sqlx.Tx, hash common.Hash) (types.R
|
||||
return rcts, nil
|
||||
}
|
||||
|
||||
// GetReceiptsByBlockHashAndNumber retrieves receipts for a provided block hash and number
|
||||
func (b *Backend) GetReceiptsByBlockHashAndNumber(tx *sqlx.Tx, hash common.Hash, number uint64) (types.Receipts, error) {
|
||||
_, receiptBytes, txs, err := b.IPLDRetriever.RetrieveReceipts(tx, hash, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rcts := make(types.Receipts, len(receiptBytes))
|
||||
for i, rctBytes := range receiptBytes {
|
||||
rct := new(types.Receipt)
|
||||
if err := rct.UnmarshalBinary(rctBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rct.TxHash = txs[i]
|
||||
rcts[i] = rct
|
||||
}
|
||||
return rcts, nil
|
||||
}
|
||||
|
||||
// GetTransaction retrieves a tx by hash
|
||||
// It also returns the blockhash, blocknumber, and tx index associated with the transaction
|
||||
func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
|
||||
@@ -523,20 +608,13 @@ func (b *Backend) GetReceipts(ctx context.Context, hash common.Hash) (types.Rece
|
||||
}
|
||||
}()
|
||||
|
||||
_, receiptBytes, txs, err := b.IPLDRetriever.RetrieveReceiptsByBlockHash(tx, hash)
|
||||
headerCID, err := b.Retriever.RetrieveHeaderCIDByHash(tx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rcts := make(types.Receipts, len(receiptBytes))
|
||||
for i, rctBytes := range receiptBytes {
|
||||
rct := new(types.Receipt)
|
||||
if err := rct.UnmarshalBinary(rctBytes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rct.TxHash = txs[i]
|
||||
rcts[i] = rct
|
||||
}
|
||||
return rcts, nil
|
||||
blockNumber, _ := strconv.ParseUint(string(headerCID.BlockNumber), 10, 64)
|
||||
|
||||
return b.GetReceiptsByBlockHashAndNumber(tx, hash, blockNumber)
|
||||
}
|
||||
|
||||
// GetLogs returns all the logs for the given block hash
|
||||
@@ -557,7 +635,7 @@ func (b *Backend) GetLogs(ctx context.Context, hash common.Hash, number uint64)
|
||||
}
|
||||
}()
|
||||
|
||||
_, receiptBytes, txs, err := b.IPLDRetriever.RetrieveReceiptsByBlockHash(tx, hash)
|
||||
_, receiptBytes, txs, err := b.IPLDRetriever.RetrieveReceipts(tx, hash, number)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -642,11 +720,11 @@ 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, func() error, error) {
|
||||
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)
|
||||
context := core.NewEVMBlockContext(header, b, nil)
|
||||
return vm.NewEVM(context, txContext, state, b.Config.ChainConfig, b.Config.VMConfig), vmError, nil
|
||||
evmCtx := core.NewEVMBlockContext(header, b, nil)
|
||||
return vm.NewEVM(evmCtx, 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
|
||||
@@ -833,6 +911,192 @@ func (b *Backend) GetStorageByHash(ctx context.Context, address common.Address,
|
||||
return storageRlp, err
|
||||
}
|
||||
|
||||
func (b *Backend) GetSlice(path string, depth int, root common.Hash, storage bool) (*GetSliceResponse, error) {
|
||||
response := new(GetSliceResponse)
|
||||
response.init(path, depth, root)
|
||||
|
||||
// Metadata fields
|
||||
metaData := metaDataFields{}
|
||||
|
||||
startTime := makeTimestamp()
|
||||
t, _ := b.StateDatabase.OpenTrie(root)
|
||||
metaData.trieLoadingTime = makeTimestamp() - startTime
|
||||
|
||||
// Convert the head hex path to a decoded byte path
|
||||
headPath := common.FromHex(path)
|
||||
|
||||
// Get Stem nodes
|
||||
err := b.getSliceStem(headPath, t, response, &metaData, storage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get Head node
|
||||
err = b.getSliceHead(headPath, t, response, &metaData, storage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if depth > 0 {
|
||||
// Get Slice nodes
|
||||
err = b.getSliceTrie(headPath, t, response, &metaData, depth, storage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
response.populateMetaData(metaData)
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (b *Backend) getSliceStem(headPath []byte, t state.Trie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error {
|
||||
leavesFetchTime := int64(0)
|
||||
totalStemStartTime := makeTimestamp()
|
||||
|
||||
for i := 0; i < len(headPath); i++ {
|
||||
// Create path for each node along the stem
|
||||
nodePath := make([]byte, len(headPath[:i]))
|
||||
copy(nodePath, headPath[:i])
|
||||
|
||||
rawNode, _, err := t.(*trie.StateTrie).TryGetNode(trie.HexToCompact(nodePath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Skip if node not found
|
||||
if rawNode == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
node, nodeElements, err := ResolveNode(nodePath, rawNode, b.StateDatabase.TrieDB())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
leafFetchTime, err := fillSliceNodeData(b.EthDB, response.TrieNodes.Stem, response.Leaves, node, nodeElements, storage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update metadata
|
||||
depthReached := len(node.Path) - len(headPath)
|
||||
if depthReached > metaData.maxDepth {
|
||||
metaData.maxDepth = depthReached
|
||||
}
|
||||
if node.NodeType == sdtypes.Leaf {
|
||||
metaData.leafCount++
|
||||
}
|
||||
leavesFetchTime += leafFetchTime
|
||||
}
|
||||
|
||||
// Update metadata time metrics
|
||||
totalStemTime := makeTimestamp() - totalStemStartTime
|
||||
metaData.sliceNodesFetchTime = totalStemTime - leavesFetchTime
|
||||
metaData.leavesFetchTime += leavesFetchTime
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Backend) getSliceHead(headPath []byte, t state.Trie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error {
|
||||
totalHeadStartTime := makeTimestamp()
|
||||
|
||||
rawNode, _, err := t.(*trie.StateTrie).TryGetNode(trie.HexToCompact(headPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Skip if node not found
|
||||
if rawNode == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
node, nodeElements, err := ResolveNode(headPath, rawNode, b.StateDatabase.TrieDB())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
leafFetchTime, err := fillSliceNodeData(b.EthDB, response.TrieNodes.Head, response.Leaves, node, nodeElements, storage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update metadata
|
||||
depthReached := len(node.Path) - len(headPath)
|
||||
if depthReached > metaData.maxDepth {
|
||||
metaData.maxDepth = depthReached
|
||||
}
|
||||
if node.NodeType == sdtypes.Leaf {
|
||||
metaData.leafCount++
|
||||
}
|
||||
|
||||
// Update metadata time metrics
|
||||
totalHeadTime := makeTimestamp() - totalHeadStartTime
|
||||
metaData.stemNodesFetchTime = totalHeadTime - leafFetchTime
|
||||
metaData.leavesFetchTime += leafFetchTime
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *Backend) getSliceTrie(headPath []byte, t state.Trie, response *GetSliceResponse, metaData *metaDataFields, depth int, storage bool) error {
|
||||
it, timeTaken := getIteratorAtPath(t, headPath)
|
||||
metaData.trieLoadingTime += timeTaken
|
||||
|
||||
leavesFetchTime := int64(0)
|
||||
totalSliceStartTime := makeTimestamp()
|
||||
|
||||
headPathLen := len(headPath)
|
||||
maxPathLen := headPathLen + depth
|
||||
descend := true
|
||||
for it.Next(descend) {
|
||||
pathLen := len(it.Path())
|
||||
|
||||
// End iteration on coming out of subtrie
|
||||
if pathLen <= headPathLen {
|
||||
break
|
||||
}
|
||||
|
||||
// Avoid descending further if max depth reached
|
||||
if pathLen >= maxPathLen {
|
||||
descend = false
|
||||
} else {
|
||||
descend = true
|
||||
}
|
||||
|
||||
// Skip value nodes
|
||||
if it.Leaf() || bytes.Equal(nullHashBytes, it.Hash().Bytes()) {
|
||||
continue
|
||||
}
|
||||
|
||||
node, nodeElements, err := sdtrie.ResolveNode(it, b.StateDatabase.TrieDB())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
leafFetchTime, err := fillSliceNodeData(b.EthDB, response.TrieNodes.Slice, response.Leaves, node, nodeElements, storage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update metadata
|
||||
depthReached := len(node.Path) - len(headPath)
|
||||
if depthReached > metaData.maxDepth {
|
||||
metaData.maxDepth = depthReached
|
||||
}
|
||||
if node.NodeType == sdtypes.Leaf {
|
||||
metaData.leafCount++
|
||||
}
|
||||
leavesFetchTime += leafFetchTime
|
||||
}
|
||||
|
||||
// Update metadata time metrics
|
||||
totalSliceTime := makeTimestamp() - totalSliceStartTime
|
||||
metaData.sliceNodesFetchTime = totalSliceTime - leavesFetchTime
|
||||
metaData.leavesFetchTime += leavesFetchTime
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Engine satisfied the ChainContext interface
|
||||
func (b *Backend) Engine() consensus.Engine {
|
||||
// TODO: we need to support more than just ethash based engines
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
@@ -26,11 +27,22 @@ import (
|
||||
"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/rawdb"
|
||||
"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/ethdb"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
sdtrie "github.com/ethereum/go-ethereum/statediff/trie_helpers"
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
nodeiter "github.com/ethereum/go-ethereum/trie/concurrent_iterator"
|
||||
)
|
||||
|
||||
var nullHashBytes = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000")
|
||||
var emptyCodeHash = crypto.Keccak256([]byte{})
|
||||
|
||||
// RPCMarshalHeader converts the given header to the RPC output.
|
||||
// This function is eth/internal so we have to make our own version here...
|
||||
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
|
||||
@@ -300,3 +312,98 @@ func toBlockNumArg(number *big.Int) string {
|
||||
}
|
||||
return hexutil.EncodeBig(number)
|
||||
}
|
||||
|
||||
func getIteratorAtPath(t state.Trie, startKey []byte) (trie.NodeIterator, int64) {
|
||||
startTime := makeTimestamp()
|
||||
var it trie.NodeIterator
|
||||
|
||||
if len(startKey)%2 != 0 {
|
||||
// Zero-pad for odd-length keys, required by HexToKeyBytes()
|
||||
startKey = append(startKey, 0)
|
||||
it = t.NodeIterator(nodeiter.HexToKeyBytes(startKey))
|
||||
} else {
|
||||
it = t.NodeIterator(nodeiter.HexToKeyBytes(startKey))
|
||||
// Step to the required node (not required if original startKey was odd-length)
|
||||
it.Next(true)
|
||||
}
|
||||
|
||||
return it, makeTimestamp() - startTime
|
||||
}
|
||||
|
||||
func fillSliceNodeData(
|
||||
ethDB ethdb.KeyValueReader,
|
||||
nodesMap map[string]string,
|
||||
leavesMap map[string]GetSliceResponseAccount,
|
||||
node sdtypes.StateNode,
|
||||
nodeElements []interface{},
|
||||
storage bool,
|
||||
) (int64, error) {
|
||||
// Populate the nodes map
|
||||
nodeValHash := crypto.Keccak256Hash(node.NodeValue)
|
||||
nodesMap[common.Bytes2Hex(nodeValHash.Bytes())] = common.Bytes2Hex(node.NodeValue)
|
||||
|
||||
// Extract account data if it's a Leaf node
|
||||
leafStartTime := makeTimestamp()
|
||||
if node.NodeType == sdtypes.Leaf && !storage {
|
||||
stateLeafKey, storageRoot, code, err := extractContractAccountInfo(ethDB, node, nodeElements)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("GetSlice account lookup error: %s", err.Error())
|
||||
}
|
||||
|
||||
if len(code) > 0 {
|
||||
// Populate the leaves map
|
||||
leavesMap[stateLeafKey] = GetSliceResponseAccount{
|
||||
StorageRoot: storageRoot,
|
||||
EVMCode: common.Bytes2Hex(code),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return makeTimestamp() - leafStartTime, nil
|
||||
}
|
||||
|
||||
func extractContractAccountInfo(ethDB ethdb.KeyValueReader, node sdtypes.StateNode, nodeElements []interface{}) (string, string, []byte, error) {
|
||||
var account types.StateAccount
|
||||
if err := rlp.DecodeBytes(nodeElements[1].([]byte), &account); err != nil {
|
||||
return "", "", nil, fmt.Errorf("error decoding account for leaf node at path %x nerror: %v", node.Path, err)
|
||||
}
|
||||
|
||||
if bytes.Equal(account.CodeHash, emptyCodeHash) {
|
||||
return "", "", nil, nil
|
||||
}
|
||||
|
||||
// Extract state leaf key
|
||||
partialPath := trie.CompactToHex(nodeElements[0].([]byte))
|
||||
valueNodePath := append(node.Path, partialPath...)
|
||||
encodedPath := trie.HexToCompact(valueNodePath)
|
||||
leafKey := encodedPath[1:]
|
||||
stateLeafKeyString := common.BytesToHash(leafKey).String()
|
||||
|
||||
storageRootString := account.Root.String()
|
||||
|
||||
// Extract codeHash and get code
|
||||
codeHash := common.BytesToHash(account.CodeHash)
|
||||
codeBytes := rawdb.ReadCode(ethDB, codeHash)
|
||||
|
||||
return stateLeafKeyString, storageRootString, codeBytes, nil
|
||||
}
|
||||
|
||||
func ResolveNode(path []byte, node []byte, trieDB *trie.Database) (sdtypes.StateNode, []interface{}, error) {
|
||||
nodePath := make([]byte, len(path))
|
||||
copy(nodePath, path)
|
||||
|
||||
var nodeElements []interface{}
|
||||
if err := rlp.DecodeBytes(node, &nodeElements); err != nil {
|
||||
return sdtypes.StateNode{}, nil, err
|
||||
}
|
||||
|
||||
ty, err := sdtrie.CheckKeyType(nodeElements)
|
||||
if err != nil {
|
||||
return sdtypes.StateNode{}, nil, err
|
||||
}
|
||||
return sdtypes.StateNode{
|
||||
NodeType: ty,
|
||||
Path: nodePath,
|
||||
NodeValue: node,
|
||||
}, nodeElements, nil
|
||||
}
|
||||
+36
-25
@@ -21,12 +21,12 @@ import (
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"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"
|
||||
"gorm.io/driver/postgres"
|
||||
"gorm.io/gorm"
|
||||
|
||||
@@ -117,14 +117,14 @@ func NewCIDRetriever(db *sqlx.DB) *CIDRetriever {
|
||||
// RetrieveFirstBlockNumber is used to retrieve the first block number in the db
|
||||
func (ecr *CIDRetriever) RetrieveFirstBlockNumber() (int64, error) {
|
||||
var blockNumber int64
|
||||
err := ecr.db.Get(&blockNumber, "SELECT block_number FROM eth.header_cids ORDER BY block_number ASC LIMIT 1")
|
||||
err := ecr.db.Get(&blockNumber, "SELECT block_number FROM public.blocks ORDER BY block_number ASC LIMIT 1")
|
||||
return blockNumber, err
|
||||
}
|
||||
|
||||
// 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 public.blocks ORDER BY block_number DESC LIMIT 1")
|
||||
return blockNumber, err
|
||||
}
|
||||
|
||||
@@ -360,30 +360,31 @@ func receiptFilterConditions(id *int, pgStr string, args []interface{}, rctFilte
|
||||
|
||||
// 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) {
|
||||
func (ecr *CIDRetriever) RetrieveFilteredGQLLogs(tx *sqlx.Tx, rctFilter ReceiptFilter, blockHash *common.Hash, blockNumber *big.Int) ([]LogResult, error) {
|
||||
log.Debug("retrieving log cids for receipt ids with block hash", blockHash.String())
|
||||
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, eth.transaction_cids.index as txn_index, data,
|
||||
eth.receipt_cids.leaf_cid as cid, eth.receipt_cids.post_status, header_cids.block_hash
|
||||
FROM eth.log_cids, eth.receipt_cids, eth.transaction_cids, eth.header_cids, public.blocks
|
||||
pgStr := `SELECT CAST(eth.log_cids.block_number as Text), eth.log_cids.header_id as block_hash,
|
||||
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,
|
||||
data, eth.receipt_cids.leaf_cid as cid, eth.receipt_cids.post_status, eth.receipt_cids.tx_id AS tx_hash
|
||||
FROM eth.log_cids, eth.receipt_cids, public.blocks
|
||||
WHERE eth.log_cids.rct_id = receipt_cids.tx_id
|
||||
AND eth.log_cids.header_id = eth.receipt_cids.header_id
|
||||
AND eth.log_cids.block_number = eth.receipt_cids.block_number
|
||||
AND receipt_cids.tx_id = transaction_cids.tx_hash
|
||||
AND receipt_cids.header_id = transaction_cids.header_id
|
||||
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 eth.log_cids.header_id = receipt_cids.header_id
|
||||
AND eth.log_cids.block_number = receipt_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`
|
||||
AND receipt_cids.header_id = $1`
|
||||
|
||||
args = append(args, blockHash.String())
|
||||
id++
|
||||
|
||||
if blockNumber != nil {
|
||||
pgStr += ` AND receipt_cids.block_number = $2`
|
||||
id++
|
||||
args = append(args, blockNumber.Int64())
|
||||
}
|
||||
|
||||
pgStr, args = logFilterCondition(&id, pgStr, args, rctFilter)
|
||||
pgStr += ` ORDER BY log_cids.index`
|
||||
|
||||
@@ -711,17 +712,22 @@ func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockNumber(blockNumber int64)
|
||||
return headerCIDs, nil
|
||||
}
|
||||
|
||||
// RetrieveHeaderAndTxCIDsByBlockHash retrieves header CID and their associated tx CIDs by block hash
|
||||
func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockHash(blockHash common.Hash) (HeaderCIDRecord, error) {
|
||||
// RetrieveHeaderAndTxCIDsByBlockHash retrieves header CID and their associated tx CIDs by block hash (and optionally block number)
|
||||
func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockHash(blockHash common.Hash, blockNumber *big.Int) (HeaderCIDRecord, error) {
|
||||
log.Debug("retrieving header cid and tx cids for block hash ", blockHash.String())
|
||||
|
||||
var headerCIDs []HeaderCIDRecord
|
||||
|
||||
conditions := map[string]interface{}{"block_hash": blockHash.String()}
|
||||
if blockNumber != nil {
|
||||
conditions["header_cids.block_number"] = blockNumber.Int64()
|
||||
}
|
||||
|
||||
// https://github.com/go-gorm/gorm/issues/4083#issuecomment-778883283
|
||||
// Will use join for TransactionCIDs once preload for 1:N is supported.
|
||||
err := ecr.gormDB.Preload("TransactionCIDs", func(tx *gorm.DB) *gorm.DB {
|
||||
return tx.Select("cid", "tx_hash", "index", "src", "dst", "header_id", "block_number")
|
||||
}).Joins("IPLD").Find(&headerCIDs, "block_hash = ?", blockHash.String()).Error
|
||||
}).Joins("IPLD").Find(&headerCIDs, conditions).Error
|
||||
|
||||
if err != nil {
|
||||
log.Error("header cid retrieval error")
|
||||
@@ -737,15 +743,20 @@ func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockHash(blockHash common.Has
|
||||
return headerCIDs[0], nil
|
||||
}
|
||||
|
||||
// RetrieveTxCIDByHash returns the tx for the given tx hash
|
||||
func (ecr *CIDRetriever) RetrieveTxCIDByHash(txHash string) (TransactionCIDRecord, error) {
|
||||
// RetrieveTxCIDByHash returns the tx for the given tx hash (and optionally block number)
|
||||
func (ecr *CIDRetriever) RetrieveTxCIDByHash(txHash string, blockNumber *big.Int) (TransactionCIDRecord, error) {
|
||||
log.Debug("retrieving tx cid for tx hash ", txHash)
|
||||
|
||||
var txCIDs []TransactionCIDRecord
|
||||
|
||||
err := ecr.gormDB.Joins("IPLD").Find(&txCIDs, "tx_hash = ? AND transaction_cids.header_id = (SELECT canonical_header_hash(transaction_cids.block_number))", txHash).Error
|
||||
var err error
|
||||
if blockNumber != nil {
|
||||
err = ecr.gormDB.Joins("IPLD").Find(&txCIDs, "tx_hash = ? AND transaction_cids.header_id = (SELECT canonical_header_hash(transaction_cids.block_number)) AND transaction_cids.block_number = ?", txHash, blockNumber.Int64()).Error
|
||||
} else {
|
||||
err = ecr.gormDB.Joins("IPLD").Find(&txCIDs, "tx_hash = ? AND transaction_cids.header_id = (SELECT canonical_header_hash(transaction_cids.block_number))", txHash).Error
|
||||
}
|
||||
if err != nil {
|
||||
log.Error("header cid retrieval error")
|
||||
log.Error("tx retrieval error")
|
||||
return TransactionCIDRecord{}, err
|
||||
}
|
||||
|
||||
|
||||
@@ -300,6 +300,7 @@ var _ = Describe("Retriever", func() {
|
||||
AND header_cids.block_number = $1
|
||||
ORDER BY transaction_cids.index`
|
||||
err := db.Select(&expectedRctCIDsAndLeafNodes, pgStr, test_helpers.BlockNumber.Uint64())
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cids1, empty, err := retriever.Retrieve(rctAddressFilter, 1)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(empty).ToNot(BeTrue())
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package eth
|
||||
|
||||
import "fmt"
|
||||
|
||||
type RequiresProxyError struct {
|
||||
method string
|
||||
}
|
||||
|
||||
var _ error = RequiresProxyError{}
|
||||
|
||||
func (e RequiresProxyError) SetMethod(method string) {
|
||||
e.method = method
|
||||
}
|
||||
|
||||
func (e RequiresProxyError) Error() string {
|
||||
return fmt.Sprintf("%s requires a configured proxy geth node", e.method)
|
||||
}
|
||||
+301
-7
@@ -19,14 +19,11 @@ package eth_test
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
ethServerShared "github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -40,10 +37,48 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth/test_helpers"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
)
|
||||
|
||||
var (
|
||||
parsedABI abi.ABI
|
||||
|
||||
block1StateRoot = common.HexToHash("0xa1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21")
|
||||
rootDataHashBlock1 = "a1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21"
|
||||
rootDataBlock1 = "f871a0577652b625b77bdb5bf77bc43f3125cad7464d679d1575565277d3611b8053e780808080a0fe889f10e5db8f2c2bf355928152a17f6e3bb99a9241ac6d84c77e6264509c798080808080808080a011db0cda34a896dabeb6839bb06a38f49514cfa486435984eb013b7df9ee85c58080"
|
||||
|
||||
block5StateRoot = common.HexToHash("0x572ef3b6b3d5164ed9d83341073f13af4d60a3aab38989b6c03917544f186a43")
|
||||
rootDataHashBlock5 = "572ef3b6b3d5164ed9d83341073f13af4d60a3aab38989b6c03917544f186a43"
|
||||
rootDataBlock5 = "f8b1a0408dd81f6cd5c614f91ecd9faa01d5feba936e0314ba04f99c74069ba819e0f280808080a0b356351d60bc9894cf1f1d6cb68c815f0131d50f1da83c4023a09ec855cfff91a0180d554b171f6acf8295e376266df2311f68975d74c02753b85707d308f703e48080808080a0422c7cc4fa407603f0879a0ecaa809682ce98dbef30551a34bcce09fa3ac995180a02d264f591aa3fa9df3cbeea190a4fd8d5483ddfb1b85603b2a006d179f79ba358080"
|
||||
|
||||
account1DataHash = "180d554b171f6acf8295e376266df2311f68975d74c02753b85707d308f703e4"
|
||||
account1Data = "f869a03114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45b846f8440180a04bd45c41d863f1bcf5da53364387fcdd64f77924d388a4df47e64132273fb4c0a0ba79854f3dbf6505fdbb085888e25fae8fa97288c5ce8fcd39aa589290d9a659"
|
||||
account1StateLeafKey = "0x6114658a74d9cc9f7acf2c5cd696c3494d7c344d78bfec3add0d91ec4e8d1c45"
|
||||
account1Code = "608060405234801561001057600080fd5b50600436106100415760003560e01c806343d726d61461004657806365f3c31a1461005057806373d4a13a1461007e575b600080fd5b61004e61009c565b005b61007c6004803603602081101561006657600080fd5b810190808035906020019092919050505061017b565b005b610086610185565b6040518082815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610141576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602281526020018061018c6022913960400191505060405180910390fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b8060018190555050565b6001548156fe4f6e6c79206f776e65722063616e2063616c6c20746869732066756e6374696f6e2ea265627a7a723158205ba91466129f45285f53176d805117208c231ec6343d7896790e6fc4165b802b64736f6c63430005110032"
|
||||
account2DataHash = "2d264f591aa3fa9df3cbeea190a4fd8d5483ddfb1b85603b2a006d179f79ba35"
|
||||
account2Data = "f871a03926db69aaced518e9b9f0f434a473e7174109c943548bb8f23be41ca76d9ad2b84ef84c02881bc16d674ec82710a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
||||
account3DataHash = "408dd81f6cd5c614f91ecd9faa01d5feba936e0314ba04f99c74069ba819e0f2"
|
||||
account3Data = "f86da030bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2ab84af848058405f5b608a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
||||
account4DataHash = "422c7cc4fa407603f0879a0ecaa809682ce98dbef30551a34bcce09fa3ac9951"
|
||||
account4Data = "f871a03957f3e2f04a0764c3a0491b175f69926da61efbcc8f61fa1455fd2d2b4cdd45b84ef84c80883782dace9d9003e8a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
||||
account5DataHash = "b356351d60bc9894cf1f1d6cb68c815f0131d50f1da83c4023a09ec855cfff91"
|
||||
account5Data = "f871a03380c7b7ae81a58eb98d9c78de4a1fd7fd9535fc953ed2be602daaa41767312ab84ef84c80883782dace9d900000a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"
|
||||
|
||||
contractStorageRootBlock5 = common.HexToHash("0x4bd45c41d863f1bcf5da53364387fcdd64f77924d388a4df47e64132273fb4c0")
|
||||
storageRootDataHashBlock5 = "4bd45c41d863f1bcf5da53364387fcdd64f77924d388a4df47e64132273fb4c0"
|
||||
storageRootDataBlock5 = "f838a120290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639594703c4b2bd70c169f5717101caee543299fc946c7"
|
||||
|
||||
contractStorageRootBlock4 = common.HexToHash("0x64ad893aa7937d05983daa8b7d221acdf1c116433f29dcd1ea69f16fa96fce68")
|
||||
storageRootDataHashBlock4 = "64ad893aa7937d05983daa8b7d221acdf1c116433f29dcd1ea69f16fa96fce68"
|
||||
storageRootDataBlock4 = "f8518080a08e8ada45207a7d2f19dd6f0ee4955cec64fa5ebef29568b5c449a4c4dd361d558080808080808080a07b58866e3801680bea90c82a80eb08889ececef107b8b504ae1d1a1e1e17b7af8080808080"
|
||||
|
||||
storageNode1DataHash = "7b58866e3801680bea90c82a80eb08889ececef107b8b504ae1d1a1e1e17b7af"
|
||||
storageNode1Data = "e2a0310e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf609"
|
||||
storageNode2DataHash = "8e8ada45207a7d2f19dd6f0ee4955cec64fa5ebef29568b5c449a4c4dd361d55"
|
||||
storageNode2Data = "f7a0390decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5639594703c4b2bd70c169f5717101caee543299fc946c7"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -81,8 +116,8 @@ var _ = Describe("eth state reading tests", func() {
|
||||
ChainConfig: chainConfig,
|
||||
VMConfig: vm.Config{},
|
||||
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
|
||||
GroupCacheConfig: ðServerShared.GroupCacheConfig{
|
||||
StateDB: ethServerShared.GroupConfig{
|
||||
GroupCacheConfig: &shared.GroupCacheConfig{
|
||||
StateDB: shared.GroupConfig{
|
||||
Name: "eth_state_test",
|
||||
CacheSizeInMB: 8,
|
||||
CacheExpiryInMins: 60,
|
||||
@@ -91,7 +126,7 @@ var _ = Describe("eth state reading tests", func() {
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
api, _ = eth.NewPublicEthAPI(backend, nil, false, false, false)
|
||||
api, _ = eth.NewPublicEthAPI(backend, nil, eth.APIConfig{false, false, false, false, shared.DefaultStateDiffTimeout})
|
||||
|
||||
// make the test blockchain (and state)
|
||||
blocks, receipts, chain = test_helpers.MakeChain(chainLength, test_helpers.Genesis, test_helpers.TestChainGen)
|
||||
@@ -529,4 +564,263 @@ var _ = Describe("eth state reading tests", func() {
|
||||
Expect(header).To(Equal(expectedCanonicalHeader))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("eth_getSlice", func() {
|
||||
It("Retrieves the state slice for root path", func() {
|
||||
path := "0x"
|
||||
depth := 3
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, block5StateRoot, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, block5StateRoot.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "1",
|
||||
"01-max-depth": "1",
|
||||
"02-total-trie-nodes": "6",
|
||||
"03-leaves": "5",
|
||||
"04-smart-contracts": "1",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{},
|
||||
Head: map[string]string{
|
||||
rootDataHashBlock5: rootDataBlock5,
|
||||
},
|
||||
Slice: map[string]string{
|
||||
account1DataHash: account1Data,
|
||||
account2DataHash: account2Data,
|
||||
account3DataHash: account3Data,
|
||||
account4DataHash: account4Data,
|
||||
account5DataHash: account5Data,
|
||||
},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{
|
||||
account1StateLeafKey: {
|
||||
StorageRoot: contractStorageRootBlock5.Hex(),
|
||||
EVMCode: account1Code,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
It("Retrieves the state slice for root path with 0 depth", func() {
|
||||
path := "0x"
|
||||
depth := 0
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, block5StateRoot, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, block5StateRoot.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "1",
|
||||
"01-max-depth": "0",
|
||||
"02-total-trie-nodes": "1",
|
||||
"03-leaves": "0",
|
||||
"04-smart-contracts": "0",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{},
|
||||
Head: map[string]string{
|
||||
rootDataHashBlock5: rootDataBlock5,
|
||||
},
|
||||
Slice: map[string]string{},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
It("Retrieves the state slice for a path to an account", func() {
|
||||
path := "0x06"
|
||||
depth := 2
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, block5StateRoot, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, block5StateRoot.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "2",
|
||||
"01-max-depth": "0",
|
||||
"02-total-trie-nodes": "2",
|
||||
"03-leaves": "1",
|
||||
"04-smart-contracts": "1",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{
|
||||
rootDataHashBlock5: rootDataBlock5,
|
||||
},
|
||||
Head: map[string]string{
|
||||
account1DataHash: account1Data,
|
||||
},
|
||||
Slice: map[string]string{},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{
|
||||
account1StateLeafKey: {
|
||||
StorageRoot: contractStorageRootBlock5.Hex(),
|
||||
EVMCode: account1Code,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
It("Retrieves the state slice for a path to a non-existing account", func() {
|
||||
path := "0x06"
|
||||
depth := 2
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, block1StateRoot, false)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, block1StateRoot.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "1",
|
||||
"01-max-depth": "0",
|
||||
"02-total-trie-nodes": "1",
|
||||
"03-leaves": "0",
|
||||
"04-smart-contracts": "0",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{
|
||||
rootDataHashBlock1: rootDataBlock1,
|
||||
},
|
||||
Head: map[string]string{},
|
||||
Slice: map[string]string{},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
|
||||
It("Retrieves the storage slice for root path", func() {
|
||||
path := "0x"
|
||||
depth := 2
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, contractStorageRootBlock4, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, contractStorageRootBlock4.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "1",
|
||||
"01-max-depth": "1",
|
||||
"02-total-trie-nodes": "3",
|
||||
"03-leaves": "2",
|
||||
"04-smart-contracts": "0",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{},
|
||||
Head: map[string]string{
|
||||
storageRootDataHashBlock4: storageRootDataBlock4,
|
||||
},
|
||||
Slice: map[string]string{
|
||||
storageNode1DataHash: storageNode1Data,
|
||||
storageNode2DataHash: storageNode2Data,
|
||||
},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
It("Retrieves the storage slice for root path with 0 depth", func() {
|
||||
path := "0x"
|
||||
depth := 0
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, contractStorageRootBlock4, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, contractStorageRootBlock4.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "1",
|
||||
"01-max-depth": "0",
|
||||
"02-total-trie-nodes": "1",
|
||||
"03-leaves": "0",
|
||||
"04-smart-contracts": "0",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{},
|
||||
Head: map[string]string{
|
||||
storageRootDataHashBlock4: storageRootDataBlock4,
|
||||
},
|
||||
Slice: map[string]string{},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
It("Retrieves the storage slice for root path with deleted nodes", func() {
|
||||
path := "0x"
|
||||
depth := 2
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, contractStorageRootBlock5, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, contractStorageRootBlock5.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "1",
|
||||
"01-max-depth": "0",
|
||||
"02-total-trie-nodes": "1",
|
||||
"03-leaves": "1",
|
||||
"04-smart-contracts": "0",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{},
|
||||
Head: map[string]string{
|
||||
storageRootDataHashBlock5: storageRootDataBlock5,
|
||||
},
|
||||
Slice: map[string]string{},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
It("Retrieves the storage slice for a path to a storage node", func() {
|
||||
path := "0x0b"
|
||||
depth := 2
|
||||
sliceResponse, err := api.GetSlice(ctx, path, depth, contractStorageRootBlock4, true)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedResponse := eth.GetSliceResponse{
|
||||
SliceID: fmt.Sprintf("%s-%d-%s", path, depth, contractStorageRootBlock4.String()),
|
||||
MetaData: eth.GetSliceResponseMetadata{
|
||||
NodeStats: map[string]string{
|
||||
"00-stem-and-head-nodes": "2",
|
||||
"01-max-depth": "0",
|
||||
"02-total-trie-nodes": "2",
|
||||
"03-leaves": "1",
|
||||
"04-smart-contracts": "0",
|
||||
},
|
||||
},
|
||||
TrieNodes: eth.GetSliceResponseTrieNodes{
|
||||
Stem: map[string]string{
|
||||
storageRootDataHashBlock4: storageRootDataBlock4,
|
||||
},
|
||||
Head: map[string]string{
|
||||
storageNode1DataHash: storageNode1Data,
|
||||
},
|
||||
Slice: map[string]string{},
|
||||
},
|
||||
Leaves: map[string]eth.GetSliceResponseAccount{},
|
||||
}
|
||||
|
||||
eth.CheckGetSliceResponse(*sliceResponse, expectedResponse)
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -20,9 +20,9 @@ import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestETHSuite(t *testing.T) {
|
||||
@@ -31,5 +31,5 @@ func TestETHSuite(t *testing.T) {
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logrus.SetOutput(ioutil.Discard)
|
||||
log.SetOutput(ioutil.Discard)
|
||||
})
|
||||
+3
-6
@@ -208,7 +208,7 @@ func checkReceipts(rct *types.Receipt, wantedTopics, actualTopics [][]string, wa
|
||||
}
|
||||
// If there are no wanted contract addresses, we keep all receipts that match the topic filter
|
||||
if len(wantedAddresses) == 0 {
|
||||
if match := filterMatch(wantedTopics, actualTopics); match == true {
|
||||
if match := filterMatch(wantedTopics, actualTopics); match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -218,7 +218,7 @@ func checkReceipts(rct *types.Receipt, wantedTopics, actualTopics [][]string, wa
|
||||
for _, actualAddr := range actualAddresses {
|
||||
if wantedAddr == actualAddr {
|
||||
// we keep the receipt if it matches on the topic filter
|
||||
if match := filterMatch(wantedTopics, actualTopics); match == true {
|
||||
if match := filterMatch(wantedTopics, actualTopics); match {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -240,10 +240,7 @@ func filterMatch(wantedTopics, actualTopics [][]string) bool {
|
||||
matches++
|
||||
}
|
||||
}
|
||||
if matches == 4 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return matches == 4
|
||||
}
|
||||
|
||||
// returns 1 if the two slices have a string in common, 0 if they do not
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdtypes "github.com/ethereum/go-ethereum/statediff/types"
|
||||
)
|
||||
|
||||
@@ -34,3 +36,8 @@ func ResolveToNodeType(nodeType int) sdtypes.NodeType {
|
||||
return sdtypes.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
// Timestamp in milliseconds
|
||||
func makeTimestamp() int64 {
|
||||
return time.Now().UnixNano() / int64(time.Millisecond)
|
||||
}
|
||||
@@ -22,11 +22,11 @@ import (
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/shared"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Fetcher interface for substituting mocks in tests
|
||||
|
||||
+104
-43
@@ -32,10 +32,6 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// node type removed value.
|
||||
// https://github.com/cerc-io/go-ethereum/blob/271f4d01e7e2767ffd8e0cd469bf545be96f2a84/statediff/indexer/helpers.go#L34
|
||||
removedNode = 3
|
||||
|
||||
RetrieveHeadersByHashesPgStr = `SELECT cid, data
|
||||
FROM eth.header_cids
|
||||
INNER JOIN public.blocks ON (
|
||||
@@ -64,6 +60,19 @@ const (
|
||||
AND uncle_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = ANY($1::VARCHAR(66)[])`
|
||||
RetrieveUnclesPgStr = `SELECT uncle_cids.cid, data
|
||||
FROM eth.uncle_cids
|
||||
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 header_cids.block_hash = $1
|
||||
AND header_cids.block_number = $2
|
||||
ORDER BY uncle_cids.parent_hash`
|
||||
RetrieveUnclesByBlockHashPgStr = `SELECT uncle_cids.cid, data
|
||||
FROM eth.uncle_cids
|
||||
INNER JOIN eth.header_cids ON (
|
||||
@@ -101,6 +110,19 @@ const (
|
||||
AND transaction_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE tx_hash = ANY($1::VARCHAR(66)[])`
|
||||
RetrieveTransactionsPgStr = `SELECT transaction_cids.cid, 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
|
||||
)
|
||||
INNER JOIN public.blocks ON (
|
||||
transaction_cids.mh_key = blocks.key
|
||||
AND transaction_cids.block_number = blocks.block_number
|
||||
)
|
||||
WHERE block_hash = $1
|
||||
AND header_cids.block_number = $2
|
||||
ORDER BY eth.transaction_cids.index ASC`
|
||||
RetrieveTransactionsByBlockHashPgStr = `SELECT transaction_cids.cid, data
|
||||
FROM eth.transaction_cids
|
||||
INNER JOIN eth.header_cids ON (
|
||||
@@ -146,6 +168,24 @@ const (
|
||||
)
|
||||
WHERE tx_hash = ANY($1::VARCHAR(66)[])
|
||||
AND transaction_cids.header_id = (SELECT canonical_header_hash(transaction_cids.block_number))`
|
||||
RetrieveReceiptsPgStr = `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.tx_hash
|
||||
AND receipt_cids.header_id = transaction_cids.header_id
|
||||
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
|
||||
AND header_cids.block_number = $2
|
||||
ORDER BY eth.transaction_cids.index ASC`
|
||||
RetrieveReceiptsByBlockHashPgStr = `SELECT receipt_cids.leaf_cid, data, eth.transaction_cids.tx_hash
|
||||
FROM eth.receipt_cids
|
||||
INNER JOIN eth.transaction_cids ON (
|
||||
@@ -217,41 +257,8 @@ const (
|
||||
AND header_cids.block_number <= $2
|
||||
ORDER BY header_cids.block_number DESC
|
||||
LIMIT 1`
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockNumberPgStr = `SELECT storage_cids.cid, storage_cids.mh_key, 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.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
|
||||
)
|
||||
WHERE state_leaf_key = $1
|
||||
AND storage_leaf_key = $2
|
||||
AND header_cids.block_number <= $3
|
||||
ORDER BY header_cids.block_number DESC
|
||||
LIMIT 1`
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr = `SELECT storage_cids.cid, storage_cids.mh_key, storage_cids.block_number, 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.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
|
||||
)
|
||||
WHERE state_leaf_key = $1
|
||||
AND storage_leaf_key = $2
|
||||
AND header_cids.block_number <= (SELECT block_number
|
||||
FROM eth.header_cids
|
||||
WHERE block_hash = $3)
|
||||
AND header_cids.block_hash = (SELECT canonical_header_hash(header_cids.block_number))
|
||||
ORDER BY header_cids.block_number DESC
|
||||
LIMIT 1`
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockNumberPgStr = `SELECT cid, mh_key, block_number, node_type, state_leaf_removed FROM get_storage_at_by_number($1, $2, $3)`
|
||||
RetrieveStorageLeafByAddressHashAndLeafKeyAndBlockHashPgStr = `SELECT cid, mh_key, block_number, node_type, state_leaf_removed FROM get_storage_at_by_hash($1, $2, $3)`
|
||||
)
|
||||
|
||||
var EmptyNodeValue = make([]byte, common.HashLength)
|
||||
@@ -338,6 +345,21 @@ func (r *IPLDRetriever) RetrieveUnclesByHashes(hashes []common.Hash) ([]string,
|
||||
return cids, uncles, nil
|
||||
}
|
||||
|
||||
// RetrieveUncles returns the cids and rlp bytes for the uncles corresponding to the provided block hash, number (of non-omner root block)
|
||||
func (r *IPLDRetriever) RetrieveUncles(tx *sqlx.Tx, hash common.Hash, number uint64) ([]string, [][]byte, error) {
|
||||
uncleResults := make([]ipldResult, 0)
|
||||
if err := tx.Select(&uncleResults, RetrieveUnclesPgStr, hash.Hex(), number); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cids := make([]string, len(uncleResults))
|
||||
uncles := make([][]byte, len(uncleResults))
|
||||
for i, res := range uncleResults {
|
||||
cids[i] = res.CID
|
||||
uncles[i] = res.Data
|
||||
}
|
||||
return cids, uncles, nil
|
||||
}
|
||||
|
||||
// RetrieveUnclesByBlockHash returns the cids and rlp bytes for the uncles corresponding to the provided block hash (of non-omner root block)
|
||||
func (r *IPLDRetriever) RetrieveUnclesByBlockHash(tx *sqlx.Tx, hash common.Hash) ([]string, [][]byte, error) {
|
||||
uncleResults := make([]ipldResult, 0)
|
||||
@@ -393,6 +415,21 @@ func (r *IPLDRetriever) RetrieveTransactionsByHashes(hashes []common.Hash) ([]st
|
||||
return cids, txs, nil
|
||||
}
|
||||
|
||||
// RetrieveTransactions returns the cids and rlp bytes for the transactions corresponding to the provided block hash, number
|
||||
func (r *IPLDRetriever) RetrieveTransactions(tx *sqlx.Tx, hash common.Hash, number uint64) ([]string, [][]byte, error) {
|
||||
txResults := make([]ipldResult, 0)
|
||||
if err := tx.Select(&txResults, RetrieveTransactionsPgStr, hash.Hex(), number); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
cids := make([]string, len(txResults))
|
||||
txs := make([][]byte, len(txResults))
|
||||
for i, res := range txResults {
|
||||
cids[i] = res.CID
|
||||
txs[i] = res.Data
|
||||
}
|
||||
return cids, txs, nil
|
||||
}
|
||||
|
||||
// RetrieveTransactionsByBlockHash returns the cids and rlp bytes for the transactions corresponding to the provided block hash
|
||||
func (r *IPLDRetriever) RetrieveTransactionsByBlockHash(tx *sqlx.Tx, hash common.Hash) ([]string, [][]byte, error) {
|
||||
txResults := make([]ipldResult, 0)
|
||||
@@ -469,6 +506,30 @@ func (r *IPLDRetriever) RetrieveReceiptsByTxHashes(hashes []common.Hash) ([]stri
|
||||
return cids, rcts, nil
|
||||
}
|
||||
|
||||
// RetrieveReceipts returns the cids and rlp bytes for the receipts corresponding to the provided block hash, number.
|
||||
// cid returned corresponds to the leaf node data which contains the receipt.
|
||||
func (r *IPLDRetriever) RetrieveReceipts(tx *sqlx.Tx, hash common.Hash, number uint64) ([]string, [][]byte, []common.Hash, error) {
|
||||
rctResults := make([]rctIpldResult, 0)
|
||||
if err := tx.Select(&rctResults, RetrieveReceiptsPgStr, hash.Hex(), number); err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
cids := make([]string, len(rctResults))
|
||||
rcts := make([][]byte, len(rctResults))
|
||||
txs := make([]common.Hash, len(rctResults))
|
||||
|
||||
for i, res := range rctResults {
|
||||
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
|
||||
}
|
||||
|
||||
// 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(tx *sqlx.Tx, hash common.Hash) ([]string, [][]byte, []common.Hash, error) {
|
||||
@@ -546,7 +607,7 @@ func (r *IPLDRetriever) RetrieveAccountByAddressAndBlockHash(address common.Addr
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if accountResult.NodeType == removedNode {
|
||||
if accountResult.NodeType == sdtypes.Removed.Int() {
|
||||
return "", EmptyNodeValue, nil
|
||||
}
|
||||
|
||||
@@ -578,7 +639,7 @@ func (r *IPLDRetriever) RetrieveAccountByAddressAndBlockNumber(address common.Ad
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if accountResult.NodeType == removedNode {
|
||||
if accountResult.NodeType == sdtypes.Removed.Int() {
|
||||
return "", EmptyNodeValue, nil
|
||||
}
|
||||
|
||||
@@ -606,7 +667,7 @@ 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.StateLeafRemoved || storageResult.NodeType == removedNode {
|
||||
if storageResult.StateLeafRemoved || storageResult.NodeType == sdtypes.Removed.Int() {
|
||||
return "", EmptyNodeValue, EmptyNodeValue, nil
|
||||
}
|
||||
|
||||
@@ -639,7 +700,7 @@ func (r *IPLDRetriever) RetrieveStorageAtByAddressAndStorageKeyAndBlockNumber(ad
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if storageResult.StateLeafRemoved || storageResult.NodeType == removedNode {
|
||||
if storageResult.StateLeafRemoved || storageResult.NodeType == sdtypes.Removed.Int() {
|
||||
return "", EmptyNodeValue, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package eth
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
// TxModelsContainsCID used to check if a list of TxModels contains a specific cid string
|
||||
@@ -39,3 +40,10 @@ func ReceiptModelsContainsCID(rcts []models.ReceiptModel, cid string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func CheckGetSliceResponse(sliceResponse GetSliceResponse, expectedResponse GetSliceResponse) {
|
||||
Expect(sliceResponse.SliceID).To(Equal(expectedResponse.SliceID))
|
||||
Expect(sliceResponse.MetaData.NodeStats).To(Equal(expectedResponse.MetaData.NodeStats))
|
||||
Expect(sliceResponse.TrieNodes).To(Equal(expectedResponse.TrieNodes))
|
||||
Expect(sliceResponse.Leaves).To(Equal(expectedResponse.Leaves))
|
||||
}
|
||||
@@ -65,7 +65,7 @@ func MakeChain(n int, parent *types.Block, chainGen func(int, *core.BlockGen)) (
|
||||
config := params.TestChainConfig
|
||||
config.LondonBlock = big.NewInt(100)
|
||||
blocks, receipts := core.GenerateChain(config, parent, ethash.NewFaker(), Testdb, n, chainGen)
|
||||
chain, _ := core.NewBlockChain(Testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
chain, _ := core.NewBlockChain(Testdb, nil, nil, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
|
||||
return append([]*types.Block{parent}, blocks...), receipts, chain
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"crypto/rand"
|
||||
"math/big"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@@ -36,7 +37,6 @@ import (
|
||||
"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/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package eth
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// TransactionArgs represents the arguments to construct a new transaction
|
||||
// or a message call.
|
||||
type TransactionArgs struct {
|
||||
From *common.Address `json:"from"`
|
||||
To *common.Address `json:"to"`
|
||||
Gas *hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||
|
||||
// We accept "data" and "input" for backwards-compatibility reasons.
|
||||
// "input" is the newer name and should be preferred by clients.
|
||||
// Issue detail: https://github.com/ethereum/go-ethereum/issues/15628
|
||||
Data *hexutil.Bytes `json:"data"`
|
||||
Input *hexutil.Bytes `json:"input"`
|
||||
|
||||
// Introduced by AccessListTxType transaction.
|
||||
AccessList *types.AccessList `json:"accessList,omitempty"`
|
||||
ChainID *hexutil.Big `json:"chainId,omitempty"`
|
||||
}
|
||||
|
||||
// from retrieves the transaction sender address.
|
||||
func (args *TransactionArgs) from() common.Address {
|
||||
if args.From == nil {
|
||||
return common.Address{}
|
||||
}
|
||||
return *args.From
|
||||
}
|
||||
|
||||
// data retrieves the transaction calldata. Input field is preferred.
|
||||
func (args *TransactionArgs) data() []byte {
|
||||
if args.Input != nil {
|
||||
return *args.Input
|
||||
}
|
||||
if args.Data != nil {
|
||||
return *args.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+81
-5
@@ -18,15 +18,19 @@ package eth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strconv"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"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/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
|
||||
@@ -123,10 +127,10 @@ func (arg *CallArgs) data() []byte {
|
||||
// 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) {
|
||||
func (arg *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.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")
|
||||
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
|
||||
}
|
||||
// Set sender address or use zero address if none specified.
|
||||
addr := arg.from()
|
||||
@@ -140,7 +144,7 @@ func (arg *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Mes
|
||||
gas = uint64(*arg.Gas)
|
||||
}
|
||||
if globalGasCap != 0 && globalGasCap < gas {
|
||||
logrus.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
|
||||
log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
|
||||
gas = globalGasCap
|
||||
}
|
||||
var (
|
||||
@@ -187,7 +191,19 @@ func (arg *CallArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Mes
|
||||
if arg.AccessList != nil {
|
||||
accessList = *arg.AccessList
|
||||
}
|
||||
msg := types.NewMessage(addr, arg.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true)
|
||||
msg := &core.Message{
|
||||
Nonce: 0,
|
||||
GasLimit: gas,
|
||||
GasPrice: new(big.Int).Set(gasPrice),
|
||||
GasFeeCap: new(big.Int).Set(gasFeeCap),
|
||||
GasTipCap: new(big.Int).Set(gasTipCap),
|
||||
To: arg.To,
|
||||
Value: value,
|
||||
Data: data,
|
||||
AccessList: accessList,
|
||||
SkipAccountChecks: true,
|
||||
From: addr,
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
@@ -264,3 +280,63 @@ type LogResult struct {
|
||||
TxnIndex int64 `db:"txn_index"`
|
||||
TxHash string `db:"tx_hash"`
|
||||
}
|
||||
|
||||
// GetSliceResponse holds response for the eth_getSlice method
|
||||
type GetSliceResponse struct {
|
||||
SliceID string `json:"sliceId"`
|
||||
MetaData GetSliceResponseMetadata `json:"metadata"`
|
||||
TrieNodes GetSliceResponseTrieNodes `json:"trieNodes"`
|
||||
Leaves map[string]GetSliceResponseAccount `json:"leaves"` // key: Keccak256Hash(address) in hex (leafKey)
|
||||
}
|
||||
|
||||
func (sr *GetSliceResponse) init(path string, depth int, root common.Hash) {
|
||||
sr.SliceID = fmt.Sprintf("%s-%d-%s", path, depth, root.String())
|
||||
sr.MetaData = GetSliceResponseMetadata{
|
||||
NodeStats: make(map[string]string, 0),
|
||||
TimeStats: make(map[string]string, 0),
|
||||
}
|
||||
sr.Leaves = make(map[string]GetSliceResponseAccount)
|
||||
sr.TrieNodes = GetSliceResponseTrieNodes{
|
||||
Stem: make(map[string]string),
|
||||
Head: make(map[string]string),
|
||||
Slice: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (sr *GetSliceResponse) populateMetaData(metaData metaDataFields) {
|
||||
sr.MetaData.NodeStats["00-stem-and-head-nodes"] = strconv.Itoa(len(sr.TrieNodes.Stem) + len(sr.TrieNodes.Head))
|
||||
sr.MetaData.NodeStats["01-max-depth"] = strconv.Itoa(metaData.maxDepth)
|
||||
sr.MetaData.NodeStats["02-total-trie-nodes"] = strconv.Itoa(len(sr.TrieNodes.Stem) + len(sr.TrieNodes.Head) + len(sr.TrieNodes.Slice))
|
||||
sr.MetaData.NodeStats["03-leaves"] = strconv.Itoa(metaData.leafCount)
|
||||
sr.MetaData.NodeStats["04-smart-contracts"] = strconv.Itoa(len(sr.Leaves))
|
||||
|
||||
sr.MetaData.TimeStats["00-trie-loading"] = strconv.FormatInt(metaData.trieLoadingTime, 10)
|
||||
sr.MetaData.TimeStats["01-fetch-stem-keys"] = strconv.FormatInt(metaData.stemNodesFetchTime, 10)
|
||||
sr.MetaData.TimeStats["02-fetch-slice-keys"] = strconv.FormatInt(metaData.sliceNodesFetchTime, 10)
|
||||
sr.MetaData.TimeStats["03-fetch-leaves-info"] = strconv.FormatInt(metaData.leavesFetchTime, 10)
|
||||
}
|
||||
|
||||
type GetSliceResponseMetadata struct {
|
||||
TimeStats map[string]string `json:"timeStats"` // stem, state, storage (one by one)
|
||||
NodeStats map[string]string `json:"nodeStats"` // total, leaves, smart contracts
|
||||
}
|
||||
|
||||
type GetSliceResponseTrieNodes struct {
|
||||
Stem map[string]string `json:"stem"` // key: Keccak256Hash(data) in hex, value: trie node data in hex
|
||||
Head map[string]string `json:"head"`
|
||||
Slice map[string]string `json:"sliceNodes"`
|
||||
}
|
||||
|
||||
type GetSliceResponseAccount struct {
|
||||
StorageRoot string `json:"storageRoot"`
|
||||
EVMCode string `json:"evmCode"`
|
||||
}
|
||||
|
||||
type metaDataFields struct {
|
||||
maxDepth int
|
||||
leafCount int
|
||||
trieLoadingTime int64
|
||||
stemNodesFetchTime int64
|
||||
sliceNodesFetchTime int64
|
||||
leavesFetchTime int64
|
||||
}
|
||||
+10
-3
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
@@ -91,10 +92,16 @@ func NewClient(endpoint string) *Client {
|
||||
return &Client{client: client}
|
||||
}
|
||||
|
||||
func (c *Client) GetLogs(ctx context.Context, hash common.Hash, address *common.Address) ([]LogResponse, error) {
|
||||
func (c *Client) GetLogs(ctx context.Context, hash common.Hash, addresses []common.Address) ([]LogResponse, error) {
|
||||
params := fmt.Sprintf(`blockHash: "%s"`, hash.String())
|
||||
if address != nil {
|
||||
params += fmt.Sprintf(`, contract: "%s"`, address.String())
|
||||
|
||||
if addresses != nil {
|
||||
addressStrings := make([]string, len(addresses))
|
||||
for i, address := range addresses {
|
||||
addressStrings[i] = fmt.Sprintf(`"%s"`, address.String())
|
||||
}
|
||||
|
||||
params += fmt.Sprintf(`, addresses: [%s]`, strings.Join(addressStrings, ","))
|
||||
}
|
||||
|
||||
getLogsQuery := fmt.Sprintf(`query{
|
||||
|
||||
+16
-9
@@ -1036,13 +1036,17 @@ func (r *Resolver) GetStorageAt(ctx context.Context, args struct {
|
||||
}
|
||||
|
||||
func (r *Resolver) GetLogs(ctx context.Context, args struct {
|
||||
BlockHash common.Hash
|
||||
Contract *common.Address
|
||||
BlockHash common.Hash
|
||||
BlockNumber *BigInt
|
||||
Addresses *[]common.Address
|
||||
}) (*[]*Log, error) {
|
||||
|
||||
var filter eth.ReceiptFilter
|
||||
if args.Contract != nil {
|
||||
filter.LogAddresses = []string{args.Contract.String()}
|
||||
|
||||
if args.Addresses != nil {
|
||||
filter.LogAddresses = make([]string, len(*args.Addresses))
|
||||
for i, address := range *args.Addresses {
|
||||
filter.LogAddresses[i] = address.String()
|
||||
}
|
||||
}
|
||||
|
||||
// Begin tx
|
||||
@@ -1051,7 +1055,7 @@ func (r *Resolver) GetLogs(ctx context.Context, args struct {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
filteredLogs, err := r.backend.Retriever.RetrieveFilteredGQLLogs(tx, filter, &args.BlockHash)
|
||||
filteredLogs, err := r.backend.Retriever.RetrieveFilteredGQLLogs(tx, filter, &args.BlockHash, args.BlockNumber.ToInt())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1268,7 +1272,7 @@ func (r *Resolver) AllEthHeaderCids(ctx context.Context, args struct {
|
||||
var headerCIDs []eth.HeaderCIDRecord
|
||||
var err error
|
||||
if args.Condition.BlockHash != nil {
|
||||
headerCID, err := r.backend.Retriever.RetrieveHeaderAndTxCIDsByBlockHash(common.HexToHash(*args.Condition.BlockHash))
|
||||
headerCID, err := r.backend.Retriever.RetrieveHeaderAndTxCIDsByBlockHash(common.HexToHash(*args.Condition.BlockHash), args.Condition.BlockNumber.ToInt())
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), "not found") {
|
||||
return nil, err
|
||||
@@ -1349,9 +1353,12 @@ func (r *Resolver) AllEthHeaderCids(ctx context.Context, args struct {
|
||||
}
|
||||
|
||||
func (r *Resolver) EthTransactionCidByTxHash(ctx context.Context, args struct {
|
||||
TxHash string
|
||||
TxHash string
|
||||
BlockNumber *BigInt
|
||||
}) (*EthTransactionCID, error) {
|
||||
txCID, err := r.backend.Retriever.RetrieveTxCIDByHash(args.TxHash)
|
||||
// Need not check args.BlockNumber for nil as .ToInt() uses a pointer receiver and returns nil if BlockNumber is nil
|
||||
// https://stackoverflow.com/questions/42238624/calling-a-method-on-a-nil-struct-pointer-doesnt-panic-why-not
|
||||
txCID, err := r.backend.Retriever.RetrieveTxCIDByHash(args.TxHash, args.BlockNumber.ToInt())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -20,9 +20,9 @@ import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestGraphQL(t *testing.T) {
|
||||
@@ -31,5 +31,5 @@ func TestGraphQL(t *testing.T) {
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logrus.SetOutput(ioutil.Discard)
|
||||
log.SetOutput(ioutil.Discard)
|
||||
})
|
||||
@@ -174,7 +174,7 @@ var _ = Describe("GraphQL", func() {
|
||||
|
||||
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, []common.Address{contractAddress})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedLogs := []graphql.LogResponse{
|
||||
@@ -191,7 +191,7 @@ var _ = Describe("GraphQL", func() {
|
||||
})
|
||||
|
||||
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)
|
||||
logs, err := client.GetLogs(ctx, blockHash, []common.Address{test_helpers.AnotherAddress2})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedLogs := []graphql.LogResponse{
|
||||
@@ -207,6 +207,30 @@ var _ = Describe("GraphQL", func() {
|
||||
Expect(logs).To(Equal(expectedLogs))
|
||||
})
|
||||
|
||||
It("Retrieves logs that matches the provided blockHash and multiple contract addresses", func() {
|
||||
logs, err := client.GetLogs(ctx, blockHash, []common.Address{contractAddress, test_helpers.AnotherAddress2})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
expectedLogs := []graphql.LogResponse{
|
||||
{
|
||||
Topics: test_helpers.MockLog1.Topics,
|
||||
Data: hexutil.Bytes(test_helpers.MockLog1.Data),
|
||||
Transaction: graphql.TransactionResponse{Hash: test_helpers.MockTransactions[0].Hash()},
|
||||
ReceiptCID: test_helpers.Rct1CID.String(),
|
||||
Status: int32(test_helpers.MockReceipts[0].Status),
|
||||
},
|
||||
{
|
||||
Topics: test_helpers.MockLog6.Topics,
|
||||
Data: hexutil.Bytes(test_helpers.MockLog6.Data),
|
||||
Transaction: graphql.TransactionResponse{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())
|
||||
@@ -214,7 +238,7 @@ var _ = Describe("GraphQL", func() {
|
||||
})
|
||||
|
||||
It("Retrieves logs with random hash", func() {
|
||||
logs, err := client.GetLogs(ctx, randomHash, &contractAddress)
|
||||
logs, err := client.GetLogs(ctx, randomHash, []common.Address{contractAddress})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(len(logs)).To(Equal(0))
|
||||
})
|
||||
@@ -272,7 +296,7 @@ var _ = Describe("GraphQL", func() {
|
||||
allEthHeaderCIDsResp, err := client.AllEthHeaderCIDs(ctx, graphql.EthHeaderCIDCondition{BlockHash: &blockHash})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
headerCID, err := backend.Retriever.RetrieveHeaderAndTxCIDsByBlockHash(blocks[1].Hash())
|
||||
headerCID, err := backend.Retriever.RetrieveHeaderAndTxCIDsByBlockHash(blocks[1].Hash(), nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
Expect(len(allEthHeaderCIDsResp.Nodes)).To(Equal(1))
|
||||
@@ -287,7 +311,7 @@ var _ = Describe("GraphQL", func() {
|
||||
ethTransactionCIDResp, err := client.EthTransactionCIDByTxHash(ctx, txHash)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
txCID, err := backend.Retriever.RetrieveTxCIDByHash(txHash)
|
||||
txCID, err := backend.Retriever.RetrieveTxCIDByHash(txHash, nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
compareEthTxCID(*ethTransactionCIDResp, txCID)
|
||||
|
||||
@@ -343,12 +343,12 @@ const schema string = `
|
||||
getStorageAt(blockHash: Bytes32!, contract: Address!, slot: Bytes32!): StorageResult
|
||||
|
||||
# Get contract logs by block hash and contract address.
|
||||
getLogs(blockHash: Bytes32!, contract: Address): [Log!]
|
||||
getLogs(blockHash: Bytes32!, blockNumber: BigInt, addresses: [Address!]): [Log!]
|
||||
|
||||
# PostGraphile alternative to get headers with transactions using block number or block hash.
|
||||
allEthHeaderCids(condition: EthHeaderCidCondition): EthHeaderCidsConnection
|
||||
|
||||
# PostGraphile alternative to get transactions using transaction hash.
|
||||
ethTransactionCidByTxHash(txHash: String!): EthTransactionCid
|
||||
ethTransactionCidByTxHash(txHash: String!, blockNumber: BigInt): EthTransactionCid
|
||||
}
|
||||
`
|
||||
@@ -27,9 +27,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/graph-gophers/graphql-go"
|
||||
"github.com/graph-gophers/graphql-go/relay"
|
||||
"github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
)
|
||||
|
||||
// Service encapsulates a GraphQL service.
|
||||
@@ -77,7 +77,7 @@ func (s *Service) Start(server *p2p.Server) error {
|
||||
utils.Fatalf("Could not start RPC api: %v", err)
|
||||
}
|
||||
extapiURL := fmt.Sprintf("http://%v/", addr)
|
||||
logrus.Infof("graphQL endpoint opened for url %s", extapiURL)
|
||||
log.Infof("graphQL endpoint opened for url %s", extapiURL)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ func (s *Service) Stop() error {
|
||||
if s.listener != nil {
|
||||
s.listener.Close()
|
||||
s.listener = nil
|
||||
logrus.Debugf("graphQL endpoint closed for url %s", fmt.Sprintf("http://%s", s.endpoint))
|
||||
log.Debugf("graphQL endpoint closed for url %s", fmt.Sprintf("http://%s", s.endpoint))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+246
@@ -0,0 +1,246 @@
|
||||
// Copyright © 2023 Cerc
|
||||
|
||||
// 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 log
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
const (
|
||||
CtxKeyApiMethod = "api_method"
|
||||
CtxKeyApiParams = "api_params"
|
||||
CtxKeyApiReqId = "api_reqid"
|
||||
CtxKeyBlockHash = "block_hash"
|
||||
CtxKeyBlockNumber = "block_num"
|
||||
CtxKeyConn = "conn"
|
||||
CtxKeyDuration = "duration"
|
||||
CtxKeyError = "err"
|
||||
CtxKeyUniqId = "uuid"
|
||||
CtxKeyUserId = "user_id"
|
||||
)
|
||||
|
||||
// TODO: Allow registering arbitrary keys.
|
||||
var registeredKeys = []string{
|
||||
CtxKeyApiMethod,
|
||||
CtxKeyApiParams,
|
||||
CtxKeyApiReqId,
|
||||
CtxKeyBlockHash,
|
||||
CtxKeyBlockNumber,
|
||||
CtxKeyConn,
|
||||
CtxKeyDuration,
|
||||
CtxKeyError,
|
||||
CtxKeyUniqId,
|
||||
CtxKeyUserId,
|
||||
}
|
||||
|
||||
const FatalLevel = logrus.FatalLevel
|
||||
const ErrorLevel = logrus.ErrorLevel
|
||||
const InfoLevel = logrus.InfoLevel
|
||||
const DebugLevel = logrus.DebugLevel
|
||||
const TraceLevel = logrus.TraceLevel
|
||||
|
||||
type Entry = logrus.Entry
|
||||
type Level = logrus.Level
|
||||
|
||||
func WithFieldsFromContext(ctx context.Context) *Entry {
|
||||
entry := logrus.WithContext(ctx)
|
||||
|
||||
for _, key := range registeredKeys {
|
||||
if value := ctx.Value(key); value != nil {
|
||||
entry = entry.WithField(key, value)
|
||||
}
|
||||
}
|
||||
return entry
|
||||
}
|
||||
|
||||
func Fatalx(ctx context.Context, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Fatal(args...)
|
||||
}
|
||||
|
||||
func Errorx(ctx context.Context, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Error(args...)
|
||||
}
|
||||
|
||||
func Warnx(ctx context.Context, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Warn(args...)
|
||||
}
|
||||
|
||||
func Infox(ctx context.Context, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Info(args...)
|
||||
}
|
||||
|
||||
func Debugx(ctx context.Context, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Debug(args...)
|
||||
}
|
||||
|
||||
func Tracex(ctx context.Context, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Trace(args...)
|
||||
}
|
||||
|
||||
func Errorxf(ctx context.Context, format string, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Errorf(format, args...)
|
||||
}
|
||||
|
||||
func Warnxf(ctx context.Context, format string, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Warnf(format, args...)
|
||||
}
|
||||
|
||||
func Infoxf(ctx context.Context, format string, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Infof(format, args...)
|
||||
}
|
||||
|
||||
func Debugxf(ctx context.Context, format string, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Debugf(format, args...)
|
||||
}
|
||||
|
||||
func Tracexf(ctx context.Context, format string, args ...interface{}) {
|
||||
WithFieldsFromContext(ctx).Tracef(format, args...)
|
||||
}
|
||||
|
||||
func Fatal(args ...interface{}) {
|
||||
logrus.Fatal(args...)
|
||||
}
|
||||
|
||||
func Error(args ...interface{}) {
|
||||
logrus.Error(args...)
|
||||
}
|
||||
|
||||
func Warn(args ...interface{}) {
|
||||
logrus.Warn(args...)
|
||||
}
|
||||
|
||||
func Info(args ...interface{}) {
|
||||
logrus.Info(args...)
|
||||
}
|
||||
|
||||
func Debug(args ...interface{}) {
|
||||
logrus.Debug(args...)
|
||||
}
|
||||
|
||||
func Trace(args ...interface{}) {
|
||||
logrus.Trace(args...)
|
||||
}
|
||||
|
||||
func Fatalf(format string, args ...interface{}) {
|
||||
logrus.Fatalf(format, args...)
|
||||
}
|
||||
|
||||
func Errorf(format string, args ...interface{}) {
|
||||
logrus.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func Warnf(format string, args ...interface{}) {
|
||||
logrus.Warnf(format, args...)
|
||||
}
|
||||
|
||||
func Infof(format string, args ...interface{}) {
|
||||
logrus.Infof(format, args...)
|
||||
}
|
||||
|
||||
func Debugf(format string, args ...interface{}) {
|
||||
logrus.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func Tracef(format string, args ...interface{}) {
|
||||
logrus.Tracef(format, args...)
|
||||
}
|
||||
|
||||
func SetOutput(out io.Writer) {
|
||||
logrus.SetOutput(out)
|
||||
}
|
||||
|
||||
func SetLevel(lvl Level) {
|
||||
logrus.SetLevel(lvl)
|
||||
}
|
||||
|
||||
func IsLevelEnabled(lvl Level) bool {
|
||||
return logrus.IsLevelEnabled(lvl)
|
||||
}
|
||||
|
||||
func WithError(err error) *Entry {
|
||||
return logrus.WithError(err)
|
||||
}
|
||||
|
||||
func WithField(field string, value interface{}) *Entry {
|
||||
return logrus.WithField(field, value)
|
||||
}
|
||||
|
||||
func Init() error {
|
||||
// Set the output.
|
||||
viper.BindEnv("logrus.file", "LOGRUS_FILE")
|
||||
logFile := viper.GetString("logrus.file")
|
||||
if logFile != "" {
|
||||
file, err := os.OpenFile(logFile,
|
||||
os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0640)
|
||||
if err == nil {
|
||||
Infof("Directing output to %s", logFile)
|
||||
SetOutput(file)
|
||||
} else {
|
||||
SetOutput(os.Stdout)
|
||||
Info("Failed to logrus.to file, using default stdout")
|
||||
}
|
||||
} else {
|
||||
SetOutput(os.Stdout)
|
||||
}
|
||||
|
||||
// Set the level.
|
||||
viper.BindEnv("logrus.level", "LOGRUS_LEVEL")
|
||||
lvl, err := logrus.ParseLevel(viper.GetString("logrus.level"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
SetLevel(lvl)
|
||||
|
||||
formatter := &logrus.TextFormatter{
|
||||
FullTimestamp: true,
|
||||
}
|
||||
// Show file/line number only at Trace level.
|
||||
if lvl >= TraceLevel {
|
||||
logrus.SetReportCaller(true)
|
||||
|
||||
// We need to exclude this wrapper code, logrus.us itself, and the runtime from the stack to show anything useful.
|
||||
// cf. https://github.com/sirupsen/logrus.us/pull/973
|
||||
formatter.CallerPrettyfier = func(frame *runtime.Frame) (function string, file string) {
|
||||
pcs := make([]uintptr, 50)
|
||||
_ = runtime.Callers(0, pcs)
|
||||
frames := runtime.CallersFrames(pcs)
|
||||
|
||||
// Filter logrus.wrapper / logrus.us / runtime frames.
|
||||
for next, again := frames.Next(); again; next, again = frames.Next() {
|
||||
if !strings.Contains(next.File, "sirupsen/logrus.us") &&
|
||||
!strings.HasPrefix(next.Function, "runtime.") &&
|
||||
!strings.Contains(next.File, "ipld-eth-server/pkg/logrus") {
|
||||
return next.Function, fmt.Sprintf("%s:%d", next.File, next.Line)
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to the raw info.
|
||||
return frame.Function, fmt.Sprintf("%s:%d", frame.File, frame.Line)
|
||||
}
|
||||
}
|
||||
|
||||
logrus.SetFormatter(formatter)
|
||||
Info("Log level set to ", lvl.String())
|
||||
return nil
|
||||
}
|
||||
@@ -20,9 +20,9 @@ import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestNetSuite(t *testing.T) {
|
||||
@@ -31,5 +31,5 @@ func TestNetSuite(t *testing.T) {
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logrus.SetOutput(ioutil.Discard)
|
||||
log.SetOutput(ioutil.Discard)
|
||||
})
|
||||
+89
-7
@@ -17,25 +17,107 @@
|
||||
package prom
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
// HTTPMiddleware http connection metric reader
|
||||
func HTTPMiddleware(next http.Handler) http.Handler {
|
||||
if !metrics {
|
||||
return next
|
||||
const (
|
||||
jsonMethod = "method"
|
||||
jsonParams = "params"
|
||||
jsonReqId = "id"
|
||||
headerUserId = "X-User-Id"
|
||||
headerOriginalRemoteAddr = "X-Original-Remote-Addr"
|
||||
)
|
||||
|
||||
// Peek at the request and update the Context accordingly (eg, API method, user ID, etc.)
|
||||
func preprocessRequest(r *http.Request) (*http.Request, error) {
|
||||
// Generate a unique ID for this request.
|
||||
uniqId, err := uuid.NewUUID()
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
httpCount.Inc()
|
||||
// Read the body so that we can peek inside.
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Replace it with a re-readable copy.
|
||||
r.Body = io.NopCloser(bytes.NewBuffer(body))
|
||||
|
||||
// All API requests should be JSON.
|
||||
var result map[string]interface{}
|
||||
if len(body) > 0 {
|
||||
err = json.Unmarshal(body, &result)
|
||||
if nil != err {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Pull out the method name, request ID, user ID, and address info.
|
||||
reqId := fmt.Sprintf("%g", result[jsonReqId])
|
||||
reqMethod := fmt.Sprintf("%v", result[jsonMethod])
|
||||
reqParams := fmt.Sprintf("%v", result[jsonParams])
|
||||
// Truncate parameters unless trace logging is enabled.
|
||||
if !log.IsLevelEnabled(log.TraceLevel) {
|
||||
if len(reqParams) > 250 {
|
||||
reqParams = reqParams[:250] + "..."
|
||||
}
|
||||
}
|
||||
userId := r.Header.Get(headerUserId)
|
||||
conn := r.Header.Get(headerOriginalRemoteAddr)
|
||||
if len(conn) == 0 {
|
||||
conn = r.RemoteAddr
|
||||
}
|
||||
|
||||
// Add it all to the request context.
|
||||
ctx := r.Context()
|
||||
ctx = context.WithValue(ctx, log.CtxKeyUniqId, uniqId.String())
|
||||
ctx = context.WithValue(ctx, log.CtxKeyApiMethod, reqMethod)
|
||||
ctx = context.WithValue(ctx, log.CtxKeyApiParams, string(reqParams))
|
||||
ctx = context.WithValue(ctx, log.CtxKeyApiReqId, reqId)
|
||||
ctx = context.WithValue(ctx, log.CtxKeyUserId, userId)
|
||||
ctx = context.WithValue(ctx, log.CtxKeyConn, conn)
|
||||
|
||||
return r.WithContext(ctx), nil
|
||||
}
|
||||
|
||||
// HTTPMiddleware http connection metric reader
|
||||
func HTTPMiddleware(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
r, err := preprocessRequest(r)
|
||||
if nil != err {
|
||||
log.WithError(err).Error("Error preprocessing request")
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
ctx := r.Context()
|
||||
apiMethod := fmt.Sprintf("%s", ctx.Value(log.CtxKeyApiMethod))
|
||||
|
||||
if metrics {
|
||||
httpCount.WithLabelValues(apiMethod).Inc()
|
||||
}
|
||||
|
||||
log.Debugx(ctx, "START")
|
||||
next.ServeHTTP(w, r)
|
||||
duration := time.Now().Sub(start)
|
||||
httpDuration.Observe(float64(duration.Seconds()))
|
||||
log.Debugxf(context.WithValue(ctx, log.CtxKeyDuration, duration.Milliseconds()), "END")
|
||||
|
||||
if metrics {
|
||||
httpDuration.WithLabelValues(apiMethod).Observe(duration.Seconds())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+7
-6
@@ -33,8 +33,8 @@ const (
|
||||
var (
|
||||
metrics bool
|
||||
|
||||
httpCount prometheus.Counter
|
||||
httpDuration prometheus.Histogram
|
||||
httpCount *prometheus.CounterVec
|
||||
httpDuration *prometheus.HistogramVec
|
||||
wsCount prometheus.Gauge
|
||||
ipcCount prometheus.Gauge
|
||||
)
|
||||
@@ -43,18 +43,19 @@ var (
|
||||
func Init() {
|
||||
metrics = true
|
||||
|
||||
httpCount = promauto.NewCounter(prometheus.CounterOpts{
|
||||
httpCount = promauto.NewCounterVec(prometheus.CounterOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemHTTP,
|
||||
Name: "count",
|
||||
Help: "http request count",
|
||||
})
|
||||
httpDuration = promauto.NewHistogram(prometheus.HistogramOpts{
|
||||
}, []string{"method"})
|
||||
|
||||
httpDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystemHTTP,
|
||||
Name: "duration",
|
||||
Help: "http request duration",
|
||||
})
|
||||
}, []string{"method"})
|
||||
|
||||
wsCount = promauto.NewGauge(prometheus.GaugeOpts{
|
||||
Namespace: namespace,
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var errPromHTTP = errors.New("can't start http server for prometheus")
|
||||
@@ -36,7 +36,7 @@ func Serve(addr string) *http.Server {
|
||||
}
|
||||
go func() {
|
||||
if err := srv.ListenAndServe(); err != nil {
|
||||
logrus.
|
||||
log.
|
||||
WithError(err).
|
||||
WithField("module", "prom").
|
||||
WithField("addr", addr).
|
||||
|
||||
+4
-2
@@ -19,10 +19,12 @@ package rpc
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/prom"
|
||||
)
|
||||
|
||||
// StartHTTPEndpoint starts the HTTP RPC endpoint, configured with cors/vhosts/modules.
|
||||
@@ -33,7 +35,7 @@ func StartHTTPEndpoint(endpoint string, apis []rpc.API, modules []string, cors [
|
||||
if err != nil {
|
||||
utils.Fatalf("Could not register HTTP API: %w", err)
|
||||
}
|
||||
handler := node.NewHTTPHandlerStack(srv, cors, vhosts, nil)
|
||||
handler := prom.HTTPMiddleware(node.NewHTTPHandlerStack(srv, cors, vhosts, nil))
|
||||
|
||||
// start http server
|
||||
_, addr, err := node.StartHTTPEndpoint(endpoint, rpc.DefaultHTTPTimeouts, handler)
|
||||
|
||||
+1
-1
@@ -22,9 +22,9 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/prom"
|
||||
)
|
||||
|
||||
+1
-1
@@ -19,9 +19,9 @@ package serve
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/ethereum/go-ethereum/statediff/types"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
)
|
||||
|
||||
+33
-15
@@ -46,12 +46,14 @@ const (
|
||||
SERVER_MAX_OPEN_CONNECTIONS = "SERVER_MAX_OPEN_CONNECTIONS"
|
||||
SERVER_MAX_CONN_LIFETIME = "SERVER_MAX_CONN_LIFETIME"
|
||||
|
||||
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"
|
||||
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_STATEDIFF_TIMEOUT = "ETH_STATEDIFF_TIMEOUT"
|
||||
ETH_FORWARD_ETH_CALLS = "ETH_FORWARD_ETH_CALLS"
|
||||
ETH_FORWARD_GET_STORAGE_AT = "ETH_FORWARD_GET_STORAGE_AT"
|
||||
ETH_PROXY_ON_ERROR = "ETH_PROXY_ON_ERROR"
|
||||
|
||||
VALIDATOR_ENABLED = "VALIDATOR_ENABLED"
|
||||
VALIDATOR_EVERY_NTH_BLOCK = "VALIDATOR_EVERY_NTH_BLOCK"
|
||||
@@ -80,15 +82,17 @@ type Config struct {
|
||||
TracingHttpEndpoint string
|
||||
TracingPostgraphileEndpoint string
|
||||
|
||||
ChainConfig *params.ChainConfig
|
||||
DefaultSender *common.Address
|
||||
RPCGasCap *big.Int
|
||||
EthHttpEndpoint string
|
||||
Client *rpc.Client
|
||||
SupportStateDiff bool
|
||||
ForwardEthCalls bool
|
||||
ProxyOnError bool
|
||||
NodeNetworkID string
|
||||
ChainConfig *params.ChainConfig
|
||||
DefaultSender *common.Address
|
||||
RPCGasCap *big.Int
|
||||
EthHttpEndpoint string
|
||||
Client *rpc.Client
|
||||
SupportStateDiff bool
|
||||
StateDiffTimeout time.Duration
|
||||
ForwardEthCalls bool
|
||||
ForwardGetStorageAt bool
|
||||
ProxyOnError bool
|
||||
NodeNetworkID string
|
||||
|
||||
// Cache configuration.
|
||||
GroupCache *ethServerShared.GroupCacheConfig
|
||||
@@ -107,7 +111,9 @@ func NewConfig() (*Config, error) {
|
||||
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.stateDiffTimeout", ETH_STATEDIFF_TIMEOUT)
|
||||
viper.BindEnv("ethereum.forwardEthCalls", ETH_FORWARD_ETH_CALLS)
|
||||
viper.BindEnv("ethereum.forwardGetStorageAt", ETH_FORWARD_GET_STORAGE_AT)
|
||||
viper.BindEnv("ethereum.proxyOnError", ETH_PROXY_ON_ERROR)
|
||||
|
||||
c.dbInit()
|
||||
@@ -121,6 +127,7 @@ func NewConfig() (*Config, error) {
|
||||
c.Client = cli
|
||||
c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff")
|
||||
c.ForwardEthCalls = viper.GetBool("ethereum.forwardEthCalls")
|
||||
c.ForwardGetStorageAt = viper.GetBool("ethereum.forwardGetStorageAt")
|
||||
c.ProxyOnError = viper.GetBool("ethereum.proxyOnError")
|
||||
c.EthHttpEndpoint = ethHTTPEndpoint
|
||||
|
||||
@@ -222,6 +229,17 @@ func NewConfig() (*Config, error) {
|
||||
} else {
|
||||
c.RPCGasCap = big.NewInt(0)
|
||||
}
|
||||
if sdTimeout := viper.GetString("ethereum.stateDiffTimeout"); sdTimeout != "" {
|
||||
var err error
|
||||
if c.StateDiffTimeout, err = time.ParseDuration(sdTimeout); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
c.StateDiffTimeout = ethServerShared.DefaultStateDiffTimeout
|
||||
}
|
||||
if c.StateDiffTimeout < 0 {
|
||||
return nil, errors.New("ethereum.stateDiffTimeout < 0")
|
||||
}
|
||||
chainConfigPath := viper.GetString("ethereum.chainConfig")
|
||||
if chainConfigPath != "" {
|
||||
c.ChainConfig, err = statediff.LoadConfig(chainConfigPath)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package serve
|
||||
|
||||
import log "github.com/sirupsen/logrus"
|
||||
import "github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
|
||||
func sendNonBlockingErr(sub Subscription, err error) {
|
||||
log.Error(err)
|
||||
|
||||
+16
-3
@@ -20,7 +20,9 @@ import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@@ -30,7 +32,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/jmoiron/sqlx"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/debug"
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/eth"
|
||||
@@ -83,10 +84,14 @@ type Service struct {
|
||||
client *rpc.Client
|
||||
// whether the proxied client supports state diffing
|
||||
supportsStateDiffing bool
|
||||
// timeout for statediff RPC calls
|
||||
stateDiffTimeout time.Duration
|
||||
// backend for the server
|
||||
backend *eth.Backend
|
||||
// whether to forward eth_calls directly to proxy node
|
||||
forwardEthCalls bool
|
||||
// whether to forward eth_getStorageAt directly to proxy node
|
||||
forwardGetStorageAt bool
|
||||
// whether to forward all calls to proxy node if they throw an error locally
|
||||
proxyOnError bool
|
||||
// eth node network id
|
||||
@@ -105,7 +110,9 @@ func NewServer(settings *Config) (Server, error) {
|
||||
sap.SubscriptionTypes = make(map[common.Hash]eth.SubscriptionSettings)
|
||||
sap.client = settings.Client
|
||||
sap.supportsStateDiffing = settings.SupportStateDiff
|
||||
sap.stateDiffTimeout = settings.StateDiffTimeout
|
||||
sap.forwardEthCalls = settings.ForwardEthCalls
|
||||
sap.forwardGetStorageAt = settings.ForwardGetStorageAt
|
||||
sap.proxyOnError = settings.ProxyOnError
|
||||
sap.nodeNetworkId = settings.NodeNetworkID
|
||||
var err error
|
||||
@@ -141,8 +148,14 @@ func (sap *Service) APIs() []rpc.API {
|
||||
Public: true,
|
||||
},
|
||||
}
|
||||
|
||||
ethAPI, err := eth.NewPublicEthAPI(sap.backend, sap.client, sap.supportsStateDiffing, sap.forwardEthCalls, sap.proxyOnError)
|
||||
conf := eth.APIConfig{
|
||||
SupportsStateDiff: sap.supportsStateDiffing,
|
||||
ForwardEthCalls: sap.forwardEthCalls,
|
||||
ForwardGetStorageAt: sap.forwardGetStorageAt,
|
||||
ProxyOnError: sap.proxyOnError,
|
||||
StateDiffTimeout: sap.stateDiffTimeout,
|
||||
}
|
||||
ethAPI, err := eth.NewPublicEthAPI(sap.backend, sap.client, conf)
|
||||
if err != nil {
|
||||
log.Fatalf("unable to create public eth api: %v", err)
|
||||
}
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
|
||||
package shared
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
DefaultMaxBatchSize uint64 = 100
|
||||
DefaultMaxBatchNumber int64 = 50
|
||||
DefaultMaxBatchSize uint64 = 100
|
||||
DefaultMaxBatchNumber int64 = 50
|
||||
DefaultStateDiffTimeout time.Duration = 240 * time.Second
|
||||
|
||||
GcachePoolEnabled = "GCACHE_POOL_ENABLED"
|
||||
GcachePoolHttpPath = "GCACHE_POOL_HTTP_PATH"
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ipfs/go-cid"
|
||||
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
||||
dshelp "github.com/ipfs/go-ipfs-ds-help"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// HandleZeroAddrPointer will return an emtpy string for a nil address pointer
|
||||
@@ -44,7 +44,7 @@ func HandleZeroAddr(to common.Address) string {
|
||||
// Rollback sql transaction and log any error
|
||||
func Rollback(tx *sqlx.Tx) {
|
||||
if err := tx.Rollback(); err != nil {
|
||||
logrus.Error(err)
|
||||
log.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
@@ -15,5 +15,5 @@ func TestIntegration(t *testing.T) {
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
logrus.SetOutput(ioutil.Discard)
|
||||
log.SetOutput(ioutil.Discard)
|
||||
})
|
||||
@@ -18,9 +18,8 @@ package test_config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/cerc-io/ipld-eth-server/v4/pkg/log"
|
||||
"github.com/ethereum/go-ethereum/statediff/indexer/database/sql/postgres"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
@@ -35,7 +34,7 @@ func setTestConfig() {
|
||||
vip.SetConfigName("testing")
|
||||
vip.AddConfigPath("$GOPATH/src/github.com/cerc-io/ipld-eth-server/environments/")
|
||||
if err := vip.ReadInConfig(); err != nil {
|
||||
logrus.Fatal(err)
|
||||
log.Fatal(err)
|
||||
}
|
||||
ipc := vip.GetString("client.ipcPath")
|
||||
|
||||
@@ -45,7 +44,7 @@ func setTestConfig() {
|
||||
ipc = vip.GetString("url")
|
||||
}
|
||||
if ipc == "" {
|
||||
logrus.Fatal(errors.New("testing.toml IPC path or $INFURA_URL env variable need to be set"))
|
||||
log.Fatal(errors.New("testing.toml IPC path or $INFURA_URL env variable need to be set"))
|
||||
}
|
||||
|
||||
hn := vip.GetString("database.hostname")
|
||||
|
||||
+2
-2
@@ -20,8 +20,8 @@ import "fmt"
|
||||
|
||||
const (
|
||||
Major = 4 // Major version component of the current release
|
||||
Minor = 1 // Minor version component of the current release
|
||||
Patch = 9 // Patch version component of the current release
|
||||
Minor = 2 // Minor version component of the current release
|
||||
Patch = 0 // Patch version component of the current release
|
||||
Meta = "alpha" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
||||
Reference in new issue
Block a user