Compare commits

..

16 Commits

Author SHA1 Message Date
i-norden
402a6e183b update SO version
Some checks failed
Test the stack. / Run unit tests (pull_request) Successful in 5m4s
Test the stack. / Run integration tests (pull_request) Failing after 5m37s
2024-01-29 09:30:21 -05:00
i-norden
29c1523eb8 bump ipld-eth-db to v5.2.1-alpha
Some checks failed
Test the stack. / Run unit tests (pull_request) Successful in 5m59s
Test the stack. / Run integration tests (pull_request) Failing after 13m29s
2024-01-22 15:17:27 -05:00
i-norden
53be7fc210 update ipld-eth-db ref 2024-01-22 15:16:47 -05:00
i-norden
92ae69a2b4 fix CI errors 2024-01-22 15:16:33 -05:00
i-norden
6101d7a20d go mod 2024-01-22 15:16:33 -05:00
i-norden
0fe38eafba debug_traceBlock test 2024-01-22 15:16:33 -05:00
i-norden
c727e6dee6 TraceBlockByHash and TraceBlockByNumber methods 2024-01-22 15:16:33 -05:00
i-norden
b8153effe7 debug_traceCall test 2024-01-22 15:16:33 -05:00
i-norden
f22d919478 go mod 2024-01-22 15:16:33 -05:00
i-norden
149e98ad31 add ability to fall through to another RPC provider 2024-01-22 15:16:33 -05:00
i-norden
e7547983a8 go fmt; temporary go mod using replace directive 2024-01-22 15:16:33 -05:00
i-norden
4364ee74c7 update top-level service 2024-01-22 15:16:33 -05:00
i-norden
42a168f6e4 update config 2024-01-22 15:16:33 -05:00
i-norden
39ddcdc9dc tracing API for traceBlock and traceCall 2024-01-22 15:16:33 -05:00
i-norden
f5b4e4dc94 ToMessage method for transaction_arguments 2024-01-22 15:16:33 -05:00
i-norden
89082466fc BlockOverride required by tracing endpoints 2024-01-22 15:16:33 -05:00
45 changed files with 4225 additions and 2312 deletions

View File

@ -12,7 +12,5 @@ integration
test test
scripts scripts
Dockerfile Dockerfile
environments
**/node_modules **/node_modules
build

View File

@ -12,9 +12,9 @@ on:
- ci-test - ci-test
env: env:
SO_VERSION: v1.1.0-36d4969-202407091537 # Needed until we can incorporate docker startup into the executor container
FIXTURENET_ETH_STACKS_REF: main DOCKER_HOST: unix:///var/run/dind.sock
SYSTEM_TESTS_REF: main SO_VERSION: v1.1.0-b7f215d-202401282321 # contains fixes for plugeth stack
jobs: jobs:
test: test:
@ -26,12 +26,21 @@ jobs:
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
check-latest: true check-latest: true
- name: Run dockerd
run: |
dockerd -H $DOCKER_HOST --userland-proxy=false &
sleep 5
- name: Run DB container - name: Run DB container
run: docker compose -f test/compose-db.yml up --wait --quiet-pull run: docker compose -f test/compose-db.yml up --wait --quiet-pull
- name: Configure Gitea access
env:
TOKEN: ${{ secrets.CICD_REPO_TOKEN }}
run: |
git config --global url."https://$TOKEN:@git.vdb.to/".insteadOf https://git.vdb.to/
- name: Build and run tests - name: Build and run tests
run: | run: |
go install github.com/onsi/ginkgo/v2/ginkgo go install github.com/onsi/ginkgo/v2/ginkgo
ginkgo -v -r --skip-package=./integration ginkgo -v -r --skipPackage=./integration
integration-test: integration-test:
name: Run integration tests name: Run integration tests
@ -42,6 +51,10 @@ jobs:
with: with:
go-version-file: 'go.mod' go-version-file: 'go.mod'
check-latest: true check-latest: true
- name: Run dockerd
run: |
dockerd -H $DOCKER_HOST --userland-proxy=false &
sleep 5
- name: Build server image - name: Build server image
env: env:
@ -51,18 +64,10 @@ jobs:
env: env:
DEBIAN_FRONTEND: noninteractive DEBIAN_FRONTEND: noninteractive
run: apt-get update && apt-get install -y jq run: apt-get update && apt-get install -y jq
# At present the stock setup-python action fails on Linux/aarch64 - name: Install Python
# Conditional steps below workaroud this by using deadsnakes for that case only
- name: "Install Python for ARM on Linux"
if: ${{ runner.arch == 'arm64' && runner.os == 'Linux' }}
uses: deadsnakes/action@v3.0.1
with:
python-version: 3.11
- name: "Install Python cases other than ARM on Linux"
if: ${{ ! (runner.arch == 'arm64' && runner.os == 'Linux') }}
uses: actions/setup-python@v4 uses: actions/setup-python@v4
with: with:
python-version: 3.11 python-version: '3.11'
- name: Install stack-orchestrator - name: Install stack-orchestrator
uses: actions/checkout@v3 uses: actions/checkout@v3
with: with:
@ -70,18 +75,16 @@ jobs:
ref: ${{ env.SO_VERSION }} ref: ${{ env.SO_VERSION }}
path: ./stack-orchestrator path: ./stack-orchestrator
- run: pip install ./stack-orchestrator - run: pip install ./stack-orchestrator
- name: Clone fixturenet stack repo - name: Configure Gitea access
uses: actions/checkout@v4 env:
with: TOKEN: ${{ secrets.CICD_REPO_TOKEN }}
repository: cerc-io/fixturenet-eth-stacks run: |
ref: ${{ env.FIXTURENET_ETH_STACKS_REF }} git config --global url."https://$TOKEN:@git.vdb.to/".insteadOf https://git.vdb.to/
path: ./fixturenet-eth-stacks
progress: false
- name: Run testnet stack - name: Run testnet stack
env: env:
CERC_GO_AUTH_TOKEN: ${{ secrets.CICD_REPO_TOKEN }} CERC_GO_AUTH_TOKEN: ${{ secrets.CICD_REPO_TOKEN }}
run: ./scripts/run-test-stack.sh ./fixturenet-eth-stacks/stack-orchestrator/stacks/fixturenet-plugeth run: ./scripts/integration-setup.sh
- name: Run server - name: Run server
env: env:
ETH_FORWARD_ETH_CALLS: false ETH_FORWARD_ETH_CALLS: false
@ -92,31 +95,11 @@ jobs:
go install github.com/onsi/ginkgo/v2/ginkgo go install github.com/onsi/ginkgo/v2/ginkgo
ginkgo -v --label-filter '!proxy' -r ./integration ginkgo -v --label-filter '!proxy' -r ./integration
- name: Clone system-tests
uses: actions/checkout@v4
with:
repository: cerc-io/system-tests
ref: ${{ env.SYSTEM_TESTS_REF }}
path: ./system-tests
token: ${{ secrets.CICD_REPO_TOKEN }}
progress: false
- name: Run system tests
working-directory: ./system-tests
# Work around dependency conflict in system-tests:
# web3 uses an older eth-account until (unreleased) v7
run: |
pip3 install pytest
pip3 install -r requirements.txt
pip3 install --no-deps 'eth-account>=0.12.3,<0.13'
pip3 install 'pydantic>=2.0.0'
# Skips tests that require Blob indexing
python3 -m pytest -vv -m "not blob_db"
- name: Run testnet stack without statediff - name: Run testnet stack without statediff
env: env:
CERC_RUN_STATEDIFF: false CERC_RUN_STATEDIFF: false
SKIP_BUILD: 1 SKIP_BUILD: 1
run: ./scripts/run-test-stack.sh ./fixturenet-eth-stacks/stack-orchestrator/stacks/fixturenet-plugeth run: ./scripts/integration-setup.sh
- name: Run server with call forwarding - name: Run server with call forwarding
env: env:
ETH_FORWARD_ETH_CALLS: true ETH_FORWARD_ETH_CALLS: true

View File

@ -1,9 +1,9 @@
FROM golang:1.21-alpine AS debugger FROM golang:1.19-alpine as debugger
# Include dlv # Include dlv
RUN go install github.com/go-delve/delve/cmd/dlv@latest RUN go install github.com/go-delve/delve/cmd/dlv@latest
FROM golang:1.21-alpine AS builder FROM golang:1.19-alpine as builder
RUN apk --update --no-cache add gcc musl-dev binutils-gold git RUN apk --update --no-cache add gcc musl-dev binutils-gold git
@ -29,6 +29,7 @@ RUN GOOS=linux go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -
FROM alpine FROM alpine
ARG USER="vdm" ARG USER="vdm"
ARG CONFIG_FILE="./environments/example.toml"
RUN adduser -Du 5000 $USER RUN adduser -Du 5000 $USER
WORKDIR /app WORKDIR /app
@ -37,10 +38,13 @@ USER $USER
# chown first so dir is writable # chown first so dir is writable
# note: using $USER is merged, but not in the stable release yet # note: using $USER is merged, but not in the stable release yet
COPY --chown=5000:5000 --from=builder /go/src/github.com/cerc-io/ipld-eth-server/$CONFIG_FILE config.toml
COPY --chown=5000:5000 --from=builder /go/src/github.com/cerc-io/ipld-eth-server/entrypoint.sh . COPY --chown=5000:5000 --from=builder /go/src/github.com/cerc-io/ipld-eth-server/entrypoint.sh .
# keep binaries immutable # keep binaries immutable
COPY --from=builder /go/src/github.com/cerc-io/ipld-eth-server/ipld-eth-server ipld-eth-server COPY --from=builder /go/src/github.com/cerc-io/ipld-eth-server/ipld-eth-server ipld-eth-server
COPY --from=builder /go/src/github.com/cerc-io/ipld-eth-server/environments environments
# Allow for debugging # Allow for debugging
COPY --from=debugger /go/bin/dlv /usr/local/bin/ COPY --from=debugger /go/bin/dlv /usr/local/bin/

138
Makefile Normal file
View File

@ -0,0 +1,138 @@
BIN = $(GOPATH)/bin
BASE = $(GOPATH)/src/$(PACKAGE)
PKGS = go list ./... | grep -v "^vendor/"
# Tools
## Migration tool
GOOSE = $(BIN)/goose
$(BIN)/goose:
go get -u github.com/pressly/goose/cmd/goose
## Source linter
LINT = $(BIN)/golint
$(BIN)/golint:
go get -u golang.org/x/lint/golint
## Combination linter
METALINT = $(BIN)/gometalinter.v2
$(BIN)/gometalinter.v2:
go get -u gopkg.in/alecthomas/gometalinter.v2
$(METALINT) --install
.PHONY: installtools
installtools: | $(LINT) $(GOOSE)
echo "Installing tools"
go mod download
.PHONY: metalint
metalint: | $(METALINT)
$(METALINT) ./... --vendor \
--fast \
--exclude="exported (function)|(var)|(method)|(type).*should have comment or be unexported" \
--format="{{.Path.Abs}}:{{.Line}}:{{if .Col}}{{.Col}}{{end}}:{{.Severity}}: {{.Message}} ({{.Linter}})"
.PHONY: lint
lint:
$(LINT) $$($(PKGS)) | grep -v -E "exported (function)|(var)|(method)|(type).*should have comment or be unexported"
#Database
HOST_NAME = localhost
PORT = 5432
NAME =
USER = postgres
PASSWORD = password
CONNECT_STRING=postgresql://$(USER):$(PASSWORD)@$(HOST_NAME):$(PORT)/$(NAME)?sslmode=disable
#Test
TEST_DB = vulcanize_testing
TEST_CONNECT_STRING = postgresql://$(DATABASE_USER):$(DATABASE_PASSWORD)@$(DATABASE_HOSTNAME):$(DATABASE_PORT)/$(TEST_DB)?sslmode=disable
TEST_CONNECT_STRING_LOCAL = postgresql://$(USER)@$(HOST_NAME):$(PORT)/$(TEST_DB)?sslmode=disable
.PHONY: test
test:
go vet ./...
go fmt ./...
go run github.com/onsi/ginkgo/ginkgo -r --skipPackage=test
.PHONY: integrationtest
integrationtest:
go vet ./...
go fmt ./...
go run github.com/onsi/ginkgo/ginkgo -r test/ -v
.PHONY: test_local
test_local:
go vet ./...
go fmt ./...
./scripts/run_unit_test.sh
build:
go fmt ./...
GO111MODULE=on go build
# Parameter checks
## Check that DB variables are provided
.PHONY: checkdbvars
checkdbvars:
test -n "$(HOST_NAME)" # $$HOST_NAME
test -n "$(PORT)" # $$PORT
test -n "$(NAME)" # $$NAME
@echo $(CONNECT_STRING)
## Check that the migration variable (id/timestamp) is provided
.PHONY: checkmigration
checkmigration:
test -n "$(MIGRATION)" # $$MIGRATION
# Check that the migration name is provided
.PHONY: checkmigname
checkmigname:
test -n "$(NAME)" # $$NAME
# Migration operations
## Rollback the last migration
.PHONY: rollback
rollback: $(GOOSE) checkdbvars
$(GOOSE) -dir db/migrations postgres "$(CONNECT_STRING)" down
pg_dump -O -s $(CONNECT_STRING) > db/schema.sql
## Rollback to a select migration (id/timestamp)
.PHONY: rollback_to
rollback_to: $(GOOSE) checkmigration checkdbvars
$(GOOSE) -dir db/migrations postgres "$(CONNECT_STRING)" down-to "$(MIGRATION)"
## Apply all migrations not already run
.PHONY: migrate
migrate: $(GOOSE) checkdbvars
$(GOOSE) -dir db/migrations postgres "$(CONNECT_STRING)" up
pg_dump -O -s $(CONNECT_STRING) > db/schema.sql
## Create a new migration file
.PHONY: new_migration
new_migration: $(GOOSE) checkmigname
$(GOOSE) -dir db/migrations create $(NAME) sql
## Check which migrations are applied at the moment
.PHONY: migration_status
migration_status: $(GOOSE) checkdbvars
$(GOOSE) -dir db/migrations postgres "$(CONNECT_STRING)" status
# Convert timestamped migrations to versioned (to be run in CI);
# merge timestamped files to prevent conflict
.PHONY: version_migrations
version_migrations:
$(GOOSE) -dir db/migrations fix
# Import a psql schema to the database
.PHONY: import
import:
test -n "$(NAME)" # $$NAME
psql $(NAME) < db/schema.sql
## Build docker image
.PHONY: docker-build
docker-build:
docker build -t cerc-io/ipld-eth-server .

View File

