Compare commits
16 Commits
v5
...
ian/tracin
Author | SHA1 | Date | |
---|---|---|---|
|
402a6e183b | ||
|
29c1523eb8 | ||
|
53be7fc210 | ||
|
92ae69a2b4 | ||
|
6101d7a20d | ||
|
0fe38eafba | ||
|
c727e6dee6 | ||
|
b8153effe7 | ||
|
f22d919478 | ||
|
149e98ad31 | ||
|
e7547983a8 | ||
|
4364ee74c7 | ||
|
42a168f6e4 | ||
|
39ddcdc9dc | ||
|
f5b4e4dc94 | ||
|
89082466fc |
@ -12,7 +12,5 @@ integration
|
|||||||
test
|
test
|
||||||
scripts
|
scripts
|
||||||
Dockerfile
|
Dockerfile
|
||||||
environments
|
|
||||||
|
|
||||||
**/node_modules
|
**/node_modules
|
||||||
build
|
|
69
.github/workflows/tests.yaml
vendored
69
.github/workflows/tests.yaml
vendored
@ -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
|
||||||
|
@ -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
138
Makefile
Normal 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 .
|
@ -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 != "" {
|
||||||
|
@ -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
87
cmd/validate.go
Normal 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"))
|
||||||
|
}
|
@ -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
|
@ -1,5 +1,5 @@
|
|||||||
[database]
|
[database]
|
||||||
name = "cerc_testing"
|
name = "vulcanize_testing"
|
||||||
hostname = "localhost"
|
hostname = "localhost"
|
||||||
port = 5432
|
port = 5432
|
||||||
|
|
||||||
|
318
go.mod
318
go.mod
@ -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
|
||||||
)
|
)
|
||||||
|
@ -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())
|
||||||
|
|
||||||
|
@ -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"))
|
||||||
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
224
pkg/eth/api.go
224
pkg/eth/api.go
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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))
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
466
pkg/eth/debug_test/debug_test.go
Normal file
466
pkg/eth/debug_test/debug_test.go
Normal 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, ð.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: ð.TraceCallConfig{
|
||||||
|
BlockOverrides: ð.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
|
||||||
|
}
|
29
pkg/eth/debug_test/eth_suite_test.go
Normal file
29
pkg/eth/debug_test/eth_suite_test.go
Normal 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")
|
||||||
|
}
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
|
@ -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)))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
84
pkg/eth/test_helpers/chain_indexer.go
Normal file
84
pkg/eth/test_helpers/chain_indexer.go
Normal 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
|
||||||
|
}
|
@ -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
476
pkg/eth/tracing.go
Normal 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
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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) {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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, ð.Config{
|
sap.backend, err = eth.NewEthBackend(sap.db, ð.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
|
||||||
|
@ -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
53
scripts/integration-setup.sh
Executable 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
|
@ -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
|
|
@ -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"
|
||||||
|
@ -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
|
||||||
|
@ -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 ./
|
||||||
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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))); */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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: {
|
||||||
'*': {
|
'*': {
|
||||||
|
2110
test/contract/package-lock.json
generated
2110
test/contract/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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
2
test/stack-refs.txt
Normal 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
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user