@ -95,7 +95,7 @@ func init() {
func initConfig() { func initConfig() {
if cfgFile == "" && envFile == "" { if cfgFile == "" && envFile == "" {
log.Warn("No configuration file specified, use --config , --env flag to provide configuration") log.Fatal("No configuration file specified, use --config , --env flag to provide configuration")
} }
if cfgFile != "" { if cfgFile != "" {

View File

@ -60,7 +60,6 @@ func serve() {
logWithCommand.Fatal(err) logWithCommand.Fatal(err)
} }
logWithCommand.Debugf("server config: %+v", serverConfig) logWithCommand.Debugf("server config: %+v", serverConfig)
logWithCommand.Debugf("chain config: %+v", serverConfig.ChainConfig)
server, err := s.NewServer(serverConfig) server, err := s.NewServer(serverConfig)
if err != nil { if err != nil {
logWithCommand.Fatal(err) logWithCommand.Fatal(err)
@ -277,10 +276,10 @@ func init() {
serveCmd.PersistentFlags().String("eth-client-name", "Geth", "eth client name") serveCmd.PersistentFlags().String("eth-client-name", "Geth", "eth client name")
serveCmd.PersistentFlags().String("eth-genesis-block", "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "eth genesis block hash") serveCmd.PersistentFlags().String("eth-genesis-block", "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3", "eth genesis block hash")
serveCmd.PersistentFlags().String("eth-network-id", "1", "eth network id") serveCmd.PersistentFlags().String("eth-network-id", "1", "eth network id")
serveCmd.PersistentFlags().String("eth-chain-id", "", "eth chain id") serveCmd.PersistentFlags().String("eth-chain-id", "1", "eth chain id")
serveCmd.PersistentFlags().String("eth-chain-config", "", "json chain config file location")
serveCmd.PersistentFlags().String("eth-default-sender", "", "default sender address") serveCmd.PersistentFlags().String("eth-default-sender", "", "default sender address")
serveCmd.PersistentFlags().String("eth-rpc-gas-cap", "", "rpc gas cap (for eth_Call execution)") serveCmd.PersistentFlags().String("eth-rpc-gas-cap", "", "rpc gas cap (for eth_Call execution)")
serveCmd.PersistentFlags().String("eth-chain-config", "", "json chain config file location")
serveCmd.PersistentFlags().Bool("eth-supports-state-diff", false, "whether the proxy ethereum client supports statediffing endpoints") serveCmd.PersistentFlags().Bool("eth-supports-state-diff", false, "whether the proxy ethereum client supports statediffing endpoints")
serveCmd.PersistentFlags().Bool("eth-forward-eth-calls", false, "whether to immediately forward eth_calls to proxy client") serveCmd.PersistentFlags().Bool("eth-forward-eth-calls", false, "whether to immediately forward eth_calls to proxy client")
serveCmd.PersistentFlags().Bool("eth-proxy-on-error", true, "whether to forward all failed calls to proxy client") serveCmd.PersistentFlags().Bool("eth-proxy-on-error", true, "whether to forward all failed calls to proxy client")

87
cmd/validate.go Normal file
View File

@ -0,0 +1,87 @@
// Copyright © 2021 Vulcanize, Inc
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package cmd
import (
"time"
validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg"
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v0"
"github.com/cerc-io/ipld-eth-server/v5/pkg/log"
"github.com/ethereum/go-ethereum/common"
"github.com/spf13/cobra"
"github.com/spf13/viper"
s "github.com/cerc-io/ipld-eth-server/v5/pkg/serve"
)
const GroupName = "statedb-validate"
const CacheExpiryInMins = 8 * 60 // 8 hours
const CacheSizeInMB = 16 // 16 MB
var validateCmd = &cobra.Command{
Use: "validate",
Short: "validate state",
Long: `This command validates the trie for the given state root`,
Run: func(cmd *cobra.Command, args []string) {
subCommand = cmd.CalledAs()
logWithCommand = *log.WithField("SubCommand", subCommand)
validate()
},
}
func validate() {
config, err := s.NewConfig()
if err != nil {
logWithCommand.Fatal(err)
}
stateRootStr := viper.GetString("stateRoot")
if stateRootStr == "" {
logWithCommand.Fatal("must provide a state root for state validation")
}
stateRoot := common.HexToHash(stateRootStr)
cacheSize := viper.GetInt("cacheSize")
ethDB := ipfsethdb.NewDatabase(config.DB, ipfsethdb.CacheConfig{
Name: GroupName,
Size: cacheSize * 1024 * 1024,
ExpiryDuration: time.Minute * time.Duration(CacheExpiryInMins),
})
val := validator.NewValidator(nil, ethDB)
if err = val.ValidateTrie(stateRoot); err != nil {
log.Fatal("Error validating state root")
}
stats := ethDB.(*ipfsethdb.Database).GetCacheStats()
log.Debugf("groupcache stats %+v", stats)
log.Info("Successfully validated state root")
}
func init() {
rootCmd.AddCommand(validateCmd)
addDatabaseFlags(validateCmd)
validateCmd.PersistentFlags().String("state-root", "", "root of the state trie we wish to validate")
viper.BindPFlag("stateRoot", validateCmd.PersistentFlags().Lookup("state-root"))
validateCmd.PersistentFlags().Int("cache-size", CacheSizeInMB, "cache size in MB")
viper.BindPFlag("cacheSize", validateCmd.PersistentFlags().Lookup("cache-size"))
}

View File

@ -1,8 +1,17 @@
#!/bin/sh #!/bin/sh
echo "Beginning the ipld-eth-server process"
START_CMD="./ipld-eth-server" START_CMD="./ipld-eth-server"
if [ "true" == "$CERC_REMOTE_DEBUG" ] && [ -x "/usr/local/bin/dlv" ]; then 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 --" START_CMD="/usr/local/bin/dlv --listen=:40000 --headless=true --api-version=2 --accept-multiclient exec `pwd`/ipld-eth-server --continue --"
fi fi
exec $START_CMD ${VDB_COMMAND:-serve} echo running: $START_CMD ${VDB_COMMAND} --config=`pwd`/config.toml
$START_CMD ${VDB_COMMAND} --config=`pwd`/config.toml
rv=$?
if [ $rv != 0 ]; then
echo "ipld-eth-server startup failed"
exit 1
fi

View File

@ -1,5 +1,5 @@
[database] [database]
name = "cerc_testing" name = "vulcanize_testing"
hostname = "localhost" hostname = "localhost"
port = 5432 port = 5432

318
go.mod
View File

@ -1,29 +1,28 @@
module github.com/cerc-io/ipld-eth-server/v5 module github.com/cerc-io/ipld-eth-server/v5
go 1.21 go 1.19
require ( require (
github.com/cerc-io/eth-ipfs-state-validator/v5 v5.2.0-alpha github.com/cerc-io/eth-ipfs-state-validator/v5 v5.0.0-alpha
github.com/cerc-io/eth-iterator-utils v0.3.1 github.com/cerc-io/eth-iterator-utils v0.1.1
github.com/cerc-io/ipfs-ethdb/v5 v5.1.0-alpha github.com/cerc-io/ipfs-ethdb/v5 v5.0.0-alpha
github.com/cerc-io/ipld-eth-statedb v0.1.1 github.com/cerc-io/ipld-eth-statedb v0.0.5-alpha
github.com/cerc-io/plugeth-statediff v0.3.2 github.com/cerc-io/plugeth-statediff v0.1.1
github.com/ethereum/go-ethereum v1.13.14 github.com/ethereum/go-ethereum v1.11.6
github.com/google/uuid v1.6.0 github.com/google/uuid v1.3.0
github.com/graph-gophers/graphql-go v1.3.0 github.com/graph-gophers/graphql-go v1.3.0
github.com/holiman/uint256 v1.2.4
github.com/ipfs/go-cid v0.4.1 github.com/ipfs/go-cid v0.4.1
github.com/jmoiron/sqlx v1.3.5 github.com/jmoiron/sqlx v1.3.5
github.com/joho/godotenv v1.4.0 github.com/joho/godotenv v1.4.0
github.com/lib/pq v1.10.9 github.com/lib/pq v1.10.9
github.com/machinebox/graphql v0.2.2 github.com/machinebox/graphql v0.2.2
github.com/mailgun/groupcache/v2 v2.3.0 github.com/mailgun/groupcache/v2 v2.3.0
github.com/onsi/ginkgo/v2 v2.15.0 github.com/onsi/ginkgo/v2 v2.9.2
github.com/onsi/gomega v1.30.0 github.com/onsi/gomega v1.27.4
github.com/prometheus/client_golang v1.18.0 github.com/prometheus/client_golang v1.16.0
github.com/sirupsen/logrus v1.9.3 github.com/sirupsen/logrus v1.9.0
github.com/spf13/cobra v1.8.0 github.com/spf13/cobra v1.4.0
github.com/spf13/viper v1.18.2 github.com/spf13/viper v1.11.0
gorm.io/driver/postgres v1.3.7 gorm.io/driver/postgres v1.3.7
gorm.io/gorm v1.23.5 gorm.io/gorm v1.23.5
) )
@ -31,266 +30,275 @@ require (
require ( require (
bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect bazil.org/fuse v0.0.0-20200117225306-7b5117fecadc // indirect
github.com/DataDog/zstd v1.5.5 // indirect github.com/DataDog/zstd v1.5.5 // indirect
github.com/Jorropo/jsync v1.0.1 // indirect github.com/VictoriaMetrics/fastcache v1.12.1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect
github.com/VictoriaMetrics/fastcache v1.12.2 // indirect github.com/benbjohnson/clock v1.3.0 // indirect
github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 // indirect
github.com/benbjohnson/clock v1.3.5 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.10.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect github.com/blang/semver/v4 v4.0.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cockroachdb/errors v1.10.0 // indirect github.com/cockroachdb/errors v1.10.0 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 // indirect github.com/cockroachdb/pebble v0.0.0-20230720154706-692f3b61a3c4 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect github.com/cockroachdb/redact v1.1.5 // indirect
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect github.com/cockroachdb/tokenbucket v0.0.0-20230613231145-182959a1fad6 // indirect
github.com/consensys/bavard v0.1.13 // indirect github.com/containerd/cgroups v1.0.4 // indirect
github.com/consensys/gnark-crypto v0.12.1 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/crackcomm/go-gitignore v0.0.0-20231225121904-e25f5bc08668 // indirect github.com/crackcomm/go-gitignore v0.0.0-20170627025303-887ab5e44cc3 // indirect
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 // indirect
github.com/crate-crypto/go-kzg-4844 v0.7.0 // indirect
github.com/cskr/pubsub v1.0.2 // indirect github.com/cskr/pubsub v1.0.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/deckarep/golang-set/v2 v2.3.0 // indirect github.com/deckarep/golang-set/v2 v2.3.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/deepmap/oapi-codegen v1.8.2 // indirect github.com/deepmap/oapi-codegen v1.8.2 // indirect
github.com/docker/go-units v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // 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/elastic/gosigar v0.14.2 // indirect
github.com/ethereum/c-kzg-4844 v0.4.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect
github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect github.com/facebookgo/atomicfile v0.0.0-20151019160806-2de1f203e7d5 // indirect
github.com/ferranbt/fastssz v0.1.2 // indirect github.com/fjl/memsize v0.0.1 // indirect
github.com/fjl/memsize v0.0.2 // indirect github.com/flynn/noise v1.0.0 // indirect
github.com/flynn/noise v1.1.0 // indirect
github.com/francoispqt/gojay v1.2.13 // indirect github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/gballet/go-verkle v0.1.1-0.20231031103413-a67434b50f46 // indirect
github.com/georgysavva/scany v0.2.9 // indirect github.com/georgysavva/scany v0.2.9 // indirect
github.com/getsentry/sentry-go v0.22.0 // indirect github.com/getsentry/sentry-go v0.22.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-stack/stack v1.8.1 // indirect github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/flock v0.8.1 // indirect github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/go-cmp v0.6.0 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gopacket v1.1.19 // indirect github.com/google/gopacket v1.1.19 // indirect
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect github.com/google/pprof v0.0.0-20221203041831-ce31453925ec // indirect
github.com/gorilla/websocket v1.5.1 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hannahhoward/go-pubsub v0.0.0-20200423002714-8d62886cc36e // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-bexpr v0.1.12 // indirect github.com/hashicorp/go-bexpr v0.1.12 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/hashicorp/golang-lru v1.0.2 // indirect github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 // indirect
github.com/holiman/bloomfilter/v2 v2.0.3 // indirect github.com/holiman/bloomfilter/v2 v2.0.3 // indirect
github.com/huin/goupnp v1.3.0 // indirect github.com/holiman/uint256 v1.2.3 // indirect
github.com/huin/goupnp v1.2.0 // indirect
github.com/inconshreveable/log15 v2.16.0+incompatible // indirect github.com/inconshreveable/log15 v2.16.0+incompatible // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect github.com/influxdata/influxdb-client-go/v2 v2.4.0 // indirect
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c // indirect
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
github.com/ipfs/bbloom v0.0.4 // indirect github.com/ipfs/bbloom v0.0.4 // indirect
github.com/ipfs/boxo v0.19.0 // indirect github.com/ipfs/go-bitfield v1.0.0 // indirect
github.com/ipfs/go-bitfield v1.1.0 // indirect github.com/ipfs/go-bitswap v0.11.0 // indirect
github.com/ipfs/go-block-format v0.2.0 // indirect github.com/ipfs/go-block-format v0.0.3 // indirect
github.com/ipfs/go-blockservice v0.5.0 // indirect
github.com/ipfs/go-cidutil v0.1.0 // indirect github.com/ipfs/go-cidutil v0.1.0 // indirect
github.com/ipfs/go-datastore v0.6.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-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-fs-lock v0.0.7 // indirect
github.com/ipfs/go-graphsync v0.14.1 // indirect
github.com/ipfs/go-ipfs-blockstore v1.2.0 // 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-delay v0.0.1 // indirect
github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
github.com/ipfs/go-ipfs-pq v0.0.3 // indirect github.com/ipfs/go-ipfs-exchange-interface v0.2.0 // indirect
github.com/ipfs/go-ipfs-redirects-file v0.1.1 // indirect github.com/ipfs/go-ipfs-exchange-offline v0.3.0 // indirect
github.com/ipfs/go-ipfs-util v0.0.3 // indirect github.com/ipfs/go-ipfs-keystore v0.1.0 // indirect
github.com/ipfs/go-ipld-cbor v0.1.0 // indirect github.com/ipfs/go-ipfs-pinner v0.2.1 // indirect
github.com/ipfs/go-ipld-format v0.6.0 // indirect github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
github.com/ipfs/go-ipld-legacy v0.2.1 // indirect github.com/ipfs/go-ipfs-pq v0.0.2 // 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.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.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 v1.0.5 // indirect
github.com/ipfs/go-log/v2 v2.5.1 // indirect github.com/ipfs/go-log/v2 v2.5.1 // indirect
github.com/ipfs/go-merkledag v0.9.0 // indirect
github.com/ipfs/go-metrics-interface v0.0.1 // indirect github.com/ipfs/go-metrics-interface v0.0.1 // indirect
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect github.com/ipfs/go-mfs v0.2.1 // indirect
github.com/ipfs/go-unixfsnode v1.9.0 // indirect github.com/ipfs/go-namesys v0.6.0 // indirect
github.com/ipfs/kubo v0.27.0 // indirect github.com/ipfs/go-path v0.3.0 // indirect
github.com/ipld/go-car/v2 v2.13.1 // indirect github.com/ipfs/go-peertaskqueue v0.8.0 // indirect
github.com/ipld/go-codec-dagpb v1.6.0 // indirect github.com/ipfs/go-unixfs v0.4.2 // indirect
github.com/ipld/go-ipld-prime v0.21.0 // 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/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgconn v1.14.0 // indirect
github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect github.com/jackc/pgproto3/v2 v2.3.2 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/pgx/v4 v4.18.3 // indirect github.com/jackc/pgx/v4 v4.18.1 // indirect
github.com/jackc/puddle v1.3.0 // indirect github.com/jackc/puddle v1.3.0 // indirect
github.com/jackpal/go-nat-pmp v1.0.2 // indirect github.com/jackpal/go-nat-pmp v1.0.2 // indirect
github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
github.com/jbenet/goprocess v0.1.4 // indirect github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.4 // indirect github.com/jinzhu/now v1.1.4 // indirect
github.com/klauspost/compress v1.17.6 // indirect github.com/klauspost/compress v1.16.7 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect github.com/koron/go-ssdp v0.0.3 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
github.com/libp2p/go-buffer-pool v0.1.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-cidranger v1.1.0 // indirect
github.com/libp2p/go-doh-resolver v0.4.0 // indirect github.com/libp2p/go-doh-resolver v0.4.0 // indirect
github.com/libp2p/go-flow-metrics v0.1.0 // indirect github.com/libp2p/go-flow-metrics v0.1.0 // indirect
github.com/libp2p/go-libp2p v0.33.0 // indirect github.com/libp2p/go-libp2p v0.24.2 // indirect
github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect
github.com/libp2p/go-libp2p-kad-dht v0.24.4 // indirect github.com/libp2p/go-libp2p-kad-dht v0.20.0 // indirect
github.com/libp2p/go-libp2p-kbucket v0.6.3 // indirect github.com/libp2p/go-libp2p-kbucket v0.5.0 // indirect
github.com/libp2p/go-libp2p-pubsub v0.10.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-pubsub-router v0.6.0 // indirect
github.com/libp2p/go-libp2p-record v0.2.0 // indirect github.com/libp2p/go-libp2p-record v0.2.0 // indirect
github.com/libp2p/go-libp2p-routing-helpers v0.7.3 // 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-libp2p-xor v0.1.0 // indirect
github.com/libp2p/go-msgio v0.3.0 // indirect github.com/libp2p/go-mplex v0.7.0 // indirect
github.com/libp2p/go-nat v0.2.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.1 // indirect github.com/libp2p/go-netroute v0.2.1 // indirect
github.com/libp2p/go-reuseport v0.4.0 // indirect github.com/libp2p/go-openssl v0.1.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.1 // indirect github.com/libp2p/go-reuseport v0.2.0 // indirect
github.com/libp2p/go-yamux/v4 v4.0.0 // indirect
github.com/libp2p/zeroconf/v2 v2.2.0 // indirect github.com/libp2p/zeroconf/v2 v2.2.0 // indirect
github.com/magiconair/properties v1.8.7 // indirect github.com/lucas-clemente/quic-go v0.31.1 // indirect
github.com/magiconair/properties v1.8.6 // 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/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect
github.com/marten-seemann/webtransport-go v0.4.3 // indirect
github.com/matryer/is v1.4.1 // indirect github.com/matryer/is v1.4.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-pointer v0.0.1 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/miekg/dns v1.1.58 // 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/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect
github.com/minio/sha256-simd v1.0.1 // indirect github.com/minio/sha256-simd v1.0.1 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/pointerstructure v1.2.1 // indirect github.com/mitchellh/pointerstructure v1.2.1 // indirect
github.com/mmcloughlin/addchain v0.4.0 // indirect
github.com/mr-tron/base58 v1.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect
github.com/multiformats/go-base32 v0.1.0 // indirect github.com/multiformats/go-base32 v0.1.0 // indirect
github.com/multiformats/go-base36 v0.2.0 // indirect github.com/multiformats/go-base36 v0.2.0 // indirect
github.com/multiformats/go-multiaddr v0.12.2 // 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-dns v0.3.1 // indirect
github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect
github.com/multiformats/go-multibase v0.2.0 // indirect github.com/multiformats/go-multibase v0.2.0 // indirect
github.com/multiformats/go-multicodec v0.9.0 // indirect github.com/multiformats/go-multicodec v0.7.0 // indirect
github.com/multiformats/go-multihash v0.2.3 // indirect github.com/multiformats/go-multihash v0.2.3 // indirect
github.com/multiformats/go-multistream v0.5.0 // indirect github.com/multiformats/go-multistream v0.3.3 // indirect
github.com/multiformats/go-varint v0.0.7 // indirect github.com/multiformats/go-varint v0.0.7 // indirect
github.com/olekukonko/tablewriter v0.0.5 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect
github.com/opencontainers/runtime-spec v1.2.0 // indirect github.com/opencontainers/runtime-spec v1.0.2 // indirect
github.com/openrelayxyz/plugeth-utils v1.5.0 // indirect github.com/openrelayxyz/plugeth-utils v1.2.0 // indirect
github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect
github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect
github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/pelletier/go-toml v1.9.4 // indirect
github.com/petar/GoLLRB v0.0.0-20210522233825-ae3b015fd3e9 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect
github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect github.com/peterh/liner v1.1.1-0.20190123174540-a2c9a5303de7 // indirect
github.com/pganalyze/pg_query_go/v4 v4.2.1 // indirect github.com/pganalyze/pg_query_go/v4 v4.2.1 // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.8 // indirect
github.com/pion/ice/v2 v2.3.11 // indirect
github.com/pion/interceptor v0.1.25 // indirect
github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.9 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.13 // indirect
github.com/pion/rtp v1.8.3 // indirect
github.com/pion/sctp v1.8.9 // indirect
github.com/pion/sdp/v3 v3.0.6 // indirect
github.com/pion/srtp/v2 v2.0.18 // indirect
github.com/pion/stun v0.6.1 // indirect
github.com/pion/transport/v2 v2.2.4 // indirect
github.com/pion/turn/v2 v2.1.4 // indirect
github.com/pion/webrtc/v3 v3.2.23 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polydawn/refmt v0.89.0 // indirect github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
github.com/prometheus/client_model v0.6.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.47.0 // indirect github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.11.0 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/quic-go v0.41.0 // indirect
github.com/quic-go/webtransport-go v0.6.0 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/rs/cors v1.9.0 // indirect github.com/rs/cors v1.9.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/samber/lo v1.36.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/samber/lo v1.39.0 // indirect
github.com/segmentio/fasthash v1.0.3 // indirect github.com/segmentio/fasthash v1.0.3 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/shopspring/decimal v1.2.0 // indirect github.com/shopspring/decimal v1.2.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.11.0 // indirect github.com/spf13/afero v1.8.2 // indirect
github.com/spf13/cast v1.6.0 // indirect github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/status-im/keycard-go v0.2.0 // indirect github.com/status-im/keycard-go v0.2.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/objx v0.5.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect github.com/stretchr/testify v1.8.2 // indirect
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect
github.com/supranational/blst v0.3.11 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect github.com/syndtr/goleveldb v1.0.1-0.20220614013038-64ee5596c38a // indirect
github.com/thoas/go-funk v0.9.3 // indirect github.com/thoas/go-funk v0.9.3 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect github.com/tklauser/numcpus v0.6.1 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb // indirect
github.com/urfave/cli/v2 v2.25.7 // indirect github.com/urfave/cli/v2 v2.25.7 // indirect
github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc // indirect
github.com/whyrusleeping/cbor v0.0.0-20171005072247-63513f603b11 // indirect github.com/whyrusleeping/cbor-gen v0.0.0-20221220214510-0333c149dec0 // indirect
github.com/whyrusleeping/cbor-gen v0.0.0-20240109153615-66e95c3e8a87 // indirect
github.com/whyrusleeping/chunker v0.0.0-20181014151217-fe64bd25879f // 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/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.opentelemetry.io/otel v1.25.0 // indirect go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/metric v1.25.0 // indirect go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.25.0 // indirect go.uber.org/atomic v1.10.0 // indirect
go.uber.org/dig v1.17.1 // indirect go.uber.org/dig v1.15.0 // indirect
go.uber.org/fx v1.20.1 // indirect go.uber.org/fx v1.18.2 // indirect
go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.9.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.24.0 // indirect
go.uber.org/zap v1.27.0 // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
go4.org v0.0.0-20230225012048-214862532bf5 // indirect golang.org/x/crypto v0.11.0 // indirect
golang.org/x/crypto v0.22.0 // indirect golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // indirect golang.org/x/mod v0.11.0 // indirect
golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.10.0 // indirect
golang.org/x/net v0.24.0 // indirect golang.org/x/sync v0.3.0 // indirect
golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.10.0 // indirect
golang.org/x/sys v0.19.0 // indirect golang.org/x/term v0.10.0 // indirect
golang.org/x/term v0.19.0 // indirect golang.org/x/text v0.11.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.3.0 // indirect
golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.7.0 // indirect
golang.org/x/tools v0.20.0 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/protobuf v1.31.0 // indirect
gonum.org/v1/gonum v0.14.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/blake3 v1.2.2 // indirect lukechampine.com/blake3 v1.2.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect )
replace (
github.com/cerc-io/eth-ipfs-state-validator/v5 => git.vdb.to/cerc-io/eth-ipfs-state-validator/v5 v5.1.1-alpha
github.com/cerc-io/eth-iterator-utils => git.vdb.to/cerc-io/eth-iterator-utils v0.1.2-beta
github.com/cerc-io/eth-testing => git.vdb.to/cerc-io/eth-testing v0.3.1
github.com/cerc-io/ipld-eth-statedb => git.vdb.to/cerc-io/ipld-eth-statedb v0.0.7-alpha-0.0.1 // git.vdb.to/cerc-io/ipld-eth-statedb v0.0.6-alpha
github.com/cerc-io/plugeth-statediff => git.vdb.to/cerc-io/plugeth-statediff v0.1.4
github.com/ethereum/go-ethereum => git.vdb.to/cerc-io/plugeth v0.0.0-20230808125822-691dc334fab1
github.com/openrelayxyz/plugeth-utils => git.vdb.to/cerc-io/plugeth-utils v0.0.0-20230706160122-cd41de354c46
) )

1472
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -22,13 +22,13 @@ var _ = Describe("Direct proxy integration test", Label("proxy"), func() {
var contractErr error var contractErr error
var txErr error var txErr error
Describe("Get Block", func() { Describe("get Block", func() {
BeforeEach(func() { BeforeEach(func() {
contract, contractErr = integration.DeployContract() contract, contractErr = integration.DeployContract()
Expect(contractErr).ToNot(HaveOccurred()) Expect(contractErr).ToNot(HaveOccurred())
}) })
It("gets not existing block by number", func() { It("get not existing block by number", func() {
blockNum := contract.BlockNumber + 100 blockNum := contract.BlockNumber + 100
gethBlock, err := gethClient.BlockByNumber(ctx, big.NewInt(blockNum)) gethBlock, err := gethClient.BlockByNumber(ctx, big.NewInt(blockNum))
@ -40,7 +40,7 @@ var _ = Describe("Direct proxy integration test", Label("proxy"), func() {
Expect(ipldBlock).To(BeZero()) Expect(ipldBlock).To(BeZero())
}) })
It("gets not existing block by hash", func() { It("get not existing block by hash", func() {
gethBlock, err := gethClient.BlockByHash(ctx, nonExistingBlockHash) gethBlock, err := gethClient.BlockByHash(ctx, nonExistingBlockHash)
Expect(err).To(MatchError(ethereum.NotFound)) Expect(err).To(MatchError(ethereum.NotFound))
Expect(gethBlock).To(BeZero()) Expect(gethBlock).To(BeZero())
@ -50,7 +50,7 @@ var _ = Describe("Direct proxy integration test", Label("proxy"), func() {
Expect(ipldBlock).To(BeZero()) Expect(ipldBlock).To(BeZero())
}) })
It("gets block by number", func() { It("get block by number", func() {
blockNum := contract.BlockNumber blockNum := contract.BlockNumber
_, err := gethClient.BlockByNumber(ctx, big.NewInt(blockNum)) _, err := gethClient.BlockByNumber(ctx, big.NewInt(blockNum))
@ -60,7 +60,7 @@ var _ = Describe("Direct proxy integration test", Label("proxy"), func() {
Expect(err).To(HaveOccurred()) Expect(err).To(HaveOccurred())
}) })
It("gets block by hash", func() { It("get block by hash", func() {
_, err := gethClient.BlockByHash(ctx, contract.BlockHash) _, err := gethClient.BlockByHash(ctx, contract.BlockHash)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())

View File

@ -34,7 +34,7 @@ var _ = Describe("Basic integration test", func() {
var contractErr error var contractErr error
var txErr error var txErr error
Describe("Get Block", func() { Describe("get Block", func() {
BeforeEach(func() { BeforeEach(func() {
contract, contractErr = integration.DeployContract() contract, contractErr = integration.DeployContract()
Expect(contractErr).ToNot(HaveOccurred()) Expect(contractErr).ToNot(HaveOccurred())
@ -43,7 +43,7 @@ var _ = Describe("Basic integration test", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
}) })
It("gets not existing block by number", func() { It("get not existing block by number", func() {
blockNum := big.NewInt(contract.BlockNumber + 100) blockNum := big.NewInt(contract.BlockNumber + 100)
gethBlock, err := gethClient.BlockByNumber(ctx, blockNum) gethBlock, err := gethClient.BlockByNumber(ctx, blockNum)
@ -55,7 +55,7 @@ var _ = Describe("Basic integration test", func() {
Expect(ipldBlock).To(BeZero()) Expect(ipldBlock).To(BeZero())
}) })
It("gets not existing block by hash", func() { It("get not existing block by hash", func() {
gethBlock, err := gethClient.BlockByHash(ctx, nonExistingBlockHash) gethBlock, err := gethClient.BlockByHash(ctx, nonExistingBlockHash)
Expect(err).To(MatchError(ethereum.NotFound)) Expect(err).To(MatchError(ethereum.NotFound))
Expect(gethBlock).To(BeZero()) Expect(gethBlock).To(BeZero())
@ -65,7 +65,7 @@ var _ = Describe("Basic integration test", func() {
Expect(ipldBlock).To(BeZero()) Expect(ipldBlock).To(BeZero())
}) })
It("gets block by number", func() { It("get block by number", func() {
blockNum := big.NewInt(contract.BlockNumber) blockNum := big.NewInt(contract.BlockNumber)
gethBlock, err := gethClient.BlockByNumber(ctx, blockNum) gethBlock, err := gethClient.BlockByNumber(ctx, blockNum)
@ -84,7 +84,7 @@ var _ = Describe("Basic integration test", func() {
Expect(types.TxDifference(gethTxs, ipldTxs).Len()).To(Equal(0)) Expect(types.TxDifference(gethTxs, ipldTxs).Len()).To(Equal(0))
}) })
It("gets block by hash", func() { It("get block by hash", func() {
gethBlock, err := gethClient.BlockByHash(ctx, contract.BlockHash) gethBlock, err := gethClient.BlockByHash(ctx, contract.BlockHash)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
@ -391,7 +391,7 @@ var _ = Describe("Basic integration test", func() {
Expect(ipldCountA).To(Equal(slvCountA)) Expect(ipldCountA).To(Equal(slvCountA))
}) })
It("gets storage after destruction", func() { It("gets storage after destruction and redeploy", func() {
slvContract, contractErr := integration.Create2Contract("SLVToken", contractSalt) slvContract, contractErr := integration.Create2Contract("SLVToken", contractSalt)
Expect(contractErr).ToNot(HaveOccurred()) Expect(contractErr).ToNot(HaveOccurred())
@ -431,6 +431,21 @@ var _ = Describe("Basic integration test", func() {
ipldStorage, err := ipldClient.StorageAt(ctx, slvContract.Address, countAIndex, big.NewInt(slvTx.BlockNumber)) ipldStorage, err := ipldClient.StorageAt(ctx, slvContract.Address, countAIndex, big.NewInt(slvTx.BlockNumber))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(ipldStorage).To(Equal(gethStorage)) Expect(ipldStorage).To(Equal(gethStorage))
// Redeploy to same address
slvContract, contractErr = integration.Create2Contract("SLVToken", contractSalt)
Expect(contractErr).ToNot(HaveOccurred())
gethStorage, err = gethClient.StorageAt(ctx, slvContract.Address, countAIndex, big.NewInt(slvContract.BlockNumber))
Expect(err).ToNot(HaveOccurred())
ipldStorage, err = ipldClient.StorageAt(ctx, slvContract.Address, countAIndex, big.NewInt(slvContract.BlockNumber))
Expect(err).ToNot(HaveOccurred())
Expect(gethStorage).To(Equal(ipldStorage))
ipldCountA := new(big.Int).SetBytes(ipldStorage)
Expect(ipldCountA.String()).To(Equal("0"))
}) })
}) })

View File

@ -19,25 +19,21 @@ package eth
import ( import (
"context" "context"
"database/sql" "database/sql"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"strconv" "strconv"
"strings"
"time" "time"
ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf" "github.com/ethereum/go-ethereum/core/vm"
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state"
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie"
statediff "github.com/cerc-io/plugeth-statediff" statediff "github.com/cerc-io/plugeth-statediff"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -45,9 +41,9 @@ import (
"github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/holiman/uint256"
"github.com/cerc-io/ipld-eth-server/v5/pkg/log" "github.com/cerc-io/ipld-eth-server/v5/pkg/log"
ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf"
) )
const ( const (
@ -112,25 +108,6 @@ Headers and blocks
*/ */
// decodeHash parses a hex-encoded 32-byte hash. The input may optionally
// be prefixed by 0x and can have a byte length up to 32.
func decodeHash(s string) (h common.Hash, inputLength int, err error) {
if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
s = s[2:]
}
if (len(s) & 1) > 0 {
s = "0" + s
}
b, err := hex.DecodeString(s)
if err != nil {
return common.Hash{}, 0, errors.New("hex string invalid")
}
if len(b) > 32 {
return common.Hash{}, len(b), errors.New("hex string too long, want at most 32 bytes")
}
return common.BytesToHash(b), len(b), nil
}
// GetHeaderByNumber returns the requested canonical block header. // GetHeaderByNumber returns the requested canonical block header.
// * When blockNr is -1 the chain head is returned. // * When blockNr is -1 the chain head is returned.
// * We cannot support pending block calls since we do not have an active miner // * We cannot support pending block calls since we do not have an active miner
@ -247,7 +224,8 @@ Uncles
*/ */
// GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. When fullTx is true
// all transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
func (pea *PublicEthAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { func (pea *PublicEthAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) {
block, err := pea.B.BlockByNumber(ctx, blockNr) block, err := pea.B.BlockByNumber(ctx, blockNr)
if block != nil && err == nil { if block != nil && err == nil {
@ -403,7 +381,7 @@ func (pea *PublicEthAPI) GetBlockTransactionCountByHash(ctx context.Context, blo
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil { if block, _ := pea.B.BlockByNumber(ctx, blockNr); block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index), pea.B.ChainConfig()) return newRPCTransactionFromBlockIndex(block, uint64(index))
} }
if pea.config.ProxyOnError { if pea.config.ProxyOnError {
@ -420,7 +398,7 @@ func (pea *PublicEthAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
func (pea *PublicEthAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { func (pea *PublicEthAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil { if block, _ := pea.B.BlockByHash(ctx, blockHash); block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index), pea.B.ChainConfig()) return newRPCTransactionFromBlockIndex(block, uint64(index))
} }
if pea.config.ProxyOnError { if pea.config.ProxyOnError {
@ -467,14 +445,14 @@ func (pea *PublicEthAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Contex
// GetTransactionByHash returns the transaction for the given hash // GetTransactionByHash returns the transaction for the given hash
// eth ipld-eth-server cannot currently handle pending/tx_pool txs // eth ipld-eth-server cannot currently handle pending/tx_pool txs
func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
_, tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash) tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash)
if tx != nil && err == nil { if tx != nil && err == nil {
header, err := pea.B.HeaderByHash(ctx, blockHash) header, err := pea.B.HeaderByHash(ctx, blockHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, pea.B.ChainConfig()), nil return NewRPCTransaction(tx, blockHash, blockNumber, index, header.BaseFee), nil
} }
if pea.config.ProxyOnError { if pea.config.ProxyOnError {
var tx *RPCTransaction var tx *RPCTransaction
@ -489,7 +467,7 @@ func (pea *PublicEthAPI) GetTransactionByHash(ctx context.Context, hash common.H
// GetRawTransactionByHash returns the bytes of the transaction for the given hash. // GetRawTransactionByHash returns the bytes of the transaction for the given hash.
func (pea *PublicEthAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { func (pea *PublicEthAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
// Retrieve a finalized transaction, or a pooled otherwise // Retrieve a finalized transaction, or a pooled otherwise
_, tx, _, _, _, err := pea.B.GetTransaction(ctx, hash) tx, _, _, _, err := pea.B.GetTransaction(ctx, hash)
if tx != nil && err == nil { if tx != nil && err == nil {
return tx.MarshalBinary() return tx.MarshalBinary()
} }
@ -604,7 +582,7 @@ func (pea *PublicEthAPI) GetTransactionReceipt(ctx context.Context, hash common.
func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
// TODO: this can be optimized for Postgres // TODO: this can be optimized for Postgres
_, tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash) tx, blockHash, blockNumber, index, err := pea.B.GetTransaction(ctx, hash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -619,11 +597,7 @@ func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash co
if err != nil { if err != nil {
return nil, err return nil, err
} }
var blobGasPrice *big.Int err = receipts.DeriveFields(pea.B.Config.ChainConfig, blockHash, blockNumber, block.BaseFee(), block.Transactions())
if excessBlobGas := block.ExcessBlobGas(); excessBlobGas != nil {
blobGasPrice = eip4844.CalcBlobFee(*excessBlobGas)
}
err = receipts.DeriveFields(pea.B.Config.ChainConfig, blockHash, blockNumber, block.Time(), block.BaseFee(), blobGasPrice, block.Transactions())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -660,12 +634,6 @@ func (pea *PublicEthAPI) localGetTransactionReceipt(ctx context.Context, hash co
if receipt.Logs == nil { if receipt.Logs == nil {
fields["logs"] = []*types.Log{} fields["logs"] = []*types.Log{}
} }
if tx.Type() == types.BlobTxType {
fields["blobGasUsed"] = hexutil.Uint64(receipt.BlobGasUsed)
fields["blobGasPrice"] = (*hexutil.Big)(receipt.BlobGasPrice)
}
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
if receipt.ContractAddress != (common.Address{}) { if receipt.ContractAddress != (common.Address{}) {
fields["contractAddress"] = receipt.ContractAddress fields["contractAddress"] = receipt.ContractAddress
@ -827,7 +795,7 @@ func (pea *PublicEthAPI) localGetBalance(ctx context.Context, address common.Add
if err != nil { if err != nil {
return nil, err return nil, err
} }
return (*hexutil.Big)(account.Balance.ToBig()), nil return (*hexutil.Big)(account.Balance), nil
} }
// GetStorageAt returns the storage from the state at the given address, key and // GetStorageAt returns the storage from the state at the given address, key and
@ -856,7 +824,7 @@ func (pea *PublicEthAPI) GetStorageAt(ctx context.Context, address common.Addres
return value[:], nil return value[:], nil
} }
if pea.config.ProxyOnError { if pea.config.ProxyOnError {
log.Warnxf(ctx, "Missing eth_getStorageAt(%s, %s, %s)", address, key, blockNrOrHash.String()) log.Warnxf(ctx, "Missing eth_getStorageAt(%s, %s, %s)", address.Hash().String(), key, blockNrOrHash.String())
var res hexutil.Bytes var res hexutil.Bytes
if err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash); res != nil && err == nil { if err := pea.rpc.CallContext(ctx, &res, "eth_getStorageAt", address, key, blockNrOrHash); res != nil && err == nil {
return res, nil return res, nil
@ -902,95 +870,57 @@ func (pea *PublicEthAPI) GetProof(ctx context.Context, address common.Address, s
return nil, err return nil, err
} }
// proofList implements ethdb.KeyValueWriter and collects the proofs as
// hex-strings for delivery to rpc-caller.
type proofList []string
func (n *proofList) Put(key []byte, value []byte) error {
*n = append(*n, hexutil.Encode(value))
return nil
}
func (n *proofList) Delete(key []byte) error {
panic("not supported")
}
// this continues to use ipfs-ethdb based geth StateDB as it requires trie access // this continues to use ipfs-ethdb based geth StateDB as it requires trie access
func (pea *PublicEthAPI) localGetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) { func (pea *PublicEthAPI) localGetProof(ctx context.Context, address common.Address, storageKeys []string, blockNrOrHash rpc.BlockNumberOrHash) (*AccountResult, error) {
var ( state, _, err := pea.B.IPLDTrieStateDBAndHeaderByNumberOrHash(ctx, blockNrOrHash)
keys = make([]common.Hash, len(storageKeys)) if state == nil || err != nil {
keyLengths = make([]int, len(storageKeys))
storageProof = make([]StorageResult, len(storageKeys))
)
// Deserialize all keys. This prevents state access on invalid input.
for i, hexKey := range storageKeys {
var err error
keys[i], keyLengths[i], err = decodeHash(hexKey)
if err != nil {
return nil, err return nil, err
} }
}
statedb, header, err := pea.B.IPLDTrieStateDBAndHeaderByNumberOrHash(ctx, blockNrOrHash)
// statedb, header, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if statedb == nil || err != nil {
return nil, err
}
codeHash := statedb.GetCodeHash(address)
storageRoot := statedb.GetStorageRoot(address)
if len(keys) > 0 { storageTrie, err := state.StorageTrie(address)
var storageTrie state.Trie if storageTrie == nil || err != nil {
if storageRoot != types.EmptyRootHash && storageRoot != (common.Hash{}) {
id := trie.StorageTrieID(header.Root, crypto.Keccak256Hash(address.Bytes()), storageRoot)
st, err := trie.NewStateTrie(id, statedb.Database().TrieDB())
if err != nil {
return nil, err return nil, err
} }
storageTrie = st storageHash := types.EmptyRootHash
} codeHash := state.GetCodeHash(address)
// Create the proofs for the storageKeys. storageProof := make([]StorageResult, len(storageKeys))
for i, key := range keys {
// Output key encoding is a bit special: if the input was a 32-byte hash, it is // if we have a storageTrie, (which means the account exists), we can update the storagehash
// returned as such. Otherwise, we apply the QUANTITY encoding mandated by the if storageTrie != nil {
// JSON-RPC spec for getProof. This behavior exists to preserve backwards storageHash = storageTrie.Hash()
// compatibility with older client versions.
var outputKey string
if keyLengths[i] != 32 {
outputKey = hexutil.EncodeBig(key.Big())
} else { } else {
outputKey = hexutil.Encode(key[:]) // no storageTrie means the account does not exist, so the codeHash is the hash of an empty bytearray.
codeHash = crypto.Keccak256Hash(nil)
} }
if storageTrie == nil {
storageProof[i] = StorageResult{outputKey, &hexutil.Big{}, []string{}} // create the proof for the storageKeys
continue for i, key := range storageKeys {
if storageTrie != nil {
proof, storageError := state.GetStorageProof(address, common.HexToHash(key))
if storageError != nil {
return nil, storageError
} }
var proof proofList storageProof[i] = StorageResult{key, (*hexutil.Big)(state.GetState(address, common.HexToHash(key)).Big()), toHexSlice(proof)}
if err := storageTrie.Prove(crypto.Keccak256(key.Bytes()), &proof); err != nil { } else {
return nil, err storageProof[i] = StorageResult{key, &hexutil.Big{}, []string{}}
}
value := (*hexutil.Big)(statedb.GetState(address, key).Big())
storageProof[i] = StorageResult{outputKey, value, proof}
} }
} }
// Create the accountProof.
tr, err := trie.NewStateTrie(trie.StateTrieID(header.Root), statedb.Database().TrieDB()) // create the accountProof
if err != nil { accountProof, proofErr := state.GetProof(address)
return nil, err if proofErr != nil {
return nil, proofErr
} }
var accountProof proofList
if err := tr.Prove(crypto.Keccak256(address.Bytes()), &accountProof); err != nil {
return nil, err
}
balance := statedb.GetBalance(address).ToBig()
return &AccountResult{ return &AccountResult{
Address: address, Address: address,
AccountProof: accountProof, AccountProof: toHexSlice(accountProof),
Balance: (*hexutil.Big)(balance), Balance: (*hexutil.Big)(state.GetBalance(address)),
CodeHash: codeHash, CodeHash: codeHash,
Nonce: hexutil.Uint64(statedb.GetNonce(address)), Nonce: hexutil.Uint64(state.GetNonce(address)),
StorageHash: storageRoot, StorageHash: storageHash,
StorageProof: storageProof, StorageProof: storageProof,
}, statedb.Error() }, 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 // GetSlice returns a slice of state or storage nodes from a provided root to a provided path and past it to a certain depth
@ -1061,7 +991,7 @@ func (diff *StateOverride) Apply(state *ipld_direct_state.StateDB) error {
} }
// Override account balance. // Override account balance.
if account.Balance != nil { if account.Balance != nil {
state.SetBalance(addr, uint256.MustFromBig((*big.Int)(*account.Balance))) state.SetBalance(addr, (*big.Int)(*account.Balance))
} }
if account.State != nil && account.StateDiff != nil { if account.State != nil && account.StateDiff != nil {
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex()) return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
@ -1077,9 +1007,52 @@ func (diff *StateOverride) Apply(state *ipld_direct_state.StateDB) error {
} }
} }
} }
// Now finalize the changes. Finalize is normally performed between transactions.
// By using finalize, the overrides are semantically behaving as
// if they were created in a transaction just before the tracing occur.
state.Finalise(false)
return nil return nil
} }
// BlockOverrides is a set of header fields to override.
type BlockOverrides struct {
Number *hexutil.Big
Difficulty *hexutil.Big
Time *hexutil.Uint64
GasLimit *hexutil.Uint64
Coinbase *common.Address
Random *common.Hash
BaseFee *hexutil.Big
}
// Apply overrides the given header fields into the given block context.
func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
if diff == nil {
return
}
if diff.Number != nil {
blockCtx.BlockNumber = diff.Number.ToInt()
}
if diff.Difficulty != nil {
blockCtx.Difficulty = diff.Difficulty.ToInt()
}
if diff.Time != nil {
blockCtx.Time = uint64(*diff.Time)
}
if diff.GasLimit != nil {
blockCtx.GasLimit = uint64(*diff.GasLimit)
}
if diff.Coinbase != nil {
blockCtx.Coinbase = *diff.Coinbase
}
if diff.Random != nil {
blockCtx.Random = diff.Random
}
if diff.BaseFee != nil {
blockCtx.BaseFee = diff.BaseFee.ToInt()
}
}
// Call executes the given transaction on the state for the given block number. // Call executes the given transaction on the state for the given block number.
// //
// Additionally, the caller can specify a batch of contract for fields overriding. // Additionally, the caller can specify a batch of contract for fields overriding.
@ -1247,22 +1220,25 @@ func (pea *PublicEthAPI) writeStateDiffFor(blockHash common.Hash) {
// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field // rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field
func (pea *PublicEthAPI) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { func (pea *PublicEthAPI) rpcMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
fields := RPCMarshalBlock(b, inclTx, fullTx, pea.B.ChainConfig()) fields, err := RPCMarshalBlock(b, inclTx, fullTx)
if err != nil {
log.Errorf("error RPC marshalling block with hash %s: %s", b.Hash().String(), err)
return nil, err
}
if inclTx { if inclTx {
td, err := pea.B.GetTd(b.Hash()) td, err := pea.B.GetTd(b.Hash())
if err != nil { if err != nil {
err = fmt.Errorf("error getting TD for block at (%s, %s): %s", b.Number(), b.Hash(), err) log.Errorf("error getting td for block with hash and number %s, %s: %s", b.Hash().String(), b.Number().String(), err)
log.Error(err)
return nil, err return nil, err
} }
fields["totalDifficulty"] = (*hexutil.Big)(td) fields["totalDifficulty"] = (*hexutil.Big)(td)
} }
return fields, nil return fields, err
} }
// rpcMarshalBlockWithUncleHashes uses the generalized output filler, then adds the total difficulty field // rpcMarshalBlockWithUncleHashes uses the generalized output filler, then adds the total difficulty field
func (pea *PublicEthAPI) rpcMarshalBlockWithUncleHashes(b *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool) (map[string]interface{}, error) { func (pea *PublicEthAPI) rpcMarshalBlockWithUncleHashes(b *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool) (map[string]interface{}, error) {
fields, err := RPCMarshalBlockWithUncleHashes(b, uncleHashes, inclTx, fullTx, pea.B.ChainConfig()) fields, err := RPCMarshalBlockWithUncleHashes(b, uncleHashes, inclTx, fullTx)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -19,6 +19,7 @@ package eth_api_test
import ( import (
"context" "context"
"math/big" "math/big"
"strconv"
"github.com/cerc-io/plugeth-statediff/indexer/interfaces" "github.com/cerc-io/plugeth-statediff/indexer/interfaces"
"github.com/cerc-io/plugeth-statediff/indexer/ipld" "github.com/cerc-io/plugeth-statediff/indexer/ipld"
@ -43,14 +44,12 @@ import (
var ( var (
randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f") randomAddr = common.HexToAddress("0x1C3ab14BBaD3D99F4203bd7a11aCB94882050E6f")
randomHash = crypto.Keccak256Hash(randomAddr.Bytes()) randomHash = crypto.Keccak256Hash(randomAddr.Bytes())
number = rpc.BlockNumber(test_helpers.BlockNumber1) number = rpc.BlockNumber(test_helpers.BlockNumber.Int64())
blockTime = test_helpers.BlockTime1 londonBlockNum = rpc.BlockNumber(test_helpers.LondonBlockNum.Int64())
londonBlockNum = rpc.BlockNumber(test_helpers.LondonBlockNum)
wrongNumber = number + 1 wrongNumber = number + 1
blockHash = test_helpers.MockBlock.Header().Hash() blockHash = test_helpers.MockBlock.Header().Hash()
baseFee = test_helpers.MockLondonBlock.BaseFee() baseFee = test_helpers.MockLondonBlock.BaseFee()
ctx = context.Background() ctx = context.Background()
chainConfig = &*params.MergedTestChainConfig
expectedBlock = map[string]interface{}{ expectedBlock = map[string]interface{}{
"number": (*hexutil.Big)(test_helpers.MockBlock.Number()), "number": (*hexutil.Big)(test_helpers.MockBlock.Number()),
@ -84,6 +83,7 @@ var (
"miner": test_helpers.MockBlock.Header().Coinbase, "miner": test_helpers.MockBlock.Header().Coinbase,
"difficulty": (*hexutil.Big)(test_helpers.MockBlock.Header().Difficulty), "difficulty": (*hexutil.Big)(test_helpers.MockBlock.Header().Difficulty),
"extraData": hexutil.Bytes(test_helpers.MockBlock.Header().Extra), "extraData": hexutil.Bytes(test_helpers.MockBlock.Header().Extra),
"size": hexutil.Uint64(test_helpers.MockBlock.Header().Size()),
"gasLimit": hexutil.Uint64(test_helpers.MockBlock.Header().GasLimit), "gasLimit": hexutil.Uint64(test_helpers.MockBlock.Header().GasLimit),
"gasUsed": hexutil.Uint64(test_helpers.MockBlock.Header().GasUsed), "gasUsed": hexutil.Uint64(test_helpers.MockBlock.Header().GasUsed),
"timestamp": hexutil.Uint64(test_helpers.MockBlock.Header().Time), "timestamp": hexutil.Uint64(test_helpers.MockBlock.Header().Time),
@ -131,18 +131,10 @@ var (
"receiptsRoot": test_helpers.MockUncles[1].ReceiptHash, "receiptsRoot": test_helpers.MockUncles[1].ReceiptHash,
"uncles": []common.Hash{}, "uncles": []common.Hash{},
} }
expectedTransaction = eth.NewRPCTransaction(test_helpers.MockTransactions[0], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), blockTime, 0, test_helpers.MockBlock.BaseFee(), chainConfig) expectedTransaction = eth.NewRPCTransaction(test_helpers.MockTransactions[0], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 0, test_helpers.MockBlock.BaseFee())
expectedTransaction2 = eth.NewRPCTransaction(test_helpers.MockTransactions[1], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), blockTime, 1, test_helpers.MockBlock.BaseFee(), chainConfig) expectedTransaction2 = eth.NewRPCTransaction(test_helpers.MockTransactions[1], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 1, test_helpers.MockBlock.BaseFee())
expectedTransaction3 = eth.NewRPCTransaction(test_helpers.MockTransactions[2], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), blockTime, 2, test_helpers.MockBlock.BaseFee(), chainConfig) expectedTransaction3 = eth.NewRPCTransaction(test_helpers.MockTransactions[2], test_helpers.MockBlock.Hash(), test_helpers.MockBlock.NumberU64(), 2, test_helpers.MockBlock.BaseFee())
expectedLondonTransaction = eth.NewRPCTransaction( expectedLondonTransaction = eth.NewRPCTransaction(test_helpers.MockLondonTransactions[0], test_helpers.MockLondonBlock.Hash(), test_helpers.MockLondonBlock.NumberU64(), 0, test_helpers.MockLondonBlock.BaseFee())
test_helpers.MockLondonTransactions[0],
test_helpers.MockLondonBlock.Hash(),
test_helpers.MockLondonBlock.NumberU64(),
test_helpers.MockLondonBlock.Time(),
0,
test_helpers.MockLondonBlock.BaseFee(),
chainConfig,
)
expectRawTx, _ = test_helpers.MockTransactions[0].MarshalBinary() expectRawTx, _ = test_helpers.MockTransactions[0].MarshalBinary()
expectRawTx2, _ = test_helpers.MockTransactions[1].MarshalBinary() expectRawTx2, _ = test_helpers.MockTransactions[1].MarshalBinary()
expectRawTx3, _ = test_helpers.MockTransactions[2].MarshalBinary() expectRawTx3, _ = test_helpers.MockTransactions[2].MarshalBinary()
@ -195,10 +187,10 @@ var (
"type": hexutil.Uint64(types.LegacyTxType), "type": hexutil.Uint64(types.LegacyTxType),
} }
) )
var ( var (
db *sqlx.DB db *sqlx.DB
api *eth.PublicEthAPI api *eth.PublicEthAPI
chainConfig = params.TestChainConfig
) )
var _ = BeforeSuite(func() { var _ = BeforeSuite(func() {
@ -301,7 +293,9 @@ var _ = Describe("API", func() {
Describe("eth_blockNumber", func() { Describe("eth_blockNumber", func() {
It("Retrieves the head block number", func() { It("Retrieves the head block number", func() {
bn := api.BlockNumber() bn := api.BlockNumber()
Expect(bn).To(Equal(hexutil.Uint64(test_helpers.LondonBlockNum))) ubn := (uint64)(bn)
subn := strconv.FormatUint(ubn, 10)
Expect(subn).To(Equal(test_helpers.LondonBlockNum.String()))
}) })
}) })
@ -323,7 +317,7 @@ var _ = Describe("API", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
transactions := make([]interface{}, len(test_helpers.MockBlock.Transactions())) transactions := make([]interface{}, len(test_helpers.MockBlock.Transactions()))
for i, trx := range test_helpers.MockBlock.Transactions() { for i, trx := range test_helpers.MockBlock.Transactions() {
transactions[i] = eth.NewRPCTransactionFromBlockHash(test_helpers.MockBlock, trx.Hash(), chainConfig) transactions[i] = eth.NewRPCTransactionFromBlockHash(test_helpers.MockBlock, trx.Hash())
} }
expectedBlock["transactions"] = transactions expectedBlock["transactions"] = transactions
for key, val := range expectedBlock { for key, val := range expectedBlock {
@ -377,7 +371,7 @@ var _ = Describe("API", func() {
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
transactions := make([]interface{}, len(test_helpers.MockBlock.Transactions())) transactions := make([]interface{}, len(test_helpers.MockBlock.Transactions()))
for i, trx := range test_helpers.MockBlock.Transactions() { for i, trx := range test_helpers.MockBlock.Transactions() {
transactions[i] = eth.NewRPCTransactionFromBlockHash(test_helpers.MockBlock, trx.Hash(), chainConfig) transactions[i] = eth.NewRPCTransactionFromBlockHash(test_helpers.MockBlock, trx.Hash())
} }
expectedBlock["transactions"] = transactions expectedBlock["transactions"] = transactions
for key, val := range expectedBlock { for key, val := range expectedBlock {
@ -390,7 +384,7 @@ var _ = Describe("API", func() {
Expect(block).To(BeZero()) Expect(block).To(BeZero())
}) })
It("Fetch BaseFee from london block by block hash, returns `nil` for legacy block", func() { It("Fetch BaseFee from london block by block hash, returns `nil` for legacy block", func() {
block, err := api.GetBlockByHash(ctx, test_helpers.MockBlock.Hash(), false) block, err := api.GetBlockByHash(ctx, test_helpers.MockBlock.Hash(), true)
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
_, ok := block["baseFeePerGas"] _, ok := block["baseFeePerGas"]
Expect(ok).To(Equal(false)) Expect(ok).To(Equal(false))
@ -1110,20 +1104,20 @@ var _ = Describe("API", func() {
It("Retrieves the eth balance for the provided account address at the block with the provided number", func() { It("Retrieves the eth balance for the provided account address at the block with the provided number", func() {
bal, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithNumber(number)) bal, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithNumber(number))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance.ToBig()))) Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance)))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddress, rpc.BlockNumberOrHashWithNumber(number)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddress, rpc.BlockNumberOrHashWithNumber(number))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal.ToInt().Cmp(common.Big0)).To(Equal(0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
}) })
It("Retrieves the eth balance for the provided account address at the block with the provided hash", func() { It("Retrieves the eth balance for the provided account address at the block with the provided hash", func() {
bal, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithHash(blockHash, true)) bal, err := api.GetBalance(ctx, test_helpers.AccountAddresss, rpc.BlockNumberOrHashWithHash(blockHash, true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance.ToBig()))) Expect(bal).To(Equal((*hexutil.Big)(test_helpers.AccountBalance)))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddress, rpc.BlockNumberOrHashWithHash(blockHash, true)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddress, rpc.BlockNumberOrHashWithHash(blockHash, true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal.ToInt().Cmp(common.Big0)).To(Equal(0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
}) })
It("Retrieves the eth balance for the non-existing account address at the block with the provided hash", func() { It("Retrieves the eth balance for the non-existing account address at the block with the provided hash", func() {
bal, err := api.GetBalance(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true)) bal, err := api.GetBalance(ctx, randomAddr, rpc.BlockNumberOrHashWithHash(blockHash, true))

View File

@ -25,12 +25,6 @@ import (
"math/big" "math/big"
"time" "time"
validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg"
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v0"
ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf"
ipld_sql "github.com/cerc-io/ipld-eth-statedb/sql"
ipld_trie_state "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state"
ipld_trie "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie"
"github.com/cerc-io/plugeth-statediff/indexer/ipld" "github.com/cerc-io/plugeth-statediff/indexer/ipld"
"github.com/cerc-io/plugeth-statediff/utils" "github.com/cerc-io/plugeth-statediff/utils"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -48,11 +42,15 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
validator "github.com/cerc-io/eth-ipfs-state-validator/v5/pkg"
ipfsethdb "github.com/cerc-io/ipfs-ethdb/v5/postgres/v0"
"github.com/cerc-io/ipld-eth-server/v5/pkg/log" "github.com/cerc-io/ipld-eth-server/v5/pkg/log"
"github.com/cerc-io/ipld-eth-server/v5/pkg/shared" "github.com/cerc-io/ipld-eth-server/v5/pkg/shared"
ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf"
ipld_sql "github.com/cerc-io/ipld-eth-statedb/sql"
ipld_trie_state "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/state"
) )
var ( var (
@ -82,7 +80,7 @@ type Backend struct {
// ethereum interfaces // ethereum interfaces
EthDB ethdb.Database EthDB ethdb.Database
// We use this state.Database for eth_call and any place we don't need trie access // We use this state.Database for eth_call and any place we don't need trie access
IpldDirectStateDatabase ipld_direct_state.Database IpldDirectStateDatabase ipld_direct_state.StateDatabase
// We use this where state must be accessed by trie // We use this where state must be accessed by trie
IpldTrieStateDatabase ipld_trie_state.Database IpldTrieStateDatabase ipld_trie_state.Database
@ -117,7 +115,7 @@ func NewEthBackend(db *sqlx.DB, c *Config) (*Backend, error) {
DB: db, DB: db,
Retriever: r, Retriever: r,
EthDB: ethDB, EthDB: ethDB,
IpldDirectStateDatabase: ipld_direct_state.NewDatabase(driver), IpldDirectStateDatabase: ipld_direct_state.NewStateDatabase(driver),
IpldTrieStateDatabase: ipld_trie_state.NewDatabase(ethDB), IpldTrieStateDatabase: ipld_trie_state.NewDatabase(ethDB),
Config: c, Config: c,
}, nil }, nil
@ -271,7 +269,7 @@ func (b *Backend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.Blo
func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber) (*types.Block, error) { func (b *Backend) BlockByNumber(ctx context.Context, blockNumber rpc.BlockNumber) (*types.Block, error) {
number, err := b.NormalizeBlockNumber(blockNumber) number, err := b.NormalizeBlockNumber(blockNumber)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to normalize block number: %w", err) return nil, err
} }
canonicalHash, err := b.GetCanonicalHash(uint64(number)) canonicalHash, err := b.GetCanonicalHash(uint64(number))
if err != nil { if err != nil {
@ -349,20 +347,8 @@ func (b *Backend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Blo
return nil, err return nil, err
} }
// Fetch withdrawals
var withdrawals types.Withdrawals
if b.Config.ChainConfig.IsShanghai(header.Number, header.Time) {
withdrawals, err = b.GetWithdrawals(tx, hash, blockNumber)
if err != nil && err != sql.ErrNoRows {
log.Error("error fetching withdrawals: ", err)
return nil, err
}
} else if len(withdrawals) > 0 {
return nil, errors.New("withdrawals set before Shanghai activation")
}
// Compose everything together into a complete block // Compose everything together into a complete block
return types.NewBlockWithWithdrawals(header, transactions, uncles, receipts, withdrawals, trie.NewEmpty(nil)), err return types.NewBlock(header, transactions, uncles, receipts, trie.NewEmpty(nil)), err
} }
// GetHeaderByBlockHash retrieves header for a provided block hash // GetHeaderByBlockHash retrieves header for a provided block hash
@ -506,26 +492,9 @@ func (b *Backend) GetReceiptsByBlockHashAndNumber(tx *sqlx.Tx, hash common.Hash,
return rcts, nil return rcts, nil
} }
// GetWithdrawals retrieves transactions for a provided block hash and number
func (b *Backend) GetWithdrawals(tx *sqlx.Tx, hash common.Hash, number uint64) (types.Withdrawals, error) {
_, rlpBytes, err := b.Retriever.RetrieveWithdrawals(tx, hash, number)
if err != nil {
return nil, err
}
withdrawals := make(types.Withdrawals, len(rlpBytes))
for i, bytes := range rlpBytes {
withdrawals[i] = new(types.Withdrawal)
if err := rlp.DecodeBytes(bytes, withdrawals[i]); err != nil {
return nil, err
}
}
return withdrawals, nil
}
// GetTransaction retrieves a tx by hash // GetTransaction retrieves a tx by hash
// It also returns the blockhash, blocknumber, and tx index associated with the transaction // It also returns the blockhash, blocknumber, and tx index associated with the transaction
func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) { func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
type txRes struct { type txRes struct {
Data []byte `db:"data"` Data []byte `db:"data"`
HeaderID string `db:"header_id"` HeaderID string `db:"header_id"`
@ -534,22 +503,22 @@ func (b *Backend) GetTransaction(ctx context.Context, txHash common.Hash) (bool,
} }
var res = make([]txRes, 0) var res = make([]txRes, 0)
if err := b.DB.Select(&res, RetrieveRPCTransaction, txHash.String()); err != nil { if err := b.DB.Select(&res, RetrieveRPCTransaction, txHash.String()); err != nil {
return false, nil, common.Hash{}, 0, 0, err return nil, common.Hash{}, 0, 0, err
} }
if len(res) == 0 { if len(res) == 0 {
return false, nil, common.Hash{}, 0, 0, errTxHashNotFound return nil, common.Hash{}, 0, 0, errTxHashNotFound
} else if len(res) > 1 { } else if len(res) > 1 {
// a transaction can be part of a only one canonical block // a transaction can be part of a only one canonical block
return false, nil, common.Hash{}, 0, 0, errTxHashInMultipleBlocks return nil, common.Hash{}, 0, 0, errTxHashInMultipleBlocks
} }
var transaction types.Transaction var transaction types.Transaction
if err := transaction.UnmarshalBinary(res[0].Data); err != nil { if err := transaction.UnmarshalBinary(res[0].Data); err != nil {
return false, nil, common.Hash{}, 0, 0, err return nil, common.Hash{}, 0, 0, err
} }
return true, &transaction, common.HexToHash(res[0].HeaderID), res[0].BlockNumber, res[0].Index, nil return &transaction, common.HexToHash(res[0].HeaderID), res[0].BlockNumber, res[0].Index, nil
} }
// GetReceipts retrieves receipts for provided block hash // GetReceipts retrieves receipts for provided block hash
@ -809,7 +778,7 @@ func (b *Backend) GetAccountByHash(ctx context.Context, address common.Address,
} }
return &types.StateAccount{ return &types.StateAccount{
Nonce: acctRecord.Nonce, Nonce: acctRecord.Nonce,
Balance: uint256.MustFromBig(balance), Balance: balance,
Root: common.HexToHash(acctRecord.Root), Root: common.HexToHash(acctRecord.Root),
CodeHash: acctRecord.CodeHash, CodeHash: acctRecord.CodeHash,
}, nil }, nil
@ -948,10 +917,7 @@ func (b *Backend) GetSlice(path string, depth int, root common.Hash, storage boo
var t ipld_trie_state.Trie var t ipld_trie_state.Trie
var err error var err error
if storage { if storage {
// Note 1: once Verkle tries are used, this will be the same as state trie t, err = b.IpldTrieStateDatabase.OpenStorageTrie(common.Hash{}, common.Hash{}, root)
// Note 2: a dummy hash is passed as owner here, and is only used to signal to ipld-eth-statedb
// that a storage, not state trie is being accessed
t, err = b.IpldTrieStateDatabase.OpenStorageTrie(common.Hash{}, common.Hash{1}, root, nil)
} else { } else {
t, err = b.IpldTrieStateDatabase.OpenTrie(root) t, err = b.IpldTrieStateDatabase.OpenTrie(root)
} }
@ -963,24 +929,21 @@ func (b *Backend) GetSlice(path string, depth int, root common.Hash, storage boo
// Convert the head hex path to a decoded byte path // Convert the head hex path to a decoded byte path
headPath := common.FromHex(path) headPath := common.FromHex(path)
// Convert the Trie object to its concrete type for raw node access
stateTrie := t.(*ipld_trie.StateTrie)
// Get Stem nodes // Get Stem nodes
err = b.getSliceStem(headPath, stateTrie, response, &metaData, storage) err = b.getSliceStem(headPath, t, response, &metaData, storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Get Head node // Get Head node
err = b.getSliceHead(headPath, stateTrie, response, &metaData, storage) err = b.getSliceHead(headPath, t, response, &metaData, storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if depth > 0 { if depth > 0 {
// Get Slice nodes // Get Slice nodes
err = b.getSliceTrie(headPath, stateTrie, response, &metaData, depth, storage) err = b.getSliceTrie(headPath, t, response, &metaData, depth, storage)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -991,7 +954,7 @@ func (b *Backend) GetSlice(path string, depth int, root common.Hash, storage boo
return response, nil return response, nil
} }
func (b *Backend) getSliceStem(headPath []byte, t *ipld_trie.StateTrie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error { func (b *Backend) getSliceStem(headPath []byte, t ipld_trie_state.Trie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error {
leavesFetchTime := int64(0) leavesFetchTime := int64(0)
totalStemStartTime := makeTimestamp() totalStemStartTime := makeTimestamp()
@ -1000,7 +963,7 @@ func (b *Backend) getSliceStem(headPath []byte, t *ipld_trie.StateTrie, response
// nodePath := make([]byte, len(headPath[:i])) // nodePath := make([]byte, len(headPath[:i]))
nodePath := headPath[:i] nodePath := headPath[:i]
rawNode, _, err := t.GetNode(utils.HexToCompact(nodePath)) rawNode, _, err := t.TryGetNode(utils.HexToCompact(nodePath))
if err != nil { if err != nil {
return err return err
} }
@ -1039,10 +1002,10 @@ func (b *Backend) getSliceStem(headPath []byte, t *ipld_trie.StateTrie, response
return nil return nil
} }
func (b *Backend) getSliceHead(headPath []byte, t *ipld_trie.StateTrie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error { func (b *Backend) getSliceHead(headPath []byte, t ipld_trie_state.Trie, response *GetSliceResponse, metaData *metaDataFields, storage bool) error {
totalHeadStartTime := makeTimestamp() totalHeadStartTime := makeTimestamp()
rawNode, _, err := t.GetNode(utils.HexToCompact(headPath)) rawNode, _, err := t.TryGetNode(utils.HexToCompact(headPath))
if err != nil { if err != nil {
return err return err
} }
@ -1080,10 +1043,7 @@ func (b *Backend) getSliceHead(headPath []byte, t *ipld_trie.StateTrie, response
} }
func (b *Backend) getSliceTrie(headPath []byte, t ipld_trie_state.Trie, response *GetSliceResponse, metaData *metaDataFields, depth int, storage bool) error { func (b *Backend) getSliceTrie(headPath []byte, t ipld_trie_state.Trie, response *GetSliceResponse, metaData *metaDataFields, depth int, storage bool) error {
it, timeTaken, err := getIteratorAtPath(t, headPath) it, timeTaken := getIteratorAtPath(t, headPath)
if err != nil {
return nil
}
metaData.trieLoadingTime += timeTaken metaData.trieLoadingTime += timeTaken
leavesFetchTime := int64(0) leavesFetchTime := int64(0)

View File

@ -28,9 +28,9 @@ import (
"github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "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/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
@ -41,11 +41,10 @@ import (
var nullHashBytes = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000") var nullHashBytes = common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000000")
var emptyCodeHash = crypto.Keccak256([]byte{}) var emptyCodeHash = crypto.Keccak256([]byte{})
// These marshalling functions are from internal/ethapi so we have to make our own versions here:
// RPCMarshalHeader converts the given header to the RPC output. // 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{} { func RPCMarshalHeader(head *types.Header) map[string]interface{} {
result := map[string]interface{}{ headerMap := map[string]interface{}{
"number": (*hexutil.Big)(head.Number), "number": (*hexutil.Big)(head.Number),
"hash": head.Hash(), "hash": head.Hash(),
"parentHash": head.ParentHash, "parentHash": head.ParentHash,
@ -57,67 +56,24 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
"miner": head.Coinbase, "miner": head.Coinbase,
"difficulty": (*hexutil.Big)(head.Difficulty), "difficulty": (*hexutil.Big)(head.Difficulty),
"extraData": hexutil.Bytes(head.Extra), "extraData": hexutil.Bytes(head.Extra),
"size": hexutil.Uint64(head.Size()),
"gasLimit": hexutil.Uint64(head.GasLimit), "gasLimit": hexutil.Uint64(head.GasLimit),
"gasUsed": hexutil.Uint64(head.GasUsed), "gasUsed": hexutil.Uint64(head.GasUsed),
"timestamp": hexutil.Uint64(head.Time), "timestamp": hexutil.Uint64(head.Time),
"transactionsRoot": head.TxHash, "transactionsRoot": head.TxHash,
"receiptsRoot": head.ReceiptHash, "receiptsRoot": head.ReceiptHash,
} }
if head.BaseFee != nil { if head.BaseFee != nil {
result["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee) headerMap["baseFeePerGas"] = (*hexutil.Big)(head.BaseFee)
} }
if head.WithdrawalsHash != nil { return headerMap
result["withdrawalsRoot"] = head.WithdrawalsHash
}
if head.BlobGasUsed != nil {
result["blobGasUsed"] = hexutil.Uint64(*head.BlobGasUsed)
}
if head.ExcessBlobGas != nil {
result["excessBlobGas"] = hexutil.Uint64(*head.ExcessBlobGas)
}
if head.ParentBeaconRoot != nil {
result["parentBeaconBlockRoot"] = head.ParentBeaconRoot
}
return result
} }
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
// transaction hashes. // transaction hashes.
func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) map[string]interface{} { func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
fields := RPCMarshalHeader(block.Header())
fields["size"] = hexutil.Uint64(block.Size())
if inclTx {
formatTx := func(idx int, tx *types.Transaction) interface{} {
return tx.Hash()
}
if fullTx {
formatTx = func(idx int, tx *types.Transaction) interface{} {
return newRPCTransactionFromBlockIndex(block, uint64(idx), config)
}
}
txs := block.Transactions()
transactions := make([]interface{}, len(txs))
for i, tx := range txs {
transactions[i] = formatTx(i, tx)
}
fields["transactions"] = transactions
}
uncles := block.Uncles()
uncleHashes := make([]common.Hash, len(uncles))
for i, uncle := range uncles {
uncleHashes[i] = uncle.Hash()
}
fields["uncles"] = uncleHashes
if block.Header().WithdrawalsHash != nil {
fields["withdrawals"] = block.Withdrawals()
}
return fields
}
// RPCMarshalBlockWithUncleHashes marshals the block with the provided uncle hashes
func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool, config *params.ChainConfig) (map[string]interface{}, error) {
fields := RPCMarshalHeader(block.Header()) fields := RPCMarshalHeader(block.Header())
fields["size"] = hexutil.Uint64(block.Size()) fields["size"] = hexutil.Uint64(block.Size())
@ -127,7 +83,41 @@ func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Has
} }
if fullTx { if fullTx {
formatTx = func(tx *types.Transaction) (interface{}, error) { formatTx = func(tx *types.Transaction) (interface{}, error) {
return NewRPCTransactionFromBlockHash(block, tx.Hash(), config), nil return NewRPCTransactionFromBlockHash(block, tx.Hash()), nil
}
}
txs := block.Transactions()
transactions := make([]interface{}, len(txs))
var err error
for i, tx := range txs {
if transactions[i], err = formatTx(tx); err != nil {
return nil, err
}
}
fields["transactions"] = transactions
}
uncles := block.Uncles()
uncleHashes := make([]common.Hash, len(uncles))
for i, uncle := range uncles {
uncleHashes[i] = uncle.Hash()
}
fields["uncles"] = uncleHashes
return fields, nil
}
// RPCMarshalBlockWithUncleHashes marshals the block with the provided uncle hashes
func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Hash, inclTx bool, fullTx bool) (map[string]interface{}, error) {
fields := RPCMarshalHeader(block.Header())
fields["size"] = hexutil.Uint64(block.Size())
if inclTx {
formatTx := func(tx *types.Transaction) (interface{}, error) {
return tx.Hash(), nil
}
if fullTx {
formatTx = func(tx *types.Transaction) (interface{}, error) {
return NewRPCTransactionFromBlockHash(block, tx.Hash()), nil
} }
} }
txs := block.Transactions() txs := block.Transactions()
@ -145,11 +135,11 @@ func RPCMarshalBlockWithUncleHashes(block *types.Block, uncleHashes []common.Has
return fields, nil return fields, nil
} }
// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation. // NewRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation.
func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash, config *params.ChainConfig) *RPCTransaction { func NewRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction {
for idx, tx := range b.Transactions() { for idx, tx := range b.Transactions() {
if tx.Hash() == hash { if tx.Hash() == hash {
return newRPCTransactionFromBlockIndex(b, uint64(idx), config) return newRPCTransactionFromBlockIndex(b, uint64(idx))
} }
} }
return nil return nil
@ -168,12 +158,11 @@ func SignerForTx(tx *types.Transaction) types.Signer {
// NewRPCTransaction returns a transaction that will serialize to the RPC // NewRPCTransaction returns a transaction that will serialize to the RPC
// representation, with the given location metadata set (if available). // representation, with the given location metadata set (if available).
func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, blockTime uint64, index uint64, baseFee *big.Int, config *params.ChainConfig) *RPCTransaction { func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64, baseFee *big.Int) *RPCTransaction {
signer := types.MakeSigner(config, new(big.Int).SetUint64(blockNumber), blockTime) signer := SignerForTx(tx)
from, _ := types.Sender(signer, tx) from, _ := types.Sender(signer, tx)
v, r, s := tx.RawSignatureValues() v, r, s := tx.RawSignatureValues()
result := &RPCTransaction{ result := &RPCTransaction{
Type: hexutil.Uint64(tx.Type()),
From: from, From: from,
Gas: hexutil.Uint64(tx.Gas()), Gas: hexutil.Uint64(tx.Gas()),
GasPrice: (*hexutil.Big)(tx.GasPrice()), GasPrice: (*hexutil.Big)(tx.GasPrice()),
@ -182,6 +171,7 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
Nonce: hexutil.Uint64(tx.Nonce()), Nonce: hexutil.Uint64(tx.Nonce()),
To: tx.To(), To: tx.To(),
Value: (*hexutil.Big)(tx.Value()), Value: (*hexutil.Big)(tx.Value()),
Type: hexutil.Uint64(tx.Type()),
V: (*hexutil.Big)(v), V: (*hexutil.Big)(v),
R: (*hexutil.Big)(r), R: (*hexutil.Big)(r),
S: (*hexutil.Big)(s), S: (*hexutil.Big)(s),
@ -191,69 +181,34 @@ func NewRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
result.TransactionIndex = (*hexutil.Uint64)(&index) result.TransactionIndex = (*hexutil.Uint64)(&index)
} }
switch tx.Type() { switch tx.Type() {
case types.LegacyTxType: case types.LegacyTxType:
// if a legacy transaction has an EIP-155 chain id, include it explicitly // if a legacy transaction has an EIP-155 chain id, include it explicitly
if id := tx.ChainId(); id.Sign() != 0 { if id := tx.ChainId(); id.Sign() != 0 {
result.ChainID = (*hexutil.Big)(id) result.ChainID = (*hexutil.Big)(id)
} }
case types.AccessListTxType: case types.AccessListTxType:
al := tx.AccessList() al := tx.AccessList()
yparity := hexutil.Uint64(v.Sign())
result.Accesses = &al result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId()) result.ChainID = (*hexutil.Big)(tx.ChainId())
result.YParity = &yparity
case types.DynamicFeeTxType: case types.DynamicFeeTxType:
al := tx.AccessList() al := tx.AccessList()
yparity := hexutil.Uint64(v.Sign())
result.Accesses = &al result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId()) result.ChainID = (*hexutil.Big)(tx.ChainId())
result.YParity = &yparity
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap()) result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap()) result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
// if the transaction has been mined, compute the effective gas price // if the transaction has been mined, compute the effective gas price
if baseFee != nil && blockHash != (common.Hash{}) { if baseFee != nil && blockHash != (common.Hash{}) {
// price = min(gasTipCap + baseFee, gasFeeCap) // price = min(tip, gasFeeCap - baseFee) + baseFee
result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee)) price := math.BigMin(new(big.Int).Add(tx.GasTipCap(), baseFee), tx.GasFeeCap())
result.GasPrice = (*hexutil.Big)(price)
} else { } else {
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
} }
case types.BlobTxType:
al := tx.AccessList()
yparity := hexutil.Uint64(v.Sign())
result.Accesses = &al
result.ChainID = (*hexutil.Big)(tx.ChainId())
result.YParity = &yparity
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
// if the transaction has been mined, compute the effective gas price
if baseFee != nil && blockHash != (common.Hash{}) {
result.GasPrice = (*hexutil.Big)(effectiveGasPrice(tx, baseFee))
} else {
result.GasPrice = (*hexutil.Big)(tx.GasFeeCap())
}
result.MaxFeePerBlobGas = (*hexutil.Big)(tx.BlobGasFeeCap())
result.BlobVersionedHashes = tx.BlobHashes()
} }
return result return result
} }
// effectiveGasPrice computes the transaction gas fee, based on the given basefee value.
//
// price = min(gasTipCap + baseFee, gasFeeCap)
func effectiveGasPrice(tx *types.Transaction, baseFee *big.Int) *big.Int {
fee := tx.GasTipCap()
fee = fee.Add(fee, baseFee)
if tx.GasFeeCapIntCmp(fee) < 0 {
return tx.GasFeeCap()
}
return fee
}
type rpcBlock struct { type rpcBlock struct {
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
Transactions []rpcTransaction `json:"transactions"` Transactions []rpcTransaction `json:"transactions"`
@ -315,15 +270,6 @@ func getBlockAndUncleHashes(cli *rpc.Client, ctx context.Context, method string,
return types.NewBlockWithHeader(head).WithBody(txs, nil), body.UncleHashes, nil return types.NewBlockWithHeader(head).WithBody(txs, nil), body.UncleHashes, nil
} }
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64, config *params.ChainConfig) *RPCTransaction {
txs := b.Transactions()
if index >= uint64(len(txs)) {
return nil
}
return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), b.Time(), index, b.BaseFee(), config)
}
// newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index. // newRPCRawTransactionFromBlockIndex returns the bytes of a transaction given a block and a transaction index.
func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes { func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.Bytes {
txs := b.Transactions() txs := b.Transactions()
@ -334,6 +280,15 @@ func newRPCRawTransactionFromBlockIndex(b *types.Block, index uint64) hexutil.By
return blob return blob
} }
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction {
txs := b.Transactions()
if index >= uint64(len(txs)) {
return nil
}
return NewRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index, b.BaseFee())
}
func toFilterArg(q ethereum.FilterQuery) (interface{}, error) { func toFilterArg(q ethereum.FilterQuery) (interface{}, error) {
arg := map[string]interface{}{ arg := map[string]interface{}{
"address": q.Addresses, "address": q.Addresses,
@ -362,28 +317,21 @@ func toBlockNumArg(number *big.Int) string {
return hexutil.EncodeBig(number) return hexutil.EncodeBig(number)
} }
func getIteratorAtPath(t state.Trie, startKey []byte) (trie.NodeIterator, int64, error) { func getIteratorAtPath(t state.Trie, startKey []byte) (trie.NodeIterator, int64) {
startTime := makeTimestamp() startTime := makeTimestamp()
var it trie.NodeIterator var it trie.NodeIterator
var err error
if len(startKey)%2 != 0 { if len(startKey)%2 != 0 {
// Zero-pad for odd-length keys, required by HexToKeyBytes() // Zero-pad for odd-length keys, required by HexToKeyBytes()
startKey = append(startKey, 0) startKey = append(startKey, 0)
it, err = t.NodeIterator(nodeiter.HexToKeyBytes(startKey)) it = t.NodeIterator(nodeiter.HexToKeyBytes(startKey))
if err != nil {
return nil, 0, err
}
} else { } else {
it, err = t.NodeIterator(nodeiter.HexToKeyBytes(startKey)) it = t.NodeIterator(nodeiter.HexToKeyBytes(startKey))
if err != nil {
return nil, 0, err
}
// Step to the required node (not required if original startKey was odd-length) // Step to the required node (not required if original startKey was odd-length)
it.Next(true) it.Next(true)
} }
return it, makeTimestamp() - startTime, nil return it, makeTimestamp() - startTime
} }
func fillSliceNodeData( func fillSliceNodeData(
@ -403,7 +351,7 @@ func fillSliceNodeData(
if node.NodeType == Leaf && !storage { if node.NodeType == Leaf && !storage {
stateLeafKey, storageRoot, code, err := extractContractAccountInfo(sdb, node, nodeElements) stateLeafKey, storageRoot, code, err := extractContractAccountInfo(sdb, node, nodeElements)
if err != nil { if err != nil {
return 0, fmt.Errorf("GetSlice account lookup error: %w", err) return 0, fmt.Errorf("GetSlice account lookup error: %s", err.Error())
} }
if len(code) > 0 { if len(code) > 0 {
@ -439,7 +387,7 @@ func extractContractAccountInfo(sdb state.Database, node StateNode, nodeElements
// Extract codeHash and get code // Extract codeHash and get code
codeHash := common.BytesToHash(account.CodeHash) codeHash := common.BytesToHash(account.CodeHash)
codeBytes, err := sdb.ContractCode(common.Address{}, codeHash) codeBytes, err := sdb.ContractCode(codeHash)
if err != nil { if err != nil {
return "", "", nil, err return "", "", nil, err
} }

View File

@ -0,0 +1,466 @@
// VulcanizeDB
// Copyright © 2019 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package eth_debug_test
import (
"bytes"
"context"
"crypto/ecdsa"
"encoding/json"
"errors"
"fmt"
"math/big"
"sort"
"time"
statediff "github.com/cerc-io/plugeth-statediff"
"github.com/cerc-io/plugeth-statediff/adapt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"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/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/jmoiron/sqlx"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/cerc-io/ipld-eth-server/v5/pkg/eth"
"github.com/cerc-io/ipld-eth-server/v5/pkg/shared"
)
var (
db *sqlx.DB
chainConfig = &*params.TestChainConfig
mockTD = big.NewInt(1337)
ctx = context.Background()
tb *testBackend
accounts Accounts
genBlocks int
)
var _ = BeforeSuite(func() {
// db and type initializations
var err error
db = shared.SetupDB()
// Initialize test accounts
accounts = newAccounts(3)
genesis := &core.Genesis{
Config: chainConfig,
Alloc: core.GenesisAlloc{
accounts[0].addr: {Balance: big.NewInt(params.Ether)},
accounts[1].addr: {Balance: big.NewInt(params.Ether)},
accounts[2].addr: {Balance: big.NewInt(params.Ether)},
},
}
genBlocks = 10
signer := types.HomesteadSigner{}
tb, blocks, receipts := newTestBackend(genBlocks, genesis, func(i int, b *core.BlockGen) {
// Transfer from account[0] to account[1]
// value: 1000 wei
// fee: 0 wei
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
b.AddTx(tx)
})
transformer := shared.SetupTestStateDiffIndexer(ctx, chainConfig, blocks[0].Hash())
params := statediff.Params{}
// iterate over the blocks, generating statediff payloads, and transforming the data into Postgres
builder := statediff.NewBuilder(adapt.GethStateView(tb.chain.StateCache()))
for i, block := range blocks {
var args statediff.Args
if i == 0 {
args = statediff.Args{
OldStateRoot: common.Hash{},
NewStateRoot: block.Root(),
BlockNumber: block.Number(),
BlockHash: block.Hash(),
}
} else {
args = statediff.Args{
OldStateRoot: blocks[i-1].Root(),
NewStateRoot: block.Root(),
BlockNumber: block.Number(),
BlockHash: block.Hash(),
}
}
diff, err := builder.BuildStateDiffObject(args, params)
Expect(err).ToNot(HaveOccurred())
tx, err := transformer.PushBlock(block, receipts[i], mockTD)
Expect(err).ToNot(HaveOccurred())
defer tx.RollbackOnFailure(err)
for _, node := range diff.Nodes {
err = transformer.PushStateNode(tx, node, block.Hash().String())
Expect(err).ToNot(HaveOccurred())
}
for _, ipld := range diff.IPLDs {
err = transformer.PushIPLD(tx, ipld)
Expect(err).ToNot(HaveOccurred())
}
err = tx.Submit()
Expect(err).ToNot(HaveOccurred())
}
backend, err := eth.NewEthBackend(db, &eth.Config{
ChainConfig: chainConfig,
VMConfig: vm.Config{},
RPCGasCap: big.NewInt(10000000000), // Max gas capacity for a rpc call.
GroupCacheConfig: &shared.GroupCacheConfig{
StateDB: shared.GroupConfig{
Name: "eth_debug_test",
CacheSizeInMB: 8,
CacheExpiryInMins: 60,
LogStatsIntervalInSecs: 0,
},
},
})
Expect(err).ToNot(HaveOccurred())
tracingAPI, _ = eth.NewTracingAPI(backend, nil, eth.APIConfig{StateDiffTimeout: shared.DefaultStateDiffTimeout})
tb.teardown()
})
var _ = AfterSuite(func() {
shared.TearDownDB(db)
})
var (
tracingAPI *eth.TracingAPI
)
var _ = Describe("eth state reading tests", func() {
Describe("debug_traceCall", func() {
It("Works", func() {
var testSuite = []struct {
blockNumber rpc.BlockNumber
call eth.TransactionArgs
config *eth.TraceCallConfig
expectErr error
expect string
}{
// Standard JSON trace upon the genesis, plain transfer.
{
blockNumber: rpc.BlockNumber(0),
call: eth.TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1000)),
},
config: nil,
expectErr: nil,
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
},
// Standard JSON trace upon the head, plain transfer.
{
blockNumber: rpc.BlockNumber(genBlocks),
call: eth.TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1000)),
},
config: nil,
expectErr: nil,
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
},
// Standard JSON trace upon the non-existent block, error expects
{
blockNumber: rpc.BlockNumber(genBlocks + 1),
call: eth.TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1000)),
},
config: nil,
expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
//expect: nil,
},
// Standard JSON trace upon the latest block
{
blockNumber: rpc.LatestBlockNumber,
call: eth.TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1000)),
},
config: nil,
expectErr: nil,
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
},
// Tracing on 'pending' should fail:
{
blockNumber: rpc.PendingBlockNumber,
call: eth.TransactionArgs{
From: &accounts[0].addr,
To: &accounts[1].addr,
Value: (*hexutil.Big)(big.NewInt(1000)),
},
config: nil,
expectErr: fmt.Errorf("tracing on top of pending is not supported"),
},
{
blockNumber: rpc.LatestBlockNumber,
call: eth.TransactionArgs{
From: &accounts[0].addr,
Input: &hexutil.Bytes{0x43}, // blocknumber
},
config: &eth.TraceCallConfig{
BlockOverrides: &eth.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
},
expectErr: nil,
expect: ` {"gas":53018,"failed":false,"returnValue":"","structLogs":[
{"pc":0,"op":"NUMBER","gas":9999946984,"gasCost":2,"depth":1,"stack":[]},
{"pc":1,"op":"STOP","gas":9999946982,"gasCost":0,"depth":1,"stack":["0x1337"]}]}`,
},
}
for _, testspec := range testSuite {
result, err := tracingAPI.TraceCall(context.Background(), testspec.call, rpc.BlockNumberOrHash{BlockNumber: &testspec.blockNumber}, testspec.config)
if testspec.expectErr != nil {
Expect(err).To(HaveOccurred())
Expect(err).To(Equal(testspec.expectErr))
} else {
Expect(err).ToNot(HaveOccurred())
var have *logger.ExecutionResult
err := json.Unmarshal(result.(json.RawMessage), &have)
Expect(err).ToNot(HaveOccurred())
var want *logger.ExecutionResult
err = json.Unmarshal([]byte(testspec.expect), &want)
Expect(err).ToNot(HaveOccurred())
Expect(have).To(Equal(want))
}
}
})
})
Describe("debug_traceBlock", func() {
It("Works", func() {
var testSuite = []struct {
blockNumber rpc.BlockNumber
config *eth.TraceConfig
want string
expectErr error
}{
// Trace genesis block, expect error
{
blockNumber: rpc.BlockNumber(0),
expectErr: errors.New("genesis is not traceable"),
},
// Trace head block
{
blockNumber: rpc.BlockNumber(genBlocks),
want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
},
// Trace non-existent block
{
blockNumber: rpc.BlockNumber(genBlocks + 1),
expectErr: fmt.Errorf("block #%d not found", genBlocks+1),
},
// Trace latest block
{
blockNumber: rpc.LatestBlockNumber,
want: `[{"result":{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}}]`,
},
// Trace pending block
{
blockNumber: rpc.PendingBlockNumber,
expectErr: errors.New("pending block number not supported"),
},
}
for _, tc := range testSuite {
result, err := tracingAPI.TraceBlockByNumber(context.Background(), tc.blockNumber, tc.config)
if tc.expectErr != nil {
Expect(err).To(HaveOccurred())
Expect(err).To(Equal(tc.expectErr))
} else {
Expect(err).ToNot(HaveOccurred())
have, _ := json.Marshal(result)
want := tc.want
Expect(string(have)).To(Equal(want))
}
}
})
})
})
type testBackend struct {
chainConfig *params.ChainConfig
engine consensus.Engine
chaindb ethdb.Database
chain *core.BlockChain
refHook func() // Hook is invoked when the requested state is referenced
relHook func() // Hook is invoked when the requested state is released
}
func (b *testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
return b.chain.GetHeaderByHash(hash), nil
}
func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
return b.chain.CurrentHeader(), nil
}
return b.chain.GetHeaderByNumber(uint64(number)), nil
}
func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
return b.chain.GetBlockByHash(hash), nil
}
func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber {
return b.chain.GetBlockByNumber(b.chain.CurrentBlock().Number.Uint64()), nil
}
return b.chain.GetBlockByNumber(uint64(number)), nil
}
func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
tx, hash, blockNumber, index := rawdb.ReadTransaction(b.chaindb, txHash)
return tx, hash, blockNumber, index, nil
}
func (b *testBackend) RPCGasCap() uint64 {
return 25000000
}
func (b *testBackend) ChainConfig() *params.ChainConfig {
return b.chainConfig
}
func (b *testBackend) Engine() consensus.Engine {
return b.engine
}
func (b *testBackend) ChainDb() ethdb.Database {
return b.chaindb
}
// teardown releases the associated resources.
func (b *testBackend) teardown() {
b.chain.Stop()
}
var (
errStateNotFound = errors.New("state not found")
errBlockNotFound = errors.New("block not found")
)
func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, tracers.StateReleaseFunc, error) {
statedb, err := b.chain.StateAt(block.Root())
if err != nil {
return nil, nil, errStateNotFound
}
if b.refHook != nil {
b.refHook()
}
release := func() {
if b.relHook != nil {
b.relHook()
}
}
return statedb, release, nil
}
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
}
statedb, release, err := b.StateAtBlock(ctx, parent, reexec, nil, true, false)
if err != nil {
return nil, vm.BlockContext{}, nil, nil, errStateNotFound
}
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, release, nil
}
// Recompute transactions up to the target index.
signer := types.MakeSigner(b.chainConfig, block.Number())
for idx, tx := range block.Transactions() {
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
if idx == txIndex {
return msg, context, statedb, release, nil
}
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
}
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
}
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
}
// testBackend creates a new test backend. OBS: After test is done, teardown must be
// invoked in order to release associated resources.
func newTestBackend(n int, gspec *core.Genesis, generator func(i int, b *core.BlockGen)) (*testBackend, types.Blocks, []types.Receipts) {
backend := &testBackend{
chainConfig: gspec.Config,
engine: ethash.NewFaker(),
chaindb: rawdb.NewMemoryDatabase(),
}
// Generate blocks for testing
_, blocks, receipts := core.GenerateChainWithGenesis(gspec, backend.engine, n, generator)
// Import the canonical chain
cacheConfig := &core.CacheConfig{
TrieCleanLimit: 256,
TrieDirtyLimit: 256,
TrieTimeLimit: 5 * time.Minute,
SnapshotLimit: 0,
TrieDirtyDisabled: true, // Archive mode
}
chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, nil, backend.engine, vm.Config{}, nil, nil)
Expect(err).ToNot(HaveOccurred())
n, err = chain.InsertChain(blocks)
Expect(err).ToNot(HaveOccurred())
backend.chain = chain
return backend, blocks, receipts
}
type Account struct {
key *ecdsa.PrivateKey
addr common.Address
}
type Accounts []Account
func (a Accounts) Len() int { return len(a) }
func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 }
func newAccounts(n int) (accounts Accounts) {
for i := 0; i < n; i++ {
key, _ := crypto.GenerateKey()
addr := crypto.PubkeyToAddress(key.PublicKey)
accounts = append(accounts, Account{key: key, addr: addr})
}
sort.Sort(accounts)
return accounts
}

View File

@ -0,0 +1,29 @@
// VulcanizeDB
// Copyright © 2019 Vulcanize
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package eth_debug_test
import (
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
func TestETHSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "ipld-eth-server/pkg/eth/state_test")
}

View File

@ -6,7 +6,6 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie" "github.com/cerc-io/ipld-eth-statedb/trie_by_cid/trie"
"github.com/cerc-io/ipld-eth-statedb/trie_by_cid/triedb"
) )
// NodeType for explicitly setting type of node // NodeType for explicitly setting type of node
@ -74,7 +73,7 @@ type StorageNode struct {
LeafKey []byte `json:"leafKey"` LeafKey []byte `json:"leafKey"`
} }
func ResolveNode(path []byte, node []byte, trieDB *triedb.Database) (StateNode, []interface{}, error) { func ResolveNode(path []byte, node []byte, trieDB *trie.Database) (StateNode, []interface{}, error) {
var nodeElements []interface{} var nodeElements []interface{}
if err := rlp.DecodeBytes(node, &nodeElements); err != nil { if err := rlp.DecodeBytes(node, &nodeElements); err != nil {
return StateNode{}, nil, err return StateNode{}, nil, err
@ -94,7 +93,7 @@ func ResolveNode(path []byte, node []byte, trieDB *triedb.Database) (StateNode,
} }
// ResolveNodeIt return the state diff node pointed by the iterator. // ResolveNodeIt return the state diff node pointed by the iterator.
func ResolveNodeIt(it trie.NodeIterator, trieDB *triedb.Database) (StateNode, []interface{}, error) { func ResolveNodeIt(it trie.NodeIterator, trieDB *trie.Database) (StateNode, []interface{}, error) {
node, err := it.NodeBlob(), it.Error() node, err := it.NodeBlob(), it.Error()
if err != nil { if err != nil {
return StateNode{}, nil, err return StateNode{}, nil, err

View File

@ -506,24 +506,6 @@ func (r *Retriever) RetrieveReceiptsByBlockHash(tx *sqlx.Tx, hash common.Hash) (
return cids, rcts, txs, nil return cids, rcts, txs, nil
} }
// RetrieveWithdrawals returns the CIDs and RLP bytes for the withdrawals corresponding to the
// provided block hash, number. Returned CIDs correspond to the leaf node data which contains the
// withdrawal object.
func (r *Retriever) RetrieveWithdrawals(tx *sqlx.Tx, hash common.Hash, number uint64) ([]string, [][]byte, error) {
results := make([]ipldResult, 0)
if err := tx.Select(&results, RetrieveWithdrawalsPgStr, hash.Hex(), number); err != nil {
return nil, nil, err
}
cids := make([]string, len(results))
withdrawals := make([][]byte, len(results))
for i, res := range results {
cids[i] = res.CID
withdrawals[i] = res.Data
}
return cids, withdrawals, nil
}
// RetrieveAccountByAddressAndBlockHash returns the cid and rlp bytes for the account corresponding to the provided address and block hash // RetrieveAccountByAddressAndBlockHash returns the cid and rlp bytes for the account corresponding to the provided address and block hash
// TODO: ensure this handles deleted accounts appropriately // TODO: ensure this handles deleted accounts appropriately
func (r *Retriever) RetrieveAccountByAddressAndBlockHash(address common.Address, hash common.Hash) (StateAccountRecord, error) { func (r *Retriever) RetrieveAccountByAddressAndBlockHash(address common.Address, hash common.Hash) (StateAccountRecord, error) {

View File

@ -107,21 +107,6 @@ WHERE header_cids.block_hash = $1
AND blocks.key = receipt_cids.cid AND blocks.key = receipt_cids.cid
ORDER BY eth.transaction_cids.index ASC ORDER BY eth.transaction_cids.index ASC
` `
RetrieveWithdrawalsPgStr = `
SELECT withdrawal_cids.cid,
blocks.data
FROM eth.withdrawal_cids
JOIN eth.header_cids
ON header_cids.block_hash = $1
AND header_cids.block_number = $2
AND header_cids.canonical
AND withdrawal_cids.block_number = header_cids.block_number
AND withdrawal_cids.header_id = header_cids.block_hash
JOIN ipld.blocks
ON blocks.block_number = header_cids.block_number
AND blocks.key = withdrawal_cids.cid
ORDER BY eth.withdrawal_cids.index ASC`
RetrieveAccountByLeafKeyAndBlockHashPgStr = ` RetrieveAccountByLeafKeyAndBlockHashPgStr = `
SELECT state_cids.nonce, SELECT state_cids.nonce,
state_cids.balance, state_cids.balance,

View File

@ -1,15 +1,8 @@
package eth_state_test package eth_state_test
import ( import (
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/common/hexutil"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/format"
"github.com/onsi/gomega/types"
"github.com/cerc-io/ipld-eth-server/v5/pkg/eth" "github.com/cerc-io/ipld-eth-server/v5/pkg/eth"
. "github.com/onsi/gomega"
) )
func CheckGetSliceResponse(sliceResponse eth.GetSliceResponse, expectedResponse eth.GetSliceResponse) { func CheckGetSliceResponse(sliceResponse eth.GetSliceResponse, expectedResponse eth.GetSliceResponse) {
@ -18,54 +11,3 @@ func CheckGetSliceResponse(sliceResponse eth.GetSliceResponse, expectedResponse
Expect(sliceResponse.Leaves).To(Equal(expectedResponse.Leaves)) Expect(sliceResponse.Leaves).To(Equal(expectedResponse.Leaves))
Expect(sliceResponse.MetaData.NodeStats).To(Equal(expectedResponse.MetaData.NodeStats)) Expect(sliceResponse.MetaData.NodeStats).To(Equal(expectedResponse.MetaData.NodeStats))
} }
// EqualBigInt compares a hexutil.Big for equality with a big.Int or hexutil.Big value.
// It is an error for both actual and expected to be nil. Use BeNil() instead.
func EqualBigInt(expected *big.Int) types.GomegaMatcher {
return &BigIntEqualMatcher{
Expected: expected,
}
}
// EqualBigHex compares a hexutil.Big for equality with a big.Int or hexutil.Big value.
// It is an error for both actual and expected to be nil. Use BeNil() instead.
func EqualBigHex(expected *hexutil.Big) types.GomegaMatcher {
return &BigIntEqualMatcher{
Expected: expected.ToInt(),
}
}
type BigIntEqualMatcher struct {
Expected *big.Int
}
func (matcher *BigIntEqualMatcher) Match(actual interface{}) (success bool, err error) {
if actual == nil && matcher.Expected == nil {
return false, fmt.Errorf("Refusing to compare <nil> to <nil>.\nBe explicit and use BeNil() instead. This is to avoid mistakes where both sides of an assertion are erroneously uninitialized.")
}
var asInt *big.Int
switch casted := actual.(type) {
case *big.Int:
asInt = casted
case *hexutil.Big:
asInt = (*big.Int)(casted)
default:
return false, fmt.Errorf("BigIntEqualMatcher expects a hexutil.Big or big.Int. Got:\n%s", format.Object(actual, 1))
}
return matcher.Expected.Cmp(asInt) == 0, nil
}
func (matcher *BigIntEqualMatcher) FailureMessage(actual interface{}) (message string) {
actualString, actualOK := actual.(string)
expectedString := matcher.Expected.String()
if actualOK {
return format.MessageWithDiff(actualString, "to equal", expectedString)
}
return format.Message(actual, "to equal", matcher.Expected)
}
func (matcher *BigIntEqualMatcher) NegatedFailureMessage(actual interface{}) (message string) {
return format.Message(actual, "not to equal", matcher.Expected)
}

View File

@ -23,7 +23,7 @@ import (
"math/big" "math/big"
"os" "os"
"github.com/cerc-io/plugeth-statediff" statediff "github.com/cerc-io/plugeth-statediff"
"github.com/cerc-io/plugeth-statediff/adapt" "github.com/cerc-io/plugeth-statediff/adapt"
"github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -47,7 +47,7 @@ var (
parsedABI abi.ABI parsedABI abi.ABI
randomAddress = common.HexToAddress("0x9F4203bd7a11aCB94882050E6f1C3ab14BBaD3D9") randomAddress = common.HexToAddress("0x9F4203bd7a11aCB94882050E6f1C3ab14BBaD3D9")
randomHash = crypto.Keccak256Hash(randomAddress.Bytes()) randomHash = crypto.Keccak256Hash(randomAddress.Bytes())
number = rpc.BlockNumber(test_helpers.BlockNumber1) number = rpc.BlockNumber(test_helpers.BlockNumber.Int64())
block1StateRoot = common.HexToHash("0xa1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21") block1StateRoot = common.HexToHash("0xa1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21")
rootDataHashBlock1 = "a1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21" rootDataHashBlock1 = "a1f614839ebdd58677df2c9d66a3e0acc9462acc49fad6006d0b6e5d2b98ed21"
@ -152,6 +152,7 @@ var _ = BeforeSuite(func() {
"miner": canonicalHeader.Coinbase, "miner": canonicalHeader.Coinbase,
"difficulty": (*hexutil.Big)(canonicalHeader.Difficulty), "difficulty": (*hexutil.Big)(canonicalHeader.Difficulty),
"extraData": hexutil.Bytes([]byte{}), "extraData": hexutil.Bytes([]byte{}),
"size": hexutil.Uint64(canonicalHeader.Size()),
"gasLimit": hexutil.Uint64(canonicalHeader.GasLimit), "gasLimit": hexutil.Uint64(canonicalHeader.GasLimit),
"gasUsed": hexutil.Uint64(canonicalHeader.GasUsed), "gasUsed": hexutil.Uint64(canonicalHeader.GasUsed),
"timestamp": hexutil.Uint64(canonicalHeader.Time), "timestamp": hexutil.Uint64(canonicalHeader.Time),
@ -293,198 +294,198 @@ var _ = Describe("eth state reading tests", func() {
It("Retrieves account balance by block number", func() { It("Retrieves account balance by block number", func() {
bal, err := api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(0)) bal, err := api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(0))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock0)) Expect(bal).To(Equal(expectedBankBalanceBlock0))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(1)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(1))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(1)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(1))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt((common.Big0))) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(1)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(1))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt((common.Big0))) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(1)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(1))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock1)) Expect(bal).To(Equal(expectedBankBalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(2)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(2))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(2)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(2))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock2)) Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(2)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(2))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(2)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(2))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(3)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(3))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(3)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(3))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock3)) Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(3)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(3))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(3)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(3))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(4)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(4))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(4)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(4))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(4)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(4))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(4)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(4))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(5)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(5))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock5)) Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(5)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(5))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(5)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(5))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(5)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithNumber(5))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
}) })
It("Retrieves account balance by block hash", func() { It("Retrieves account balance by block hash", func() {
bal, err := api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) bal, err := api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock0)) Expect(bal).To(Equal(expectedBankBalanceBlock0))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt((common.Big0))) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
_, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) _, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt((common.Big0))) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[1].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock1)) Expect(bal).To(Equal(expectedBankBalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock2)) Expect(bal).To(Equal(expectedAcct2BalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[2].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock3)) Expect(bal).To(Equal(expectedAcct2BalanceBlock3))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[3].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock1)) Expect(bal).To(Equal(expectedAcct1BalanceBlock1))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[4].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct1BalanceBlock5)) Expect(bal).To(Equal(expectedAcct1BalanceBlock5))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedAcct2BalanceBlock4)) Expect(bal).To(Equal(expectedAcct2BalanceBlock4))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedContractBalance)) Expect(bal).To(Equal(expectedContractBalance))
bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.TestBankAddress, rpc.BlockNumberOrHashWithHash(blocks[5].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigHex(expectedBankBalanceBlock2)) Expect(bal).To(Equal(expectedBankBalanceBlock2))
}) })
It("Returns 0 if account balance not found by block number", func() { It("Returns 0 if account balance not found by block number", func() {
bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(0)) bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithNumber(0))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt(common.Big0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(0)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithNumber(0))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt(common.Big0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithNumber(0))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt(common.Big0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
}) })
It("Returns 0 if account balance not found by block hash", func() { It("Returns 0 if account balance not found by block hash", func() {
bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) bal, err := api.GetBalance(ctx, test_helpers.Account1Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt(common.Big0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.Account2Addr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt(common.Big0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true)) bal, err = api.GetBalance(ctx, test_helpers.ContractAddr, rpc.BlockNumberOrHashWithHash(blocks[0].Hash(), true))
Expect(err).ToNot(HaveOccurred()) Expect(err).ToNot(HaveOccurred())
Expect(bal).To(EqualBigInt(common.Big0)) Expect(bal).To(Equal((*hexutil.Big)(common.Big0)))
}) })
}) })

View File

@ -0,0 +1,84 @@
package test_helpers
import (
"context"
"math/big"
statediff "github.com/cerc-io/plugeth-statediff"
"github.com/cerc-io/plugeth-statediff/adapt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/cerc-io/ipld-eth-server/v5/pkg/shared"
)
type IndexChainParams struct {
Blocks []*types.Block
Receipts []types.Receipts
StateCache state.Database
ChainConfig *params.ChainConfig
StateDiffParams statediff.Params
TotalDifficulty *big.Int
// Whether to skip indexing state nodes (state_cids, storage_cids)
SkipStateNodes bool
// Whether to skip indexing IPLD blocks
SkipIPLDs bool
}
func IndexChain(params IndexChainParams) error {
indexer := shared.SetupTestStateDiffIndexer(context.Background(), params.ChainConfig, Genesis.Hash())
builder := statediff.NewBuilder(adapt.GethStateView(params.StateCache))
// iterate over the blocks, generating statediff payloads, and transforming the data into Postgres
for i, block := range params.Blocks {
var args statediff.Args
var rcts types.Receipts
if i == 0 {
args = statediff.Args{
OldStateRoot: common.Hash{},
NewStateRoot: block.Root(),
BlockNumber: block.Number(),
BlockHash: block.Hash(),
}
} else {
args = statediff.Args{
OldStateRoot: params.Blocks[i-1].Root(),
NewStateRoot: block.Root(),
BlockNumber: block.Number(),
BlockHash: block.Hash(),
}
rcts = params.Receipts[i-1]
}
diff, err := builder.BuildStateDiffObject(args, params.StateDiffParams)
if err != nil {
return err
}
tx, err := indexer.PushBlock(block, rcts, params.TotalDifficulty)
if err != nil {
return err
}
defer tx.RollbackOnFailure(err)
if !params.SkipStateNodes {
for _, node := range diff.Nodes {
if err = indexer.PushStateNode(tx, node, block.Hash().String()); err != nil {
return err
}
}
}
if !params.SkipIPLDs {
for _, ipld := range diff.IPLDs {
if err := indexer.PushIPLD(tx, ipld); err != nil {
return err
}
}
}
if err = tx.Submit(); err != nil {
return err
}
}
return nil
}

View File

@ -31,7 +31,6 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/cerc-io/ipld-eth-server/v5/pkg/eth" "github.com/cerc-io/ipld-eth-server/v5/pkg/eth"
@ -41,11 +40,10 @@ import (
// Test variables // Test variables
var ( var (
// block data // block data
BlockNumber1 = int64(1) BlockNumber = big.NewInt(1)
BlockTime1 = uint64(0)
MockHeader = types.Header{ MockHeader = types.Header{
Time: 0, Time: 0,
Number: big.NewInt(BlockNumber1), Number: new(big.Int).Set(BlockNumber),
Root: common.HexToHash("0x0"), Root: common.HexToHash("0x0"),
TxHash: common.HexToHash("0x0"), TxHash: common.HexToHash("0x0"),
ReceiptHash: common.HexToHash("0x0"), ReceiptHash: common.HexToHash("0x0"),
@ -53,14 +51,10 @@ var (
Extra: []byte{}, Extra: []byte{},
} }
MockTransactions, MockReceipts, SenderAddr = createLegacyTransactionsAndReceipts() MockTransactions, MockReceipts, SenderAddr = createLegacyTransactionsAndReceipts()
MockWithdrawals = types.Withdrawals{
{Index: 0, Validator: 1, Address: Address, Amount: 1000000000},
{Index: 1, Validator: 5, Address: AnotherAddress, Amount: 2000000000},
}
MockUncles = []*types.Header{ MockUncles = []*types.Header{
{ {
Time: 1, Time: 1,
Number: big.NewInt(BlockNumber1 + 1), Number: new(big.Int).Add(BlockNumber, big.NewInt(1)),
Root: common.HexToHash("0x1"), Root: common.HexToHash("0x1"),
TxHash: common.HexToHash("0x1"), TxHash: common.HexToHash("0x1"),
ReceiptHash: common.HexToHash("0x1"), ReceiptHash: common.HexToHash("0x1"),
@ -70,7 +64,7 @@ var (
}, },
{ {
Time: 2, Time: 2,
Number: big.NewInt(BlockNumber1 + 2), Number: new(big.Int).Add(BlockNumber, big.NewInt(2)),
Root: common.HexToHash("0x2"), Root: common.HexToHash("0x2"),
TxHash: common.HexToHash("0x2"), TxHash: common.HexToHash("0x2"),
ReceiptHash: common.HexToHash("0x2"), ReceiptHash: common.HexToHash("0x2"),
@ -79,10 +73,10 @@ var (
ParentHash: Genesis.Hash(), ParentHash: Genesis.Hash(),
}, },
} }
MockBlock = createNewBlock(&MockHeader, MockTransactions, MockUncles, MockReceipts, nil, trie.NewEmpty(nil)) MockBlock = createNewBlock(&MockHeader, MockTransactions, MockUncles, MockReceipts, trie.NewEmpty(nil))
MockChildHeader = types.Header{ MockChildHeader = types.Header{
Time: 0, Time: 0,
Number: big.NewInt(BlockNumber1 + 1), Number: new(big.Int).Add(BlockNumber, common.Big1),
Root: common.HexToHash("0x0"), Root: common.HexToHash("0x0"),
TxHash: common.HexToHash("0x0"), TxHash: common.HexToHash("0x0"),
ReceiptHash: common.HexToHash("0x0"), ReceiptHash: common.HexToHash("0x0"),
@ -110,7 +104,7 @@ var (
Address: Address, Address: Address,
Topics: []common.Hash{mockTopic11, mockTopic12}, Topics: []common.Hash{mockTopic11, mockTopic12},
Data: []byte{}, Data: []byte{},
BlockNumber: uint64(BlockNumber1), BlockNumber: BlockNumber.Uint64(),
TxIndex: 0, TxIndex: 0,
Index: 0, Index: 0,
} }
@ -118,7 +112,7 @@ var (
Address: AnotherAddress, Address: AnotherAddress,
Topics: []common.Hash{mockTopic21, mockTopic22}, Topics: []common.Hash{mockTopic21, mockTopic22},
Data: []byte{}, Data: []byte{},
BlockNumber: uint64(BlockNumber1), BlockNumber: BlockNumber.Uint64(),
TxIndex: 1, TxIndex: 1,
Index: 1, Index: 1,
} }
@ -126,7 +120,7 @@ var (
Address: AnotherAddress1, Address: AnotherAddress1,
Topics: []common.Hash{mockTopic31}, Topics: []common.Hash{mockTopic31},
Data: []byte{}, Data: []byte{},
BlockNumber: uint64(BlockNumber1), BlockNumber: BlockNumber.Uint64(),
TxIndex: 2, TxIndex: 2,
Index: 2, Index: 2,
} }
@ -135,7 +129,7 @@ var (
Address: AnotherAddress1, Address: AnotherAddress1,
Topics: []common.Hash{mockTopic41, mockTopic42, mockTopic43}, Topics: []common.Hash{mockTopic41, mockTopic42, mockTopic43},
Data: []byte{}, Data: []byte{},
BlockNumber: uint64(BlockNumber1), BlockNumber: BlockNumber.Uint64(),
TxIndex: 2, TxIndex: 2,
Index: 3, Index: 3,
} }
@ -143,7 +137,7 @@ var (
Address: AnotherAddress1, Address: AnotherAddress1,
Topics: []common.Hash{mockTopic51}, Topics: []common.Hash{mockTopic51},
Data: []byte{}, Data: []byte{},
BlockNumber: uint64(BlockNumber1), BlockNumber: BlockNumber.Uint64(),
TxIndex: 2, TxIndex: 2,
Index: 4, Index: 4,
} }
@ -151,7 +145,7 @@ var (
Address: AnotherAddress2, Address: AnotherAddress2,
Topics: []common.Hash{mockTopic61}, Topics: []common.Hash{mockTopic61},
Data: []byte{}, Data: []byte{},
BlockNumber: uint64(BlockNumber1), BlockNumber: BlockNumber.Uint64(),
TxIndex: 3, TxIndex: 3,
Index: 5, Index: 5,
} }
@ -223,7 +217,7 @@ var (
ContractLeafKey = crypto.Keccak256(ContractAddress[:]) ContractLeafKey = crypto.Keccak256(ContractAddress[:])
ContractAccount = types.StateAccount{ ContractAccount = types.StateAccount{
Nonce: uint64(1), Nonce: uint64(1),
Balance: uint256.NewInt(0), Balance: big.NewInt(0),
CodeHash: CodeHash.Bytes(), CodeHash: CodeHash.Bytes(),
Root: common.HexToHash(ContractRoot), Root: common.HexToHash(ContractRoot),
} }
@ -235,7 +229,7 @@ var (
}) })
nonce0 = uint64(0) nonce0 = uint64(0)
AccountBalance = uint256.NewInt(1000) AccountBalance = big.NewInt(1000)
AccountRoot = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" AccountRoot = "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
AccountCodeHash = common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") AccountCodeHash = common.HexToHash("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470")
AccountAddresss = common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e") AccountAddresss = common.HexToAddress("0x0D3ab14BBaD3D99F4203bd7a11aCB94882050E7e")
@ -296,22 +290,21 @@ var (
StateNodes: MockStateNodes, StateNodes: MockStateNodes,
} }
LondonBlockNum = (BlockNumber1 + 2) LondonBlockNum = new(big.Int).Add(BlockNumber, big.NewInt(2))
LondonBlockTime = BlockTime1 + 1
MockLondonHeader = types.Header{ MockLondonHeader = types.Header{
Time: LondonBlockTime, Time: 0,
Number: big.NewInt(LondonBlockNum), Number: LondonBlockNum,
Root: common.HexToHash("0x00"), Root: common.HexToHash("0x00"),
Difficulty: big.NewInt(5000000), Difficulty: big.NewInt(5000000),
Extra: []byte{}, Extra: []byte{},
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
MockLondonTransactions, MockLondonReceipts, _ = createDynamicTransactionsAndReceipts(big.NewInt(LondonBlockNum), LondonBlockTime) MockLondonTransactions, MockLondonReceipts, _ = createDynamicTransactionsAndReceipts(LondonBlockNum)
MockLondonUncles = []*types.Header{ MockLondonUncles = []*types.Header{
{ {
Time: 1, Time: 1,
Number: big.NewInt(BlockNumber1 + 1), Number: new(big.Int).Add(BlockNumber, big.NewInt(1)),
ParentHash: common.HexToHash("0x2"), ParentHash: common.HexToHash("0x2"),
Root: common.HexToHash("0x1"), Root: common.HexToHash("0x1"),
TxHash: common.HexToHash("0x1"), TxHash: common.HexToHash("0x1"),
@ -321,7 +314,7 @@ var (
}, },
{ {
Time: 2, Time: 2,
Number: big.NewInt(BlockNumber1 + 1), Number: new(big.Int).Add(BlockNumber, big.NewInt(1)),
ParentHash: common.HexToHash("0x1"), ParentHash: common.HexToHash("0x1"),
Root: common.HexToHash("0x2"), Root: common.HexToHash("0x2"),
TxHash: common.HexToHash("0x2"), TxHash: common.HexToHash("0x2"),
@ -330,11 +323,11 @@ var (
Extra: []byte{}, Extra: []byte{},
}, },
} }
MockLondonBlock = createNewBlock(&MockLondonHeader, MockLondonTransactions, MockLondonUncles, MockLondonReceipts, MockWithdrawals, trie.NewEmpty(nil)) MockLondonBlock = createNewBlock(&MockLondonHeader, MockLondonTransactions, MockLondonUncles, MockLondonReceipts, trie.NewEmpty(nil))
) )
func createNewBlock(header *types.Header, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, withdrawals types.Withdrawals, hasher types.TrieHasher) *types.Block { func createNewBlock(header *types.Header, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt, hasher types.TrieHasher) *types.Block {
block := types.NewBlockWithWithdrawals(header, txs, uncles, receipts, withdrawals, hasher) block := types.NewBlock(header, txs, uncles, receipts, hasher)
bHash := block.Hash() bHash := block.Hash()
for _, r := range receipts { for _, r := range receipts {
for _, l := range r.Logs { for _, l := range r.Logs {
@ -345,7 +338,7 @@ func createNewBlock(header *types.Header, txs []*types.Transaction, uncles []*ty
} }
// createDynamicTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs // createDynamicTransactionsAndReceipts is a helper function to generate signed mock transactions and mock receipts with mock logs
func createDynamicTransactionsAndReceipts(blockNumber *big.Int, blockTime uint64) (types.Transactions, types.Receipts, common.Address) { func createDynamicTransactionsAndReceipts(blockNumber *big.Int) (types.Transactions, types.Receipts, common.Address) {
// make transactions // make transactions
config := *params.TestChainConfig config := *params.TestChainConfig
config.LondonBlock = blockNumber config.LondonBlock = blockNumber
@ -360,7 +353,7 @@ func createDynamicTransactionsAndReceipts(blockNumber *big.Int, blockTime uint64
Data: []byte{}, Data: []byte{},
}) })
transactionSigner := types.MakeSigner(&config, blockNumber, blockTime) transactionSigner := types.MakeSigner(&config, blockNumber)
mockCurve := elliptic.P256() mockCurve := elliptic.P256()
mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader) mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader)
if err != nil { if err != nil {
@ -398,7 +391,7 @@ func createLegacyTransactionsAndReceipts() (types.Transactions, types.Receipts,
trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{}) trx2 := types.NewTransaction(1, AnotherAddress, big.NewInt(2000), 100, big.NewInt(200), []byte{})
trx3 := types.NewContractCreation(2, big.NewInt(1500), 75, big.NewInt(150), ContractCode) trx3 := types.NewContractCreation(2, big.NewInt(1500), 75, big.NewInt(150), ContractCode)
trx4 := types.NewTransaction(3, AnotherAddress1, big.NewInt(2000), 100, big.NewInt(200), []byte{}) trx4 := types.NewTransaction(3, AnotherAddress1, big.NewInt(2000), 100, big.NewInt(200), []byte{})
transactionSigner := types.MakeSigner(params.MainnetChainConfig, big.NewInt(BlockNumber1), 0) transactionSigner := types.MakeSigner(params.MainnetChainConfig, new(big.Int).Set(BlockNumber))
mockCurve := elliptic.P256() mockCurve := elliptic.P256()
mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader) mockPrvKey, err := ecdsa.GenerateKey(mockCurve, rand.Reader)
if err != nil { if err != nil {
@ -459,7 +452,7 @@ func createLegacyTransactionsAndReceipts() (types.Transactions, types.Receipts,
func getReceiptCIDs(rcts []*types.Receipt) ([]cid.Cid, error) { func getReceiptCIDs(rcts []*types.Receipt) ([]cid.Cid, error) {
cids := make([]cid.Cid, len(rcts)) cids := make([]cid.Cid, len(rcts))
for i, rct := range rcts { for i, rct := range rcts {
ethRct, err := ipld.EncodeReceipt(rct) ethRct, err := ipld.NewReceipt(rct)
if err != nil { if err != nil {
return nil, err return nil, err
} }

476
pkg/eth/tracing.go Normal file
View File

@ -0,0 +1,476 @@
package eth
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"runtime"
"sync"
"time"
ipld_direct_state "github.com/cerc-io/ipld-eth-statedb/direct_by_leaf"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
)
const (
// defaultTraceTimeout is the amount of time a single transaction can execute
// by default before being forcefully aborted.
defaultTraceTimeout = 5 * time.Second
)
// TracingAPI is the collection of tracing APIs exposed over the private debugging endpoint.
type TracingAPI struct {
backend *Backend
rpc *rpc.Client
config APIConfig
}
// NewTracingAPI creates a new TracingAPI with the provided underlying Backend
func NewTracingAPI(b *Backend, client *rpc.Client, config APIConfig) (*TracingAPI, error) {
if b == nil {
return nil, errors.New("ipld-eth-server must be configured with an ethereum backend")
}
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 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")
}
return &TracingAPI{
backend: b,
rpc: client,
config: config,
}, nil
}
// TraceConfig holds extra parameters to trace functions.
type TraceConfig struct {
*logger.Config
Tracer *string
Timeout *string
Reexec *uint64
// Config specific to given tracer. Note struct logger
// config are historically embedded in main object.
TracerConfig json.RawMessage
}
// TraceCallConfig is the config for traceCall API. It holds one more
// field to override the state for tracing.
type TraceCallConfig struct {
TraceConfig
StateOverrides *StateOverride
BlockOverrides *BlockOverrides
}
// TraceCall lets you trace a given eth_call. It collects the structured logs
// created during the execution of EVM if the given transaction was added on
// top of the provided block and returns them as a JSON object.
func (api *TracingAPI) TraceCall(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
trace, err := api.localTraceCall(ctx, args, blockNrOrHash, config)
if trace != nil && err == nil {
return trace, nil
}
if api.config.ProxyOnError {
var res interface{}
if err := api.rpc.CallContext(ctx, &res, "debug_traceCall", args, blockNrOrHash, config); res != nil && err == nil {
return res, nil
}
}
return nil, err
}
func (api *TracingAPI) localTraceCall(ctx context.Context, args TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
// Try to retrieve the specified block
var (
err error
block *types.Block
)
if hash, ok := blockNrOrHash.Hash(); ok {
block, err = api.blockByHash(ctx, hash)
} else if number, ok := blockNrOrHash.Number(); ok {
if number == rpc.PendingBlockNumber {
// We don't have access to the miner here. For tracing 'future' transactions,
// it can be done with block- and state-overrides instead, which offers
// more flexibility and stability than trying to trace on 'pending', since
// the contents of 'pending' is unstable and probably not a true representation
// of what the next actual block is likely to contain.
return nil, errors.New("tracing on top of pending is not supported")
}
block, err = api.blockByNumber(ctx, number)
} else {
return nil, errors.New("invalid arguments; neither block nor hash specified")
}
if err != nil {
return nil, err
}
stateDB, _, err := api.backend.IPLDDirectStateDBAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithHash(block.Hash(), true))
if err != nil {
return nil, err
}
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
// Apply the customization rules if required.
if config != nil {
if err := config.StateOverrides.Apply(stateDB); err != nil {
return nil, err
}
config.BlockOverrides.Apply(&vmctx)
}
// Execute the trace
msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
if err != nil {
return nil, err
}
var traceConfig *TraceConfig
if config != nil {
traceConfig = &config.TraceConfig
}
return api.traceTx(ctx, msg, new(tracers.Context), vmctx, stateDB, traceConfig)
}
// traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will
// be tracer dependent.
func (api *TracingAPI) traceTx(ctx context.Context, message *core.Message, txctx *tracers.Context, vmctx vm.BlockContext, statedb *ipld_direct_state.StateDB, config *TraceConfig) (interface{}, error) {
var (
tracer tracers.Tracer
err error
timeout = defaultTraceTimeout
txContext = core.NewEVMTxContext(message)
)
if config == nil {
config = &TraceConfig{}
}
// Default tracer is the struct logger
tracer = logger.NewStructLogger(config.Config)
if config.Tracer != nil {
tracer, err = tracers.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
if err != nil {
return nil, err
}
}
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
return nil, err
}
}
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
go func() {
<-deadlineCtx.Done()
if errors.Is(deadlineCtx.Err(), context.DeadlineExceeded) {
tracer.Stop(errors.New("execution timeout"))
// Stop evm execution. Note cancellation is not necessarily immediate.
vmenv.Cancel()
}
}()
defer cancel()
// Call Prepare to clear out the statedb access list
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
return nil, fmt.Errorf("tracing failed: %w", err)
}
return tracer.GetResult()
}
// chainContext constructs the context reader which is used by the evm for reading
// the necessary chain context.
func (api *TracingAPI) chainContext(ctx context.Context) core.ChainContext {
return &chainContext{api: api, ctx: ctx}
}
// blockByNumber is the wrapper of the chain access function offered by the backend.
// It will return an error if the block is not found.
func (api *TracingAPI) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
block, err := api.backend.BlockByNumber(ctx, number)
if err != nil {
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block #%d not found", number)
}
return block, nil
}
// blockByHash is the wrapper of the chain access function offered by the backend.
// It will return an error if the block is not found.
func (api *TracingAPI) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
block, err := api.backend.BlockByHash(ctx, hash)
if err != nil {
return nil, err
}
if block == nil {
return nil, fmt.Errorf("block %s not found", hash.Hex())
}
return block, nil
}
// txTraceTask represents a single transaction trace task when an entire block
// is being traced.
type txTraceTask struct {
statedb *ipld_direct_state.StateDB // Intermediate state prepped for tracing
index int // Transaction offset in the block
}
// txTraceResult is the result of a single transaction trace.
type txTraceResult struct {
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
Error string `json:"error,omitempty"` // Trace failure produced by the tracer
}
var noGenesisErr = errors.New("genesis is not traceable")
// TraceBlockByNumber returns the structured logs created during the execution of
// EVM and returns them as a JSON object.
func (api *TracingAPI) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*txTraceResult, error) {
if number == 0 {
return nil, noGenesisErr
}
block, err := api.blockByNumber(ctx, number)
if err != nil {
return nil, err
}
trace, err := api.traceBlock(ctx, block, config)
if trace != nil && err == nil {
return trace, nil
}
if api.config.ProxyOnError {
var res []*txTraceResult
if err := api.rpc.CallContext(ctx, &res, "debug_traceBlockByNumber", number, config); res != nil && err == nil {
return res, nil
}
}
return nil, err
}
// TraceBlockByHash returns the structured logs created during the execution of
// EVM and returns them as a JSON object.
func (api *TracingAPI) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*txTraceResult, error) {
block, err := api.blockByHash(ctx, hash)
if err != nil {
return nil, err
}
if block.NumberU64() == 0 {
return nil, noGenesisErr
}
trace, err := api.traceBlock(ctx, block, config)
if trace != nil && err == nil {
return trace, nil
}
if api.config.ProxyOnError {
var res []*txTraceResult
if err := api.rpc.CallContext(ctx, &res, "debug_traceBlockByHash", hash, config); res != nil && err == nil {
return res, nil
}
}
return nil, err
}
// TraceBlock returns the structured logs created during the execution of EVM
// and returns them as a JSON object.
func (api *TracingAPI) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
trace, err := api.localTraceBlock(ctx, blob, config)
if trace != nil && err == nil {
return trace, nil
}
if api.config.ProxyOnError {
var res []*txTraceResult
if err := api.rpc.CallContext(ctx, &res, "debug_traceBlock", blob, config); res != nil && err == nil {
return res, nil
}
}
return nil, err
}
func (api *TracingAPI) localTraceBlock(ctx context.Context, blob hexutil.Bytes, config *TraceConfig) ([]*txTraceResult, error) {
block := new(types.Block)
if err := rlp.Decode(bytes.NewReader(blob), block); err != nil {
return nil, fmt.Errorf("could not decode block: %v", err)
}
return api.traceBlock(ctx, block, config)
}
// traceBlock configures a new tracer according to the provided configuration, and
// executes all the transactions contained within. The return value will be one item
// per transaction, dependent on the requested tracer.
func (api *TracingAPI) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*txTraceResult, error) {
if block.NumberU64() == 0 {
return nil, errors.New("genesis is not traceable")
}
stateDB, _, err := api.backend.IPLDDirectStateDBAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithHash(block.ParentHash(), true))
if err != nil {
return nil, err
}
// JS tracers have high overhead. In this case run a parallel
// process that generates states in one thread and traces txes
// in separate worker threads.
if config != nil && config.Tracer != nil && *config.Tracer != "" {
if isJS := tracers.DefaultDirectory.IsJS(*config.Tracer); isJS {
return api.traceBlockParallel(ctx, block, stateDB, config)
}
}
// Native tracers have low overhead
var (
txs = block.Transactions()
blockHash = block.Hash()
is158 = api.backend.ChainConfig().IsEIP158(block.Number())
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
results = make([]*txTraceResult, len(txs))
)
for i, tx := range txs {
// Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
txctx := &tracers.Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
TxIndex: i,
TxHash: tx.Hash(),
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, stateDB, config)
if err != nil {
return nil, err
}
results[i] = &txTraceResult{Result: res}
// Finalize the state so any modifications are written to the trie
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
stateDB.Finalise(is158)
}
return results, nil
}
// traceBlockParallel is for tracers that have a high overhead (read JS tracers). One thread
// runs along and executes txes without tracing enabled to generate their prestate.
// Worker threads take the tasks and the prestate and trace them.
func (api *TracingAPI) traceBlockParallel(ctx context.Context, block *types.Block, statedb *ipld_direct_state.StateDB, config *TraceConfig) ([]*txTraceResult, error) {
// Execute all the transaction contained within the block concurrently
var (
txs = block.Transactions()
blockHash = block.Hash()
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
results = make([]*txTraceResult, len(txs))
pend sync.WaitGroup
)
threads := runtime.NumCPU()
if threads > len(txs) {
threads = len(txs)
}
jobs := make(chan *txTraceTask, threads)
for th := 0; th < threads; th++ {
pend.Add(1)
go func() {
defer pend.Done()
// Fetch and execute the next transaction trace tasks
for task := range jobs {
msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
txctx := &tracers.Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
TxIndex: task.index,
TxHash: txs[task.index].Hash(),
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
if err != nil {
results[task.index] = &txTraceResult{Error: err.Error()}
continue
}
results[task.index] = &txTraceResult{Result: res}
}
}()
}
// Feed the transactions into the tracers and return
var failed error
txloop:
for i, tx := range txs {
// Send the trace task over for execution
task := &txTraceTask{statedb: statedb.Copy(), index: i}
select {
case <-ctx.Done():
failed = ctx.Err()
break txloop
case jobs <- task:
}
// Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
failed = err
break txloop
}
// Finalize the state so any modifications are written to the trie
// Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
statedb.Finalise(vmenv.ChainConfig().IsEIP158(block.Number()))
}
close(jobs)
pend.Wait()
// If execution failed in between, abort
if failed != nil {
return nil, failed
}
return results, nil
}
// blockByNumberAndHash is the wrapper of the chain access function offered by
// the backend. It will return an error if the block is not found.
//
// Note this function is friendly for the light client which can only retrieve the
// historical(before the CHT) header/block by number.
func (api *TracingAPI) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) {
block, err := api.blockByNumber(ctx, number)
if err != nil {
return nil, err
}
if block.Hash() == hash {
return block, nil
}
return api.blockByHash(ctx, hash)
}
type chainContext struct {
api *TracingAPI
ctx context.Context
}
func (context *chainContext) Engine() consensus.Engine {
return context.api.backend.Engine()
}
func (context *chainContext) GetHeader(hash common.Hash, number uint64) *types.Header {
header, err := context.api.backend.HeaderByNumber(context.ctx, rpc.BlockNumber(number))
if err != nil {
return nil
}
if header.Hash() == hash {
return header
}
header, err = context.api.backend.HeaderByHash(context.ctx, hash)
if err != nil {
return nil
}
return header
}

View File

@ -1,9 +1,15 @@
package eth package eth
import ( import (
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/sirupsen/logrus"
) )
// TransactionArgs represents the arguments to construct a new transaction // TransactionArgs represents the arguments to construct a new transaction
@ -47,3 +53,85 @@ func (args *TransactionArgs) data() []byte {
} }
return nil return nil
} }
// ToMessage converts the transaction arguments to the Message type used by the
// core evm. This method is used in calls and traces that do not require a real
// live transaction.
func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*core.Message, error) {
// Reject invalid combinations of pre- and post-1559 fee styles
if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
return nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}
// Set sender address or use zero address if none specified.
addr := args.from()
// Set default gas & gas price if none were set
gas := globalGasCap
if gas == 0 {
gas = uint64(math.MaxUint64 / 2)
}
if args.Gas != nil {
gas = uint64(*args.Gas)
}
if globalGasCap != 0 && globalGasCap < gas {
logrus.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
gas = globalGasCap
}
var (
gasPrice *big.Int
gasFeeCap *big.Int
gasTipCap *big.Int
)
if baseFee == nil {
// If there's no basefee, then it must be a non-1559 execution
gasPrice = new(big.Int)
if args.GasPrice != nil {
gasPrice = args.GasPrice.ToInt()
}
gasFeeCap, gasTipCap = gasPrice, gasPrice
} else {
// A basefee is provided, necessitating 1559-type execution
if args.GasPrice != nil {
// User specified the legacy gas field, convert to 1559 gas typing
gasPrice = args.GasPrice.ToInt()
gasFeeCap, gasTipCap = gasPrice, gasPrice
} else {
// User specified 1559 gas fields (or none), use those
gasFeeCap = new(big.Int)
if args.MaxFeePerGas != nil {
gasFeeCap = args.MaxFeePerGas.ToInt()
}
gasTipCap = new(big.Int)
if args.MaxPriorityFeePerGas != nil {
gasTipCap = args.MaxPriorityFeePerGas.ToInt()
}
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
gasPrice = new(big.Int)
if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
gasPrice = math.BigMin(new(big.Int).Add(gasTipCap, baseFee), gasFeeCap)
}
}
}
value := new(big.Int)
if args.Value != nil {
value = args.Value.ToInt()
}
data := args.data()
var accessList types.AccessList
if args.AccessList != nil {
accessList = *args.AccessList
}
msg := &core.Message{
From: addr,
To: args.To,
Value: value,
GasLimit: gas,
GasPrice: gasPrice,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
Data: data,
AccessList: accessList,
SkipAccountChecks: true,
}
return msg, nil
}

View File

@ -33,7 +33,6 @@ import (
) )
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
// Note: copied from go-ethereum/internal/ethapi
type RPCTransaction struct { type RPCTransaction struct {
BlockHash *common.Hash `json:"blockHash"` BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"` BlockNumber *hexutil.Big `json:"blockNumber"`
@ -42,7 +41,6 @@ type RPCTransaction struct {
GasPrice *hexutil.Big `json:"gasPrice"` GasPrice *hexutil.Big `json:"gasPrice"`
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"`
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"` Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"` Nonce hexutil.Uint64 `json:"nonce"`
@ -52,11 +50,9 @@ type RPCTransaction struct {
Type hexutil.Uint64 `json:"type"` Type hexutil.Uint64 `json:"type"`
Accesses *types.AccessList `json:"accessList,omitempty"` Accesses *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"`
BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
V *hexutil.Big `json:"v"` V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"` R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"` S *hexutil.Big `json:"s"`
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
} }
// RPCReceipt represents a receipt that will serialize to the RPC representation of a receipt // RPCReceipt represents a receipt that will serialize to the RPC representation of a receipt

View File

@ -64,7 +64,7 @@ func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) {
if err != nil { if err != nil {
return hexutil.Big{}, err return hexutil.Big{}, err
} }
return hexutil.Big(*state.GetBalance(a.address).ToBig()), nil return hexutil.Big(*state.GetBalance(a.address)), nil
} }
func (a *Account) TransactionCount(ctx context.Context) (hexutil.Uint64, error) { func (a *Account) TransactionCount(ctx context.Context) (hexutil.Uint64, error) {

View File

@ -110,6 +110,8 @@ type Config struct {
ProxyOnError bool ProxyOnError bool
GetLogsBlockLimit int64 GetLogsBlockLimit int64
NodeNetworkID string NodeNetworkID string
TracingEnabled bool
TracingPublic bool
// Cache configuration. // Cache configuration.
GroupCache *ethServerShared.GroupCacheConfig GroupCache *ethServerShared.GroupCacheConfig
@ -128,10 +130,9 @@ func NewConfig() (*Config, error) {
viper.BindEnv("server.ipcPath", SERVER_IPC_PATH) viper.BindEnv("server.ipcPath", SERVER_IPC_PATH)
viper.BindEnv("server.graphqlPath", SERVER_GRAPHQL_PATH) viper.BindEnv("server.graphqlPath", SERVER_GRAPHQL_PATH)
viper.BindEnv("ethereum.chainID", ETH_CHAIN_ID)
viper.BindEnv("ethereum.chainConfig", ETH_CHAIN_CONFIG)
viper.BindEnv("ethereum.httpPath", ETH_HTTP_PATH) viper.BindEnv("ethereum.httpPath", ETH_HTTP_PATH)
viper.BindEnv("ethereum.rpcGasCap", ETH_RPC_GAS_CAP) 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.supportsStateDiff", ETH_SUPPORTS_STATEDIFF)
viper.BindEnv("ethereum.stateDiffTimeout", ETH_STATEDIFF_TIMEOUT) viper.BindEnv("ethereum.stateDiffTimeout", ETH_STATEDIFF_TIMEOUT)
viper.BindEnv("ethereum.forwardEthCalls", ETH_FORWARD_ETH_CALLS) viper.BindEnv("ethereum.forwardEthCalls", ETH_FORWARD_ETH_CALLS)
@ -144,38 +145,19 @@ func NewConfig() (*Config, error) {
c.dbInit() c.dbInit()
ethHTTP := viper.GetString("ethereum.httpPath") ethHTTP := viper.GetString("ethereum.httpPath")
ethHTTPEndpoint := fmt.Sprintf("http://%s", ethHTTP) ethHTTPEndpoint := fmt.Sprintf("http://%s", ethHTTP)
nodeInfo, cli, err := getEthNodeAndClient(ethHTTPEndpoint)
// At least one of chain ID and chain config must be passed. c.NodeNetworkID = nodeInfo.NetworkID
// If both are passed, the chain ID must match the config.
chainID := viper.GetUint64("ethereum.chainID")
chainConfigPath := viper.GetString("ethereum.chainConfig")
var err error
if chainConfigPath != "" {
if c.ChainConfig, err = utils.LoadConfig(chainConfigPath); err != nil {
return nil, err
}
// Only validate the chain ID if it was actually passed
if viper.GetString("ethereum.chainID") != "" && c.ChainConfig.ChainID.Uint64() != chainID {
return nil, fmt.Errorf("passed chain ID %d does not match chain config chain ID %d",
chainID, c.ChainConfig.ChainID.Uint64())
}
} else {
if c.ChainConfig, err = utils.ChainConfig(chainID); err != nil {
return nil, err
}
}
nodeInfo, cli, err := getEthNodeAndClient(ethHTTPEndpoint, chainID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
c.NodeNetworkID = nodeInfo.NetworkID
c.Client = cli c.Client = cli
c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff") c.SupportStateDiff = viper.GetBool("ethereum.supportsStateDiff")
c.ForwardEthCalls = viper.GetBool("ethereum.forwardEthCalls") c.ForwardEthCalls = viper.GetBool("ethereum.forwardEthCalls")
c.ForwardGetStorageAt = viper.GetBool("ethereum.forwardGetStorageAt") c.ForwardGetStorageAt = viper.GetBool("ethereum.forwardGetStorageAt")
c.ProxyOnError = viper.GetBool("ethereum.proxyOnError") c.ProxyOnError = viper.GetBool("ethereum.proxyOnError")
c.EthHttpEndpoint = ethHTTPEndpoint c.EthHttpEndpoint = ethHTTPEndpoint
c.TracingEnabled = viper.GetBool("ethereum.tracingEnabled")
c.TracingPublic = viper.GetBool("ethereum.tracingPublic")
if viper.IsSet("ethereum.getLogsBlockLimit") { if viper.IsSet("ethereum.getLogsBlockLimit") {
c.GetLogsBlockLimit = viper.GetInt64("ethereum.getLogsBlockLimit") c.GetLogsBlockLimit = viper.GetInt64("ethereum.getLogsBlockLimit")
@ -259,6 +241,12 @@ func NewConfig() (*Config, error) {
if c.StateDiffTimeout < 0 { if c.StateDiffTimeout < 0 {
return nil, errors.New("ethereum.stateDiffTimeout < 0") return nil, errors.New("ethereum.stateDiffTimeout < 0")
} }
chainConfigPath := viper.GetString("ethereum.chainConfig")
if chainConfigPath != "" {
c.ChainConfig, err = utils.LoadConfig(chainConfigPath)
} else {
c.ChainConfig, err = utils.ChainConfig(nodeInfo.ChainID)
}
c.loadGroupCacheConfig() c.loadGroupCacheConfig()
@ -328,11 +316,12 @@ func (c *Config) loadValidatorConfig() {
} }
// GetEthNodeAndClient returns eth node info and client from path url // GetEthNodeAndClient returns eth node info and client from path url
func getEthNodeAndClient(path string, chainid uint64) (node.Info, *rpc.Client, error) { func getEthNodeAndClient(path string) (node.Info, *rpc.Client, error) {
viper.BindEnv("ethereum.nodeID", ETH_NODE_ID) viper.BindEnv("ethereum.nodeID", ETH_NODE_ID)
viper.BindEnv("ethereum.clientName", ETH_CLIENT_NAME) viper.BindEnv("ethereum.clientName", ETH_CLIENT_NAME)
viper.BindEnv("ethereum.genesisBlock", ETH_GENESIS_BLOCK) viper.BindEnv("ethereum.genesisBlock", ETH_GENESIS_BLOCK)
viper.BindEnv("ethereum.networkID", ETH_NETWORK_ID) viper.BindEnv("ethereum.networkID", ETH_NETWORK_ID)
viper.BindEnv("ethereum.chainID", ETH_CHAIN_ID)
rpcClient, err := rpc.Dial(path) rpcClient, err := rpc.Dial(path)
if err != nil { if err != nil {
@ -343,6 +332,6 @@ func getEthNodeAndClient(path string, chainid uint64) (node.Info, *rpc.Client, e
ClientName: viper.GetString("ethereum.clientName"), ClientName: viper.GetString("ethereum.clientName"),
GenesisBlock: viper.GetString("ethereum.genesisBlock"), GenesisBlock: viper.GetString("ethereum.genesisBlock"),
NetworkID: viper.GetString("ethereum.networkID"), NetworkID: viper.GetString("ethereum.networkID"),
ChainID: chainid, ChainID: viper.GetUint64("ethereum.chainID"),
}, rpcClient, nil }, rpcClient, nil
} }

View File

@ -78,6 +78,10 @@ type Service struct {
proxyOnError bool proxyOnError bool
// eth node network id // eth node network id
nodeNetworkId string nodeNetworkId string
// tracing enabled
tracingEnabled bool
// tracing public
tracingPublic bool
} }
// NewServer creates a new Server using an underlying Service struct // NewServer creates a new Server using an underlying Service struct
@ -93,6 +97,8 @@ func NewServer(settings *Config) (Server, error) {
sap.getLogsBlockLimit = settings.GetLogsBlockLimit sap.getLogsBlockLimit = settings.GetLogsBlockLimit
sap.proxyOnError = settings.ProxyOnError sap.proxyOnError = settings.ProxyOnError
sap.nodeNetworkId = settings.NodeNetworkID sap.nodeNetworkId = settings.NodeNetworkID
sap.tracingEnabled = settings.TracingEnabled
sap.tracingPublic = settings.TracingPublic
var err error var err error
sap.backend, err = eth.NewEthBackend(sap.db, &eth.Config{ sap.backend, err = eth.NewEthBackend(sap.db, &eth.Config{
ChainConfig: settings.ChainConfig, ChainConfig: settings.ChainConfig,
@ -138,9 +144,10 @@ func (sap *Service) APIs() []rpc.API {
log.Fatalf("unable to create public eth api: %v", err) log.Fatalf("unable to create public eth api: %v", err)
} }
// this uses stubbed StateAtBlock and StateAtTransaction methods and so does not support debug_traceBlock and debug_traceCall
debugTracerAPI := tracers.APIs(&debug.Backend{Backend: *sap.backend})[0] debugTracerAPI := tracers.APIs(&debug.Backend{Backend: *sap.backend})[0]
return append(apis, apis = append(apis,
rpc.API{ rpc.API{
Namespace: eth.APIName, Namespace: eth.APIName,
Version: eth.APIVersion, Version: eth.APIVersion,
@ -149,6 +156,22 @@ func (sap *Service) APIs() []rpc.API {
}, },
debugTracerAPI, debugTracerAPI,
) )
if sap.tracingEnabled {
tracingAPI, err := eth.NewTracingAPI(sap.backend, sap.client, conf)
if err != nil {
log.Fatalf("unable to create tracing api: %v", err)
}
apis = append(apis, rpc.API{
// Uses same namespace as stubbed debug API above
// Need to test if this will properly overlay and form a union with the existing methods supported by that
// Or if only one is exposed
Namespace: "debug",
Service: tracingAPI,
Public: sap.tracingPublic,
})
}
return apis
} }
// Serve listens for incoming converter data off the screenAndServePayload from the Sync process // Serve listens for incoming converter data off the screenAndServePayload from the Sync process

View File

@ -27,7 +27,6 @@ import (
"github.com/cerc-io/plugeth-statediff/indexer/interfaces" "github.com/cerc-io/plugeth-statediff/indexer/interfaces"
"github.com/cerc-io/plugeth-statediff/indexer/models" "github.com/cerc-io/plugeth-statediff/indexer/models"
"github.com/cerc-io/plugeth-statediff/indexer/node" "github.com/cerc-io/plugeth-statediff/indexer/node"
"github.com/cerc-io/plugeth-statediff/indexer/test_helpers"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
@ -56,7 +55,30 @@ func SetupDB() *sqlx.DB {
// TearDownDB is used to tear down the watcher dbs after tests // TearDownDB is used to tear down the watcher dbs after tests
func TearDownDB(db *sqlx.DB) { func TearDownDB(db *sqlx.DB) {
err := test_helpers.ClearSqlxDB(db) tx, err := db.Beginx()
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM nodes`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM ipld.blocks`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth.header_cids`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth.uncle_cids`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth.transaction_cids`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth.receipt_cids`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth.state_cids`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth.storage_cids`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth.log_cids`)
Expect(err).NotTo(HaveOccurred())
_, err = tx.Exec(`DELETE FROM eth_meta.watched_addresses`)
Expect(err).NotTo(HaveOccurred())
err = tx.Commit()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
} }

53
scripts/integration-setup.sh Executable file
View File

@ -0,0 +1,53 @@
#!/bin/bash
# Builds and deploys a stack with only what we need.
# This script assumes we are running in the project root.
set -e
export DOCKER_BUILDKIT=1
# Prevent conflicting tty output
export BUILDKIT_PROGRESS=plain
CONFIG_DIR=$(readlink -f "${CONFIG_DIR:-$(mktemp -d)}")
# By default assume we are running in the project root
export CERC_REPO_BASE_DIR="${CERC_REPO_BASE_DIR:-..}"
# v5 migrations only go up to version 18
echo CERC_STATEDIFF_DB_GOOSE_MIN_VER=18 >> $CONFIG_DIR/stack.env
# Pass this in so we can run eth_call forwarding tests, which expect no IPLD DB
echo CERC_RUN_STATEDIFF=${CERC_RUN_STATEDIFF:-true} >> $CONFIG_DIR/stack.env
laconic_so="${LACONIC_SO:-laconic-so} --stack fixturenet-plugeth-tx --verbose"
set -x
if [[ -z $SKIP_BUILD ]]; then
$laconic_so setup-repositories \
--exclude github.com/cerc-io/ipld-eth-server,github.com/cerc-io/tx-spammer,github.com/dboreham/foundry \
--branches-file ./test/stack-refs.txt
$laconic_so build-containers \
--exclude cerc/ipld-eth-server,cerc/keycloak,cerc/tx-spammer,cerc/foundry
fi
$laconic_so deploy \
--include fixturenet-plugeth,ipld-eth-db \
--env-file $CONFIG_DIR/stack.env \
--cluster test up
set +x
# Get IPv4 endpoint of geth file server
bootnode_endpoint=$(docker port test-fixturenet-eth-bootnode-geth-1 9898 | head -1)
# Extract the chain config and ID from genesis file
curl -s $bootnode_endpoint/geth.json | jq '.config' > $CONFIG_DIR/chain.json
# Output vars if we are running on Github
if [[ -n "$GITHUB_ENV" ]]; then
echo ETH_CHAIN_ID="$(jq '.chainId' $CONFIG_DIR/chain.json)" >> "$GITHUB_ENV"
echo ETH_CHAIN_CONFIG="$CONFIG_DIR/chain.json" >> "$GITHUB_ENV"
echo ETH_HTTP_PATH=$(docker port test-fixturenet-eth-geth-1-1 8545 | head -1) >> "$GITHUB_ENV"
# Read a private key so we can send from a funded account
echo DEPLOYER_PRIVATE_KEY=$(curl -s $bootnode_endpoint/accounts.csv | head -1 | cut -d',' -f3) >> "$GITHUB_ENV"
fi

View File

@ -1,56 +0,0 @@
#!/bin/bash
set -e
stack_dir=$(readlink -f "$1")
[[ -d "$stack_dir" ]]
laconic_so="laconic-so --verbose --stack $stack_dir"
CONFIG_DIR=$(readlink -f "${CONFIG_DIR:-$(mktemp -d)}")
# By default assume we are running in the project root.
export CERC_REPO_BASE_DIR="${CERC_REPO_BASE_DIR:-$(git rev-parse --show-toplevel)/..}"
# Don't run geth/plugeth in the debugger, it will swallow error backtraces
echo CERC_REMOTE_DEBUG=false >> $CONFIG_DIR/stack.env
# Passing this lets us run eth_call forwarding tests without running ipld-eth-db
echo CERC_RUN_STATEDIFF=${CERC_RUN_STATEDIFF:-true} >> $CONFIG_DIR/stack.env
set -x
if [[ -z $SKIP_BUILD ]]; then
# Prevent conflicting tty output
export BUILDKIT_PROGRESS=plain
# The server itself will be run separately
$laconic_so setup-repositories \
--exclude git.vdb.to/cerc-io/ipld-eth-server
$laconic_so build-containers \
--exclude cerc/ipld-eth-server
fi
if ! $laconic_so deploy \
--exclude ipld-eth-server \
--env-file $CONFIG_DIR/stack.env \
--cluster test up
then
$laconic_so deploy --cluster test logs
exit 1
fi
set +x
# Get IPv4 endpoint of geth bootnode file server
bootnode_endpoint=$(docker port test-fixturenet-eth-bootnode-geth-1 9898 | head -1)
# Extract the chain config and ID from genesis file
curl -s $bootnode_endpoint/geth.json | jq '.config' > $CONFIG_DIR/chain.json
# Output vars if we are running on Github
if [[ -n "$GITHUB_ENV" ]]; then
echo ETH_CHAIN_ID="$(jq '.chainId' $CONFIG_DIR/chain.json)" >> "$GITHUB_ENV"
echo ETH_CHAIN_CONFIG="$CONFIG_DIR/chain.json" >> "$GITHUB_ENV"
echo ETH_HTTP_PATH=$(docker port test-fixturenet-eth-geth-1-1 8545 | head -1) >> "$GITHUB_ENV"
# Read a private key so we can send from a funded account
echo DEPLOYER_PRIVATE_KEY=$(curl -s $bootnode_endpoint/accounts.csv | head -1 | cut -d',' -f3) >> "$GITHUB_ENV"
fi

View File

@ -5,7 +5,7 @@ services:
restart: on-failure restart: on-failure
depends_on: depends_on:
- ipld-eth-db - ipld-eth-db
image: git.vdb.to/cerc-io/ipld-eth-db/ipld-eth-db:v5.4.0-alpha image: git.vdb.to/cerc-io/ipld-eth-db/ipld-eth-db:v5.2.1-alpha
environment: environment:
DATABASE_USER: "vdbm" DATABASE_USER: "vdbm"
DATABASE_NAME: "cerc_testing" DATABASE_NAME: "cerc_testing"

View File

@ -4,8 +4,6 @@ services:
ipld-eth-server: ipld-eth-server:
restart: unless-stopped restart: unless-stopped
image: cerc/ipld-eth-server:local image: cerc/ipld-eth-server:local
build:
context: ..
networks: networks:
- test_default - test_default
environment: environment:
@ -30,7 +28,7 @@ services:
contract-deployer: contract-deployer:
restart: on-failure restart: on-failure
image: cerc/ipld-eth-server/test-contract-deployer:local image: cerc/ipld-eth-server/contract-deployer:local
build: ./contract build: ./contract
networks: networks:
- test_default - test_default

View File

@ -1,5 +1,5 @@
# Downgrade from 18.16, see https://github.com/NomicFoundation/hardhat/issues/3877 # Downgrade from 18.16, see https://github.com/NomicFoundation/hardhat/issues/3877
FROM node:20-slim FROM node:18.15-slim
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY package*.json ./ COPY package*.json ./

View File

@ -1,16 +1,11 @@
pragma solidity ^0.8.25; pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract GLDToken is ERC20 { contract GLDToken is ERC20 {
constructor() ERC20("Gold", "GLD") { constructor() ERC20("Gold", "GLD") {
_mint(msg.sender, 1000000000000000000000); _mint(msg.sender, 1000000000000000000000);
} }
function destroy() public { function destroy() public {
(bool ok, ) = payable(msg.sender).call{value: address(this).balance}(""); selfdestruct(payable(msg.sender));
require(ok, "ETH transfer failed");
_burn(msg.sender, balanceOf(msg.sender));
} }
} }

View File

@ -1,5 +1,5 @@
// SPDX-License-Identifier: AGPL-3.0 // SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.25; pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
@ -7,9 +7,7 @@ contract SLVToken is ERC20 {
uint256 private countA; uint256 private countA;
uint256 private countB; uint256 private countB;
constructor() ERC20("Silver", "SLV") { constructor() ERC20("Silver", "SLV") {}
/* _mint(address(this), 1); */
}
function incrementCountA() public { function incrementCountA() public {
countA = countA + 1; countA = countA + 1;
@ -22,9 +20,6 @@ contract SLVToken is ERC20 {
receive() external payable {} receive() external payable {}
function destroy() public { function destroy() public {
(bool ok, ) = payable(msg.sender).call{value: address(this).balance}(""); selfdestruct(payable(msg.sender));
require(ok, "ETH transfer failed");
/* _burn(address(this), balanceOf(address(this))); */
} }
} }

View File

@ -28,7 +28,7 @@ if (process.env.DEPLOYER_PRIVATE_KEY) {
module.exports = { module.exports = {
solidity: { solidity: {
version: "0.8.25", version: "0.8.0",
settings: { settings: {
outputSelection: { outputSelection: {
'*': { '*': {

File diff suppressed because it is too large Load Diff

View File

@ -11,9 +11,9 @@
"license": "ISC", "license": "ISC",
"description": "Solidity contract deployment server for integration testing", "description": "Solidity contract deployment server for integration testing",
"dependencies": { "dependencies": {
"@openzeppelin/contracts": "^5.0.2", "@openzeppelin/contracts": "^4.0.0",
"fastify": "^4.26.2", "fastify": "^4.0.0",
"hardhat": "^2.22.3", "hardhat": "^2.14.0",
"solidity-create2-deployer": "^0.4.0" "solidity-create2-deployer": "^0.4.0"
}, },
"devDependencies": { "devDependencies": {

2
test/stack-refs.txt Normal file
View File

@ -0,0 +1,2 @@
git.vdb.to/cerc-io/ipld-eth-db v5.2.1-alpha
git.vdb.to/cerc-io/plugeth-statediff v0.1.1

View File

@ -20,9 +20,9 @@ import "fmt"
const ( const (
Major = 5 // Major version component of the current release Major = 5 // Major version component of the current release
Minor = 2 // Minor version component of the current release Minor = 0 // Minor version component of the current release
Patch = 0 // Patch version component of the current release Patch = 0 // Patch version component of the current release
Meta = "" // Version metadata to append to the version string Meta = "alpha" // Version metadata to append to the version string
) )
// Version holds the textual version string. // Version holds the textual version string.