Compare commits
187 Commits
v1.14.0
...
unbork-mas
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5c36a8e2c | ||
|
|
afddce396d | ||
|
|
2b5d289b66 | ||
|
|
09056601d8 | ||
|
|
41abab9e39 | ||
|
|
a4e338f05e | ||
|
|
7cfff30ba3 | ||
|
|
06f1d077d3 | ||
|
|
4939c25341 | ||
|
|
36d67be41b | ||
|
|
19c3c1e205 | ||
|
|
045b9718d5 | ||
|
|
269e80b07e | ||
|
|
9298d2db88 | ||
|
|
98b5930d2d | ||
|
|
ed8fd0ac09 | ||
|
|
73f7e7c087 | ||
|
|
fe0c0b04fe | ||
|
|
0a651f8972 | ||
|
|
d8ea7ac2b0 | ||
|
|
a71f6f91fd | ||
|
|
c10ac4f48f | ||
|
|
e0e45dbc32 | ||
|
|
27654d3022 | ||
|
|
00675c5876 | ||
|
|
27008408a5 | ||
|
|
c11aac249d | ||
|
|
0e3a0a693c | ||
|
|
67a862db9d | ||
|
|
7cf6a63687 | ||
|
|
d8664490da | ||
|
|
c736b04d9b | ||
|
|
115d154392 | ||
|
|
b78d2352ef | ||
|
|
a58e4f0674 | ||
|
|
34b46a2f75 | ||
|
|
fd5078c779 | ||
|
|
86150af2e5 | ||
|
|
69351e8b0f | ||
|
|
3687c34cfc | ||
|
|
1e97148249 | ||
|
|
b6f2bbd417 | ||
|
|
c732039a34 | ||
|
|
caa066dcb0 | ||
|
|
ffb29be7d4 | ||
|
|
3aa874bed2 | ||
|
|
85587d5ef2 | ||
|
|
2eb185c92b | ||
|
|
db273c8733 | ||
|
|
8bda642963 | ||
|
|
349fcdd22d | ||
|
|
1098d148a5 | ||
|
|
deaf10982c | ||
|
|
6a49d13c13 | ||
|
|
4405f18519 | ||
|
|
4461c1fc17 | ||
|
|
0dd173a727 | ||
|
|
85459e1439 | ||
|
|
0750cb0c8f | ||
|
|
cbbfa3eac0 | ||
|
|
6c518fe606 | ||
|
|
bc6569462d | ||
|
|
d09ddac399 | ||
|
|
e85e21c932 | ||
|
|
fc40d68e5b | ||
|
|
5550d8399f | ||
|
|
125fb1ff58 | ||
|
|
682ae838b2 | ||
|
|
68c0ec0815 | ||
|
|
adbbd8cd7b | ||
|
|
a6751d6fc8 | ||
|
|
7270cba25c | ||
|
|
b36c73813c | ||
|
|
50405e29b7 | ||
|
|
d38b88a5a1 | ||
|
|
c9e0b3105b | ||
|
|
d4b81f0e08 | ||
|
|
2613523cb5 | ||
|
|
bdc62f9beb | ||
|
|
5d7d48fc3e | ||
|
|
2262bf3415 | ||
|
|
e015c1116f | ||
|
|
6bb13e8e2b | ||
|
|
2f06c1e854 | ||
|
|
3fef53447f | ||
|
|
94a8b296e4 | ||
|
|
e26fa9e40e | ||
|
|
2f0e63e5ac | ||
|
|
06263b1b35 | ||
|
|
b8cf1636d4 | ||
|
|
153f8da887 | ||
|
|
daf4f72077 | ||
|
|
5534c849b6 | ||
|
|
cc22e0cdf0 | ||
|
|
171430c3f5 | ||
|
|
e517183719 | ||
|
|
af0a3274be | ||
|
|
b88051ec83 | ||
|
|
61932e4710 | ||
|
|
871e55d93e | ||
|
|
42471d7a3e | ||
|
|
caafa93598 | ||
|
|
ea6c16007c | ||
|
|
513276864b | ||
|
|
1a4e4a4fe1 | ||
|
|
7224576fba | ||
|
|
7f5cc02a99 | ||
|
|
d1d9f34e51 | ||
|
|
b6474e9f90 | ||
|
|
64b1cd8aaf | ||
|
|
08fe6a8614 | ||
|
|
61b3d93bb0 | ||
|
|
cc9e2bd9dd | ||
|
|
6a9158bb1b | ||
|
|
70bee977d6 | ||
|
|
b779e469da | ||
|
|
fa581766f5 | ||
|
|
0d4cdb3dbe | ||
|
|
7fd7c1f7dd | ||
|
|
be5df74ed5 | ||
|
|
473ee8fc07 | ||
|
|
7ed52c949e | ||
|
|
d2f00cb54e | ||
|
|
8919c5c0fc | ||
|
|
be3284373f | ||
|
|
5b3e3cd2be | ||
|
|
2ac83e197b | ||
|
|
44a50c9f96 | ||
|
|
47af69c2bc | ||
|
|
603fd898d4 | ||
|
|
e5f5eaebc4 | ||
|
|
74edc93864 | ||
|
|
0e456d9eeb | ||
|
|
6d51c1f5f4 | ||
|
|
ab48ba42f4 | ||
|
|
804afb8faa | ||
|
|
faff03c403 | ||
|
|
1a79f8fe58 | ||
|
|
35b2d07f4b | ||
|
|
eeb22089fd | ||
|
|
14f4228472 | ||
|
|
dd09f7e3fa | ||
|
|
6154f87c33 | ||
|
|
dd4afb9fec | ||
|
|
9ec50080eb | ||
|
|
e96de6489c | ||
|
|
71aa15c98f | ||
|
|
d6e91e2e05 | ||
|
|
e4b8058d5a | ||
|
|
3e896c875a | ||
|
|
43cbcd78ea | ||
|
|
a09a610384 | ||
|
|
905e325cd8 | ||
|
|
86a1f0c394 | ||
|
|
2c67fab0d7 | ||
|
|
fbf6238ae9 | ||
|
|
bc609e852a | ||
|
|
682ee820fa | ||
|
|
9f96e07c1c | ||
|
|
f8820f170c | ||
|
|
45baf21111 | ||
|
|
2e8e35f2ad | ||
|
|
5e07054589 | ||
|
|
bd6bc37eec | ||
|
|
7c7e3a77fc | ||
|
|
ea89f9adf0 | ||
|
|
242b24af9f | ||
|
|
f46c878441 | ||
|
|
c04b8e6d74 | ||
|
|
69f815f6f5 | ||
|
|
fecc8a0f4a | ||
|
|
8c3fc56d7f | ||
|
|
4bdbaab471 | ||
|
|
4253030ef6 | ||
|
|
8d42e115b1 | ||
|
|
ad4fb2c729 | ||
|
|
634d037937 | ||
|
|
a0282fc94f | ||
|
|
1f628d842c | ||
|
|
243cde0f54 | ||
|
|
a13b92524d | ||
|
|
2f6ff492ae | ||
|
|
4f4f9d88d3 | ||
|
|
7362691479 | ||
|
|
ac21f9bfb5 | ||
|
|
0d4c38865e | ||
|
|
938734be3c |
7
.github/CODEOWNERS
vendored
7
.github/CODEOWNERS
vendored
@@ -4,13 +4,18 @@
|
||||
accounts/usbwallet @karalabe
|
||||
accounts/scwallet @gballet
|
||||
accounts/abi @gballet @MariusVanDerWijden
|
||||
beacon/engine @lightclient
|
||||
cmd/clef @holiman
|
||||
cmd/evm @holiman @MariusVanDerWijden @lightclient
|
||||
consensus @karalabe
|
||||
core/ @karalabe @holiman @rjl493456442
|
||||
eth/ @karalabe @holiman @rjl493456442
|
||||
eth/catalyst/ @gballet
|
||||
eth/catalyst/ @gballet @lightclient
|
||||
eth/tracers/ @s1na
|
||||
core/tracing/ @s1na
|
||||
graphql/ @s1na
|
||||
internal/ethapi @lightclient
|
||||
internal/era @lightclient
|
||||
les/ @zsfelfoldi @rjl493456442
|
||||
light/ @zsfelfoldi @rjl493456442
|
||||
node/ @fjl
|
||||
|
||||
5
.github/workflows/go.yml
vendored
5
.github/workflows/go.yml
vendored
@@ -11,11 +11,12 @@ jobs:
|
||||
build:
|
||||
runs-on: self-hosted
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.21.4
|
||||
cache: false
|
||||
- name: Run tests
|
||||
run: go test -short ./...
|
||||
env:
|
||||
|
||||
@@ -6,8 +6,6 @@ run:
|
||||
# default is true. Enables skipping of directories:
|
||||
# vendor$, third_party$, testdata$, examples$, Godeps$, builtin$
|
||||
skip-dirs-use-default: true
|
||||
skip-files:
|
||||
- core/genesis_alloc.go
|
||||
|
||||
linters:
|
||||
disable-all: true
|
||||
@@ -25,7 +23,10 @@ linters:
|
||||
- durationcheck
|
||||
- exportloopref
|
||||
- whitespace
|
||||
- revive # only certain checks enabled
|
||||
|
||||
### linters we tried and will not be using:
|
||||
###
|
||||
# - structcheck # lots of false positives
|
||||
# - errcheck #lot of false positives
|
||||
# - contextcheck
|
||||
@@ -38,13 +39,27 @@ linters:
|
||||
linters-settings:
|
||||
gofmt:
|
||||
simplify: true
|
||||
revive:
|
||||
enable-all-rules: false
|
||||
# here we enable specific useful rules
|
||||
# see https://golangci-lint.run/usage/linters/#revive for supported rules
|
||||
rules:
|
||||
- name: receiver-naming
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
|
||||
issues:
|
||||
exclude-files:
|
||||
- core/genesis_alloc.go
|
||||
exclude-rules:
|
||||
- path: crypto/bn256/cloudflare/optate.go
|
||||
linters:
|
||||
- deadcode
|
||||
- staticcheck
|
||||
- path: crypto/bn256/
|
||||
linters:
|
||||
- revive
|
||||
- path: internal/build/pgp.go
|
||||
text: 'SA1019: "golang.org/x/crypto/openpgp" is deprecated: this package is unmaintained except for security fixes.'
|
||||
- path: core/vm/contracts.go
|
||||
|
||||
56
.travis.yml
56
.travis.yml
@@ -15,7 +15,7 @@ jobs:
|
||||
if: type = push
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: bionic
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
env:
|
||||
- docker
|
||||
@@ -32,7 +32,7 @@ jobs:
|
||||
if: type = push
|
||||
os: linux
|
||||
arch: arm64
|
||||
dist: bionic
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
env:
|
||||
- docker
|
||||
@@ -49,21 +49,20 @@ jobs:
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
dist: bionic
|
||||
dist: noble
|
||||
sudo: required
|
||||
go: 1.22.x
|
||||
env:
|
||||
- azure-linux
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gcc-multilib
|
||||
script:
|
||||
# Build for the primary platforms that Trusty can manage
|
||||
# build amd64
|
||||
- go run build/ci.go install -dlgo
|
||||
- go run build/ci.go archive -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||
|
||||
# build 386
|
||||
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install gcc-multilib
|
||||
- go run build/ci.go install -dlgo -arch 386
|
||||
- go run build/ci.go archive -arch 386 -type tar -signer LINUX_SIGNING_KEY -signify SIGNIFY_KEY -upload gethstore/builds
|
||||
|
||||
@@ -98,48 +97,34 @@ jobs:
|
||||
|
||||
# These builders run the tests
|
||||
- stage: build
|
||||
if: type = push
|
||||
os: linux
|
||||
arch: amd64
|
||||
dist: bionic
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
- stage: build
|
||||
if: type = pull_request
|
||||
if: type = push
|
||||
os: linux
|
||||
arch: arm64
|
||||
dist: bionic
|
||||
dist: noble
|
||||
go: 1.21.x
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
- stage: build
|
||||
os: linux
|
||||
dist: bionic
|
||||
go: 1.21.x
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test $TEST_PACKAGES
|
||||
- travis_wait 45 go run build/ci.go test $TEST_PACKAGES
|
||||
|
||||
# This builder does the Ubuntu PPA nightly uploads
|
||||
- stage: build
|
||||
if: type = cron || (type = push && tag ~= /^v[0-9]/)
|
||||
os: linux
|
||||
dist: bionic
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
env:
|
||||
- ubuntu-ppa
|
||||
git:
|
||||
submodules: false # avoid cloning ethereum/tests
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- devscripts
|
||||
- debhelper
|
||||
- dput
|
||||
- fakeroot
|
||||
- python-bzrlib
|
||||
- python-paramiko
|
||||
before_install:
|
||||
- sudo -E apt-get -yq --no-install-suggests --no-install-recommends install devscripts debhelper dput fakeroot
|
||||
script:
|
||||
- echo '|1|7SiYPr9xl3uctzovOTj4gMwAC1M=|t6ReES75Bo/PxlOPJ6/GsGbTrM0= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0aKz5UTUndYgIGG7dQBV+HaeuEZJ2xPHo2DS2iSKvUL4xNMSAY4UguNW+pX56nAQmZKIZZ8MaEvSj6zMEDiq6HFfn5JcTlM80UwlnyKe8B8p7Nk06PPQLrnmQt5fh0HmEcZx+JU9TZsfCHPnX7MNz4ELfZE6cFsclClrKim3BHUIGq//t93DllB+h4O9LHjEUsQ1Sr63irDLSutkLJD6RXchjROXkNirlcNVHH/jwLWR5RcYilNX7S5bIkK8NlWPjsn/8Ua5O7I9/YoE97PpO6i73DTGLh5H9JN/SITwCKBkgSDWUt61uPK3Y11Gty7o2lWsBjhBUm2Y38CBsoGmBw==' >> ~/.ssh/known_hosts
|
||||
- go run build/ci.go debsrc -upload ethereum/ethereum -sftp-user geth-ci -signer "Go Ethereum Linux Builder <geth-ci@ethereum.org>"
|
||||
@@ -148,7 +133,7 @@ jobs:
|
||||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: bionic
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
env:
|
||||
- azure-purge
|
||||
@@ -161,8 +146,9 @@ jobs:
|
||||
- stage: build
|
||||
if: type = cron
|
||||
os: linux
|
||||
dist: bionic
|
||||
dist: noble
|
||||
go: 1.22.x
|
||||
env:
|
||||
- racetests
|
||||
script:
|
||||
- travis_wait 30 go run build/ci.go test -race $TEST_PACKAGES
|
||||
|
||||
- travis_wait 60 go run build/ci.go test -race $TEST_PACKAGES
|
||||
|
||||
24
Makefile
24
Makefile
@@ -2,31 +2,35 @@
|
||||
# with Go source code. If you know what GOPATH is then you probably
|
||||
# don't need to bother with make.
|
||||
|
||||
.PHONY: geth all test lint clean devtools help
|
||||
.PHONY: geth all test lint fmt clean devtools help
|
||||
|
||||
GOBIN = ./build/bin
|
||||
GO ?= latest
|
||||
GORUN = go run
|
||||
|
||||
#? geth: Build geth
|
||||
#? geth: Build geth.
|
||||
geth:
|
||||
$(GORUN) build/ci.go install ./cmd/geth
|
||||
@echo "Done building."
|
||||
@echo "Run \"$(GOBIN)/geth\" to launch geth."
|
||||
|
||||
#? all: Build all packages and executables
|
||||
#? all: Build all packages and executables.
|
||||
all:
|
||||
$(GORUN) build/ci.go install
|
||||
|
||||
#? test: Run the tests
|
||||
#? test: Run the tests.
|
||||
test: all
|
||||
$(GORUN) build/ci.go test
|
||||
|
||||
#? lint: Run certain pre-selected linters
|
||||
#? lint: Run certain pre-selected linters.
|
||||
lint: ## Run linters.
|
||||
$(GORUN) build/ci.go lint
|
||||
|
||||
#? clean: Clean go cache, built executables, and the auto generated folder
|
||||
#? fmt: Ensure consistent code formatting.
|
||||
fmt:
|
||||
gofmt -s -w $(shell find . -name "*.go")
|
||||
|
||||
#? clean: Clean go cache, built executables, and the auto generated folder.
|
||||
clean:
|
||||
go clean -cache
|
||||
rm -fr build/_workspace/pkg/ $(GOBIN)/*
|
||||
@@ -34,7 +38,7 @@ clean:
|
||||
# The devtools target installs tools required for 'go generate'.
|
||||
# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
|
||||
|
||||
#? devtools: Install recommended developer tools
|
||||
#? devtools: Install recommended developer tools.
|
||||
devtools:
|
||||
env GOBIN= go install golang.org/x/tools/cmd/stringer@latest
|
||||
env GOBIN= go install github.com/fjl/gencodec@latest
|
||||
@@ -45,5 +49,9 @@ devtools:
|
||||
|
||||
#? help: Get more info on make commands.
|
||||
help: Makefile
|
||||
@echo " Choose a command run in go-ethereum:"
|
||||
@echo ''
|
||||
@echo 'Usage:'
|
||||
@echo ' make [target]'
|
||||
@echo ''
|
||||
@echo 'Targets:'
|
||||
@sed -n 's/^#?//p' $< | column -t -s ':' | sort | sed -e 's/^/ /'
|
||||
|
||||
487
accounts/abi/bind/source.go.tpl
Normal file
487
accounts/abi/bind/source.go.tpl
Normal file
@@ -0,0 +1,487 @@
|
||||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package {{.Package}}
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
"errors"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = strings.NewReader
|
||||
_ = ethereum.NotFound
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = event.NewSubscription
|
||||
_ = abi.ConvertType
|
||||
)
|
||||
|
||||
{{$structs := .Structs}}
|
||||
{{range $structs}}
|
||||
// {{.Name}} is an auto generated low-level Go binding around an user-defined struct.
|
||||
type {{.Name}} struct {
|
||||
{{range $field := .Fields}}
|
||||
{{$field.Name}} {{$field.Type}}{{end}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range $contract := .Contracts}}
|
||||
// {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract.
|
||||
var {{.Type}}MetaData = &bind.MetaData{
|
||||
ABI: "{{.InputABI}}",
|
||||
{{if $contract.FuncSigs -}}
|
||||
Sigs: map[string]string{
|
||||
{{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}",
|
||||
{{end}}
|
||||
},
|
||||
{{end -}}
|
||||
{{if .InputBin -}}
|
||||
Bin: "0x{{.InputBin}}",
|
||||
{{end}}
|
||||
}
|
||||
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
||||
// Deprecated: Use {{.Type}}MetaData.ABI instead.
|
||||
var {{.Type}}ABI = {{.Type}}MetaData.ABI
|
||||
|
||||
{{if $contract.FuncSigs}}
|
||||
// Deprecated: Use {{.Type}}MetaData.Sigs instead.
|
||||
// {{.Type}}FuncSigs maps the 4-byte function signature to its string representation.
|
||||
var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs
|
||||
{{end}}
|
||||
|
||||
{{if .InputBin}}
|
||||
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
||||
// Deprecated: Use {{.Type}}MetaData.Bin instead.
|
||||
var {{.Type}}Bin = {{.Type}}MetaData.Bin
|
||||
|
||||
// Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
|
||||
func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
if parsed == nil {
|
||||
return common.Address{}, nil, nil, errors.New("GetABI returned nil")
|
||||
}
|
||||
{{range $pattern, $name := .Libraries}}
|
||||
{{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend)
|
||||
{{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:])
|
||||
{{end}}
|
||||
address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}})
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// {{.Type}} is an auto generated Go binding around an Ethereum contract.
|
||||
type {{.Type}} struct {
|
||||
{{.Type}}Caller // Read-only binding to the contract
|
||||
{{.Type}}Transactor // Write-only binding to the contract
|
||||
{{.Type}}Filterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Caller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Transactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type {{.Type}}Filterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Session is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type {{.Type}}Session struct {
|
||||
Contract *{{.Type}} // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type {{.Type}}CallerSession struct {
|
||||
Contract *{{.Type}}Caller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type {{.Type}}TransactorSession struct {
|
||||
Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type {{.Type}}Raw struct {
|
||||
Contract *{{.Type}} // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}CallerRaw struct {
|
||||
Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}TransactorRaw struct {
|
||||
Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) {
|
||||
contract, err := bind{{.Type}}(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) {
|
||||
contract, err := bind{{.Type}}(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Caller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Transactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Filterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bind{{.Type}} binds a generic wrapper to an already deployed contract.
|
||||
func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
{{range .Calls}}
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
|
||||
var out []interface{}
|
||||
err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
{{if .Structured}}
|
||||
outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} })
|
||||
if err != nil {
|
||||
return *outstruct, err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return *outstruct, err
|
||||
{{else}}
|
||||
if err != nil {
|
||||
return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err
|
||||
{{end}}
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Transacts}}
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Fallback}}
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Receive}}
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Events}}
|
||||
// {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}}Iterator struct {
|
||||
Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log
|
||||
|
||||
contract *bind.BoundContract // Generic contract to use for unpacking event data
|
||||
event string // Event name to use for unpacking event data
|
||||
|
||||
logs chan types.Log // Log channel receiving the found contract events
|
||||
sub ethereum.Subscription // Subscription for errors, completion and termination
|
||||
done bool // Whether the subscription completed delivering logs
|
||||
fail error // Occurred error to stop iteration
|
||||
}
|
||||
// Next advances the iterator to the subsequent event, returning whether there
|
||||
// are any more events found. In case of a retrieval or parsing error, false is
|
||||
// returned and Error() can be queried for the exact failure.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool {
|
||||
// If the iterator failed, stop iterating
|
||||
if (it.fail != nil) {
|
||||
return false
|
||||
}
|
||||
// If the iterator completed, deliver directly whatever's available
|
||||
if (it.done) {
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Iterator still in progress, wait for either a data or an error event
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
case err := <-it.sub.Err():
|
||||
it.done = true
|
||||
it.fail = err
|
||||
return it.Next()
|
||||
}
|
||||
}
|
||||
// Error returns any retrieval or parsing error occurred during filtering.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error {
|
||||
return it.fail
|
||||
}
|
||||
// Close terminates the iteration process, releasing any pending underlying
|
||||
// resources.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error {
|
||||
it.sub.Unsubscribe()
|
||||
return nil
|
||||
}
|
||||
|
||||
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
|
||||
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}}
|
||||
Raw types.Log // Blockchain specific contextual infos
|
||||
}
|
||||
|
||||
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil
|
||||
}
|
||||
|
||||
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
defer sub.Unsubscribe()
|
||||
for {
|
||||
select {
|
||||
case log := <-logs:
|
||||
// New log arrived, parse the event and forward to the user
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Raw = log
|
||||
|
||||
select {
|
||||
case sink <- event:
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) {
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
event.Raw = log
|
||||
return event, nil
|
||||
}
|
||||
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
package bind
|
||||
|
||||
import "github.com/ethereum/go-ethereum/accounts/abi"
|
||||
import (
|
||||
_ "embed"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
)
|
||||
|
||||
// tmplData is the data structure required to fill the binding template.
|
||||
type tmplData struct {
|
||||
@@ -80,492 +84,6 @@ var tmplSource = map[Lang]string{
|
||||
|
||||
// tmplSourceGo is the Go source template that the generated Go contract binding
|
||||
// is based on.
|
||||
const tmplSourceGo = `
|
||||
// Code generated - DO NOT EDIT.
|
||||
// This file is a generated binding and any manual changes will be lost.
|
||||
|
||||
package {{.Package}}
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"strings"
|
||||
"errors"
|
||||
|
||||
ethereum "github.com/ethereum/go-ethereum"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/event"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var (
|
||||
_ = errors.New
|
||||
_ = big.NewInt
|
||||
_ = strings.NewReader
|
||||
_ = ethereum.NotFound
|
||||
_ = bind.Bind
|
||||
_ = common.Big1
|
||||
_ = types.BloomLookup
|
||||
_ = event.NewSubscription
|
||||
_ = abi.ConvertType
|
||||
)
|
||||
|
||||
{{$structs := .Structs}}
|
||||
{{range $structs}}
|
||||
// {{.Name}} is an auto generated low-level Go binding around an user-defined struct.
|
||||
type {{.Name}} struct {
|
||||
{{range $field := .Fields}}
|
||||
{{$field.Name}} {{$field.Type}}{{end}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range $contract := .Contracts}}
|
||||
// {{.Type}}MetaData contains all meta data concerning the {{.Type}} contract.
|
||||
var {{.Type}}MetaData = &bind.MetaData{
|
||||
ABI: "{{.InputABI}}",
|
||||
{{if $contract.FuncSigs -}}
|
||||
Sigs: map[string]string{
|
||||
{{range $strsig, $binsig := .FuncSigs}}"{{$binsig}}": "{{$strsig}}",
|
||||
{{end}}
|
||||
},
|
||||
{{end -}}
|
||||
{{if .InputBin -}}
|
||||
Bin: "0x{{.InputBin}}",
|
||||
{{end}}
|
||||
}
|
||||
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
||||
// Deprecated: Use {{.Type}}MetaData.ABI instead.
|
||||
var {{.Type}}ABI = {{.Type}}MetaData.ABI
|
||||
|
||||
{{if $contract.FuncSigs}}
|
||||
// Deprecated: Use {{.Type}}MetaData.Sigs instead.
|
||||
// {{.Type}}FuncSigs maps the 4-byte function signature to its string representation.
|
||||
var {{.Type}}FuncSigs = {{.Type}}MetaData.Sigs
|
||||
{{end}}
|
||||
|
||||
{{if .InputBin}}
|
||||
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
||||
// Deprecated: Use {{.Type}}MetaData.Bin instead.
|
||||
var {{.Type}}Bin = {{.Type}}MetaData.Bin
|
||||
|
||||
// Deploy{{.Type}} deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
|
||||
func Deploy{{.Type}}(auth *bind.TransactOpts, backend bind.ContractBackend {{range .Constructor.Inputs}}, {{.Name}} {{bindtype .Type $structs}}{{end}}) (common.Address, *types.Transaction, *{{.Type}}, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
if parsed == nil {
|
||||
return common.Address{}, nil, nil, errors.New("GetABI returned nil")
|
||||
}
|
||||
{{range $pattern, $name := .Libraries}}
|
||||
{{decapitalise $name}}Addr, _, _, _ := Deploy{{capitalise $name}}(auth, backend)
|
||||
{{$contract.Type}}Bin = strings.ReplaceAll({{$contract.Type}}Bin, "__${{$pattern}}$__", {{decapitalise $name}}Addr.String()[2:])
|
||||
{{end}}
|
||||
address, tx, contract, err := bind.DeployContract(auth, *parsed, common.FromHex({{.Type}}Bin), backend {{range .Constructor.Inputs}}, {{.Name}}{{end}})
|
||||
if err != nil {
|
||||
return common.Address{}, nil, nil, err
|
||||
}
|
||||
return address, tx, &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// {{.Type}} is an auto generated Go binding around an Ethereum contract.
|
||||
type {{.Type}} struct {
|
||||
{{.Type}}Caller // Read-only binding to the contract
|
||||
{{.Type}}Transactor // Write-only binding to the contract
|
||||
{{.Type}}Filterer // Log filterer for contract events
|
||||
}
|
||||
|
||||
// {{.Type}}Caller is an auto generated read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Caller struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Transactor is an auto generated write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}Transactor struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Filterer is an auto generated log filtering Go binding around an Ethereum contract events.
|
||||
type {{.Type}}Filterer struct {
|
||||
contract *bind.BoundContract // Generic contract wrapper for the low level calls
|
||||
}
|
||||
|
||||
// {{.Type}}Session is an auto generated Go binding around an Ethereum contract,
|
||||
// with pre-set call and transact options.
|
||||
type {{.Type}}Session struct {
|
||||
Contract *{{.Type}} // Generic contract binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}CallerSession is an auto generated read-only Go binding around an Ethereum contract,
|
||||
// with pre-set call options.
|
||||
type {{.Type}}CallerSession struct {
|
||||
Contract *{{.Type}}Caller // Generic contract caller binding to set the session for
|
||||
CallOpts bind.CallOpts // Call options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorSession is an auto generated write-only Go binding around an Ethereum contract,
|
||||
// with pre-set transact options.
|
||||
type {{.Type}}TransactorSession struct {
|
||||
Contract *{{.Type}}Transactor // Generic contract transactor binding to set the session for
|
||||
TransactOpts bind.TransactOpts // Transaction auth options to use throughout this session
|
||||
}
|
||||
|
||||
// {{.Type}}Raw is an auto generated low-level Go binding around an Ethereum contract.
|
||||
type {{.Type}}Raw struct {
|
||||
Contract *{{.Type}} // Generic contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}CallerRaw is an auto generated low-level read-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}CallerRaw struct {
|
||||
Contract *{{.Type}}Caller // Generic read-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// {{.Type}}TransactorRaw is an auto generated low-level write-only Go binding around an Ethereum contract.
|
||||
type {{.Type}}TransactorRaw struct {
|
||||
Contract *{{.Type}}Transactor // Generic write-only contract binding to access the raw methods on
|
||||
}
|
||||
|
||||
// New{{.Type}} creates a new instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}(address common.Address, backend bind.ContractBackend) (*{{.Type}}, error) {
|
||||
contract, err := bind{{.Type}}(address, backend, backend, backend)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}{ {{.Type}}Caller: {{.Type}}Caller{contract: contract}, {{.Type}}Transactor: {{.Type}}Transactor{contract: contract}, {{.Type}}Filterer: {{.Type}}Filterer{contract: contract} }, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Caller creates a new read-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Caller(address common.Address, caller bind.ContractCaller) (*{{.Type}}Caller, error) {
|
||||
contract, err := bind{{.Type}}(address, caller, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Caller{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Transactor creates a new write-only instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Transactor(address common.Address, transactor bind.ContractTransactor) (*{{.Type}}Transactor, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, transactor, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Transactor{contract: contract}, nil
|
||||
}
|
||||
|
||||
// New{{.Type}}Filterer creates a new log filterer instance of {{.Type}}, bound to a specific deployed contract.
|
||||
func New{{.Type}}Filterer(address common.Address, filterer bind.ContractFilterer) (*{{.Type}}Filterer, error) {
|
||||
contract, err := bind{{.Type}}(address, nil, nil, filterer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{.Type}}Filterer{contract: contract}, nil
|
||||
}
|
||||
|
||||
// bind{{.Type}} binds a generic wrapper to an already deployed contract.
|
||||
func bind{{.Type}}(address common.Address, caller bind.ContractCaller, transactor bind.ContractTransactor, filterer bind.ContractFilterer) (*bind.BoundContract, error) {
|
||||
parsed, err := {{.Type}}MetaData.GetAbi()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bind.NewBoundContract(address, *parsed, caller, transactor, filterer), nil
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Caller.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Raw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{$contract.Type}}Transactor.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
// Call invokes the (constant) contract method with params as input values and
|
||||
// sets the output to result. The result type might be a single field for simple
|
||||
// returns, a slice of interfaces for anonymous returns and a struct for named
|
||||
// returns.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerRaw) Call(opts *bind.CallOpts, result *[]interface{}, method string, params ...interface{}) error {
|
||||
return _{{$contract.Type}}.Contract.contract.Call(opts, result, method, params...)
|
||||
}
|
||||
|
||||
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||
// its default method if one is available.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transfer(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transfer(opts)
|
||||
}
|
||||
|
||||
// Transact invokes the (paid) contract method with params as input values.
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorRaw) Transact(opts *bind.TransactOpts, method string, params ...interface{}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.contract.Transact(opts, method, params...)
|
||||
}
|
||||
|
||||
{{range .Calls}}
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Caller) {{.Normalized.Name}}(opts *bind.CallOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} },{{else}}{{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}}{{end}} error) {
|
||||
var out []interface{}
|
||||
err := _{{$contract.Type}}.contract.Call(opts, &out, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
{{if .Structured}}
|
||||
outstruct := new(struct{ {{range .Normalized.Outputs}} {{.Name}} {{bindtype .Type $structs}}; {{end}} })
|
||||
if err != nil {
|
||||
return *outstruct, err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
outstruct.{{.Name}} = *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return *outstruct, err
|
||||
{{else}}
|
||||
if err != nil {
|
||||
return {{range $i, $_ := .Normalized.Outputs}}*new({{bindtype .Type $structs}}), {{end}} err
|
||||
}
|
||||
{{range $i, $t := .Normalized.Outputs}}
|
||||
out{{$i}} := *abi.ConvertType(out[{{$i}}], new({{bindtype .Type $structs}})).(*{{bindtype .Type $structs}}){{end}}
|
||||
|
||||
return {{range $i, $t := .Normalized.Outputs}}out{{$i}}, {{end}} err
|
||||
{{end}}
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}CallerSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) ({{if .Structured}}struct{ {{range .Normalized.Outputs}}{{.Name}} {{bindtype .Type $structs}};{{end}} }, {{else}} {{range .Normalized.Outputs}}{{bindtype .Type $structs}},{{end}} {{end}} error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.CallOpts {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Transacts}}
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) {{.Normalized.Name}}(opts *bind.TransactOpts {{range .Normalized.Inputs}}, {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.Transact(opts, "{{.Original.Name}}" {{range .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
|
||||
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) {{.Normalized.Name}}({{range $i, $_ := .Normalized.Inputs}}{{if ne $i 0}},{{end}} {{.Name}} {{bindtype .Type $structs}} {{end}}) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.{{.Normalized.Name}}(&_{{$contract.Type}}.TransactOpts {{range $i, $_ := .Normalized.Inputs}}, {{.Name}}{{end}})
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Fallback}}
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Fallback(opts *bind.TransactOpts, calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
|
||||
// Fallback is a paid mutator transaction binding the contract fallback function.
|
||||
//
|
||||
// Solidity: {{.Fallback.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Fallback(calldata []byte) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Fallback(&_{{$contract.Type}}.TransactOpts, calldata)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{if .Receive}}
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Transactor) Receive(opts *bind.TransactOpts) (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.contract.RawTransact(opts, nil) // calldata is disallowed for receive function
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Session) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
|
||||
// Receive is a paid mutator transaction binding the contract receive function.
|
||||
//
|
||||
// Solidity: {{.Receive.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}TransactorSession) Receive() (*types.Transaction, error) {
|
||||
return _{{$contract.Type}}.Contract.Receive(&_{{$contract.Type}}.TransactOpts)
|
||||
}
|
||||
{{end}}
|
||||
|
||||
{{range .Events}}
|
||||
// {{$contract.Type}}{{.Normalized.Name}}Iterator is returned from Filter{{.Normalized.Name}} and is used to iterate over the raw logs and unpacked data for {{.Normalized.Name}} events raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}}Iterator struct {
|
||||
Event *{{$contract.Type}}{{.Normalized.Name}} // Event containing the contract specifics and raw log
|
||||
|
||||
contract *bind.BoundContract // Generic contract to use for unpacking event data
|
||||
event string // Event name to use for unpacking event data
|
||||
|
||||
logs chan types.Log // Log channel receiving the found contract events
|
||||
sub ethereum.Subscription // Subscription for errors, completion and termination
|
||||
done bool // Whether the subscription completed delivering logs
|
||||
fail error // Occurred error to stop iteration
|
||||
}
|
||||
// Next advances the iterator to the subsequent event, returning whether there
|
||||
// are any more events found. In case of a retrieval or parsing error, false is
|
||||
// returned and Error() can be queried for the exact failure.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Next() bool {
|
||||
// If the iterator failed, stop iterating
|
||||
if (it.fail != nil) {
|
||||
return false
|
||||
}
|
||||
// If the iterator completed, deliver directly whatever's available
|
||||
if (it.done) {
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
// Iterator still in progress, wait for either a data or an error event
|
||||
select {
|
||||
case log := <-it.logs:
|
||||
it.Event = new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := it.contract.UnpackLog(it.Event, it.event, log); err != nil {
|
||||
it.fail = err
|
||||
return false
|
||||
}
|
||||
it.Event.Raw = log
|
||||
return true
|
||||
|
||||
case err := <-it.sub.Err():
|
||||
it.done = true
|
||||
it.fail = err
|
||||
return it.Next()
|
||||
}
|
||||
}
|
||||
// Error returns any retrieval or parsing error occurred during filtering.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Error() error {
|
||||
return it.fail
|
||||
}
|
||||
// Close terminates the iteration process, releasing any pending underlying
|
||||
// resources.
|
||||
func (it *{{$contract.Type}}{{.Normalized.Name}}Iterator) Close() error {
|
||||
it.sub.Unsubscribe()
|
||||
return nil
|
||||
}
|
||||
|
||||
// {{$contract.Type}}{{.Normalized.Name}} represents a {{.Normalized.Name}} event raised by the {{$contract.Type}} contract.
|
||||
type {{$contract.Type}}{{.Normalized.Name}} struct { {{range .Normalized.Inputs}}
|
||||
{{capitalise .Name}} {{if .Indexed}}{{bindtopictype .Type $structs}}{{else}}{{bindtype .Type $structs}}{{end}}; {{end}}
|
||||
Raw types.Log // Blockchain specific contextual infos
|
||||
}
|
||||
|
||||
// Filter{{.Normalized.Name}} is a free log retrieval operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Filter{{.Normalized.Name}}(opts *bind.FilterOpts{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (*{{$contract.Type}}{{.Normalized.Name}}Iterator, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.FilterLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &{{$contract.Type}}{{.Normalized.Name}}Iterator{contract: _{{$contract.Type}}.contract, event: "{{.Original.Name}}", logs: logs, sub: sub}, nil
|
||||
}
|
||||
|
||||
// Watch{{.Normalized.Name}} is a free log subscription operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Watch{{.Normalized.Name}}(opts *bind.WatchOpts, sink chan<- *{{$contract.Type}}{{.Normalized.Name}}{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}} []{{bindtype .Type $structs}}{{end}}{{end}}) (event.Subscription, error) {
|
||||
{{range .Normalized.Inputs}}
|
||||
{{if .Indexed}}var {{.Name}}Rule []interface{}
|
||||
for _, {{.Name}}Item := range {{.Name}} {
|
||||
{{.Name}}Rule = append({{.Name}}Rule, {{.Name}}Item)
|
||||
}{{end}}{{end}}
|
||||
|
||||
logs, sub, err := _{{$contract.Type}}.contract.WatchLogs(opts, "{{.Original.Name}}"{{range .Normalized.Inputs}}{{if .Indexed}}, {{.Name}}Rule{{end}}{{end}})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return event.NewSubscription(func(quit <-chan struct{}) error {
|
||||
defer sub.Unsubscribe()
|
||||
for {
|
||||
select {
|
||||
case log := <-logs:
|
||||
// New log arrived, parse the event and forward to the user
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return err
|
||||
}
|
||||
event.Raw = log
|
||||
|
||||
select {
|
||||
case sink <- event:
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
case err := <-sub.Err():
|
||||
return err
|
||||
case <-quit:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}), nil
|
||||
}
|
||||
|
||||
// Parse{{.Normalized.Name}} is a log parse operation binding the contract event 0x{{printf "%x" .Original.ID}}.
|
||||
//
|
||||
// Solidity: {{.Original.String}}
|
||||
func (_{{$contract.Type}} *{{$contract.Type}}Filterer) Parse{{.Normalized.Name}}(log types.Log) (*{{$contract.Type}}{{.Normalized.Name}}, error) {
|
||||
event := new({{$contract.Type}}{{.Normalized.Name}})
|
||||
if err := _{{$contract.Type}}.contract.UnpackLog(event, "{{.Original.Name}}", log); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
event.Raw = log
|
||||
return event, nil
|
||||
}
|
||||
|
||||
{{end}}
|
||||
{{end}}
|
||||
`
|
||||
//
|
||||
//go:embed source.go.tpl
|
||||
var tmplSourceGo string
|
||||
|
||||
@@ -64,6 +64,9 @@ type Type struct {
|
||||
var (
|
||||
// typeRegex parses the abi sub types
|
||||
typeRegex = regexp.MustCompile("([a-zA-Z]+)(([0-9]+)(x([0-9]+))?)?")
|
||||
|
||||
// sliceSizeRegex grab the slice size
|
||||
sliceSizeRegex = regexp.MustCompile("[0-9]+")
|
||||
)
|
||||
|
||||
// NewType creates a new reflection type of abi type given in t.
|
||||
@@ -91,8 +94,7 @@ func NewType(t string, internalType string, components []ArgumentMarshaling) (ty
|
||||
// grab the last cell and create a type from there
|
||||
sliced := t[i:]
|
||||
// grab the slice size with regexp
|
||||
re := regexp.MustCompile("[0-9]+")
|
||||
intz := re.FindAllString(sliced, -1)
|
||||
intz := sliceSizeRegex.FindAllString(sliced, -1)
|
||||
|
||||
if len(intz) == 0 {
|
||||
// is a slice
|
||||
|
||||
@@ -325,7 +325,8 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create a temporary keystore to test with
|
||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
dir := t.TempDir()
|
||||
|
||||
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
||||
|
||||
list := ks.Accounts()
|
||||
@@ -335,9 +336,7 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
||||
if !waitWatcherStart(ks) {
|
||||
t.Fatal("keystore watcher didn't start in time")
|
||||
}
|
||||
// Create the directory and copy a key file into it.
|
||||
os.MkdirAll(dir, 0700)
|
||||
defer os.RemoveAll(dir)
|
||||
// Copy a key file into it
|
||||
file := filepath.Join(dir, "aaa")
|
||||
|
||||
// Place one of our testfiles in there
|
||||
|
||||
@@ -312,11 +312,10 @@ func (ks *KeyStore) Unlock(a accounts.Account, passphrase string) error {
|
||||
// Lock removes the private key with the given address from memory.
|
||||
func (ks *KeyStore) Lock(addr common.Address) error {
|
||||
ks.mu.Lock()
|
||||
if unl, found := ks.unlocked[addr]; found {
|
||||
ks.mu.Unlock()
|
||||
unl, found := ks.unlocked[addr]
|
||||
ks.mu.Unlock()
|
||||
if found {
|
||||
ks.expire(addr, unl, time.Duration(0)*time.Nanosecond)
|
||||
} else {
|
||||
ks.mu.Unlock()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ func (hub *Hub) readPairings() error {
|
||||
}
|
||||
return err
|
||||
}
|
||||
defer pairingFile.Close()
|
||||
|
||||
pairingData, err := io.ReadAll(pairingFile)
|
||||
if err != nil {
|
||||
|
||||
@@ -73,6 +73,14 @@ var (
|
||||
DerivationSignatureHash = sha256.Sum256(common.Hash{}.Bytes())
|
||||
)
|
||||
|
||||
var (
|
||||
// PinRegexp is the regular expression used to validate PIN codes.
|
||||
pinRegexp = regexp.MustCompile(`^[0-9]{6,}$`)
|
||||
|
||||
// PukRegexp is the regular expression used to validate PUK codes.
|
||||
pukRegexp = regexp.MustCompile(`^[0-9]{12,}$`)
|
||||
)
|
||||
|
||||
// List of APDU command-related constants
|
||||
const (
|
||||
claISO7816 = 0
|
||||
@@ -380,7 +388,7 @@ func (w *Wallet) Open(passphrase string) error {
|
||||
case passphrase == "":
|
||||
return ErrPINUnblockNeeded
|
||||
case status.PinRetryCount > 0:
|
||||
if !regexp.MustCompile(`^[0-9]{6,}$`).MatchString(passphrase) {
|
||||
if !pinRegexp.MatchString(passphrase) {
|
||||
w.log.Error("PIN needs to be at least 6 digits")
|
||||
return ErrPINNeeded
|
||||
}
|
||||
@@ -388,7 +396,7 @@ func (w *Wallet) Open(passphrase string) error {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
if !regexp.MustCompile(`^[0-9]{12,}$`).MatchString(passphrase) {
|
||||
if !pukRegexp.MatchString(passphrase) {
|
||||
w.log.Error("PUK needs to be at least 12 digits")
|
||||
return ErrPINUnblockNeeded
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,8 @@
|
||||
syntax = "proto2";
|
||||
package hw.trezor.messages.common;
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
/**
|
||||
* Response: Success of the previous request
|
||||
* @end
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,8 @@
|
||||
syntax = "proto2";
|
||||
package hw.trezor.messages.ethereum;
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
// Sugar for easier handling in Java
|
||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||
option java_outer_classname = "TrezorMessageEthereum";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,8 @@
|
||||
syntax = "proto2";
|
||||
package hw.trezor.messages.management;
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
// Sugar for easier handling in Java
|
||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||
option java_outer_classname = "TrezorMessageManagement";
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,13 @@ package hw.trezor.messages;
|
||||
* Messages for TREZOR communication
|
||||
*/
|
||||
|
||||
option go_package = "github.com/ethereum/go-ethereum/accounts/usbwallet/trezor";
|
||||
|
||||
// Sugar for easier handling in Java
|
||||
option java_package = "com.satoshilabs.trezor.lib.protobuf";
|
||||
option java_outer_classname = "TrezorMessage";
|
||||
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
// - Grab the latest Go plugin `go get -u github.com/golang/protobuf/protoc-gen-go`
|
||||
// - Vendor in the latest Go plugin `govendor fetch github.com/golang/protobuf/...`
|
||||
|
||||
//go:generate protoc -I/usr/local/include:. --go_out=import_path=trezor:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
||||
//go:generate protoc -I/usr/local/include:. --go_out=paths=source_relative:. messages.proto messages-common.proto messages-management.proto messages-ethereum.proto
|
||||
|
||||
// Package trezor contains the wire protocol.
|
||||
package trezor
|
||||
|
||||
@@ -24,6 +24,7 @@ for:
|
||||
- image: Ubuntu
|
||||
build_script:
|
||||
- go run build/ci.go lint
|
||||
- go run build/ci.go generate -verify
|
||||
- go run build/ci.go install -dlgo
|
||||
test_script:
|
||||
- go run build/ci.go test -dlgo -short
|
||||
|
||||
@@ -209,7 +209,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash,
|
||||
if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
|
||||
return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
|
||||
}
|
||||
var blobHashes []common.Hash
|
||||
var blobHashes = make([]common.Hash, 0, len(txs))
|
||||
for _, tx := range txs {
|
||||
blobHashes = append(blobHashes, tx.BlobHashes()...)
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash,
|
||||
BlobGasUsed: params.BlobGasUsed,
|
||||
ParentBeaconRoot: beaconRoot,
|
||||
}
|
||||
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
|
||||
block := types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs, Uncles: nil, Withdrawals: params.Withdrawals})
|
||||
if block.Hash() != params.BlockHash {
|
||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
|
||||
}
|
||||
|
||||
@@ -494,9 +494,6 @@ func (api *BeaconLightApi) StartHeadListener(listener HeadEventListener) func()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
stream.Close()
|
||||
|
||||
case event, ok := <-stream.Events:
|
||||
if !ok {
|
||||
log.Trace("Event stream closed")
|
||||
|
||||
@@ -186,10 +186,14 @@ func (s *serverWithTimeout) eventCallback(event Event) {
|
||||
// call will just do nothing
|
||||
timer.Stop()
|
||||
delete(s.timeouts, id)
|
||||
s.childEventCb(event)
|
||||
if s.childEventCb != nil {
|
||||
s.childEventCb(event)
|
||||
}
|
||||
}
|
||||
default:
|
||||
s.childEventCb(event)
|
||||
if s.childEventCb != nil {
|
||||
s.childEventCb(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,25 +215,27 @@ func (s *serverWithTimeout) startTimeout(reqData RequestResponse) {
|
||||
delete(s.timeouts, id)
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
childEventCb(Event{Type: EvFail, Data: reqData})
|
||||
if childEventCb != nil {
|
||||
childEventCb(Event{Type: EvFail, Data: reqData})
|
||||
}
|
||||
})
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
childEventCb(Event{Type: EvTimeout, Data: reqData})
|
||||
if childEventCb != nil {
|
||||
childEventCb(Event{Type: EvTimeout, Data: reqData})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// unsubscribe stops all goroutines associated with the server.
|
||||
func (s *serverWithTimeout) unsubscribe() {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
for _, timer := range s.timeouts {
|
||||
if timer != nil {
|
||||
timer.Stop()
|
||||
}
|
||||
}
|
||||
s.childEventCb = nil
|
||||
s.lock.Unlock()
|
||||
s.parent.Unsubscribe()
|
||||
}
|
||||
|
||||
@@ -328,10 +334,10 @@ func (s *serverWithLimits) eventCallback(event Event) {
|
||||
}
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
if passEvent {
|
||||
if passEvent && childEventCb != nil {
|
||||
childEventCb(event)
|
||||
}
|
||||
if sendCanRequestAgain {
|
||||
if sendCanRequestAgain && childEventCb != nil {
|
||||
childEventCb(Event{Type: EvCanRequestAgain})
|
||||
}
|
||||
}
|
||||
@@ -347,13 +353,12 @@ func (s *serverWithLimits) sendRequest(request Request) (reqId ID) {
|
||||
// unsubscribe stops all goroutines associated with the server.
|
||||
func (s *serverWithLimits) unsubscribe() {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
if s.delayTimer != nil {
|
||||
s.delayTimer.Stop()
|
||||
s.delayTimer = nil
|
||||
}
|
||||
s.childEventCb = nil
|
||||
s.lock.Unlock()
|
||||
s.serverWithTimeout.unsubscribe()
|
||||
}
|
||||
|
||||
@@ -383,7 +388,7 @@ func (s *serverWithLimits) canRequestNow() bool {
|
||||
}
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
if sendCanRequestAgain {
|
||||
if sendCanRequestAgain && childEventCb != nil {
|
||||
childEventCb(Event{Type: EvCanRequestAgain})
|
||||
}
|
||||
return canRequest
|
||||
@@ -415,7 +420,7 @@ func (s *serverWithLimits) delay(delay time.Duration) {
|
||||
}
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
if sendCanRequestAgain {
|
||||
if sendCanRequestAgain && childEventCb != nil {
|
||||
childEventCb(Event{Type: EvCanRequestAgain})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -51,6 +51,7 @@ func TestServerEvents(t *testing.T) {
|
||||
expEvent(EvFail)
|
||||
rs.eventCb(Event{Type: EvResponse, Data: RequestResponse{ID: 1, Request: testRequest, Response: testResponse}})
|
||||
expEvent(nil)
|
||||
srv.unsubscribe()
|
||||
}
|
||||
|
||||
func TestServerParallel(t *testing.T) {
|
||||
@@ -129,9 +130,7 @@ func TestServerEventRateLimit(t *testing.T) {
|
||||
srv := NewServer(rs, clock)
|
||||
var eventCount int
|
||||
srv.subscribe(func(event Event) {
|
||||
if !event.IsRequestEvent() {
|
||||
eventCount++
|
||||
}
|
||||
eventCount++
|
||||
})
|
||||
expEvents := func(send, expAllowed int) {
|
||||
eventCount = 0
|
||||
@@ -147,6 +146,30 @@ func TestServerEventRateLimit(t *testing.T) {
|
||||
expEvents(5, 1)
|
||||
clock.Run(maxServerEventRate * maxServerEventBuffer * 2)
|
||||
expEvents(maxServerEventBuffer+5, maxServerEventBuffer)
|
||||
srv.unsubscribe()
|
||||
}
|
||||
|
||||
func TestServerUnsubscribe(t *testing.T) {
|
||||
rs := &testRequestServer{}
|
||||
clock := &mclock.Simulated{}
|
||||
srv := NewServer(rs, clock)
|
||||
var eventCount int
|
||||
srv.subscribe(func(event Event) {
|
||||
eventCount++
|
||||
})
|
||||
eventCb := rs.eventCb
|
||||
eventCb(Event{Type: testEventType})
|
||||
if eventCount != 1 {
|
||||
t.Errorf("Server event callback not called before unsubscribe")
|
||||
}
|
||||
srv.unsubscribe()
|
||||
if rs.eventCb != nil {
|
||||
t.Errorf("Server event callback not removed after unsubscribe")
|
||||
}
|
||||
eventCb(Event{Type: testEventType})
|
||||
if eventCount != 1 {
|
||||
t.Errorf("Server event callback called after unsubscribe")
|
||||
}
|
||||
}
|
||||
|
||||
type testRequestServer struct {
|
||||
@@ -156,4 +179,4 @@ type testRequestServer struct {
|
||||
func (rs *testRequestServer) Name() string { return "" }
|
||||
func (rs *testRequestServer) Subscribe(eventCb func(Event)) { rs.eventCb = eventCb }
|
||||
func (rs *testRequestServer) SendRequest(ID, Request) {}
|
||||
func (rs *testRequestServer) Unsubscribe() {}
|
||||
func (rs *testRequestServer) Unsubscribe() { rs.eventCb = nil }
|
||||
|
||||
@@ -91,7 +91,7 @@ func TestValidatedHead(t *testing.T) {
|
||||
ts.ServerEvent(EvNewOptimisticUpdate, testServer3, testOptUpdate4)
|
||||
// finality should be requested from both servers
|
||||
ts.Run(4, testServer1, ReqFinality{}, testServer3, ReqFinality{})
|
||||
// future period annonced heads should be queued
|
||||
// future period announced heads should be queued
|
||||
ht.ExpValidated(t, 4, nil)
|
||||
|
||||
chain.SetNextSyncPeriod(2)
|
||||
|
||||
@@ -173,24 +173,24 @@ type TestCommitteeChain struct {
|
||||
init bool
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error {
|
||||
t.fsp, t.nsp, t.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true
|
||||
func (tc *TestCommitteeChain) CheckpointInit(bootstrap types.BootstrapData) error {
|
||||
tc.fsp, tc.nsp, tc.init = bootstrap.Header.SyncPeriod(), bootstrap.Header.SyncPeriod()+2, true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error {
|
||||
func (tc *TestCommitteeChain) InsertUpdate(update *types.LightClientUpdate, nextCommittee *types.SerializedSyncCommittee) error {
|
||||
period := update.AttestedHeader.Header.SyncPeriod()
|
||||
if period < t.fsp || period > t.nsp || !t.init {
|
||||
if period < tc.fsp || period > tc.nsp || !tc.init {
|
||||
return light.ErrInvalidPeriod
|
||||
}
|
||||
if period == t.nsp {
|
||||
t.nsp++
|
||||
if period == tc.nsp {
|
||||
tc.nsp++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) NextSyncPeriod() (uint64, bool) {
|
||||
return t.nsp, t.init
|
||||
func (tc *TestCommitteeChain) NextSyncPeriod() (uint64, bool) {
|
||||
return tc.nsp, tc.init
|
||||
}
|
||||
|
||||
func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) {
|
||||
@@ -199,8 +199,8 @@ func (tc *TestCommitteeChain) ExpInit(t *testing.T, ExpInit bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) {
|
||||
t.init, t.nsp = true, nsp
|
||||
func (tc *TestCommitteeChain) SetNextSyncPeriod(nsp uint64) {
|
||||
tc.init, tc.nsp = true, nsp
|
||||
}
|
||||
|
||||
func (tc *TestCommitteeChain) ExpNextSyncPeriod(t *testing.T, expNsp uint64) {
|
||||
|
||||
@@ -63,11 +63,9 @@ func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*typ
|
||||
panic("unsupported block type")
|
||||
}
|
||||
|
||||
block := types.NewBlockWithHeader(&header)
|
||||
block = block.WithBody(transactions, nil)
|
||||
block = block.WithWithdrawals(withdrawals)
|
||||
block := types.NewBlockWithHeader(&header).WithBody(types.Body{Transactions: transactions, Withdrawals: withdrawals})
|
||||
if hash := block.Hash(); hash != expectedHash {
|
||||
return nil, fmt.Errorf("Sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash)
|
||||
return nil, fmt.Errorf("sanity check failed, payload hash does not match (expected %x, got %x)", expectedHash, hash)
|
||||
}
|
||||
return block, nil
|
||||
}
|
||||
|
||||
@@ -5,61 +5,122 @@
|
||||
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||
|
||||
# version:golang 1.22.2
|
||||
# version:golang 1.22.4
|
||||
# https://go.dev/dl/
|
||||
374ea82b289ec738e968267cac59c7d5ff180f9492250254784b2044e90df5a9 go1.22.2.src.tar.gz
|
||||
33e7f63077b1c5bce4f1ecadd4d990cf229667c40bfb00686990c950911b7ab7 go1.22.2.darwin-amd64.tar.gz
|
||||
660298be38648723e783ba0398e90431de1cb288c637880cdb124f39bd977f0d go1.22.2.darwin-arm64.tar.gz
|
||||
efc7162b0cad2f918ac566a923d4701feb29dc9c0ab625157d49b1cbcbba39da go1.22.2.freebsd-386.tar.gz
|
||||
d753428296e6709527e291fd204700a587ffef2c0a472b21aebea11618245929 go1.22.2.freebsd-amd64.tar.gz
|
||||
586d9eb7fe0489ab297ad80dd06414997df487c5cf536c490ffeaa8d8f1807a7 go1.22.2.linux-386.tar.gz
|
||||
5901c52b7a78002aeff14a21f93e0f064f74ce1360fce51c6ee68cd471216a17 go1.22.2.linux-amd64.tar.gz
|
||||
36e720b2d564980c162a48c7e97da2e407dfcc4239e1e58d98082dfa2486a0c1 go1.22.2.linux-arm64.tar.gz
|
||||
9243dfafde06e1efe24d59df6701818e6786b4adfdf1191098050d6d023c5369 go1.22.2.linux-armv6l.tar.gz
|
||||
251a8886c5113be6490bdbb955ddee98763b49c9b1bf4c8364c02d3b482dab00 go1.22.2.linux-ppc64le.tar.gz
|
||||
2b39019481c28c560d65e9811a478ae10e3ef765e0f59af362031d386a71bfef go1.22.2.linux-s390x.tar.gz
|
||||
651753c06df037020ef4d162c5b273452e9ba976ed17ae39e66ef7ee89d8147e go1.22.2.windows-386.zip
|
||||
8e581cf330f49d3266e936521a2d8263679ef7e2fc2cbbceb85659122d883596 go1.22.2.windows-amd64.zip
|
||||
ddfca5beb9a0c62254266c3090c2555d899bf3e7aa26243e7de3621108f06875 go1.22.2.windows-arm64.zip
|
||||
fed720678e728a7ca30ba8d1ded1caafe27d16028fab0232b8ba8e22008fb784 go1.22.4.src.tar.gz
|
||||
b9647fa9fc83a0cc5d4f092a19eaeaecf45f063a5aa7d4962fde65aeb7ae6ce1 go1.22.4.aix-ppc64.tar.gz
|
||||
7788f40f3a46f201df1dc46ca640403eb535d5513fc33449164a90dbd229b761 go1.22.4.darwin-amd64.pkg
|
||||
c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 go1.22.4.darwin-amd64.tar.gz
|
||||
4036c88faf57a6b096916f1827edcdbf5290a47cc5f59956e88cdd9b1b71088c go1.22.4.darwin-arm64.pkg
|
||||
242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 go1.22.4.darwin-arm64.tar.gz
|
||||
f2fbb51af4719d3616efb482d6ed2b96579b474156f85a7ddc6f126764feec4b go1.22.4.dragonfly-amd64.tar.gz
|
||||
7c54884bb9f274884651d41e61d1bc12738863ad1497e97ea19ad0e9aa6bf7b5 go1.22.4.freebsd-386.tar.gz
|
||||
88d44500e1701dd35797619774d6dd51bf60f45a8338b0a82ddc018e4e63fb78 go1.22.4.freebsd-amd64.tar.gz
|
||||
3d9efe47db142a22679aba46b1772e3900b0d87ae13bd2b3bc80dbf2ac0b2cd6 go1.22.4.freebsd-arm.tar.gz
|
||||
726dc093cf020277be45debf03c3b02b43c2efb3e2a5d4fba8f52579d65327dc go1.22.4.freebsd-arm64.tar.gz
|
||||
5f6b67e5e32f1d6ccb2d4dcb44934a5e2e870a877ba7443d86ec43cfc28afa71 go1.22.4.freebsd-riscv64.tar.gz
|
||||
d56ecc2f85b6418a21ef83879594d0c42ab4f65391a676bb12254870e6690d63 go1.22.4.illumos-amd64.tar.gz
|
||||
47a2a8d249a91eb8605c33bceec63aedda0441a43eac47b4721e3975ff916cec go1.22.4.linux-386.tar.gz
|
||||
ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d go1.22.4.linux-amd64.tar.gz
|
||||
a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 go1.22.4.linux-arm64.tar.gz
|
||||
e2b143fbacbc9cbd448e9ef41ac3981f0488ce849af1cf37e2341d09670661de go1.22.4.linux-armv6l.tar.gz
|
||||
e2ff9436e4b34bf6926b06d97916e26d67a909a2effec17967245900f0816f1d go1.22.4.linux-loong64.tar.gz
|
||||
73f0dcc60458c4770593b05a7bc01cc0d31fc98f948c0c2334812c7a1f2fc3f1 go1.22.4.linux-mips.tar.gz
|
||||
417af97fc2630a647052375768be4c38adcc5af946352ea5b28613ea81ca5d45 go1.22.4.linux-mips64.tar.gz
|
||||
7486e2d7dd8c98eb44df815ace35a7fe7f30b7c02326e3741bd934077508139b go1.22.4.linux-mips64le.tar.gz
|
||||
69479c8aad301e459a8365b40cad1074a0dbba5defb9291669f94809c4c4be6e go1.22.4.linux-mipsle.tar.gz
|
||||
dd238847e65bc3e2745caca475a5db6522a2fcf85cf6c38fc36a06642b19efd7 go1.22.4.linux-ppc64.tar.gz
|
||||
a3e5834657ef92523f570f798fed42f1f87bc18222a16815ec76b84169649ec4 go1.22.4.linux-ppc64le.tar.gz
|
||||
56a827ff7dc6245bcd7a1e9288dffaa1d8b0fd7468562264c1523daf3b4f1b4a go1.22.4.linux-riscv64.tar.gz
|
||||
7590c3e278e2dc6040aae0a39da3ca1eb2e3921673a7304cc34d588c45889eec go1.22.4.linux-s390x.tar.gz
|
||||
ddd2eebe34471a2502de6c5dad04ab27c9fc80cbde7a9ad5b3c66ecec4504e1d go1.22.4.netbsd-386.tar.gz
|
||||
33af79f6f935f6fbacc5d23876450b3567b79348fc065beef8e64081127dd234 go1.22.4.netbsd-amd64.tar.gz
|
||||
fa3550ebd5375a70b3bcd342b5a71f4bd271dcbbfaf4eabefa2144ab5d8924b6 go1.22.4.netbsd-arm.tar.gz
|
||||
c9a2971dec9f6d320c6f2b049b2353c6d0a2d35e87b8a4b2d78a2f0d62545f8e go1.22.4.netbsd-arm64.tar.gz
|
||||
d21af022331bfdc2b5b161d616c3a1a4573d33cf7a30416ee509a8f3641deb47 go1.22.4.openbsd-386.tar.gz
|
||||
72c0094c43f7e5722ec49c2a3e9dfa7a1123ac43a5f3a63eecf3e3795d3ff0ae go1.22.4.openbsd-amd64.tar.gz
|
||||
1096831ea3c5ea3ca57d14251d9eda3786889531eb40d7d6775dcaa324d4b065 go1.22.4.openbsd-arm.tar.gz
|
||||
a7ab8d4e0b02bf06ed144ba42c61c0e93ee00f2b433415dfd4ad4b6e79f31650 go1.22.4.openbsd-arm64.tar.gz
|
||||
9716327c8a628358798898dc5148c49dbbeb5196bf2cbf088e550721a6e4f60b go1.22.4.openbsd-ppc64.tar.gz
|
||||
a8dd4503c95c32a502a616ab78870a19889c9325fe9bd31eb16dd69346e4bfa8 go1.22.4.plan9-386.tar.gz
|
||||
5423a25808d76fe5aca8607a2e5ac5673abf45446b168cb5e9d8519ee9fe39a1 go1.22.4.plan9-amd64.tar.gz
|
||||
6af939ad583f5c85c09c53728ab7d38c3cc2b39167562d6c18a07c5c6608b370 go1.22.4.plan9-arm.tar.gz
|
||||
e8cabe69c03085725afdb32a6f9998191a3e55a747b270d835fd05000d56abba go1.22.4.solaris-amd64.tar.gz
|
||||
5c6446e2ea80bc6a971d2b34446f16e6517e638b0ff8d3ea229228d1931790b0 go1.22.4.windows-386.msi
|
||||
aca4e2c37278a10f1c70dd0df142f7d66b50334fcee48978d409202d308d6d25 go1.22.4.windows-386.zip
|
||||
3c21105d7b584759b6e266383b777caf6e87142d304a10b539dbc66ab482bb5f go1.22.4.windows-amd64.msi
|
||||
26321c4d945a0035d8a5bc4a1965b0df401ff8ceac66ce2daadabf9030419a98 go1.22.4.windows-amd64.zip
|
||||
c4303f02b864304eb83dd1db0b4ebf9d2ec9d216e7ef44a7657b166a52889c7f go1.22.4.windows-arm.msi
|
||||
5fcd0671a49cecf39b41021621ee1b6e7aa1370f37122b72e80d4fd4185833b6 go1.22.4.windows-arm.zip
|
||||
553cc6c460f4e3eb4fad5b897c0bb22cd8bbeb20929f0e3eeb939420320292ce go1.22.4.windows-arm64.msi
|
||||
8a2daa9ea28cbdafddc6171aefed384f4e5b6e714fb52116fe9ed25a132f37ed go1.22.4.windows-arm64.zip
|
||||
|
||||
# version:golangci 1.55.2
|
||||
# version:golangci 1.59.0
|
||||
# https://github.com/golangci/golangci-lint/releases/
|
||||
# https://github.com/golangci/golangci-lint/releases/download/v1.55.2/
|
||||
632e96e6d5294fbbe7b2c410a49c8fa01c60712a0af85a567de85bcc1623ea21 golangci-lint-1.55.2-darwin-amd64.tar.gz
|
||||
234463f059249f82045824afdcdd5db5682d0593052f58f6a3039a0a1c3899f6 golangci-lint-1.55.2-darwin-arm64.tar.gz
|
||||
2bdd105e2d4e003a9058c33a22bb191a1e0f30fa0790acca0d8fbffac1d6247c golangci-lint-1.55.2-freebsd-386.tar.gz
|
||||
e75056e8b082386676ce23eba455cf893931a792c0d87e1e3743c0aec33c7fb5 golangci-lint-1.55.2-freebsd-amd64.tar.gz
|
||||
5789b933facaf6136bd23f1d50add67b79bbcf8dfdfc9069a37f729395940a66 golangci-lint-1.55.2-freebsd-armv6.tar.gz
|
||||
7f21ab1008d05f32c954f99470fc86a83a059e530fe2add1d0b7d8ed4d8992a7 golangci-lint-1.55.2-freebsd-armv7.tar.gz
|
||||
33ab06139b9219a28251f10821da94423db30285cc2af97494cbb2a281927de9 golangci-lint-1.55.2-illumos-amd64.tar.gz
|
||||
57ce6f8ce3ad6ee45d7cc3d9a047545a851c2547637834a3fcb086c7b40b1e6b golangci-lint-1.55.2-linux-386.tar.gz
|
||||
ca21c961a33be3bc15e4292dc40c98c8dcc5463a7b6768a3afc123761630c09c golangci-lint-1.55.2-linux-amd64.tar.gz
|
||||
8eb0cee9b1dbf0eaa49871798c7f8a5b35f2960c52d776a5f31eb7d886b92746 golangci-lint-1.55.2-linux-arm64.tar.gz
|
||||
3195f3e0f37d353fd5bd415cabcd4e263f5c29d3d0ffb176c26ff3d2c75eb3bb golangci-lint-1.55.2-linux-armv6.tar.gz
|
||||
c823ee36eb1a719e171de1f2f5ca3068033dce8d9817232fd10ed71fd6650406 golangci-lint-1.55.2-linux-armv7.tar.gz
|
||||
758a5d2a356dc494bd13ed4c0d4bf5a54a4dc91267ea5ecdd87b86c7ca0624e7 golangci-lint-1.55.2-linux-loong64.tar.gz
|
||||
2c7b9abdce7cae802a67d583cd7c6dca520bff6d0e17c8535a918e2f2b437aa0 golangci-lint-1.55.2-linux-mips64.tar.gz
|
||||
024e0a15b85352cc27271285526e16a4ab66d3e67afbbe446c9808c06cb8dbed golangci-lint-1.55.2-linux-mips64le.tar.gz
|
||||
6b00f89ba5506c1de1efdd9fa17c54093013a294fefd8b9b31534db626a672ee golangci-lint-1.55.2-linux-ppc64le.tar.gz
|
||||
0faa0d047d9bf7b703ed3ea65b6117043c93504f9ca1de25ae929d3901c73d4a golangci-lint-1.55.2-linux-riscv64.tar.gz
|
||||
30dec9b22e7d5bb4e9d5ccea96da20f71cd7db3c8cf30b8ddc7cb9174c4d742a golangci-lint-1.55.2-linux-s390x.tar.gz
|
||||
5a0ede48f79ad707902fdb29be8cd2abd8302dc122b65ebae3fdfc86751c7698 golangci-lint-1.55.2-netbsd-386.tar.gz
|
||||
95af20a2e617126dd5b08122ece7819101070e1582a961067ce8c41172f901ad golangci-lint-1.55.2-netbsd-amd64.tar.gz
|
||||
94fb7dacb7527847cc95d7120904e19a2a0a81a0d50d61766c9e0251da72ab9d golangci-lint-1.55.2-netbsd-armv6.tar.gz
|
||||
ca906bce5fee9619400e4a321c56476fe4a4efb6ac4fc989d340eb5563348873 golangci-lint-1.55.2-netbsd-armv7.tar.gz
|
||||
45b442f69fc8915c4500201c0247b7f3f69544dbc9165403a61f9095f2c57355 golangci-lint-1.55.2-windows-386.zip
|
||||
f57d434d231d43417dfa631587522f8c1991220b43c8ffadb9c7bd279508bf81 golangci-lint-1.55.2-windows-amd64.zip
|
||||
fd7dc8f4c6829ee6fafb252a4d81d2155cd35da7833665cbb25d53ce7cecd990 golangci-lint-1.55.2-windows-arm64.zip
|
||||
1892c3c24f9e7ef44b02f6750c703864b6dc350129f3ec39510300007b2376f1 golangci-lint-1.55.2-windows-armv6.zip
|
||||
a5e68ae73d38748b5269fad36ac7575e3c162a5dc63ef58abdea03cc5da4522a golangci-lint-1.55.2-windows-armv7.zip
|
||||
# https://github.com/golangci/golangci-lint/releases/download/v1.59.0/
|
||||
418acf7e255ddc0783e97129c9b03d9311b77826a5311d425a01c708a86417e7 golangci-lint-1.59.0-darwin-amd64.tar.gz
|
||||
5f6a1d95a6dd69f6e328eb56dd311a38e04cfab79a1305fbf4957f4e203f47b6 golangci-lint-1.59.0-darwin-arm64.tar.gz
|
||||
8899bf589185d49f747f3e5db9f0bde8a47245a100c64a3dd4d65e8e92cfc4f2 golangci-lint-1.59.0-freebsd-386.tar.gz
|
||||
658212f138d9df2ac89427e22115af34bf387c0871d70f2a25101718946a014f golangci-lint-1.59.0-freebsd-amd64.tar.gz
|
||||
4c6395ea40f314d3b6fa17d8997baab93464d5d1deeaab513155e625473bd03a golangci-lint-1.59.0-freebsd-armv6.tar.gz
|
||||
ff37da4fbaacdb6bbae70fdbdbb1ba932a859956f788c82822fa06bef5b7c6b3 golangci-lint-1.59.0-freebsd-armv7.tar.gz
|
||||
439739469ed2bda182b1ec276d40c40e02f195537f78e3672996741ad223d6b6 golangci-lint-1.59.0-illumos-amd64.tar.gz
|
||||
940801d46790e40d0a097d8fee34e2606f0ef148cd039654029b0b8750a15ed6 golangci-lint-1.59.0-linux-386.tar.gz
|
||||
3b14a439f33c4fff83dbe0349950d984042b9a1feb6c62f82787b598fc3ab5f4 golangci-lint-1.59.0-linux-amd64.tar.gz
|
||||
c57e6c0b0fa03089a2611dceddd5bc5d206716cccdff8b149da8baac598719a1 golangci-lint-1.59.0-linux-arm64.tar.gz
|
||||
93149e2d3b25ac754df9a23172403d8aa6d021a7e0d9c090a12f51897f68c9a0 golangci-lint-1.59.0-linux-armv6.tar.gz
|
||||
d10ac38239d9efee3ee87b55c96cdf3fa09e1a525babe3ffdaaf65ccc48cf3dc golangci-lint-1.59.0-linux-armv7.tar.gz
|
||||
047338114b4f0d5f08f0fb9a397b03cc171916ed0960be7dfb355c2320cd5e9c golangci-lint-1.59.0-linux-loong64.tar.gz
|
||||
5632df0f7f8fc03a80a266130faef0b5902d280cf60621f1b2bdc1aef6d97ee9 golangci-lint-1.59.0-linux-mips64.tar.gz
|
||||
71dd638c82fa4439171e7126d2c7a32b5d103bfdef282cea40c83632cb3d1f4b golangci-lint-1.59.0-linux-mips64le.tar.gz
|
||||
6cf9ea0d34e91669948483f9ae7f07da319a879344373a1981099fbd890cde00 golangci-lint-1.59.0-linux-ppc64le.tar.gz
|
||||
af0205fa6fbab197cee613c359947711231739095d21b5c837086233b36ad971 golangci-lint-1.59.0-linux-riscv64.tar.gz
|
||||
a9d2fb93f3c688ebccef94f5dc96c0b07c4d20bf6556cddebd8442159b0c80f6 golangci-lint-1.59.0-linux-s390x.tar.gz
|
||||
68ab4c57a847b8ace9679887f2f8b2b6760e57ee29dcde8c3f40dd8bb2654fa2 golangci-lint-1.59.0-netbsd-386.tar.gz
|
||||
d277b8b435c19406d00de4d509eadf5a024a5782878332e9a1b7c02bb76e87a7 golangci-lint-1.59.0-netbsd-amd64.tar.gz
|
||||
83211656be8dcfa1545af4f92894409f412d1f37566798cb9460a526593ad62c golangci-lint-1.59.0-netbsd-arm64.tar.gz
|
||||
6c6866d28bf79fa9817a0f7d2b050890ed109cae80bdb4dfa39536a7226da237 golangci-lint-1.59.0-netbsd-armv6.tar.gz
|
||||
11587566363bd03ca586b7df9776ccaed569fcd1f3489930ac02f9375b307503 golangci-lint-1.59.0-netbsd-armv7.tar.gz
|
||||
466181a8967bafa495e41494f93a0bec829c2cf715de874583b0460b3b8ae2b8 golangci-lint-1.59.0-windows-386.zip
|
||||
3317d8a87a99a49a0a1321d295c010790e6dbf43ee96b318f4b8bb23eae7a565 golangci-lint-1.59.0-windows-amd64.zip
|
||||
b3af955c7fceac8220a36fc799e1b3f19d3b247d32f422caac5f9845df8f7316 golangci-lint-1.59.0-windows-arm64.zip
|
||||
6f083c7d0c764e5a0e5bde46ee3e91ae357d80c194190fe1d9754392e9064c7e golangci-lint-1.59.0-windows-armv6.zip
|
||||
3709b4dd425deadab27748778d08e03c0f804d7748f7dd5b6bb488d98aa031c7 golangci-lint-1.59.0-windows-armv7.zip
|
||||
|
||||
# This is the builder on PPA that will build Go itself (inception-y), don't modify!
|
||||
#
|
||||
# This version is fine to be old and full of security holes, we just use it
|
||||
# to build the latest Go. Don't change it. If it ever becomes insufficient,
|
||||
# we need to switch over to a recursive builder to jump across supported
|
||||
# versions.
|
||||
# to build the latest Go. Don't change it.
|
||||
#
|
||||
# version:ppa-builder 1.19.6
|
||||
# version:ppa-builder-1 1.19.6
|
||||
# https://go.dev/dl/
|
||||
d7f0013f82e6d7f862cc6cb5c8cdb48eef5f2e239b35baa97e2f1a7466043767 go1.19.6.src.tar.gz
|
||||
|
||||
# version:ppa-builder-2 1.21.9
|
||||
# https://go.dev/dl/
|
||||
58f0c5ced45a0012bce2ff7a9df03e128abcc8818ebabe5027bb92bafe20e421 go1.21.9.src.tar.gz
|
||||
|
||||
# version:protoc 27.1
|
||||
# https://github.com/protocolbuffers/protobuf/releases/
|
||||
# https://github.com/protocolbuffers/protobuf/releases/download/v27.1/
|
||||
8809c2ec85368c6b6e9af161b6771a153aa92670a24adbe46dd34fa02a04df2f protoc-27.1-linux-aarch_64.zip
|
||||
5d21979a6d27475e810b76b88863d1e784fa01ffb15e511a3ec5bd1924d89426 protoc-27.1-linux-ppcle_64.zip
|
||||
84d8852750ed186dc4a057a1a86bcac409be5362d6af04770f42367fee6b7bc1 protoc-27.1-linux-s390_64.zip
|
||||
2f028796ff5741691650e0eea290e61ff2f1c0d87f8d31fe45ef47fd967cef0c protoc-27.1-linux-x86_32.zip
|
||||
8970e3d8bbd67d53768fe8c2e3971bdd71e51cfe2001ca06dacad17258a7dae3 protoc-27.1-linux-x86_64.zip
|
||||
03b7af1bf469e7285dc51976ee5fa99412704dbd1c017105114852a37b165c12 protoc-27.1-osx-aarch_64.zip
|
||||
f14d3973cf13283d07c520ed6f4c12405ad41b9efd18089a1c74897037d742b5 protoc-27.1-osx-universal_binary.zip
|
||||
8520d944f3a3890fa296a3b3b0d4bb18337337e2526bbbf1b507eeea3c2a1ec4 protoc-27.1-osx-x86_64.zip
|
||||
6263718ff96547b8392a079f6fdf02a4156f2e8d13cd51649a0d03fb7afa2de8 protoc-27.1-win32.zip
|
||||
da531c51ccd1290d8d34821f0ce4e219c7fbaa6f9825f5a3fb092a9d03fe6206 protoc-27.1-win64.zip
|
||||
|
||||
# version:protoc-gen-go 1.34.2
|
||||
# https://github.com/protocolbuffers/protobuf-go/releases/
|
||||
# https://github.com/protocolbuffers/protobuf-go/releases/download/v1.34.2/
|
||||
9b48d8f90add02e8e94e14962fed74e7ce2b2d6bda4dd42f1f4fbccf0f766f1a protoc-gen-go.v1.34.2.darwin.amd64.tar.gz
|
||||
17aca7f948dbb624049030cf841e35895cf34183ba006e721247fdeb95ff2780 protoc-gen-go.v1.34.2.darwin.arm64.tar.gz
|
||||
a191849433fd489f1d44f37788d762658f3f5fb225f3a85d4ce6ba32666703ed protoc-gen-go.v1.34.2.linux.386.tar.gz
|
||||
b87bc134dee55576a842141bf0ed27761c635d746780fce5dee038c6dd16554f protoc-gen-go.v1.34.2.linux.amd64.tar.gz
|
||||
63d400167e75ab9f6690688f6fdc6a9455aa20bc1faa71e32149dbd322f7f198 protoc-gen-go.v1.34.2.linux.arm64.tar.gz
|
||||
56e7675816db6e62be4f833a51544d5716b8420c462515579e05ca8444ab06ed protoc-gen-go.v1.34.2.windows.386.zip
|
||||
abafd39612177dd4e9a65207cadd5374a9352d8611e8e040f8462fcfa3010daf protoc-gen-go.v1.34.2.windows.amd64.zip
|
||||
|
||||
270
build/ci.go
270
build/ci.go
@@ -39,9 +39,11 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -117,23 +119,15 @@ var (
|
||||
debEthereum,
|
||||
}
|
||||
|
||||
// Distros for which packages are created.
|
||||
// Note: vivid is unsupported because there is no golang-1.6 package for it.
|
||||
// Note: the following Ubuntu releases have been officially deprecated on Launchpad:
|
||||
// wily, yakkety, zesty, artful, cosmic, disco, eoan, groovy, hirsuite, impish,
|
||||
// kinetic, lunar
|
||||
debDistroGoBoots = map[string]string{
|
||||
"trusty": "golang-1.11", // 14.04, EOL: 04/2024
|
||||
"xenial": "golang-go", // 16.04, EOL: 04/2026
|
||||
"bionic": "golang-go", // 18.04, EOL: 04/2028
|
||||
"focal": "golang-go", // 20.04, EOL: 04/2030
|
||||
"jammy": "golang-go", // 22.04, EOL: 04/2032
|
||||
"mantic": "golang-go", // 23.10, EOL: 07/2024
|
||||
}
|
||||
// Distros for which packages are created
|
||||
debDistros = []string{
|
||||
"xenial", // 16.04, EOL: 04/2026
|
||||
"bionic", // 18.04, EOL: 04/2028
|
||||
"focal", // 20.04, EOL: 04/2030
|
||||
"jammy", // 22.04, EOL: 04/2032
|
||||
"noble", // 24.04, EOL: 04/2034
|
||||
|
||||
debGoBootPaths = map[string]string{
|
||||
"golang-1.11": "/usr/lib/go-1.11",
|
||||
"golang-go": "/usr/lib/go",
|
||||
"mantic", // 23.10, EOL: 07/2024
|
||||
}
|
||||
|
||||
// This is where the tests should be unpacked.
|
||||
@@ -177,6 +171,8 @@ func main() {
|
||||
doPurge(os.Args[2:])
|
||||
case "sanitycheck":
|
||||
doSanityCheck()
|
||||
case "generate":
|
||||
doGenerate()
|
||||
default:
|
||||
log.Fatal("unknown command ", os.Args[1])
|
||||
}
|
||||
@@ -353,6 +349,86 @@ func downloadSpecTestFixtures(csdb *build.ChecksumDB, cachedir string) string {
|
||||
return filepath.Join(cachedir, base)
|
||||
}
|
||||
|
||||
// hashSourceFiles iterates all files under the top-level project directory
|
||||
// computing the hash of each file (excluding files within the tests
|
||||
// subrepo)
|
||||
func hashSourceFiles() (map[string]common.Hash, error) {
|
||||
res := make(map[string]common.Hash)
|
||||
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
|
||||
if strings.HasPrefix(path, filepath.FromSlash("tests/testdata")) {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
if !d.Type().IsRegular() {
|
||||
return nil
|
||||
}
|
||||
// open the file and hash it
|
||||
f, err := os.OpenFile(path, os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hasher := sha256.New()
|
||||
if _, err := io.Copy(hasher, f); err != nil {
|
||||
return err
|
||||
}
|
||||
res[path] = common.Hash(hasher.Sum(nil))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// doGenerate ensures that re-generating generated files does not cause
|
||||
// any mutations in the source file tree: i.e. all generated files were
|
||||
// updated and committed. Any stale generated files are updated.
|
||||
func doGenerate() {
|
||||
var (
|
||||
tc = new(build.GoToolchain)
|
||||
cachedir = flag.String("cachedir", "./build/cache", "directory for caching binaries.")
|
||||
verify = flag.Bool("verify", false, "check whether any files are changed by go generate")
|
||||
)
|
||||
|
||||
protocPath := downloadProtoc(*cachedir)
|
||||
protocGenGoPath := downloadProtocGenGo(*cachedir)
|
||||
|
||||
var preHashes map[string]common.Hash
|
||||
if *verify {
|
||||
var err error
|
||||
preHashes, err = hashSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("failed to compute map of source hashes", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
c := tc.Go("generate", "./...")
|
||||
pathList := []string{filepath.Join(protocPath, "bin"), protocGenGoPath, os.Getenv("PATH")}
|
||||
c.Env = append(c.Env, "PATH="+strings.Join(pathList, string(os.PathListSeparator)))
|
||||
build.MustRun(c)
|
||||
|
||||
if !*verify {
|
||||
return
|
||||
}
|
||||
// Check if files were changed.
|
||||
postHashes, err := hashSourceFiles()
|
||||
if err != nil {
|
||||
log.Fatal("error computing source tree file hashes", "err", err)
|
||||
}
|
||||
updates := []string{}
|
||||
for path, postHash := range postHashes {
|
||||
preHash, ok := preHashes[path]
|
||||
if !ok || preHash != postHash {
|
||||
updates = append(updates, path)
|
||||
}
|
||||
}
|
||||
for _, updatedFile := range updates {
|
||||
fmt.Fprintf(os.Stderr, "changed file %s\n", updatedFile)
|
||||
}
|
||||
if len(updates) != 0 {
|
||||
log.Fatal("One or more generated files were updated by running 'go generate ./...'")
|
||||
}
|
||||
}
|
||||
|
||||
// doLint runs golangci-lint on requested packages.
|
||||
func doLint(cmdline []string) {
|
||||
var (
|
||||
@@ -398,6 +474,96 @@ func downloadLinter(cachedir string) string {
|
||||
return filepath.Join(cachedir, base, "golangci-lint")
|
||||
}
|
||||
|
||||
// protocArchiveBaseName returns the name of the protoc archive file for
|
||||
// the current system, stripped of version and file suffix.
|
||||
func protocArchiveBaseName() (string, error) {
|
||||
switch runtime.GOOS + "-" + runtime.GOARCH {
|
||||
case "windows-amd64":
|
||||
return "win64", nil
|
||||
case "windows-386":
|
||||
return "win32", nil
|
||||
case "linux-arm64":
|
||||
return "linux-aarch_64", nil
|
||||
case "linux-386":
|
||||
return "linux-x86_32", nil
|
||||
case "linux-amd64":
|
||||
return "linux-x86_64", nil
|
||||
case "darwin-arm64":
|
||||
return "osx-aarch_64", nil
|
||||
case "darwin-amd64":
|
||||
return "osx-x86_64", nil
|
||||
default:
|
||||
return "", fmt.Errorf("no prebuilt release of protoc available for this system (os: %s, arch: %s)", runtime.GOOS, runtime.GOARCH)
|
||||
}
|
||||
}
|
||||
|
||||
// downloadProtocGenGo downloads protoc-gen-go, which is used by protoc
|
||||
// in the generate command. It returns the full path of the directory
|
||||
// containing the 'protoc-gen-go' executable.
|
||||
func downloadProtocGenGo(cachedir string) string {
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
version, err := build.Version(csdb, "protoc-gen-go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
baseName := fmt.Sprintf("protoc-gen-go.v%s.%s.%s", version, runtime.GOOS, runtime.GOARCH)
|
||||
archiveName := baseName
|
||||
if runtime.GOOS == "windows" {
|
||||
archiveName += ".zip"
|
||||
} else {
|
||||
archiveName += ".tar.gz"
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf-go/releases/download/v%s/%s", version, archiveName)
|
||||
|
||||
archivePath := path.Join(cachedir, archiveName)
|
||||
if err := csdb.DownloadFile(url, archivePath); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest := filepath.Join(cachedir, baseName)
|
||||
if err := build.ExtractArchive(archivePath, extractDest); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest, err = filepath.Abs(extractDest)
|
||||
if err != nil {
|
||||
log.Fatal("error resolving absolute path for protoc", "err", err)
|
||||
}
|
||||
return extractDest
|
||||
}
|
||||
|
||||
// downloadProtoc downloads the prebuilt protoc binary used to lint generated
|
||||
// files as a CI step. It returns the full path to the directory containing
|
||||
// the protoc executable.
|
||||
func downloadProtoc(cachedir string) string {
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
version, err := build.Version(csdb, "protoc")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
baseName, err := protocArchiveBaseName()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fileName := fmt.Sprintf("protoc-%s-%s", version, baseName)
|
||||
archiveFileName := fileName + ".zip"
|
||||
url := fmt.Sprintf("https://github.com/protocolbuffers/protobuf/releases/download/v%s/%s", version, archiveFileName)
|
||||
archivePath := filepath.Join(cachedir, archiveFileName)
|
||||
|
||||
if err := csdb.DownloadFile(url, archivePath); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest := filepath.Join(cachedir, fileName)
|
||||
if err := build.ExtractArchive(archivePath, extractDest); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
extractDest, err = filepath.Abs(extractDest)
|
||||
if err != nil {
|
||||
log.Fatal("error resolving absolute path for protoc", "err", err)
|
||||
}
|
||||
return extractDest
|
||||
}
|
||||
|
||||
// Release Packaging
|
||||
func doArchive(cmdline []string) {
|
||||
var (
|
||||
@@ -694,8 +860,8 @@ func doDebianSource(cmdline []string) {
|
||||
}
|
||||
// Download and verify the Go source packages.
|
||||
var (
|
||||
gobootbundle = downloadGoBootstrapSources(*cachedir)
|
||||
gobundle = downloadGoSources(*cachedir)
|
||||
gobootbundles = downloadGoBootstrapSources(*cachedir)
|
||||
gobundle = downloadGoSources(*cachedir)
|
||||
)
|
||||
// Download all the dependencies needed to build the sources and run the ci script
|
||||
srcdepfetch := tc.Go("mod", "download")
|
||||
@@ -708,17 +874,19 @@ func doDebianSource(cmdline []string) {
|
||||
|
||||
// Create Debian packages and upload them.
|
||||
for _, pkg := range debPackages {
|
||||
for distro, goboot := range debDistroGoBoots {
|
||||
for _, distro := range debDistros {
|
||||
// Prepare the debian package with the go-ethereum sources.
|
||||
meta := newDebMetadata(distro, goboot, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
|
||||
meta := newDebMetadata(distro, *signer, env, now, pkg.Name, pkg.Version, pkg.Executables)
|
||||
pkgdir := stageDebianSource(*workdir, meta)
|
||||
|
||||
// Add bootstrapper Go source code
|
||||
if err := build.ExtractArchive(gobootbundle, pkgdir); err != nil {
|
||||
log.Fatalf("Failed to extract bootstrapper Go sources: %v", err)
|
||||
}
|
||||
if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, ".goboot")); err != nil {
|
||||
log.Fatalf("Failed to rename bootstrapper Go source folder: %v", err)
|
||||
for i, gobootbundle := range gobootbundles {
|
||||
if err := build.ExtractArchive(gobootbundle, pkgdir); err != nil {
|
||||
log.Fatalf("Failed to extract bootstrapper Go sources: %v", err)
|
||||
}
|
||||
if err := os.Rename(filepath.Join(pkgdir, "go"), filepath.Join(pkgdir, fmt.Sprintf(".goboot-%d", i+1))); err != nil {
|
||||
log.Fatalf("Failed to rename bootstrapper Go source folder: %v", err)
|
||||
}
|
||||
}
|
||||
// Add builder Go source code
|
||||
if err := build.ExtractArchive(gobundle, pkgdir); err != nil {
|
||||
@@ -754,21 +922,26 @@ func doDebianSource(cmdline []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// downloadGoBootstrapSources downloads the Go source tarball that will be used
|
||||
// downloadGoBootstrapSources downloads the Go source tarball(s) that will be used
|
||||
// to bootstrap the builder Go.
|
||||
func downloadGoBootstrapSources(cachedir string) string {
|
||||
func downloadGoBootstrapSources(cachedir string) []string {
|
||||
csdb := build.MustLoadChecksums("build/checksums.txt")
|
||||
gobootVersion, err := build.Version(csdb, "ppa-builder")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
|
||||
var bundles []string
|
||||
for _, booter := range []string{"ppa-builder-1", "ppa-builder-2"} {
|
||||
gobootVersion, err := build.Version(csdb, booter)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
|
||||
url := "https://dl.google.com/go/" + file
|
||||
dst := filepath.Join(cachedir, file)
|
||||
if err := csdb.DownloadFile(url, dst); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
bundles = append(bundles, dst)
|
||||
}
|
||||
file := fmt.Sprintf("go%s.src.tar.gz", gobootVersion)
|
||||
url := "https://dl.google.com/go/" + file
|
||||
dst := filepath.Join(cachedir, file)
|
||||
if err := csdb.DownloadFile(url, dst); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return dst
|
||||
return bundles
|
||||
}
|
||||
|
||||
// downloadGoSources downloads the Go source tarball.
|
||||
@@ -846,10 +1019,7 @@ type debPackage struct {
|
||||
}
|
||||
|
||||
type debMetadata struct {
|
||||
Env build.Environment
|
||||
GoBootPackage string
|
||||
GoBootPath string
|
||||
|
||||
Env build.Environment
|
||||
PackageName string
|
||||
|
||||
// go-ethereum version being built. Note that this
|
||||
@@ -877,21 +1047,19 @@ func (d debExecutable) Package() string {
|
||||
return d.BinaryName
|
||||
}
|
||||
|
||||
func newDebMetadata(distro, goboot, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata {
|
||||
func newDebMetadata(distro, author string, env build.Environment, t time.Time, name string, version string, exes []debExecutable) debMetadata {
|
||||
if author == "" {
|
||||
// No signing key, use default author.
|
||||
author = "Ethereum Builds <fjl@ethereum.org>"
|
||||
}
|
||||
return debMetadata{
|
||||
GoBootPackage: goboot,
|
||||
GoBootPath: debGoBootPaths[goboot],
|
||||
PackageName: name,
|
||||
Env: env,
|
||||
Author: author,
|
||||
Distro: distro,
|
||||
Version: version,
|
||||
Time: t.Format(time.RFC1123Z),
|
||||
Executables: exes,
|
||||
PackageName: name,
|
||||
Env: env,
|
||||
Author: author,
|
||||
Distro: distro,
|
||||
Version: version,
|
||||
Time: t.Format(time.RFC1123Z),
|
||||
Executables: exes,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ Source: {{.Name}}
|
||||
Section: science
|
||||
Priority: extra
|
||||
Maintainer: {{.Author}}
|
||||
Build-Depends: debhelper (>= 8.0.0), {{.GoBootPackage}}
|
||||
Build-Depends: debhelper (>= 8.0.0), golang-go
|
||||
Standards-Version: 3.9.5
|
||||
Homepage: https://ethereum.org
|
||||
Vcs-Git: https://github.com/ethereum/go-ethereum.git
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# Launchpad rejects Go's access to $HOME, use custom folders
|
||||
export GOCACHE=/tmp/go-build
|
||||
export GOPATH=/tmp/gopath
|
||||
export GOROOT_BOOTSTRAP={{.GoBootPath}}
|
||||
export GOROOT_BOOTSTRAP=/usr/lib/go
|
||||
|
||||
override_dh_auto_clean:
|
||||
# Don't try to be smart Launchpad, we know our build rules better than you
|
||||
@@ -19,8 +19,9 @@ override_dh_auto_build:
|
||||
#
|
||||
# We're also shipping the bootstrapper as of Go 1.20 as it had minimum version
|
||||
# requirements opposed to older versions of Go.
|
||||
(mv .goboot ../ && cd ../.goboot/src && ./make.bash)
|
||||
(mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot ./make.bash)
|
||||
(mv .goboot-1 ../ && cd ../.goboot-1/src && ./make.bash)
|
||||
(mv .goboot-2 ../ && cd ../.goboot-2/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-1 ./make.bash)
|
||||
(mv .go ../ && cd ../.go/src && GOROOT_BOOTSTRAP=`pwd`/../../.goboot-2 ./make.bash)
|
||||
|
||||
# We can't download external go modules within Launchpad, so we're shipping the
|
||||
# entire dependency source cache with go-ethereum.
|
||||
|
||||
@@ -19,39 +19,21 @@ package main
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/ethereum/go-ethereum/beacon/blsync"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
"github.com/ethereum/go-ethereum/internal/debug"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/mattn/go-isatty"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var (
|
||||
verbosityFlag = &cli.IntFlag{
|
||||
Name: "verbosity",
|
||||
Usage: "Logging verbosity: 0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail",
|
||||
Value: 3,
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
vmoduleFlag = &cli.StringFlag{
|
||||
Name: "vmodule",
|
||||
Usage: "Per-module verbosity: comma-separated list of <pattern>=<level> (e.g. eth/*=5,p2p=4)",
|
||||
Value: "",
|
||||
Hidden: true,
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
app := flags.NewApp("beacon light syncer tool")
|
||||
app.Flags = []cli.Flag{
|
||||
app.Flags = flags.Merge([]cli.Flag{
|
||||
utils.BeaconApiFlag,
|
||||
utils.BeaconApiHeaderFlag,
|
||||
utils.BeaconThresholdFlag,
|
||||
@@ -66,8 +48,16 @@ func main() {
|
||||
utils.GoerliFlag,
|
||||
utils.BlsyncApiFlag,
|
||||
utils.BlsyncJWTSecretFlag,
|
||||
verbosityFlag,
|
||||
vmoduleFlag,
|
||||
},
|
||||
debug.Flags,
|
||||
)
|
||||
app.Before = func(ctx *cli.Context) error {
|
||||
flags.MigrateGlobalFlags(ctx)
|
||||
return debug.Setup(ctx)
|
||||
}
|
||||
app.After = func(ctx *cli.Context) error {
|
||||
debug.Exit()
|
||||
return nil
|
||||
}
|
||||
app.Action = sync
|
||||
|
||||
@@ -78,14 +68,6 @@ func main() {
|
||||
}
|
||||
|
||||
func sync(ctx *cli.Context) error {
|
||||
usecolor := (isatty.IsTerminal(os.Stderr.Fd()) || isatty.IsCygwinTerminal(os.Stderr.Fd())) && os.Getenv("TERM") != "dumb"
|
||||
output := io.Writer(os.Stderr)
|
||||
if usecolor {
|
||||
output = colorable.NewColorable(os.Stderr)
|
||||
}
|
||||
verbosity := log.FromLegacyLevel(ctx.Int(verbosityFlag.Name))
|
||||
log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(output, verbosity, usecolor)))
|
||||
|
||||
// set up blsync
|
||||
client := blsync.NewClient(ctx)
|
||||
client.SetEngineRPC(makeRPCClient(ctx))
|
||||
|
||||
@@ -225,8 +225,8 @@ Response
|
||||
- `value` [number:optional]: amount of Wei to send with the transaction
|
||||
- `data` [data:optional]: input data
|
||||
- `nonce` [number]: account nonce
|
||||
1. method signature [string:optional]
|
||||
- The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
|
||||
2. method signature [string:optional]
|
||||
- The method signature, if present, is to aid decoding the calldata. Should consist of `methodname(paramtype,...)`, e.g. `transfer(uint256,address)`. The signer may use this data to parse the supplied calldata, and show the user. The data, however, is considered totally untrusted, and reliability is not expected.
|
||||
|
||||
|
||||
#### Result
|
||||
|
||||
@@ -552,7 +552,7 @@ func listWallets(c *cli.Context) error {
|
||||
// accountImport imports a raw hexadecimal private key via CLI.
|
||||
func accountImport(c *cli.Context) error {
|
||||
if c.Args().Len() != 1 {
|
||||
return errors.New("<keyfile> must be given as first argument.")
|
||||
return errors.New("<keyfile> must be given as first argument")
|
||||
}
|
||||
internalApi, ui, err := initInternalApi(c)
|
||||
if err != nil {
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -28,9 +29,11 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -45,6 +48,7 @@ var (
|
||||
discv4ResolveJSONCommand,
|
||||
discv4CrawlCommand,
|
||||
discv4TestCommand,
|
||||
discv4ListenCommand,
|
||||
},
|
||||
}
|
||||
discv4PingCommand = &cli.Command{
|
||||
@@ -75,6 +79,14 @@ var (
|
||||
Flags: discoveryNodeFlags,
|
||||
ArgsUsage: "<nodes.json file>",
|
||||
}
|
||||
discv4ListenCommand = &cli.Command{
|
||||
Name: "listen",
|
||||
Usage: "Runs a discovery node",
|
||||
Action: discv4Listen,
|
||||
Flags: flags.Merge(discoveryNodeFlags, []cli.Flag{
|
||||
httpAddrFlag,
|
||||
}),
|
||||
}
|
||||
discv4CrawlCommand = &cli.Command{
|
||||
Name: "crawl",
|
||||
Usage: "Updates a nodes.json file with random nodes found in the DHT",
|
||||
@@ -131,6 +143,10 @@ var (
|
||||
Usage: "Enode of the remote node under test",
|
||||
EnvVars: []string{"REMOTE_ENODE"},
|
||||
}
|
||||
httpAddrFlag = &cli.StringFlag{
|
||||
Name: "rpc",
|
||||
Usage: "HTTP server listening address",
|
||||
}
|
||||
)
|
||||
|
||||
var discoveryNodeFlags = []cli.Flag{
|
||||
@@ -154,6 +170,27 @@ func discv4Ping(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func discv4Listen(ctx *cli.Context) error {
|
||||
disc, _ := startV4(ctx)
|
||||
defer disc.Close()
|
||||
|
||||
fmt.Println(disc.Self())
|
||||
|
||||
httpAddr := ctx.String(httpAddrFlag.Name)
|
||||
if httpAddr == "" {
|
||||
// Non-HTTP mode.
|
||||
select {}
|
||||
}
|
||||
|
||||
api := &discv4API{disc}
|
||||
log.Info("Starting RPC API server", "addr", httpAddr)
|
||||
srv := rpc.NewServer()
|
||||
srv.RegisterName("discv4", api)
|
||||
http.DefaultServeMux.Handle("/", srv)
|
||||
httpsrv := http.Server{Addr: httpAddr, Handler: http.DefaultServeMux}
|
||||
return httpsrv.ListenAndServe()
|
||||
}
|
||||
|
||||
func discv4RequestRecord(ctx *cli.Context) error {
|
||||
n := getNodeArg(ctx)
|
||||
disc, _ := startV4(ctx)
|
||||
@@ -362,3 +399,23 @@ func parseBootnodes(ctx *cli.Context) ([]*enode.Node, error) {
|
||||
}
|
||||
return nodes, nil
|
||||
}
|
||||
|
||||
type discv4API struct {
|
||||
host *discover.UDPv4
|
||||
}
|
||||
|
||||
func (api *discv4API) LookupRandom(n int) (ns []*enode.Node) {
|
||||
it := api.host.RandomNodes()
|
||||
for len(ns) < n && it.Next() {
|
||||
ns = append(ns, it.Node())
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (api *discv4API) Buckets() [][]discover.BucketNode {
|
||||
return api.host.TableBuckets()
|
||||
}
|
||||
|
||||
func (api *discv4API) Self() *enode.Node {
|
||||
return api.host.Self()
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@ func (s *Suite) dial() (*Conn, error) {
|
||||
// dialAs attempts to dial a given node and perform a handshake using the given
|
||||
// private key.
|
||||
func (s *Suite) dialAs(key *ecdsa.PrivateKey) (*Conn, error) {
|
||||
fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP()))
|
||||
tcpEndpoint, _ := s.Dest.TCPEndpoint()
|
||||
fd, err := net.Dial("tcp", tcpEndpoint.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
func (c *Conn) snapRequest(code uint64, msg any) (any, error) {
|
||||
@@ -905,7 +904,7 @@ func (s *Suite) snapGetByteCodes(t *utesting.T, tc *byteCodesTest) error {
|
||||
// that the serving node is missing
|
||||
var (
|
||||
bytecodes = res.Codes
|
||||
hasher = sha3.NewLegacyKeccak256().(crypto.KeccakState)
|
||||
hasher = crypto.NewKeccakState()
|
||||
hash = make([]byte, 32)
|
||||
codes = make([][]byte, len(req.Hashes))
|
||||
)
|
||||
@@ -964,7 +963,7 @@ func (s *Suite) snapGetTrieNodes(t *utesting.T, tc *trieNodesTest) error {
|
||||
|
||||
// Cross reference the requested trienodes with the response to find gaps
|
||||
// that the serving node is missing
|
||||
hasher := sha3.NewLegacyKeccak256().(crypto.KeccakState)
|
||||
hasher := crypto.NewKeccakState()
|
||||
hash := make([]byte, 32)
|
||||
trienodes := res.Nodes
|
||||
if got, want := len(trienodes), len(tc.expHashes); got != want {
|
||||
|
||||
@@ -53,16 +53,18 @@ func newTestEnv(remote string, listen1, listen2 string) *testenv {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if node.IP() == nil || node.UDP() == 0 {
|
||||
if !node.IPAddr().IsValid() || node.UDP() == 0 {
|
||||
var ip net.IP
|
||||
var tcpPort, udpPort int
|
||||
if ip = node.IP(); ip == nil {
|
||||
if node.IPAddr().IsValid() {
|
||||
ip = node.IPAddr().AsSlice()
|
||||
} else {
|
||||
ip = net.ParseIP("127.0.0.1")
|
||||
}
|
||||
if tcpPort = node.TCP(); tcpPort == 0 {
|
||||
tcpPort = 30303
|
||||
}
|
||||
if udpPort = node.TCP(); udpPort == 0 {
|
||||
if udpPort = node.UDP(); udpPort == 0 {
|
||||
udpPort = 30303
|
||||
}
|
||||
node = enode.NewV4(node.Pubkey(), ip, tcpPort, udpPort)
|
||||
@@ -110,7 +112,7 @@ func (te *testenv) localEndpoint(c net.PacketConn) v4wire.Endpoint {
|
||||
}
|
||||
|
||||
func (te *testenv) remoteEndpoint() v4wire.Endpoint {
|
||||
return v4wire.NewEndpoint(te.remoteAddr, 0)
|
||||
return v4wire.NewEndpoint(te.remoteAddr.AddrPort(), 0)
|
||||
}
|
||||
|
||||
func contains(ns []v4wire.Node, key v4wire.Pubkey) bool {
|
||||
|
||||
@@ -19,7 +19,7 @@ package main
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -205,11 +205,11 @@ func trueFilter(args []string) (nodeFilter, error) {
|
||||
}
|
||||
|
||||
func ipFilter(args []string) (nodeFilter, error) {
|
||||
_, cidr, err := net.ParseCIDR(args[0])
|
||||
prefix, err := netip.ParsePrefix(args[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f := func(n nodeJSON) bool { return cidr.Contains(n.N.IP()) }
|
||||
f := func(n nodeJSON) bool { return prefix.Contains(n.N.IPAddr()) }
|
||||
return f, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,11 @@ var (
|
||||
|
||||
func rlpxPing(ctx *cli.Context) error {
|
||||
n := getNodeArg(ctx)
|
||||
fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", n.IP(), n.TCP()))
|
||||
tcpEndpoint, ok := n.TCPEndpoint()
|
||||
if !ok {
|
||||
return fmt.Errorf("node has no TCP endpoint")
|
||||
}
|
||||
fd, err := net.Dial("tcp", tcpEndpoint.String())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -105,7 +109,7 @@ func rlpxPing(ctx *cli.Context) error {
|
||||
}
|
||||
return fmt.Errorf("received disconnect message: %v", msg[0])
|
||||
default:
|
||||
return fmt.Errorf("invalid message code %d, expected handshake (code zero)", code)
|
||||
return fmt.Errorf("invalid message code %d, expected handshake (code zero) or disconnect (code one)", code)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,15 +14,15 @@ The `evm t8n` tool is a stateless state transition utility. It is a utility
|
||||
which can
|
||||
|
||||
1. Take a prestate, including
|
||||
- Accounts,
|
||||
- Block context information,
|
||||
- Previous blockshashes (*optional)
|
||||
- Accounts,
|
||||
- Block context information,
|
||||
- Previous blockshashes (*optional)
|
||||
2. Apply a set of transactions,
|
||||
3. Apply a mining-reward (*optional),
|
||||
4. And generate a post-state, including
|
||||
- State root, transaction root, receipt root,
|
||||
- Information about rejected transactions,
|
||||
- Optionally: a full or partial post-state dump
|
||||
- State root, transaction root, receipt root,
|
||||
- Information about rejected transactions,
|
||||
- Optionally: a full or partial post-state dump
|
||||
|
||||
### Specification
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ func blockTestCmd(ctx *cli.Context) error {
|
||||
continue
|
||||
}
|
||||
test := tests[name]
|
||||
if err := test.Run(false, rawdb.HashScheme, tracer, func(res error, chain *core.BlockChain) {
|
||||
if err := test.Run(false, rawdb.HashScheme, false, tracer, func(res error, chain *core.BlockChain) {
|
||||
if ctx.Bool(DumpFlag.Name) {
|
||||
if state, _ := chain.State(); state != nil {
|
||||
fmt.Println(string(state.Dump(nil)))
|
||||
|
||||
@@ -160,7 +160,7 @@ func (i *bbInput) ToBlock() *types.Block {
|
||||
if i.Header.Difficulty != nil {
|
||||
header.Difficulty = i.Header.Difficulty
|
||||
}
|
||||
return types.NewBlockWithHeader(header).WithBody(i.Txs, i.Ommers).WithWithdrawals(i.Withdrawals)
|
||||
return types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: i.Txs, Uncles: i.Ommers, Withdrawals: i.Withdrawals})
|
||||
}
|
||||
|
||||
// SealBlock seals the given block using the configured engine.
|
||||
|
||||
@@ -306,7 +306,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
if tracer.Hooks.OnTxEnd != nil {
|
||||
tracer.Hooks.OnTxEnd(receipt, nil)
|
||||
}
|
||||
writeTraceResult(tracer, traceOutput)
|
||||
if err = writeTraceResult(tracer, traceOutput); err != nil {
|
||||
log.Warn("Error writing tracer output", "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,7 +325,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
var (
|
||||
blockReward = big.NewInt(miningReward)
|
||||
minerReward = new(big.Int).Set(blockReward)
|
||||
perOmmer = new(big.Int).Div(blockReward, big.NewInt(32))
|
||||
perOmmer = new(big.Int).Rsh(blockReward, 5)
|
||||
)
|
||||
for _, ommer := range pre.Env.Ommers {
|
||||
// Add 1/32th for each ommer included
|
||||
@@ -332,7 +334,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||
reward := big.NewInt(8)
|
||||
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
|
||||
reward.Mul(reward, blockReward)
|
||||
reward.Div(reward, big.NewInt(8))
|
||||
reward.Rsh(reward, 3)
|
||||
statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), tracing.BalanceIncreaseRewardMineUncle)
|
||||
}
|
||||
statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), tracing.BalanceIncreaseRewardMineBlock)
|
||||
|
||||
@@ -181,7 +181,7 @@ func Transition(ctx *cli.Context) error {
|
||||
// Set the chain id
|
||||
chainConfig.ChainID = big.NewInt(ctx.Int64(ChainIDFlag.Name))
|
||||
|
||||
if txIt, err = loadTransactions(txStr, inputData, prestate.Env, chainConfig); err != nil {
|
||||
if txIt, err = loadTransactions(txStr, inputData, chainConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := applyLondonChecks(&prestate.Env, chainConfig); err != nil {
|
||||
@@ -217,7 +217,7 @@ func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error {
|
||||
return nil
|
||||
}
|
||||
if env.ParentBaseFee == nil || env.Number == 0 {
|
||||
return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section"))
|
||||
return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'parentBaseFee' in env section"))
|
||||
}
|
||||
env.BaseFee = eip1559.CalcBaseFee(chainConfig, &types.Header{
|
||||
Number: new(big.Int).SetUint64(env.Number - 1),
|
||||
@@ -296,7 +296,7 @@ func (g Alloc) OnAccount(addr *common.Address, dumpAccount state.DumpAccount) {
|
||||
balance, _ := new(big.Int).SetString(dumpAccount.Balance, 0)
|
||||
var storage map[common.Hash]common.Hash
|
||||
if dumpAccount.Storage != nil {
|
||||
storage = make(map[common.Hash]common.Hash)
|
||||
storage = make(map[common.Hash]common.Hash, len(dumpAccount.Storage))
|
||||
for k, v := range dumpAccount.Storage {
|
||||
storage[k] = common.HexToHash(v)
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran
|
||||
return signedTxs, nil
|
||||
}
|
||||
|
||||
func loadTransactions(txStr string, inputData *input, env stEnv, chainConfig *params.ChainConfig) (txIterator, error) {
|
||||
func loadTransactions(txStr string, inputData *input, chainConfig *params.ChainConfig) (txIterator, error) {
|
||||
var txsWithKeys []*txWithKey
|
||||
if txStr != stdinSelector {
|
||||
data, err := os.ReadFile(txStr)
|
||||
|
||||
@@ -234,7 +234,7 @@ func TestT8n(t *testing.T) {
|
||||
{ // Test post-merge transition
|
||||
base: "./testdata/24",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.json", "env.json", "Merge", "",
|
||||
"alloc.json", "txs.json", "env.json", "Paris", "",
|
||||
},
|
||||
output: t8nOutput{alloc: true, result: true},
|
||||
expOut: "exp.json",
|
||||
@@ -242,7 +242,7 @@ func TestT8n(t *testing.T) {
|
||||
{ // Test post-merge transition where input is missing random
|
||||
base: "./testdata/24",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.json", "env-missingrandom.json", "Merge", "",
|
||||
"alloc.json", "txs.json", "env-missingrandom.json", "Paris", "",
|
||||
},
|
||||
output: t8nOutput{alloc: false, result: false},
|
||||
expExitCode: 3,
|
||||
@@ -250,7 +250,7 @@ func TestT8n(t *testing.T) {
|
||||
{ // Test base fee calculation
|
||||
base: "./testdata/25",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.json", "env.json", "Merge", "",
|
||||
"alloc.json", "txs.json", "env.json", "Paris", "",
|
||||
},
|
||||
output: t8nOutput{alloc: true, result: true},
|
||||
expOut: "exp.json",
|
||||
@@ -378,7 +378,7 @@ func TestT8nTracing(t *testing.T) {
|
||||
{
|
||||
base: "./testdata/32",
|
||||
input: t8nInput{
|
||||
"alloc.json", "txs.json", "env.json", "Merge", "",
|
||||
"alloc.json", "txs.json", "env.json", "Paris", "",
|
||||
},
|
||||
extraArgs: []string{"--trace", "--trace.callframes"},
|
||||
expectedTraces: []string{"trace-0-0x47806361c0fa084be3caa18afe8c48156747c01dbdfc1ee11b5aecdbe4fcf23e.jsonl"},
|
||||
|
||||
@@ -39,7 +39,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -337,7 +336,7 @@ func importChain(ctx *cli.Context) error {
|
||||
fmt.Printf("Import done in %v.\n\n", time.Since(start))
|
||||
|
||||
// Output pre-compaction stats mostly to see the import trashing
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
|
||||
// Print the memory statistics used by the importing
|
||||
mem := new(runtime.MemStats)
|
||||
@@ -360,7 +359,7 @@ func importChain(ctx *cli.Context) error {
|
||||
}
|
||||
fmt.Printf("Compaction done in %v.\n\n", time.Since(start))
|
||||
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
return importErr
|
||||
}
|
||||
|
||||
@@ -516,7 +515,7 @@ func importPreimages(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseDumpConfig(ctx *cli.Context, stack *node.Node, db ethdb.Database) (*state.DumpConfig, common.Hash, error) {
|
||||
func parseDumpConfig(ctx *cli.Context, db ethdb.Database) (*state.DumpConfig, common.Hash, error) {
|
||||
var header *types.Header
|
||||
if ctx.NArg() > 1 {
|
||||
return nil, common.Hash{}, fmt.Errorf("expected 1 argument (number or hash), got %d", ctx.NArg())
|
||||
@@ -580,7 +579,7 @@ func dump(ctx *cli.Context) error {
|
||||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
conf, root, err := parseDumpConfig(ctx, stack, db)
|
||||
conf, root, err := parseDumpConfig(ctx, db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -103,17 +103,17 @@ func TestAttachWelcome(t *testing.T) {
|
||||
"--http", "--http.port", httpPort,
|
||||
"--ws", "--ws.port", wsPort)
|
||||
t.Run("ipc", func(t *testing.T) {
|
||||
waitForEndpoint(t, ipc, 3*time.Second)
|
||||
waitForEndpoint(t, ipc, 4*time.Second)
|
||||
testAttachWelcome(t, geth, "ipc:"+ipc, ipcAPIs)
|
||||
})
|
||||
t.Run("http", func(t *testing.T) {
|
||||
endpoint := "http://127.0.0.1:" + httpPort
|
||||
waitForEndpoint(t, endpoint, 3*time.Second)
|
||||
waitForEndpoint(t, endpoint, 4*time.Second)
|
||||
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
||||
})
|
||||
t.Run("ws", func(t *testing.T) {
|
||||
endpoint := "ws://127.0.0.1:" + wsPort
|
||||
waitForEndpoint(t, endpoint, 3*time.Second)
|
||||
waitForEndpoint(t, endpoint, 4*time.Second)
|
||||
testAttachWelcome(t, geth, endpoint, httpAPIs)
|
||||
})
|
||||
geth.Kill()
|
||||
|
||||
@@ -246,11 +246,17 @@ func removeDB(ctx *cli.Context) error {
|
||||
ancientDir = config.Node.ResolvePath(ancientDir)
|
||||
}
|
||||
// Delete state data
|
||||
statePaths := []string{rootDir, filepath.Join(ancientDir, rawdb.StateFreezerName)}
|
||||
statePaths := []string{
|
||||
rootDir,
|
||||
filepath.Join(ancientDir, rawdb.StateFreezerName),
|
||||
}
|
||||
confirmAndRemoveDB(statePaths, "state data", ctx, removeStateDataFlag.Name)
|
||||
|
||||
// Delete ancient chain
|
||||
chainPaths := []string{filepath.Join(ancientDir, rawdb.ChainFreezerName)}
|
||||
chainPaths := []string{filepath.Join(
|
||||
ancientDir,
|
||||
rawdb.ChainFreezerName,
|
||||
)}
|
||||
confirmAndRemoveDB(chainPaths, "ancient chain", ctx, removeChainDataFlag.Name)
|
||||
return nil
|
||||
}
|
||||
@@ -401,17 +407,13 @@ func checkStateContent(ctx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func showLeveldbStats(db ethdb.KeyValueStater) {
|
||||
if stats, err := db.Stat("leveldb.stats"); err != nil {
|
||||
func showDBStats(db ethdb.KeyValueStater) {
|
||||
stats, err := db.Stat()
|
||||
if err != nil {
|
||||
log.Warn("Failed to read database stats", "error", err)
|
||||
} else {
|
||||
fmt.Println(stats)
|
||||
}
|
||||
if ioStats, err := db.Stat("leveldb.iostats"); err != nil {
|
||||
log.Warn("Failed to read database iostats", "error", err)
|
||||
} else {
|
||||
fmt.Println(ioStats)
|
||||
return
|
||||
}
|
||||
fmt.Println(stats)
|
||||
}
|
||||
|
||||
func dbStats(ctx *cli.Context) error {
|
||||
@@ -421,7 +423,7 @@ func dbStats(ctx *cli.Context) error {
|
||||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -433,7 +435,7 @@ func dbCompact(ctx *cli.Context) error {
|
||||
defer db.Close()
|
||||
|
||||
log.Info("Stats before compaction")
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
|
||||
log.Info("Triggering compaction")
|
||||
if err := db.Compact(nil, nil); err != nil {
|
||||
@@ -441,7 +443,7 @@ func dbCompact(ctx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
log.Info("Stats after compaction")
|
||||
showLeveldbStats(db)
|
||||
showDBStats(db)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ func testConsoleLogging(t *testing.T, format string, tStart, tEnd int) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer readFile.Close()
|
||||
wantLines := split(readFile)
|
||||
haveLines := split(bytes.NewBuffer(haveB))
|
||||
for i, want := range wantLines {
|
||||
@@ -109,6 +110,7 @@ func TestJsonLogging(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer readFile.Close()
|
||||
wantLines := split(readFile)
|
||||
haveLines := split(bytes.NewBuffer(haveB))
|
||||
for i, wantLine := range wantLines {
|
||||
|
||||
@@ -156,6 +156,7 @@ var (
|
||||
utils.BeaconGenesisRootFlag,
|
||||
utils.BeaconGenesisTimeFlag,
|
||||
utils.BeaconCheckpointFlag,
|
||||
utils.CollectWitnessFlag,
|
||||
}, utils.NetworkFlags, utils.DatabaseFlags)
|
||||
|
||||
rpcFlags = []cli.Flag{
|
||||
|
||||
@@ -91,7 +91,7 @@ data, and verifies that all snapshot storage data has a corresponding account.
|
||||
},
|
||||
{
|
||||
Name: "inspect-account",
|
||||
Usage: "Check all snapshot layers for the a specific account",
|
||||
Usage: "Check all snapshot layers for the specific account",
|
||||
ArgsUsage: "<address | hash>",
|
||||
Action: checkAccount,
|
||||
Flags: flags.Merge(utils.NetworkFlags, utils.DatabaseFlags),
|
||||
@@ -544,7 +544,7 @@ func dumpState(ctx *cli.Context) error {
|
||||
db := utils.MakeChainDatabase(ctx, stack, true)
|
||||
defer db.Close()
|
||||
|
||||
conf, root, err := parseDumpConfig(ctx, stack, db)
|
||||
conf, root, err := parseDumpConfig(ctx, db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
32
cmd/geth/testdata/vcheck/vulnerabilities.json
vendored
32
cmd/geth/testdata/vcheck/vulnerabilities.json
vendored
@@ -166,5 +166,37 @@
|
||||
"severity": "Low",
|
||||
"CVE": "CVE-2022-29177",
|
||||
"check": "(Geth\\/v1\\.10\\.(0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16)-.*)$"
|
||||
},
|
||||
{
|
||||
"name": "DoS via malicious p2p message",
|
||||
"uid": "GETH-2023-01",
|
||||
"summary": "A vulnerable node can be made to consume unbounded amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
|
||||
"description": "The p2p handler spawned a new goroutine to respond to ping requests. By flooding a node with ping requests, an unbounded number of goroutines can be created, leading to resource exhaustion and potentially crash due to OOM.",
|
||||
"links": [
|
||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-ppjg-v974-84cm",
|
||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities"
|
||||
],
|
||||
"introduced": "v1.10.0",
|
||||
"fixed": "v1.12.1",
|
||||
"published": "2023-09-06",
|
||||
"severity": "High",
|
||||
"CVE": "CVE-2023-40591",
|
||||
"check": "(Geth\\/v1\\.(10|11)\\..*)|(Geth\\/v1\\.12\\.0-.*)$"
|
||||
},
|
||||
{
|
||||
"name": "DoS via malicious p2p message",
|
||||
"uid": "GETH-2024-01",
|
||||
"summary": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node.",
|
||||
"description": "A vulnerable node can be made to consume very large amounts of memory when handling specially crafted p2p messages sent from an attacker node. Full details will be available at the Github security [advisory](https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652)",
|
||||
"links": [
|
||||
"https://github.com/ethereum/go-ethereum/security/advisories/GHSA-4xc9-8hmq-j652",
|
||||
"https://geth.ethereum.org/docs/vulnerabilities/vulnerabilities"
|
||||
],
|
||||
"introduced": "v1.10.0",
|
||||
"fixed": "v1.13.15",
|
||||
"published": "2024-05-06",
|
||||
"severity": "High",
|
||||
"CVE": "CVE-2024-32972",
|
||||
"check": "(Geth\\/v1\\.(10|11|12)\\..*)|(Geth\\/v1\\.13\\.\\d-.*)|(Geth\\/v1\\.13\\.1(0|1|2|3|4)-.*)$"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -28,7 +28,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/internal/flags"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/gballet/go-verkle"
|
||||
"github.com/ethereum/go-verkle"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
||||
@@ -604,6 +604,11 @@ var (
|
||||
Usage: "Disables db compaction after import",
|
||||
Category: flags.LoggingCategory,
|
||||
}
|
||||
CollectWitnessFlag = &cli.BoolFlag{
|
||||
Name: "collectwitness",
|
||||
Usage: "Enable state witness generation during block execution. Work in progress flag, don't use.",
|
||||
Category: flags.MiscCategory,
|
||||
}
|
||||
|
||||
// MISC settings
|
||||
SyncTargetFlag = &cli.StringFlag{
|
||||
@@ -1760,6 +1765,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
// TODO(fjl): force-enable this in --dev mode
|
||||
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
|
||||
}
|
||||
if ctx.IsSet(CollectWitnessFlag.Name) {
|
||||
cfg.EnableWitnessCollection = ctx.Bool(CollectWitnessFlag.Name)
|
||||
}
|
||||
|
||||
if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
|
||||
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
|
||||
@@ -1872,13 +1880,15 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||
Fatalf("Could not read genesis from database: %v", err)
|
||||
}
|
||||
if !genesis.Config.TerminalTotalDifficultyPassed {
|
||||
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficultyPassed must be true in developer mode")
|
||||
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficultyPassed must be true")
|
||||
}
|
||||
if genesis.Config.TerminalTotalDifficulty == nil {
|
||||
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be specified.")
|
||||
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be specified")
|
||||
} else if genesis.Config.TerminalTotalDifficulty.Cmp(big.NewInt(0)) != 0 {
|
||||
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be 0")
|
||||
}
|
||||
if genesis.Difficulty.Cmp(genesis.Config.TerminalTotalDifficulty) != 1 {
|
||||
Fatalf("Bad developer-mode genesis configuration: genesis block difficulty must be > terminalTotalDifficulty")
|
||||
if genesis.Difficulty.Cmp(big.NewInt(0)) != 0 {
|
||||
Fatalf("Bad developer-mode genesis configuration: difficulty must be 0")
|
||||
}
|
||||
}
|
||||
chaindb.Close()
|
||||
@@ -2188,7 +2198,10 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
|
||||
if ctx.IsSet(CacheFlag.Name) || ctx.IsSet(CacheGCFlag.Name) {
|
||||
cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
|
||||
}
|
||||
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}
|
||||
vmcfg := vm.Config{
|
||||
EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name),
|
||||
EnableWitnessCollection: ctx.Bool(CollectWitnessFlag.Name),
|
||||
}
|
||||
if ctx.IsSet(VMTraceFlag.Name) {
|
||||
if name := ctx.String(VMTraceFlag.Name); name != "" {
|
||||
var config json.RawMessage
|
||||
|
||||
@@ -162,8 +162,7 @@ func TestHistoryImportAndExport(t *testing.T) {
|
||||
}
|
||||
|
||||
// Now import Era.
|
||||
freezer := t.TempDir()
|
||||
db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false)
|
||||
db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ func NewHexOrDecimal256(x int64) *HexOrDecimal256 {
|
||||
// It is similar to UnmarshalText, but allows parsing real decimals too, not just
|
||||
// quoted decimal strings.
|
||||
func (i *HexOrDecimal256) UnmarshalJSON(input []byte) error {
|
||||
if len(input) > 0 && input[0] == '"' {
|
||||
if len(input) > 1 && input[0] == '"' {
|
||||
input = input[1 : len(input)-1]
|
||||
}
|
||||
return i.UnmarshalText(input)
|
||||
|
||||
@@ -180,9 +180,9 @@ func BenchmarkByteAtOld(b *testing.B) {
|
||||
func TestReadBits(t *testing.T) {
|
||||
check := func(input string) {
|
||||
want, _ := hex.DecodeString(input)
|
||||
int, _ := new(big.Int).SetString(input, 16)
|
||||
n, _ := new(big.Int).SetString(input, 16)
|
||||
buf := make([]byte, len(want))
|
||||
ReadBits(int, buf)
|
||||
ReadBits(n, buf)
|
||||
if !bytes.Equal(buf, want) {
|
||||
t.Errorf("have: %x\nwant: %x", buf, want)
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ type HexOrDecimal64 uint64
|
||||
// It is similar to UnmarshalText, but allows parsing real decimals too, not just
|
||||
// quoted decimal strings.
|
||||
func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error {
|
||||
if len(input) > 0 && input[0] == '"' {
|
||||
if len(input) > 1 && input[0] == '"' {
|
||||
input = input[1 : len(input)-1]
|
||||
}
|
||||
return i.UnmarshalText(input)
|
||||
@@ -54,11 +54,11 @@ func (i *HexOrDecimal64) UnmarshalJSON(input []byte) error {
|
||||
|
||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||
func (i *HexOrDecimal64) UnmarshalText(input []byte) error {
|
||||
int, ok := ParseUint64(string(input))
|
||||
n, ok := ParseUint64(string(input))
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid hex or decimal integer %q", input)
|
||||
}
|
||||
*i = HexOrDecimal64(int)
|
||||
*i = HexOrDecimal64(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -468,7 +468,7 @@ func (d *Decimal) UnmarshalJSON(input []byte) error {
|
||||
if !isString(input) {
|
||||
return &json.UnmarshalTypeError{Value: "non-string", Type: reflect.TypeOf(uint64(0))}
|
||||
}
|
||||
if i, err := strconv.ParseInt(string(input[1:len(input)-1]), 10, 64); err == nil {
|
||||
if i, err := strconv.ParseUint(string(input[1:len(input)-1]), 10, 64); err == nil {
|
||||
*d = Decimal(i)
|
||||
return nil
|
||||
} else {
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"reflect"
|
||||
"strings"
|
||||
@@ -595,3 +596,29 @@ func BenchmarkPrettyDuration(b *testing.B) {
|
||||
}
|
||||
b.Logf("Post %s", a)
|
||||
}
|
||||
|
||||
func TestDecimalUnmarshalJSON(t *testing.T) {
|
||||
// These should error
|
||||
for _, tc := range []string{``, `"`, `""`, `"-1"`} {
|
||||
if err := new(Decimal).UnmarshalJSON([]byte(tc)); err == nil {
|
||||
t.Errorf("input %s should cause error", tc)
|
||||
}
|
||||
}
|
||||
// These should succeed
|
||||
for _, tc := range []struct {
|
||||
input string
|
||||
want uint64
|
||||
}{
|
||||
{`"0"`, 0},
|
||||
{`"9223372036854775807"`, math.MaxInt64},
|
||||
{`"18446744073709551615"`, math.MaxUint64},
|
||||
} {
|
||||
have := new(Decimal)
|
||||
if err := have.UnmarshalJSON([]byte(tc.input)); err != nil {
|
||||
t.Errorf("input %q triggered error: %v", tc.input, err)
|
||||
}
|
||||
if uint64(*have) != tc.want {
|
||||
t.Errorf("input %q, have %d want %d", tc.input, *have, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +388,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||
header.Root = state.IntermediateRoot(true)
|
||||
|
||||
// Assemble and return the final block.
|
||||
return types.NewBlockWithWithdrawals(header, body.Transactions, body.Uncles, receipts, body.Withdrawals, trie.NewStackTrie(nil)), nil
|
||||
return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// Seal generates a new sealing request for the given input block and pushes
|
||||
|
||||
@@ -597,7 +597,7 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
|
||||
// Assemble and return the final block for sealing.
|
||||
return types.NewBlock(header, body.Transactions, nil, receipts, trie.NewStackTrie(nil)), nil
|
||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions}, receipts, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// Authorize injects a private key into the consensus engine to mint new blocks
|
||||
|
||||
@@ -19,6 +19,7 @@ package clique
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"maps"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
@@ -108,28 +109,16 @@ func (s *Snapshot) store(db ethdb.Database) error {
|
||||
|
||||
// copy creates a deep copy of the snapshot, though not the individual votes.
|
||||
func (s *Snapshot) copy() *Snapshot {
|
||||
cpy := &Snapshot{
|
||||
return &Snapshot{
|
||||
config: s.config,
|
||||
sigcache: s.sigcache,
|
||||
Number: s.Number,
|
||||
Hash: s.Hash,
|
||||
Signers: make(map[common.Address]struct{}),
|
||||
Recents: make(map[uint64]common.Address),
|
||||
Votes: make([]*Vote, len(s.Votes)),
|
||||
Tally: make(map[common.Address]Tally),
|
||||
Signers: maps.Clone(s.Signers),
|
||||
Recents: maps.Clone(s.Recents),
|
||||
Votes: slices.Clone(s.Votes),
|
||||
Tally: maps.Clone(s.Tally),
|
||||
}
|
||||
for signer := range s.Signers {
|
||||
cpy.Signers[signer] = struct{}{}
|
||||
}
|
||||
for block, signer := range s.Recents {
|
||||
cpy.Recents[block] = signer
|
||||
}
|
||||
for address, tally := range s.Tally {
|
||||
cpy.Tally[address] = tally
|
||||
}
|
||||
copy(cpy.Votes, s.Votes)
|
||||
|
||||
return cpy
|
||||
}
|
||||
|
||||
// validVote returns whether it makes sense to cast the specified vote in the
|
||||
|
||||
@@ -520,7 +520,7 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
|
||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||
|
||||
// Header seems complete, assemble into a block and return
|
||||
return types.NewBlock(header, body.Transactions, body.Uncles, receipts, trie.NewStackTrie(nil)), nil
|
||||
return types.NewBlock(header, &types.Body{Transactions: body.Transactions, Uncles: body.Uncles}, receipts, trie.NewStackTrie(nil)), nil
|
||||
}
|
||||
|
||||
// SealHash returns the hash of a block prior to it being sealed.
|
||||
@@ -562,12 +562,6 @@ func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) {
|
||||
return hash
|
||||
}
|
||||
|
||||
// Some weird constants to avoid constant memory allocs for them.
|
||||
var (
|
||||
u256_8 = uint256.NewInt(8)
|
||||
u256_32 = uint256.NewInt(32)
|
||||
)
|
||||
|
||||
// accumulateRewards credits the coinbase of the given block with the mining
|
||||
// reward. The total reward consists of the static block reward and rewards for
|
||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
||||
@@ -589,10 +583,10 @@ func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, heade
|
||||
r.AddUint64(uNum, 8)
|
||||
r.Sub(r, hNum)
|
||||
r.Mul(r, blockReward)
|
||||
r.Div(r, u256_8)
|
||||
r.Rsh(r, 3)
|
||||
stateDB.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle)
|
||||
|
||||
r.Div(blockReward, u256_32)
|
||||
r.Rsh(blockReward, 5)
|
||||
reward.Add(reward, r)
|
||||
}
|
||||
stateDB.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock)
|
||||
|
||||
@@ -20,8 +20,10 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
@@ -34,14 +36,12 @@ import (
|
||||
type BlockValidator struct {
|
||||
config *params.ChainConfig // Chain configuration options
|
||||
bc *BlockChain // Canonical block chain
|
||||
engine consensus.Engine // Consensus engine used for validating
|
||||
}
|
||||
|
||||
// NewBlockValidator returns a new block validator which is safe for re-use
|
||||
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engine consensus.Engine) *BlockValidator {
|
||||
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *BlockValidator {
|
||||
validator := &BlockValidator{
|
||||
config: config,
|
||||
engine: engine,
|
||||
bc: blockchain,
|
||||
}
|
||||
return validator
|
||||
@@ -59,7 +59,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||
// Header validity is known at this point. Here we verify that uncles, transactions
|
||||
// and withdrawals given in the block body match the header.
|
||||
header := block.Header()
|
||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
if err := v.bc.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
return err
|
||||
}
|
||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||
@@ -121,7 +121,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||
|
||||
// ValidateState validates the various changes that happen after a state transition,
|
||||
// such as amount of used gas, the receipt roots and the state root itself.
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error {
|
||||
func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, stateless bool) error {
|
||||
header := block.Header()
|
||||
if block.GasUsed() != usedGas {
|
||||
return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas)
|
||||
@@ -132,6 +132,11 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
||||
if rbloom != header.Bloom {
|
||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||
}
|
||||
// In stateless mode, return early because the receipt and state root are not
|
||||
// provided through the witness, rather the cross validator needs to return it.
|
||||
if stateless {
|
||||
return nil
|
||||
}
|
||||
// The receipt Trie's root (R = (Tr [[H1, R1], ... [Hn, Rn]]))
|
||||
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||
if receiptSha != header.ReceiptHash {
|
||||
@@ -145,6 +150,28 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateWitness cross validates a block execution with stateless remote clients.
|
||||
//
|
||||
// Normally we'd distribute the block witness to remote cross validators, wait
|
||||
// for them to respond and then merge the results. For now, however, it's only
|
||||
// Geth, so do an internal stateless run.
|
||||
func (v *BlockValidator) ValidateWitness(witness *stateless.Witness, receiptRoot common.Hash, stateRoot common.Hash) error {
|
||||
// Run the cross client stateless execution
|
||||
// TODO(karalabe): Self-stateless for now, swap with other clients
|
||||
crossReceiptRoot, crossStateRoot, err := ExecuteStateless(v.config, witness)
|
||||
if err != nil {
|
||||
return fmt.Errorf("stateless execution failed: %v", err)
|
||||
}
|
||||
// Stateless cross execution suceeeded, validate the withheld computed fields
|
||||
if crossReceiptRoot != receiptRoot {
|
||||
return fmt.Errorf("cross validator receipt root mismatch (cross: %x local: %x)", crossReceiptRoot, receiptRoot)
|
||||
}
|
||||
if crossStateRoot != stateRoot {
|
||||
return fmt.Errorf("cross validator state root mismatch (cross: %x local: %x)", crossStateRoot, stateRoot)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CalcGasLimit computes the gas limit of the next block after parent. It aims
|
||||
// to keep the baseline gas close to the provided target, and increase it towards
|
||||
// the target if the baseline gas is lower.
|
||||
|
||||
@@ -154,12 +154,10 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
|
||||
preHeaders := make([]*types.Header, len(preBlocks))
|
||||
for i, block := range preBlocks {
|
||||
preHeaders[i] = block.Header()
|
||||
t.Logf("Pre-merge header: %d", block.NumberU64())
|
||||
}
|
||||
postHeaders := make([]*types.Header, len(postBlocks))
|
||||
for i, block := range postBlocks {
|
||||
postHeaders[i] = block.Header()
|
||||
t.Logf("Post-merge header: %d", block.NumberU64())
|
||||
}
|
||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||
"github.com/ethereum/go-ethereum/core/stateless"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
@@ -68,7 +69,6 @@ var (
|
||||
accountCommitTimer = metrics.NewRegisteredResettingTimer("chain/account/commits", nil)
|
||||
|
||||
storageReadTimer = metrics.NewRegisteredResettingTimer("chain/storage/reads", nil)
|
||||
storageHashTimer = metrics.NewRegisteredResettingTimer("chain/storage/hashes", nil)
|
||||
storageUpdateTimer = metrics.NewRegisteredResettingTimer("chain/storage/updates", nil)
|
||||
storageCommitTimer = metrics.NewRegisteredResettingTimer("chain/storage/commits", nil)
|
||||
|
||||
@@ -101,7 +101,6 @@ const (
|
||||
blockCacheLimit = 256
|
||||
receiptsCacheLimit = 32
|
||||
txLookupCacheLimit = 1024
|
||||
TriesInMemory = 128
|
||||
|
||||
// BlockChainVersion ensures that an incompatible database forces a resync from scratch.
|
||||
//
|
||||
@@ -304,18 +303,18 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
vmConfig: vmConfig,
|
||||
logger: vmConfig.Tracer,
|
||||
}
|
||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine)
|
||||
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
||||
|
||||
var err error
|
||||
bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||
bc.validator = NewBlockValidator(chainConfig, bc)
|
||||
bc.prefetcher = newStatePrefetcher(chainConfig, bc.hc)
|
||||
bc.processor = NewStateProcessor(chainConfig, bc.hc)
|
||||
|
||||
bc.genesisBlock = bc.GetBlockByNumber(0)
|
||||
if bc.genesisBlock == nil {
|
||||
return nil, ErrNoGenesis
|
||||
@@ -1129,7 +1128,7 @@ func (bc *BlockChain) Stop() {
|
||||
if !bc.cacheConfig.TrieDirtyDisabled {
|
||||
triedb := bc.triedb
|
||||
|
||||
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
|
||||
for _, offset := range []uint64{0, 1, state.TriesInMemory - 1} {
|
||||
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
|
||||
recent := bc.GetBlockByNumber(number - offset)
|
||||
|
||||
@@ -1310,7 +1309,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||
// Delete block data from the main database.
|
||||
var (
|
||||
batch = bc.db.NewBatch()
|
||||
canonHashes = make(map[common.Hash]struct{})
|
||||
canonHashes = make(map[common.Hash]struct{}, len(blockChain))
|
||||
)
|
||||
for _, block := range blockChain {
|
||||
canonHashes[block.Hash()] = struct{}{}
|
||||
@@ -1453,7 +1452,7 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
|
||||
|
||||
// writeBlockWithState writes block, metadata and corresponding state data to the
|
||||
// database.
|
||||
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error {
|
||||
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, statedb *state.StateDB) error {
|
||||
// Calculate the total difficulty of the block
|
||||
ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
|
||||
if ptd == nil {
|
||||
@@ -1470,12 +1469,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
|
||||
rawdb.WriteBlock(blockBatch, block)
|
||||
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)
|
||||
rawdb.WritePreimages(blockBatch, state.Preimages())
|
||||
rawdb.WritePreimages(blockBatch, statedb.Preimages())
|
||||
if err := blockBatch.Write(); err != nil {
|
||||
log.Crit("Failed to write block into disk", "err", err)
|
||||
}
|
||||
// Commit all cached state changes into underlying memory database.
|
||||
root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()))
|
||||
root, err := statedb.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -1494,7 +1493,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
|
||||
// Flush limits are not considered for the first TriesInMemory blocks.
|
||||
current := block.NumberU64()
|
||||
if current <= TriesInMemory {
|
||||
if current <= state.TriesInMemory {
|
||||
return nil
|
||||
}
|
||||
// If we exceeded our memory allowance, flush matured singleton nodes to disk
|
||||
@@ -1506,7 +1505,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
bc.triedb.Cap(limit - ethdb.IdealBatchSize)
|
||||
}
|
||||
// Find the next state trie we need to commit
|
||||
chosen := current - TriesInMemory
|
||||
chosen := current - state.TriesInMemory
|
||||
flushInterval := time.Duration(bc.flushInterval.Load())
|
||||
// If we exceeded time allowance, flush an entire trie to disk
|
||||
if bc.gcproc > flushInterval {
|
||||
@@ -1518,8 +1517,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
} else {
|
||||
// If we're exceeding limits but haven't reached a large enough memory gap,
|
||||
// warn the user that the system is becoming unstable.
|
||||
if chosen < bc.lastWrite+TriesInMemory && bc.gcproc >= 2*flushInterval {
|
||||
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/TriesInMemory)
|
||||
if chosen < bc.lastWrite+state.TriesInMemory && bc.gcproc >= 2*flushInterval {
|
||||
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/state.TriesInMemory)
|
||||
}
|
||||
// Flush an entire trie and restart the counters
|
||||
bc.triedb.Commit(header.Root, true)
|
||||
@@ -1807,8 +1806,19 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
}
|
||||
statedb.SetLogger(bc.logger)
|
||||
|
||||
// Enable prefetching to pull in trie node paths while processing transactions
|
||||
statedb.StartPrefetcher("chain")
|
||||
// If we are past Byzantium, enable prefetching to pull in trie node paths
|
||||
// while processing transactions. Before Byzantium the prefetcher is mostly
|
||||
// useless due to the intermediate root hashing after each transaction.
|
||||
if bc.chainConfig.IsByzantium(block.Number()) {
|
||||
var witness *stateless.Witness
|
||||
if bc.vmConfig.EnableWitnessCollection {
|
||||
witness, err = stateless.NewWitness(bc, block)
|
||||
if err != nil {
|
||||
return it.index, err
|
||||
}
|
||||
}
|
||||
statedb.StartPrefetcher("chain", witness)
|
||||
}
|
||||
activeState = statedb
|
||||
|
||||
// If we have a followup block, run that against the current state to pre-cache
|
||||
@@ -1922,11 +1932,18 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||
ptime := time.Since(pstart)
|
||||
|
||||
vstart := time.Now()
|
||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
|
||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
return nil, err
|
||||
}
|
||||
vtime := time.Since(vstart)
|
||||
|
||||
if witness := statedb.Witness(); witness != nil {
|
||||
if err = bc.validator.ValidateWitness(witness, block.ReceiptHash(), block.Root()); err != nil {
|
||||
bc.reportBlock(block, receipts, err)
|
||||
return nil, fmt.Errorf("cross verification failed: %v", err)
|
||||
}
|
||||
}
|
||||
proctime := time.Since(start) // processing + validation
|
||||
|
||||
// Update the metrics touched during block processing and validation
|
||||
@@ -1937,8 +1954,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
|
||||
triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
|
||||
triehash := statedb.AccountHashes // The time spent on tries hashing
|
||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
||||
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
|
||||
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
|
||||
@@ -1965,7 +1981,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||
snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
|
||||
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
|
||||
|
||||
blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||
blockWriteTimer.Update(time.Since(wstart) - max(statedb.AccountCommits, statedb.StorageCommits) /* concurrent */ - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||
blockInsertTimer.UpdateSince(start)
|
||||
|
||||
return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil
|
||||
|
||||
@@ -168,8 +168,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||
blockchain.reportBlock(block, receipts, err)
|
||||
return err
|
||||
}
|
||||
err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas)
|
||||
if err != nil {
|
||||
if err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, false); err != nil {
|
||||
blockchain.reportBlock(block, receipts, err)
|
||||
return err
|
||||
}
|
||||
@@ -785,7 +784,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
|
||||
t.Fatalf("failed to insert receipt %d: %v", n, err)
|
||||
}
|
||||
// Freezer style fast import the chain.
|
||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
}
|
||||
@@ -875,12 +874,12 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
)
|
||||
height := uint64(1024)
|
||||
height := uint64(64)
|
||||
_, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil)
|
||||
|
||||
// makeDb creates a db instance for testing.
|
||||
makeDb := func() ethdb.Database {
|
||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
}
|
||||
@@ -1712,7 +1711,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||
Config: params.TestChainConfig,
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
||||
|
||||
// Generate a bunch of fork blocks, each side forking from the canonical chain
|
||||
forks := make([]*types.Block, len(blocks))
|
||||
@@ -1740,7 +1739,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||
}
|
||||
}
|
||||
// Dereference all the recent tries and ensure no past trie is left in
|
||||
for i := 0; i < TriesInMemory; i++ {
|
||||
for i := 0; i < state.TriesInMemory; i++ {
|
||||
chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root())
|
||||
chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root())
|
||||
}
|
||||
@@ -1764,11 +1763,11 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
genDb, shared, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
|
||||
original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) })
|
||||
competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
|
||||
original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) })
|
||||
competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
|
||||
|
||||
// Import the shared chain and the original canonical one
|
||||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
defer db.Close()
|
||||
|
||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
@@ -1804,7 +1803,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
|
||||
}
|
||||
// In path-based trie database implementation, it will keep 128 diff + 1 disk
|
||||
// layers, totally 129 latest states available. In hash-based it's 128.
|
||||
states := TriesInMemory
|
||||
states := state.TriesInMemory
|
||||
if scheme == rawdb.PathScheme {
|
||||
states = states + 1
|
||||
}
|
||||
@@ -1833,7 +1832,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
|
||||
funds = big.NewInt(1000000000)
|
||||
gspec = &Genesis{Config: params.TestChainConfig, Alloc: types.GenesisAlloc{address: {Balance: funds}}}
|
||||
)
|
||||
height := uint64(1024)
|
||||
height := uint64(64)
|
||||
_, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil)
|
||||
|
||||
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||
@@ -1908,7 +1907,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) {
|
||||
}
|
||||
|
||||
// Set up a BlockChain that uses the ancient store.
|
||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
}
|
||||
@@ -1972,13 +1971,13 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
|
||||
}
|
||||
// We must use a pretty long chain to ensure that the fork doesn't overtake us
|
||||
// until after at least 128 blocks post tip
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*TriesInMemory, func(i int, b *BlockGen) {
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*state.TriesInMemory, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
b.OffsetTime(-9)
|
||||
})
|
||||
|
||||
// Import the canonical chain
|
||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
defer diskdb.Close()
|
||||
|
||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
@@ -1992,7 +1991,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
|
||||
}
|
||||
// Generate fork chain, starting from an early block
|
||||
parent := blocks[10]
|
||||
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*TriesInMemory, func(i int, b *BlockGen) {
|
||||
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*state.TriesInMemory, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{2})
|
||||
})
|
||||
|
||||
@@ -2055,7 +2054,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||
// Set the terminal total difficulty in the config
|
||||
gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
|
||||
}
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) {
|
||||
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create tx: %v", err)
|
||||
@@ -2070,9 +2069,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
|
||||
lastPrunedIndex := len(blocks) - TriesInMemory - 1
|
||||
lastPrunedIndex := len(blocks) - state.TriesInMemory - 1
|
||||
lastPrunedBlock := blocks[lastPrunedIndex]
|
||||
firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory]
|
||||
firstNonPrunedBlock := blocks[len(blocks)-state.TriesInMemory]
|
||||
|
||||
// Verify pruning of lastPrunedBlock
|
||||
if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
|
||||
@@ -2099,7 +2098,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||
// Generate fork chain, make it longer than canon
|
||||
parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock
|
||||
parent := blocks[parentIndex]
|
||||
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) {
|
||||
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) {
|
||||
b.SetCoinbase(common.Address{2})
|
||||
if int(b.header.Number.Uint64()) >= mergeBlock {
|
||||
b.SetPoS()
|
||||
@@ -2190,7 +2189,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
|
||||
b.OffsetTime(-9) // A higher difficulty
|
||||
})
|
||||
// Import the shared chain and the original canonical one
|
||||
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
}
|
||||
@@ -2361,7 +2360,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
|
||||
}
|
||||
})
|
||||
// Import the shared chain and the original canonical one
|
||||
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
}
|
||||
@@ -2742,7 +2741,7 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
// Generate and import the canonical chain
|
||||
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, nil)
|
||||
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
|
||||
|
||||
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||
if err != nil {
|
||||
@@ -2755,9 +2754,9 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
|
||||
}
|
||||
// In path-based trie database implementation, it will keep 128 diff + 1 disk
|
||||
// layers, totally 129 latest states available. In hash-based it's 128.
|
||||
states := TriesInMemory
|
||||
states := state.TriesInMemory
|
||||
if scheme == rawdb.PathScheme {
|
||||
states = TriesInMemory + 1
|
||||
states = state.TriesInMemory + 1
|
||||
}
|
||||
lastPrunedIndex := len(blocks) - states - 1
|
||||
lastPrunedBlock := blocks[lastPrunedIndex]
|
||||
@@ -3634,18 +3633,19 @@ func testSetCanonical(t *testing.T, scheme string) {
|
||||
Alloc: types.GenesisAlloc{address: {Balance: funds}},
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
}
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
engine = ethash.NewFaker()
|
||||
signer = types.LatestSigner(gspec.Config)
|
||||
engine = ethash.NewFaker()
|
||||
chainLength = 10
|
||||
)
|
||||
// Generate and import the canonical chain
|
||||
_, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) {
|
||||
_, canon, _ := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, gen *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gen.AddTx(tx)
|
||||
})
|
||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
|
||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||
defer diskdb.Close()
|
||||
|
||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||
@@ -3659,7 +3659,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
||||
}
|
||||
|
||||
// Generate the side chain and import them
|
||||
_, side, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) {
|
||||
_, side, _ := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, gen *BlockGen) {
|
||||
tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@@ -3698,8 +3698,8 @@ func testSetCanonical(t *testing.T, scheme string) {
|
||||
verify(side[len(side)-1])
|
||||
|
||||
// Reset the chain head to original chain
|
||||
chain.SetCanonical(canon[TriesInMemory-1])
|
||||
verify(canon[TriesInMemory-1])
|
||||
chain.SetCanonical(canon[chainLength-1])
|
||||
verify(canon[chainLength-1])
|
||||
}
|
||||
|
||||
// TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
// request represents a bloom retrieval task to prioritize and pull from the local
|
||||
// database or remotely from the network.
|
||||
type request struct {
|
||||
section uint64 // Section index to retrieve the a bit-vector from
|
||||
section uint64 // Section index to retrieve the bit-vector from
|
||||
bit uint // Bit index within the section to retrieve the vector of
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ func (b *testChainIndexBackend) Process(ctx context.Context, header *types.Heade
|
||||
b.t.Error("Unexpected call to Process")
|
||||
// Can't use Fatal since this is not the test's goroutine.
|
||||
// Returning error stops the chainIndexer's updateLoop
|
||||
return errors.New("Unexpected call to Process")
|
||||
return errors.New("unexpected call to Process")
|
||||
case b.processCh <- header.Number.Uint64():
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -32,7 +32,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/gballet/go-verkle"
|
||||
"github.com/ethereum/go-verkle"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
|
||||
@@ -43,12 +43,11 @@ func TestGeneratePOSChain(t *testing.T) {
|
||||
bb = common.Address{0xbb}
|
||||
funds = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether))
|
||||
config = *params.AllEthashProtocolChanges
|
||||
asm4788 = common.Hex2Bytes("3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500")
|
||||
gspec = &Genesis{
|
||||
Config: &config,
|
||||
Alloc: types.GenesisAlloc{
|
||||
address: {Balance: funds},
|
||||
params.BeaconRootsAddress: {Balance: common.Big0, Code: asm4788},
|
||||
params.BeaconRootsAddress: {Code: params.BeaconRootsCode},
|
||||
},
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Difficulty: common.Big1,
|
||||
|
||||
@@ -64,6 +64,11 @@ var (
|
||||
// than init code size limit.
|
||||
ErrMaxInitCodeSizeExceeded = errors.New("max initcode size exceeded")
|
||||
|
||||
// ErrInsufficientBalanceWitness is returned if the transaction sender has enough
|
||||
// funds to cover the transfer, but not enough to pay for witness access/modification
|
||||
// costs for the transaction
|
||||
ErrInsufficientBalanceWitness = errors.New("insufficient funds to cover witness access costs for transaction")
|
||||
|
||||
// ErrInsufficientFunds is returned if the total cost of executing a transaction
|
||||
// is higher than the balance of the user's account.
|
||||
ErrInsufficientFunds = errors.New("insufficient funds for gas * price + value")
|
||||
|
||||
@@ -476,7 +476,7 @@ func (g *Genesis) ToBlock() *types.Block {
|
||||
}
|
||||
}
|
||||
}
|
||||
return types.NewBlock(head, nil, nil, nil, trie.NewStackTrie(nil)).WithWithdrawals(withdrawals)
|
||||
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
|
||||
}
|
||||
|
||||
// Commit writes the block and state of a genesis specification to the database.
|
||||
@@ -593,6 +593,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
||||
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||
// Pre-deploy EIP-4788 system contract
|
||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||
},
|
||||
}
|
||||
if faucet != nil {
|
||||
|
||||
@@ -304,7 +304,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
expected := common.Hex2Bytes("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b")
|
||||
expected := common.FromHex("14398d42be3394ff8d50681816a4b7bf8d8283306f577faba2d5bc57498de23b")
|
||||
got := genesis.ToBlock().Root().Bytes()
|
||||
if !bytes.Equal(got, expected) {
|
||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||
@@ -314,7 +314,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||
triedb := triedb.NewDatabase(db, &triedb.Config{IsVerkle: true, PathDB: pathdb.Defaults})
|
||||
block := genesis.MustCommit(db, triedb)
|
||||
if !bytes.Equal(block.Root().Bytes(), expected) {
|
||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root())
|
||||
}
|
||||
|
||||
// Test that the trie is verkle
|
||||
@@ -322,7 +322,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||
t.Fatalf("expected trie to be verkle")
|
||||
}
|
||||
|
||||
if !rawdb.ExistsAccountTrieNode(db, nil) {
|
||||
if !rawdb.HasAccountTrieNode(db, nil) {
|
||||
t.Fatal("could not find node")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer file.Close()
|
||||
if err := json.NewDecoder(file).Decode(g); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ package rawdb
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"slices"
|
||||
@@ -695,27 +694,6 @@ func (r *receiptLogs) DecodeRLP(s *rlp.Stream) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// deriveLogFields fills the logs in receiptLogs with information such as block number, txhash, etc.
|
||||
func deriveLogFields(receipts []*receiptLogs, hash common.Hash, number uint64, txs types.Transactions) error {
|
||||
logIndex := uint(0)
|
||||
if len(txs) != len(receipts) {
|
||||
return errors.New("transaction and receipt count mismatch")
|
||||
}
|
||||
for i := 0; i < len(receipts); i++ {
|
||||
txHash := txs[i].Hash()
|
||||
// The derived log fields can simply be set from the block and transaction
|
||||
for j := 0; j < len(receipts[i].Logs); j++ {
|
||||
receipts[i].Logs[j].BlockNumber = number
|
||||
receipts[i].Logs[j].BlockHash = hash
|
||||
receipts[i].Logs[j].TxHash = txHash
|
||||
receipts[i].Logs[j].TxIndex = uint(i)
|
||||
receipts[i].Logs[j].Index = logIndex
|
||||
logIndex++
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadLogs retrieves the logs for all transactions in a block. In case
|
||||
// receipts is not found, a nil is returned.
|
||||
// Note: ReadLogs does not derive unstored log fields.
|
||||
@@ -753,7 +731,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block {
|
||||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithWithdrawals(body.Withdrawals)
|
||||
return types.NewBlockWithHeader(header).WithBody(*body)
|
||||
}
|
||||
|
||||
// WriteBlock serializes a block into the database, header and body separately.
|
||||
@@ -843,7 +821,11 @@ func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block {
|
||||
}
|
||||
for _, bad := range badBlocks {
|
||||
if bad.Header.Hash() == hash {
|
||||
return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals)
|
||||
block := types.NewBlockWithHeader(bad.Header)
|
||||
if bad.Body != nil {
|
||||
block = block.WithBody(*bad.Body)
|
||||
}
|
||||
return block
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -862,7 +844,11 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block {
|
||||
}
|
||||
var blocks []*types.Block
|
||||
for _, bad := range badBlocks {
|
||||
blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals))
|
||||
block := types.NewBlockWithHeader(bad.Header)
|
||||
if bad.Body != nil {
|
||||
block = block.WithBody(*bad.Body)
|
||||
}
|
||||
blocks = append(blocks, block)
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
||||
@@ -640,7 +640,7 @@ func makeTestBlocks(nblock int, txsPerBlock int) []*types.Block {
|
||||
Number: big.NewInt(int64(i)),
|
||||
Extra: []byte("test block"),
|
||||
}
|
||||
blocks[i] = types.NewBlockWithHeader(header).WithBody(txs, nil)
|
||||
blocks[i] = types.NewBlockWithHeader(header).WithBody(types.Body{Transactions: txs})
|
||||
blocks[i].Hash() // pre-cache the block hash
|
||||
}
|
||||
return blocks
|
||||
@@ -794,7 +794,7 @@ func TestDeriveLogFields(t *testing.T) {
|
||||
}),
|
||||
}
|
||||
// Create the corresponding receipts
|
||||
receipts := []*receiptLogs{
|
||||
receipts := []*types.Receipt{
|
||||
{
|
||||
Logs: []*types.Log{
|
||||
{Address: common.BytesToAddress([]byte{0x11})},
|
||||
@@ -818,9 +818,7 @@ func TestDeriveLogFields(t *testing.T) {
|
||||
// Derive log metadata fields
|
||||
number := big.NewInt(1)
|
||||
hash := common.BytesToHash([]byte{0x03, 0x14})
|
||||
if err := deriveLogFields(receipts, hash, number.Uint64(), txs); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
types.Receipts(receipts).DeriveFields(params.TestChainConfig, hash, number.Uint64(), 0, big.NewInt(0), big.NewInt(0), txs)
|
||||
|
||||
// Iterate over all the computed fields and check that they're correct
|
||||
logIndex := uint(0)
|
||||
|
||||
@@ -76,7 +76,7 @@ func TestLookupStorage(t *testing.T) {
|
||||
tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33})
|
||||
txs := []*types.Transaction{tx1, tx2, tx3}
|
||||
|
||||
block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil, newTestHasher())
|
||||
block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, &types.Body{Transactions: txs}, nil, newTestHasher())
|
||||
|
||||
// Check that no transactions entries are in a pristine database
|
||||
for i, tx := range txs {
|
||||
|
||||
@@ -24,7 +24,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// HashScheme is the legacy hash-based state scheme with which trie nodes are
|
||||
@@ -50,7 +49,7 @@ const PathScheme = "path"
|
||||
type hasher struct{ sha crypto.KeccakState }
|
||||
|
||||
var hasherPool = sync.Pool{
|
||||
New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} },
|
||||
New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} },
|
||||
}
|
||||
|
||||
func newHasher() *hasher {
|
||||
@@ -65,33 +64,15 @@ func (h *hasher) release() {
|
||||
hasherPool.Put(h)
|
||||
}
|
||||
|
||||
// ReadAccountTrieNode retrieves the account trie node and the associated node
|
||||
// hash with the specified node path.
|
||||
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) {
|
||||
data, err := db.Get(accountTrieNodeKey(path))
|
||||
if err != nil {
|
||||
return nil, common.Hash{}
|
||||
}
|
||||
h := newHasher()
|
||||
defer h.release()
|
||||
return data, h.hash(data)
|
||||
// ReadAccountTrieNode retrieves the account trie node with the specified node path.
|
||||
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) []byte {
|
||||
data, _ := db.Get(accountTrieNodeKey(path))
|
||||
return data
|
||||
}
|
||||
|
||||
// HasAccountTrieNode checks the account trie node presence with the specified
|
||||
// node path and the associated node hash.
|
||||
func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte, hash common.Hash) bool {
|
||||
data, err := db.Get(accountTrieNodeKey(path))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
h := newHasher()
|
||||
defer h.release()
|
||||
return h.hash(data) == hash
|
||||
}
|
||||
|
||||
// ExistsAccountTrieNode checks the presence of the account trie node with the
|
||||
// HasAccountTrieNode checks the presence of the account trie node with the
|
||||
// specified node path, regardless of the node hash.
|
||||
func ExistsAccountTrieNode(db ethdb.KeyValueReader, path []byte) bool {
|
||||
func HasAccountTrieNode(db ethdb.KeyValueReader, path []byte) bool {
|
||||
has, err := db.Has(accountTrieNodeKey(path))
|
||||
if err != nil {
|
||||
return false
|
||||
@@ -113,33 +94,15 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
// ReadStorageTrieNode retrieves the storage trie node and the associated node
|
||||
// hash with the specified node path.
|
||||
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) {
|
||||
data, err := db.Get(storageTrieNodeKey(accountHash, path))
|
||||
if err != nil {
|
||||
return nil, common.Hash{}
|
||||
}
|
||||
h := newHasher()
|
||||
defer h.release()
|
||||
return data, h.hash(data)
|
||||
// ReadStorageTrieNode retrieves the storage trie node with the specified node path.
|
||||
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) []byte {
|
||||
data, _ := db.Get(storageTrieNodeKey(accountHash, path))
|
||||
return data
|
||||
}
|
||||
|
||||
// HasStorageTrieNode checks the storage trie node presence with the provided
|
||||
// node path and the associated node hash.
|
||||
func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte, hash common.Hash) bool {
|
||||
data, err := db.Get(storageTrieNodeKey(accountHash, path))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
h := newHasher()
|
||||
defer h.release()
|
||||
return h.hash(data) == hash
|
||||
}
|
||||
|
||||
// ExistsStorageTrieNode checks the presence of the storage trie node with the
|
||||
// HasStorageTrieNode checks the presence of the storage trie node with the
|
||||
// specified account hash and node path, regardless of the node hash.
|
||||
func ExistsStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) bool {
|
||||
func HasStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) bool {
|
||||
has, err := db.Has(storageTrieNodeKey(accountHash, path))
|
||||
if err != nil {
|
||||
return false
|
||||
@@ -198,10 +161,18 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c
|
||||
case HashScheme:
|
||||
return HasLegacyTrieNode(db, hash)
|
||||
case PathScheme:
|
||||
var blob []byte
|
||||
if owner == (common.Hash{}) {
|
||||
return HasAccountTrieNode(db, path, hash)
|
||||
blob = ReadAccountTrieNode(db, path)
|
||||
} else {
|
||||
blob = ReadStorageTrieNode(db, owner, path)
|
||||
}
|
||||
return HasStorageTrieNode(db, owner, path, hash)
|
||||
if len(blob) == 0 {
|
||||
return false
|
||||
}
|
||||
h := newHasher()
|
||||
defer h.release()
|
||||
return h.hash(blob) == hash // exists but not match
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown scheme %v", scheme))
|
||||
}
|
||||
@@ -209,43 +180,35 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c
|
||||
|
||||
// ReadTrieNode retrieves the trie node from database with the provided node info
|
||||
// and associated node hash.
|
||||
// hashScheme-based lookup requires the following:
|
||||
// - hash
|
||||
//
|
||||
// pathScheme-based lookup requires the following:
|
||||
// - owner
|
||||
// - path
|
||||
func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte {
|
||||
switch scheme {
|
||||
case HashScheme:
|
||||
return ReadLegacyTrieNode(db, hash)
|
||||
case PathScheme:
|
||||
var (
|
||||
blob []byte
|
||||
nHash common.Hash
|
||||
)
|
||||
var blob []byte
|
||||
if owner == (common.Hash{}) {
|
||||
blob, nHash = ReadAccountTrieNode(db, path)
|
||||
blob = ReadAccountTrieNode(db, path)
|
||||
} else {
|
||||
blob, nHash = ReadStorageTrieNode(db, owner, path)
|
||||
blob = ReadStorageTrieNode(db, owner, path)
|
||||
}
|
||||
if nHash != hash {
|
||||
if len(blob) == 0 {
|
||||
return nil
|
||||
}
|
||||
h := newHasher()
|
||||
defer h.release()
|
||||
if h.hash(blob) != hash {
|
||||
return nil // exists but not match
|
||||
}
|
||||
return blob
|
||||
default:
|
||||
panic(fmt.Sprintf("Unknown scheme %v", scheme))
|
||||
}
|
||||
}
|
||||
|
||||
// WriteTrieNode writes the trie node into database with the provided node info
|
||||
// and associated node hash.
|
||||
// hashScheme-based lookup requires the following:
|
||||
// - hash
|
||||
// WriteTrieNode writes the trie node into database with the provided node info.
|
||||
//
|
||||
// pathScheme-based lookup requires the following:
|
||||
// - owner
|
||||
// - path
|
||||
// hash-scheme requires the node hash as the identifier.
|
||||
// path-scheme requires the node owner and path as the identifier.
|
||||
func WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, node []byte, scheme string) {
|
||||
switch scheme {
|
||||
case HashScheme:
|
||||
@@ -261,14 +224,10 @@ func WriteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash
|
||||
}
|
||||
}
|
||||
|
||||
// DeleteTrieNode deletes the trie node from database with the provided node info
|
||||
// and associated node hash.
|
||||
// hashScheme-based lookup requires the following:
|
||||
// - hash
|
||||
// DeleteTrieNode deletes the trie node from database with the provided node info.
|
||||
//
|
||||
// pathScheme-based lookup requires the following:
|
||||
// - owner
|
||||
// - path
|
||||
// hash-scheme requires the node hash as the identifier.
|
||||
// path-scheme requires the node owner and path as the identifier.
|
||||
func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, hash common.Hash, scheme string) {
|
||||
switch scheme {
|
||||
case HashScheme:
|
||||
@@ -287,9 +246,8 @@ func DeleteTrieNode(db ethdb.KeyValueWriter, owner common.Hash, path []byte, has
|
||||
// ReadStateScheme reads the state scheme of persistent state, or none
|
||||
// if the state is not present in database.
|
||||
func ReadStateScheme(db ethdb.Reader) string {
|
||||
// Check if state in path-based scheme is present
|
||||
blob, _ := ReadAccountTrieNode(db, nil)
|
||||
if len(blob) != 0 {
|
||||
// Check if state in path-based scheme is present.
|
||||
if HasAccountTrieNode(db, nil) {
|
||||
return PathScheme
|
||||
}
|
||||
// The root node might be deleted during the initial snap sync, check
|
||||
@@ -304,8 +262,7 @@ func ReadStateScheme(db ethdb.Reader) string {
|
||||
if header == nil {
|
||||
return "" // empty datadir
|
||||
}
|
||||
blob = ReadLegacyTrieNode(db, header.Root)
|
||||
if len(blob) == 0 {
|
||||
if !HasLegacyTrieNode(db, header.Root) {
|
||||
return "" // no state in disk
|
||||
}
|
||||
return HashScheme
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
package rawdb
|
||||
|
||||
import "path/filepath"
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
// The list of table names of chain freezer.
|
||||
const (
|
||||
@@ -75,7 +79,15 @@ var (
|
||||
// freezers the collections of all builtin freezers.
|
||||
var freezers = []string{ChainFreezerName, StateFreezerName}
|
||||
|
||||
// NewStateFreezer initializes the freezer for state history.
|
||||
func NewStateFreezer(ancientDir string, readOnly bool) (*ResettableFreezer, error) {
|
||||
return NewResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
|
||||
// NewStateFreezer initializes the ancient store for state history.
|
||||
//
|
||||
// - if the empty directory is given, initializes the pure in-memory
|
||||
// state freezer (e.g. dev mode).
|
||||
// - if non-empty directory is given, initializes the regular file-based
|
||||
// state freezer.
|
||||
func NewStateFreezer(ancientDir string, readOnly bool) (ethdb.ResettableAncientStore, error) {
|
||||
if ancientDir == "" {
|
||||
return NewMemoryFreezer(readOnly, stateFreezerNoSnappy), nil
|
||||
}
|
||||
return newResettableFreezer(filepath.Join(ancientDir, StateFreezerName), "eth/db/state", readOnly, stateHistoryTableSize, stateFreezerNoSnappy)
|
||||
}
|
||||
|
||||
@@ -89,20 +89,17 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
|
||||
infos = append(infos, info)
|
||||
|
||||
case StateFreezerName:
|
||||
if ReadStateScheme(db) != PathScheme {
|
||||
continue
|
||||
}
|
||||
datadir, err := db.AncientDatadir()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
f, err := NewStateFreezer(datadir, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
continue // might be possible the state freezer is not existent
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
info, err := inspect(StateFreezerName, stateFreezerNoSnappy, f)
|
||||
info, err := inspect(freezer, stateFreezerNoSnappy, f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
325
core/rawdb/ancienttest/testsuite.go
Normal file
325
core/rawdb/ancienttest/testsuite.go
Normal file
@@ -0,0 +1,325 @@
|
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package ancienttest
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/internal/testrand"
|
||||
)
|
||||
|
||||
// TestAncientSuite runs a suite of tests against an ancient database
|
||||
// implementation.
|
||||
func TestAncientSuite(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) {
|
||||
// Test basic read methods
|
||||
t.Run("BasicRead", func(t *testing.T) { basicRead(t, newFn) })
|
||||
|
||||
// Test batch read method
|
||||
t.Run("BatchRead", func(t *testing.T) { batchRead(t, newFn) })
|
||||
|
||||
// Test basic write methods
|
||||
t.Run("BasicWrite", func(t *testing.T) { basicWrite(t, newFn) })
|
||||
|
||||
// Test if data mutation is allowed after db write
|
||||
t.Run("nonMutable", func(t *testing.T) { nonMutable(t, newFn) })
|
||||
}
|
||||
|
||||
func basicRead(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) {
|
||||
var (
|
||||
db = newFn([]string{"a"})
|
||||
data = makeDataset(100, 32)
|
||||
)
|
||||
defer db.Close()
|
||||
|
||||
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 0; i < len(data); i++ {
|
||||
op.AppendRaw("a", uint64(i), data[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
db.TruncateTail(10)
|
||||
db.TruncateHead(90)
|
||||
|
||||
// Test basic tail and head retrievals
|
||||
tail, err := db.Tail()
|
||||
if err != nil || tail != 10 {
|
||||
t.Fatal("Failed to retrieve tail")
|
||||
}
|
||||
ancient, err := db.Ancients()
|
||||
if err != nil || ancient != 90 {
|
||||
t.Fatal("Failed to retrieve ancient")
|
||||
}
|
||||
|
||||
// Test the deleted items shouldn't be reachable
|
||||
var cases = []struct {
|
||||
start int
|
||||
limit int
|
||||
}{
|
||||
{0, 10},
|
||||
{90, 100},
|
||||
}
|
||||
for _, c := range cases {
|
||||
for i := c.start; i < c.limit; i++ {
|
||||
exist, err := db.HasAncient("a", uint64(i))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to check presence, %v", err)
|
||||
}
|
||||
if exist {
|
||||
t.Fatalf("Item %d is already truncated", uint64(i))
|
||||
}
|
||||
_, err = db.Ancient("a", uint64(i))
|
||||
if err == nil {
|
||||
t.Fatal("Error is expected for non-existent item")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test the items in range should be reachable
|
||||
for i := 10; i < 90; i++ {
|
||||
exist, err := db.HasAncient("a", uint64(i))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to check presence, %v", err)
|
||||
}
|
||||
if !exist {
|
||||
t.Fatalf("Item %d is missing", uint64(i))
|
||||
}
|
||||
blob, err := db.Ancient("a", uint64(i))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve item, %v", err)
|
||||
}
|
||||
if !bytes.Equal(blob, data[i]) {
|
||||
t.Fatalf("Unexpected item content, want: %v, got: %v", data[i], blob)
|
||||
}
|
||||
}
|
||||
|
||||
// Test the items in unknown table shouldn't be reachable
|
||||
exist, err := db.HasAncient("b", uint64(0))
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to check presence, %v", err)
|
||||
}
|
||||
if exist {
|
||||
t.Fatal("Item in unknown table shouldn't be found")
|
||||
}
|
||||
_, err = db.Ancient("b", uint64(0))
|
||||
if err == nil {
|
||||
t.Fatal("Error is expected for unknown table")
|
||||
}
|
||||
}
|
||||
|
||||
func batchRead(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) {
|
||||
var (
|
||||
db = newFn([]string{"a"})
|
||||
data = makeDataset(100, 32)
|
||||
)
|
||||
defer db.Close()
|
||||
|
||||
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 0; i < 100; i++ {
|
||||
op.AppendRaw("a", uint64(i), data[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
db.TruncateTail(10)
|
||||
db.TruncateHead(90)
|
||||
|
||||
// Test the items in range should be reachable
|
||||
var cases = []struct {
|
||||
start uint64
|
||||
count uint64
|
||||
maxSize uint64
|
||||
expStart int
|
||||
expLimit int
|
||||
}{
|
||||
// Items in range [10, 90) with no size limitation
|
||||
{
|
||||
10, 80, 0, 10, 90,
|
||||
},
|
||||
// Items in range [10, 90) with 32 size cap, single item is expected
|
||||
{
|
||||
10, 80, 32, 10, 11,
|
||||
},
|
||||
// Items in range [10, 90) with 31 size cap, single item is expected
|
||||
{
|
||||
10, 80, 31, 10, 11,
|
||||
},
|
||||
// Items in range [10, 90) with 32*80 size cap, all items are expected
|
||||
{
|
||||
10, 80, 32 * 80, 10, 90,
|
||||
},
|
||||
// Extra items above the last item are not returned
|
||||
{
|
||||
10, 90, 0, 10, 90,
|
||||
},
|
||||
}
|
||||
for i, c := range cases {
|
||||
batch, err := db.AncientRange("a", c.start, c.count, c.maxSize)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to retrieve item in range, %v", err)
|
||||
}
|
||||
if !reflect.DeepEqual(batch, data[c.expStart:c.expLimit]) {
|
||||
t.Fatalf("Case %d, Batch content is not matched", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Test out-of-range / zero-size retrieval should be rejected
|
||||
_, err := db.AncientRange("a", 0, 1, 0)
|
||||
if err == nil {
|
||||
t.Fatal("Out-of-range retrieval should be rejected")
|
||||
}
|
||||
_, err = db.AncientRange("a", 90, 1, 0)
|
||||
if err == nil {
|
||||
t.Fatal("Out-of-range retrieval should be rejected")
|
||||
}
|
||||
_, err = db.AncientRange("a", 10, 0, 0)
|
||||
if err == nil {
|
||||
t.Fatal("Zero-size retrieval should be rejected")
|
||||
}
|
||||
|
||||
// Test item in unknown table shouldn't be reachable
|
||||
_, err = db.AncientRange("b", 10, 1, 0)
|
||||
if err == nil {
|
||||
t.Fatal("Item in unknown table shouldn't be found")
|
||||
}
|
||||
}
|
||||
|
||||
func basicWrite(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) {
|
||||
var (
|
||||
db = newFn([]string{"a", "b"})
|
||||
dataA = makeDataset(100, 32)
|
||||
dataB = makeDataset(100, 32)
|
||||
)
|
||||
defer db.Close()
|
||||
|
||||
// The ancient write to tables should be aligned
|
||||
_, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 0; i < 100; i++ {
|
||||
op.AppendRaw("a", uint64(i), dataA[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err == nil {
|
||||
t.Fatal("Unaligned ancient write should be rejected")
|
||||
}
|
||||
|
||||
// Test normal ancient write
|
||||
size, err := db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 0; i < 100; i++ {
|
||||
op.AppendRaw("a", uint64(i), dataA[i])
|
||||
op.AppendRaw("b", uint64(i), dataB[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write ancient data %v", err)
|
||||
}
|
||||
wantSize := int64(6400)
|
||||
if size != wantSize {
|
||||
t.Fatalf("Ancient write size is not expected, want: %d, got: %d", wantSize, size)
|
||||
}
|
||||
|
||||
// Write should work after head truncating
|
||||
db.TruncateHead(90)
|
||||
_, err = db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 90; i < 100; i++ {
|
||||
op.AppendRaw("a", uint64(i), dataA[i])
|
||||
op.AppendRaw("b", uint64(i), dataB[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write ancient data %v", err)
|
||||
}
|
||||
|
||||
// Write should work after truncating everything
|
||||
db.TruncateTail(0)
|
||||
_, err = db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 0; i < 100; i++ {
|
||||
op.AppendRaw("a", uint64(i), dataA[i])
|
||||
op.AppendRaw("b", uint64(i), dataB[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to write ancient data %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func nonMutable(t *testing.T, newFn func(kinds []string) ethdb.AncientStore) {
|
||||
db := newFn([]string{"a"})
|
||||
defer db.Close()
|
||||
|
||||
// We write 100 zero-bytes to the freezer and immediately mutate the slice
|
||||
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
data := make([]byte, 100)
|
||||
op.AppendRaw("a", uint64(0), data)
|
||||
for i := range data {
|
||||
data[i] = 0xff
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// Now read it.
|
||||
data, err := db.Ancient("a", uint64(0))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for k, v := range data {
|
||||
if v != 0 {
|
||||
t.Fatalf("byte %d != 0: %x", k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestResettableAncientSuite runs a suite of tests against a resettable ancient
|
||||
// database implementation.
|
||||
func TestResettableAncientSuite(t *testing.T, newFn func(kinds []string) ethdb.ResettableAncientStore) {
|
||||
t.Run("Reset", func(t *testing.T) {
|
||||
var (
|
||||
db = newFn([]string{"a"})
|
||||
data = makeDataset(100, 32)
|
||||
)
|
||||
defer db.Close()
|
||||
|
||||
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 0; i < 100; i++ {
|
||||
op.AppendRaw("a", uint64(i), data[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
db.TruncateTail(10)
|
||||
db.TruncateHead(90)
|
||||
|
||||
// Ancient write should work after resetting
|
||||
db.Reset()
|
||||
db.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for i := 0; i < 100; i++ {
|
||||
op.AppendRaw("a", uint64(i), data[i])
|
||||
}
|
||||
return nil
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func makeDataset(size, value int) [][]byte {
|
||||
var vals [][]byte
|
||||
for i := 0; i < size; i += 1 {
|
||||
vals = append(vals, testrand.Bytes(value))
|
||||
}
|
||||
return vals
|
||||
}
|
||||
@@ -39,26 +39,40 @@ const (
|
||||
freezerBatchLimit = 30000
|
||||
)
|
||||
|
||||
// chainFreezer is a wrapper of freezer with additional chain freezing feature.
|
||||
// The background thread will keep moving ancient chain segments from key-value
|
||||
// database to flat files for saving space on live database.
|
||||
// chainFreezer is a wrapper of chain ancient store with additional chain freezing
|
||||
// feature. The background thread will keep moving ancient chain segments from
|
||||
// key-value database to flat files for saving space on live database.
|
||||
type chainFreezer struct {
|
||||
*Freezer
|
||||
ethdb.AncientStore // Ancient store for storing cold chain segment
|
||||
|
||||
quit chan struct{}
|
||||
wg sync.WaitGroup
|
||||
trigger chan chan struct{} // Manual blocking freeze trigger, test determinism
|
||||
}
|
||||
|
||||
// newChainFreezer initializes the freezer for ancient chain data.
|
||||
// newChainFreezer initializes the freezer for ancient chain segment.
|
||||
//
|
||||
// - if the empty directory is given, initializes the pure in-memory
|
||||
// state freezer (e.g. dev mode).
|
||||
// - if non-empty directory is given, initializes the regular file-based
|
||||
// state freezer.
|
||||
func newChainFreezer(datadir string, namespace string, readonly bool) (*chainFreezer, error) {
|
||||
freezer, err := NewChainFreezer(datadir, namespace, readonly)
|
||||
var (
|
||||
err error
|
||||
freezer ethdb.AncientStore
|
||||
)
|
||||
if datadir == "" {
|
||||
freezer = NewMemoryFreezer(readonly, chainFreezerNoSnappy)
|
||||
} else {
|
||||
freezer, err = NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &chainFreezer{
|
||||
Freezer: freezer,
|
||||
quit: make(chan struct{}),
|
||||
trigger: make(chan chan struct{}),
|
||||
AncientStore: freezer,
|
||||
quit: make(chan struct{}),
|
||||
trigger: make(chan chan struct{}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -70,7 +84,7 @@ func (f *chainFreezer) Close() error {
|
||||
close(f.quit)
|
||||
}
|
||||
f.wg.Wait()
|
||||
return f.Freezer.Close()
|
||||
return f.AncientStore.Close()
|
||||
}
|
||||
|
||||
// readHeadNumber returns the number of chain head block. 0 is returned if the
|
||||
@@ -167,7 +181,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
||||
log.Debug("Current full block not old enough to freeze", "err", err)
|
||||
continue
|
||||
}
|
||||
frozen := f.frozen.Load()
|
||||
frozen, _ := f.Ancients() // no error will occur, safe to ignore
|
||||
|
||||
// Short circuit if the blocks below threshold are already frozen.
|
||||
if frozen != 0 && frozen-1 >= threshold {
|
||||
@@ -190,7 +204,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
||||
backoff = true
|
||||
continue
|
||||
}
|
||||
// Batch of blocks have been frozen, flush them before wiping from leveldb
|
||||
// Batch of blocks have been frozen, flush them before wiping from key-value store
|
||||
if err := f.Sync(); err != nil {
|
||||
log.Crit("Failed to flush frozen tables", "err", err)
|
||||
}
|
||||
@@ -210,7 +224,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
||||
|
||||
// Wipe out side chains also and track dangling side chains
|
||||
var dangling []common.Hash
|
||||
frozen = f.frozen.Load() // Needs reload after during freezeRange
|
||||
frozen, _ = f.Ancients() // Needs reload after during freezeRange
|
||||
for number := first; number < frozen; number++ {
|
||||
// Always keep the genesis block in active database
|
||||
if number != 0 {
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestChainIterator(t *testing.T) {
|
||||
var block *types.Block
|
||||
var txs []*types.Transaction
|
||||
to := common.BytesToAddress([]byte{0x11})
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newTestHasher()) // Empty genesis block
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher()) // Empty genesis block
|
||||
WriteBlock(chainDb, block)
|
||||
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||
for i := uint64(1); i <= 10; i++ {
|
||||
@@ -60,7 +60,7 @@ func TestChainIterator(t *testing.T) {
|
||||
})
|
||||
}
|
||||
txs = append(txs, tx)
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newTestHasher())
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher())
|
||||
WriteBlock(chainDb, block)
|
||||
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||
}
|
||||
@@ -111,7 +111,7 @@ func TestIndexTransactions(t *testing.T) {
|
||||
to := common.BytesToAddress([]byte{0x11})
|
||||
|
||||
// Write empty genesis block
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, nil, newTestHasher())
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(0))}, nil, nil, newTestHasher())
|
||||
WriteBlock(chainDb, block)
|
||||
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||
|
||||
@@ -138,7 +138,7 @@ func TestIndexTransactions(t *testing.T) {
|
||||
})
|
||||
}
|
||||
txs = append(txs, tx)
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, []*types.Transaction{tx}, nil, nil, newTestHasher())
|
||||
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, &types.Body{Transactions: types.Transactions{tx}}, nil, newTestHasher())
|
||||
WriteBlock(chainDb, block)
|
||||
WriteCanonicalHash(chainDb, block.Hash(), block.NumberU64())
|
||||
}
|
||||
|
||||
@@ -34,11 +34,13 @@ import (
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
// freezerdb is a database wrapper that enables freezer data retrievals.
|
||||
// freezerdb is a database wrapper that enables ancient chain segment freezing.
|
||||
type freezerdb struct {
|
||||
ancientRoot string
|
||||
ethdb.KeyValueStore
|
||||
ethdb.AncientStore
|
||||
*chainFreezer
|
||||
|
||||
readOnly bool
|
||||
ancientRoot string
|
||||
}
|
||||
|
||||
// AncientDatadir returns the path of root ancient directory.
|
||||
@@ -50,7 +52,7 @@ func (frdb *freezerdb) AncientDatadir() (string, error) {
|
||||
// the slow ancient tables.
|
||||
func (frdb *freezerdb) Close() error {
|
||||
var errs []error
|
||||
if err := frdb.AncientStore.Close(); err != nil {
|
||||
if err := frdb.chainFreezer.Close(); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := frdb.KeyValueStore.Close(); err != nil {
|
||||
@@ -66,12 +68,12 @@ func (frdb *freezerdb) Close() error {
|
||||
// a freeze cycle completes, without having to sleep for a minute to trigger the
|
||||
// automatic background run.
|
||||
func (frdb *freezerdb) Freeze() error {
|
||||
if frdb.AncientStore.(*chainFreezer).readonly {
|
||||
if frdb.readOnly {
|
||||
return errReadOnly
|
||||
}
|
||||
// Trigger a freeze cycle and block until it's done
|
||||
trigger := make(chan struct{}, 1)
|
||||
frdb.AncientStore.(*chainFreezer).trigger <- trigger
|
||||
frdb.chainFreezer.trigger <- trigger
|
||||
<-trigger
|
||||
return nil
|
||||
}
|
||||
@@ -192,8 +194,14 @@ func resolveChainFreezerDir(ancient string) string {
|
||||
// storage. The passed ancient indicates the path of root ancient directory
|
||||
// where the chain freezer can be opened.
|
||||
func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace string, readonly bool) (ethdb.Database, error) {
|
||||
// Create the idle freezer instance
|
||||
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly)
|
||||
// Create the idle freezer instance. If the given ancient directory is empty,
|
||||
// in-memory chain freezer is used (e.g. dev mode); otherwise the regular
|
||||
// file-based freezer is created.
|
||||
chainFreezerDir := ancient
|
||||
if chainFreezerDir != "" {
|
||||
chainFreezerDir = resolveChainFreezerDir(chainFreezerDir)
|
||||
}
|
||||
frdb, err := newChainFreezer(chainFreezerDir, namespace, readonly)
|
||||
if err != nil {
|
||||
printChainMetadata(db)
|
||||
return nil, err
|
||||
@@ -277,7 +285,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
}
|
||||
}
|
||||
// Freezer is consistent with the key-value database, permit combining the two
|
||||
if !frdb.readonly {
|
||||
if !readonly {
|
||||
frdb.wg.Add(1)
|
||||
go func() {
|
||||
frdb.freeze(db)
|
||||
@@ -287,7 +295,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
return &freezerdb{
|
||||
ancientRoot: ancient,
|
||||
KeyValueStore: db,
|
||||
AncientStore: frdb,
|
||||
chainFreezer: frdb,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ const freezerTableSize = 2 * 1000 * 1000 * 1000
|
||||
// reserving it for go-ethereum. This would also reduce the memory requirements
|
||||
// of Geth, and thus also GC overhead.
|
||||
type Freezer struct {
|
||||
frozen atomic.Uint64 // Number of blocks already frozen
|
||||
frozen atomic.Uint64 // Number of items already frozen
|
||||
tail atomic.Uint64 // Number of the first stored item in the freezer
|
||||
|
||||
// This lock synchronizes writers and the truncate operation, as well as
|
||||
@@ -76,12 +76,6 @@ type Freezer struct {
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
// NewChainFreezer is a small utility method around NewFreezer that sets the
|
||||
// default parameters for the chain storage.
|
||||
func NewChainFreezer(datadir string, namespace string, readonly bool) (*Freezer, error) {
|
||||
return NewFreezer(datadir, namespace, readonly, freezerTableSize, chainFreezerNoSnappy)
|
||||
}
|
||||
|
||||
// NewFreezer creates a freezer instance for maintaining immutable ordered
|
||||
// data according to the given parameters.
|
||||
//
|
||||
|
||||
428
core/rawdb/freezer_memory.go
Normal file
428
core/rawdb/freezer_memory.go
Normal file
@@ -0,0 +1,428 @@
|
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rawdb
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
// memoryTable is used to store a list of sequential items in memory.
|
||||
type memoryTable struct {
|
||||
name string // Table name
|
||||
items uint64 // Number of stored items in the table, including the deleted ones
|
||||
offset uint64 // Number of deleted items from the table
|
||||
data [][]byte // List of rlp-encoded items, sort in order
|
||||
size uint64 // Total memory size occupied by the table
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// newMemoryTable initializes the memory table.
|
||||
func newMemoryTable(name string) *memoryTable {
|
||||
return &memoryTable{name: name}
|
||||
}
|
||||
|
||||
// has returns an indicator whether the specified data exists.
|
||||
func (t *memoryTable) has(number uint64) bool {
|
||||
t.lock.RLock()
|
||||
defer t.lock.RUnlock()
|
||||
|
||||
return number >= t.offset && number < t.items
|
||||
}
|
||||
|
||||
// retrieve retrieves multiple items in sequence, starting from the index 'start'.
|
||||
// It will return:
|
||||
// - at most 'count' items,
|
||||
// - if maxBytes is specified: at least 1 item (even if exceeding the maxByteSize),
|
||||
// but will otherwise return as many items as fit into maxByteSize.
|
||||
// - if maxBytes is not specified, 'count' items will be returned if they are present
|
||||
func (t *memoryTable) retrieve(start uint64, count, maxBytes uint64) ([][]byte, error) {
|
||||
t.lock.RLock()
|
||||
defer t.lock.RUnlock()
|
||||
|
||||
var (
|
||||
size uint64
|
||||
batch [][]byte
|
||||
)
|
||||
// Ensure the start is written, not deleted from the tail, and that the
|
||||
// caller actually wants something.
|
||||
if t.items <= start || t.offset > start || count == 0 {
|
||||
return nil, errOutOfBounds
|
||||
}
|
||||
// Cap the item count if the retrieval is out of bound.
|
||||
if start+count > t.items {
|
||||
count = t.items - start
|
||||
}
|
||||
for n := start; n < start+count; n++ {
|
||||
index := n - t.offset
|
||||
if len(batch) != 0 && maxBytes != 0 && size+uint64(len(t.data[index])) > maxBytes {
|
||||
return batch, nil
|
||||
}
|
||||
batch = append(batch, t.data[index])
|
||||
size += uint64(len(t.data[index]))
|
||||
}
|
||||
return batch, nil
|
||||
}
|
||||
|
||||
// truncateHead discards any recent data above the provided threshold number.
|
||||
func (t *memoryTable) truncateHead(items uint64) error {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
// Short circuit if nothing to delete.
|
||||
if t.items <= items {
|
||||
return nil
|
||||
}
|
||||
if items < t.offset {
|
||||
return errors.New("truncation below tail")
|
||||
}
|
||||
t.data = t.data[:items-t.offset]
|
||||
t.items = items
|
||||
return nil
|
||||
}
|
||||
|
||||
// truncateTail discards any recent data before the provided threshold number.
|
||||
func (t *memoryTable) truncateTail(items uint64) error {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
// Short circuit if nothing to delete.
|
||||
if t.offset >= items {
|
||||
return nil
|
||||
}
|
||||
if t.items < items {
|
||||
return errors.New("truncation above head")
|
||||
}
|
||||
t.data = t.data[items-t.offset:]
|
||||
t.offset = items
|
||||
return nil
|
||||
}
|
||||
|
||||
// commit merges the given item batch into table. It's presumed that the
|
||||
// batch is ordered and continuous with table.
|
||||
func (t *memoryTable) commit(batch [][]byte) error {
|
||||
t.lock.Lock()
|
||||
defer t.lock.Unlock()
|
||||
|
||||
for _, item := range batch {
|
||||
t.size += uint64(len(item))
|
||||
}
|
||||
t.data = append(t.data, batch...)
|
||||
t.items += uint64(len(batch))
|
||||
return nil
|
||||
}
|
||||
|
||||
// memoryBatch is the singleton batch used for ancient write.
|
||||
type memoryBatch struct {
|
||||
data map[string][][]byte
|
||||
next map[string]uint64
|
||||
size map[string]int64
|
||||
}
|
||||
|
||||
func newMemoryBatch() *memoryBatch {
|
||||
return &memoryBatch{
|
||||
data: make(map[string][][]byte),
|
||||
next: make(map[string]uint64),
|
||||
size: make(map[string]int64),
|
||||
}
|
||||
}
|
||||
|
||||
func (b *memoryBatch) reset(freezer *MemoryFreezer) {
|
||||
b.data = make(map[string][][]byte)
|
||||
b.next = make(map[string]uint64)
|
||||
b.size = make(map[string]int64)
|
||||
|
||||
for name, table := range freezer.tables {
|
||||
b.next[name] = table.items
|
||||
}
|
||||
}
|
||||
|
||||
// Append adds an RLP-encoded item.
|
||||
func (b *memoryBatch) Append(kind string, number uint64, item interface{}) error {
|
||||
if b.next[kind] != number {
|
||||
return errOutOrderInsertion
|
||||
}
|
||||
blob, err := rlp.EncodeToBytes(item)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.data[kind] = append(b.data[kind], blob)
|
||||
b.next[kind]++
|
||||
b.size[kind] += int64(len(blob))
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppendRaw adds an item without RLP-encoding it.
|
||||
func (b *memoryBatch) AppendRaw(kind string, number uint64, blob []byte) error {
|
||||
if b.next[kind] != number {
|
||||
return errOutOrderInsertion
|
||||
}
|
||||
b.data[kind] = append(b.data[kind], common.CopyBytes(blob))
|
||||
b.next[kind]++
|
||||
b.size[kind] += int64(len(blob))
|
||||
return nil
|
||||
}
|
||||
|
||||
// commit is called at the end of a write operation and writes all remaining
|
||||
// data to tables.
|
||||
func (b *memoryBatch) commit(freezer *MemoryFreezer) (items uint64, writeSize int64, err error) {
|
||||
// Check that count agrees on all batches.
|
||||
items = math.MaxUint64
|
||||
for name, next := range b.next {
|
||||
if items < math.MaxUint64 && next != items {
|
||||
return 0, 0, fmt.Errorf("table %s is at item %d, want %d", name, next, items)
|
||||
}
|
||||
items = next
|
||||
}
|
||||
// Commit all table batches.
|
||||
for name, batch := range b.data {
|
||||
table := freezer.tables[name]
|
||||
if err := table.commit(batch); err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
writeSize += b.size[name]
|
||||
}
|
||||
return items, writeSize, nil
|
||||
}
|
||||
|
||||
// MemoryFreezer is an ephemeral ancient store. It implements the ethdb.AncientStore
|
||||
// interface and can be used along with ephemeral key-value store.
|
||||
type MemoryFreezer struct {
|
||||
items uint64 // Number of items stored
|
||||
tail uint64 // Number of the first stored item in the freezer
|
||||
readonly bool // Flag if the freezer is only for reading
|
||||
lock sync.RWMutex // Lock to protect fields
|
||||
tables map[string]*memoryTable // Tables for storing everything
|
||||
writeBatch *memoryBatch // Pre-allocated write batch
|
||||
}
|
||||
|
||||
// NewMemoryFreezer initializes an in-memory freezer instance.
|
||||
func NewMemoryFreezer(readonly bool, tableName map[string]bool) *MemoryFreezer {
|
||||
tables := make(map[string]*memoryTable)
|
||||
for name := range tableName {
|
||||
tables[name] = newMemoryTable(name)
|
||||
}
|
||||
return &MemoryFreezer{
|
||||
writeBatch: newMemoryBatch(),
|
||||
readonly: readonly,
|
||||
tables: tables,
|
||||
}
|
||||
}
|
||||
|
||||
// HasAncient returns an indicator whether the specified data exists.
|
||||
func (f *MemoryFreezer) HasAncient(kind string, number uint64) (bool, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
if table := f.tables[kind]; table != nil {
|
||||
return table.has(number), nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Ancient retrieves an ancient binary blob from the in-memory freezer.
|
||||
func (f *MemoryFreezer) Ancient(kind string, number uint64) ([]byte, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
t := f.tables[kind]
|
||||
if t == nil {
|
||||
return nil, errUnknownTable
|
||||
}
|
||||
data, err := t.retrieve(number, 1, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data[0], nil
|
||||
}
|
||||
|
||||
// AncientRange retrieves multiple items in sequence, starting from the index 'start'.
|
||||
// It will return
|
||||
// - at most 'count' items,
|
||||
// - if maxBytes is specified: at least 1 item (even if exceeding the maxByteSize),
|
||||
// but will otherwise return as many items as fit into maxByteSize.
|
||||
// - if maxBytes is not specified, 'count' items will be returned if they are present
|
||||
func (f *MemoryFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
t := f.tables[kind]
|
||||
if t == nil {
|
||||
return nil, errUnknownTable
|
||||
}
|
||||
return t.retrieve(start, count, maxBytes)
|
||||
}
|
||||
|
||||
// Ancients returns the ancient item numbers in the freezer.
|
||||
func (f *MemoryFreezer) Ancients() (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return f.items, nil
|
||||
}
|
||||
|
||||
// Tail returns the number of first stored item in the freezer.
|
||||
// This number can also be interpreted as the total deleted item numbers.
|
||||
func (f *MemoryFreezer) Tail() (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return f.tail, nil
|
||||
}
|
||||
|
||||
// AncientSize returns the ancient size of the specified category.
|
||||
func (f *MemoryFreezer) AncientSize(kind string) (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
if table := f.tables[kind]; table != nil {
|
||||
return table.size, nil
|
||||
}
|
||||
return 0, errUnknownTable
|
||||
}
|
||||
|
||||
// ReadAncients runs the given read operation while ensuring that no writes take place
|
||||
// on the underlying freezer.
|
||||
func (f *MemoryFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
return fn(f)
|
||||
}
|
||||
|
||||
// ModifyAncients runs the given write operation.
|
||||
func (f *MemoryFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.readonly {
|
||||
return 0, errReadOnly
|
||||
}
|
||||
// Roll back all tables to the starting position in case of error.
|
||||
defer func(old uint64) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
// The write operation has failed. Go back to the previous item position.
|
||||
for name, table := range f.tables {
|
||||
err := table.truncateHead(old)
|
||||
if err != nil {
|
||||
log.Error("Freezer table roll-back failed", "table", name, "index", old, "err", err)
|
||||
}
|
||||
}
|
||||
}(f.items)
|
||||
|
||||
// Modify the ancients in batch.
|
||||
f.writeBatch.reset(f)
|
||||
if err := fn(f.writeBatch); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
item, writeSize, err := f.writeBatch.commit(f)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
f.items = item
|
||||
return writeSize, nil
|
||||
}
|
||||
|
||||
// TruncateHead discards any recent data above the provided threshold number.
|
||||
// It returns the previous head number.
|
||||
func (f *MemoryFreezer) TruncateHead(items uint64) (uint64, error) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.readonly {
|
||||
return 0, errReadOnly
|
||||
}
|
||||
old := f.items
|
||||
if old <= items {
|
||||
return old, nil
|
||||
}
|
||||
for _, table := range f.tables {
|
||||
if err := table.truncateHead(items); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
f.items = items
|
||||
return old, nil
|
||||
}
|
||||
|
||||
// TruncateTail discards any recent data below the provided threshold number.
|
||||
func (f *MemoryFreezer) TruncateTail(tail uint64) (uint64, error) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.readonly {
|
||||
return 0, errReadOnly
|
||||
}
|
||||
old := f.tail
|
||||
if old >= tail {
|
||||
return old, nil
|
||||
}
|
||||
for _, table := range f.tables {
|
||||
if err := table.truncateTail(tail); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
f.tail = tail
|
||||
return old, nil
|
||||
}
|
||||
|
||||
// Sync flushes all data tables to disk.
|
||||
func (f *MemoryFreezer) Sync() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MigrateTable processes and migrates entries of a given table to a new format.
|
||||
// The second argument is a function that takes a raw entry and returns it
|
||||
// in the newest format.
|
||||
func (f *MemoryFreezer) MigrateTable(string, func([]byte) ([]byte, error)) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
// Close releases all the sources held by the memory freezer. It will panic if
|
||||
// any following invocation is made to a closed freezer.
|
||||
func (f *MemoryFreezer) Close() error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
f.tables = nil
|
||||
f.writeBatch = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reset drops all the data cached in the memory freezer and reset itself
|
||||
// back to default state.
|
||||
func (f *MemoryFreezer) Reset() error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
tables := make(map[string]*memoryTable)
|
||||
for name := range f.tables {
|
||||
tables[name] = newMemoryTable(name)
|
||||
}
|
||||
f.tables = tables
|
||||
f.items, f.tail = 0, 0
|
||||
return nil
|
||||
}
|
||||
41
core/rawdb/freezer_memory_test.go
Normal file
41
core/rawdb/freezer_memory_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package rawdb
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/rawdb/ancienttest"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
)
|
||||
|
||||
func TestMemoryFreezer(t *testing.T) {
|
||||
ancienttest.TestAncientSuite(t, func(kinds []string) ethdb.AncientStore {
|
||||
tables := make(map[string]bool)
|
||||
for _, kind := range kinds {
|
||||
tables[kind] = true
|
||||
}
|
||||
return NewMemoryFreezer(false, tables)
|
||||
})
|
||||
ancienttest.TestResettableAncientSuite(t, func(kinds []string) ethdb.ResettableAncientStore {
|
||||
tables := make(map[string]bool)
|
||||
for _, kind := range kinds {
|
||||
tables[kind] = true
|
||||
}
|
||||
return NewMemoryFreezer(false, tables)
|
||||
})
|
||||
}
|
||||
@@ -30,16 +30,17 @@ const tmpSuffix = ".tmp"
|
||||
// freezerOpenFunc is the function used to open/create a freezer.
|
||||
type freezerOpenFunc = func() (*Freezer, error)
|
||||
|
||||
// ResettableFreezer is a wrapper of the freezer which makes the
|
||||
// resettableFreezer is a wrapper of the freezer which makes the
|
||||
// freezer resettable.
|
||||
type ResettableFreezer struct {
|
||||
freezer *Freezer
|
||||
opener freezerOpenFunc
|
||||
datadir string
|
||||
lock sync.RWMutex
|
||||
type resettableFreezer struct {
|
||||
readOnly bool
|
||||
freezer *Freezer
|
||||
opener freezerOpenFunc
|
||||
datadir string
|
||||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
// NewResettableFreezer creates a resettable freezer, note freezer is
|
||||
// newResettableFreezer creates a resettable freezer, note freezer is
|
||||
// only resettable if the passed file directory is exclusively occupied
|
||||
// by the freezer. And also the user-configurable ancient root directory
|
||||
// is **not** supported for reset since it might be a mount and rename
|
||||
@@ -48,7 +49,7 @@ type ResettableFreezer struct {
|
||||
//
|
||||
// The reset function will delete directory atomically and re-create the
|
||||
// freezer from scratch.
|
||||
func NewResettableFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*ResettableFreezer, error) {
|
||||
func newResettableFreezer(datadir string, namespace string, readonly bool, maxTableSize uint32, tables map[string]bool) (*resettableFreezer, error) {
|
||||
if err := cleanup(datadir); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -59,10 +60,11 @@ func NewResettableFreezer(datadir string, namespace string, readonly bool, maxTa
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ResettableFreezer{
|
||||
freezer: freezer,
|
||||
opener: opener,
|
||||
datadir: datadir,
|
||||
return &resettableFreezer{
|
||||
readOnly: readonly,
|
||||
freezer: freezer,
|
||||
opener: opener,
|
||||
datadir: datadir,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -70,10 +72,13 @@ func NewResettableFreezer(datadir string, namespace string, readonly bool, maxTa
|
||||
// recreate the freezer from scratch. The atomicity of directory deletion
|
||||
// is guaranteed by the rename operation, the leftover directory will be
|
||||
// cleaned up in next startup in case crash happens after rename.
|
||||
func (f *ResettableFreezer) Reset() error {
|
||||
func (f *resettableFreezer) Reset() error {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
if f.readOnly {
|
||||
return errReadOnly
|
||||
}
|
||||
if err := f.freezer.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -93,7 +98,7 @@ func (f *ResettableFreezer) Reset() error {
|
||||
}
|
||||
|
||||
// Close terminates the chain freezer, unmapping all the data files.
|
||||
func (f *ResettableFreezer) Close() error {
|
||||
func (f *resettableFreezer) Close() error {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -102,7 +107,7 @@ func (f *ResettableFreezer) Close() error {
|
||||
|
||||
// HasAncient returns an indicator whether the specified ancient data exists
|
||||
// in the freezer
|
||||
func (f *ResettableFreezer) HasAncient(kind string, number uint64) (bool, error) {
|
||||
func (f *resettableFreezer) HasAncient(kind string, number uint64) (bool, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -110,7 +115,7 @@ func (f *ResettableFreezer) HasAncient(kind string, number uint64) (bool, error)
|
||||
}
|
||||
|
||||
// Ancient retrieves an ancient binary blob from the append-only immutable files.
|
||||
func (f *ResettableFreezer) Ancient(kind string, number uint64) ([]byte, error) {
|
||||
func (f *resettableFreezer) Ancient(kind string, number uint64) ([]byte, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -123,7 +128,7 @@ func (f *ResettableFreezer) Ancient(kind string, number uint64) ([]byte, error)
|
||||
// - if maxBytes is specified: at least 1 item (even if exceeding the maxByteSize),
|
||||
// but will otherwise return as many items as fit into maxByteSize.
|
||||
// - if maxBytes is not specified, 'count' items will be returned if they are present.
|
||||
func (f *ResettableFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
||||
func (f *resettableFreezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -131,7 +136,7 @@ func (f *ResettableFreezer) AncientRange(kind string, start, count, maxBytes uin
|
||||
}
|
||||
|
||||
// Ancients returns the length of the frozen items.
|
||||
func (f *ResettableFreezer) Ancients() (uint64, error) {
|
||||
func (f *resettableFreezer) Ancients() (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -139,7 +144,7 @@ func (f *ResettableFreezer) Ancients() (uint64, error) {
|
||||
}
|
||||
|
||||
// Tail returns the number of first stored item in the freezer.
|
||||
func (f *ResettableFreezer) Tail() (uint64, error) {
|
||||
func (f *resettableFreezer) Tail() (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -147,7 +152,7 @@ func (f *ResettableFreezer) Tail() (uint64, error) {
|
||||
}
|
||||
|
||||
// AncientSize returns the ancient size of the specified category.
|
||||
func (f *ResettableFreezer) AncientSize(kind string) (uint64, error) {
|
||||
func (f *resettableFreezer) AncientSize(kind string) (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -156,7 +161,7 @@ func (f *ResettableFreezer) AncientSize(kind string) (uint64, error) {
|
||||
|
||||
// ReadAncients runs the given read operation while ensuring that no writes take place
|
||||
// on the underlying freezer.
|
||||
func (f *ResettableFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) {
|
||||
func (f *resettableFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -164,7 +169,7 @@ func (f *ResettableFreezer) ReadAncients(fn func(ethdb.AncientReaderOp) error) (
|
||||
}
|
||||
|
||||
// ModifyAncients runs the given write operation.
|
||||
func (f *ResettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) {
|
||||
func (f *resettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error) (writeSize int64, err error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -173,7 +178,7 @@ func (f *ResettableFreezer) ModifyAncients(fn func(ethdb.AncientWriteOp) error)
|
||||
|
||||
// TruncateHead discards any recent data above the provided threshold number.
|
||||
// It returns the previous head number.
|
||||
func (f *ResettableFreezer) TruncateHead(items uint64) (uint64, error) {
|
||||
func (f *resettableFreezer) TruncateHead(items uint64) (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -182,7 +187,7 @@ func (f *ResettableFreezer) TruncateHead(items uint64) (uint64, error) {
|
||||
|
||||
// TruncateTail discards any recent data below the provided threshold number.
|
||||
// It returns the previous value
|
||||
func (f *ResettableFreezer) TruncateTail(tail uint64) (uint64, error) {
|
||||
func (f *resettableFreezer) TruncateTail(tail uint64) (uint64, error) {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -190,7 +195,7 @@ func (f *ResettableFreezer) TruncateTail(tail uint64) (uint64, error) {
|
||||
}
|
||||
|
||||
// Sync flushes all data tables to disk.
|
||||
func (f *ResettableFreezer) Sync() error {
|
||||
func (f *resettableFreezer) Sync() error {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
@@ -199,7 +204,7 @@ func (f *ResettableFreezer) Sync() error {
|
||||
|
||||
// MigrateTable processes the entries in a given table in sequence
|
||||
// converting them to a new format if they're of an old format.
|
||||
func (f *ResettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
func (f *resettableFreezer) MigrateTable(kind string, convert convertLegacyFn) error {
|
||||
f.lock.RLock()
|
||||
defer f.lock.RUnlock()
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ func TestResetFreezer(t *testing.T) {
|
||||
{1, bytes.Repeat([]byte{1}, 2048)},
|
||||
{2, bytes.Repeat([]byte{2}, 2048)},
|
||||
}
|
||||
f, _ := NewResettableFreezer(t.TempDir(), "", false, 2048, freezerTestTableDef)
|
||||
f, _ := newResettableFreezer(t.TempDir(), "", false, 2048, freezerTestTableDef)
|
||||
defer f.Close()
|
||||
|
||||
f.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
@@ -87,7 +87,7 @@ func TestFreezerCleanup(t *testing.T) {
|
||||
{2, bytes.Repeat([]byte{2}, 2048)},
|
||||
}
|
||||
datadir := t.TempDir()
|
||||
f, _ := NewResettableFreezer(datadir, "", false, 2048, freezerTestTableDef)
|
||||
f, _ := newResettableFreezer(datadir, "", false, 2048, freezerTestTableDef)
|
||||
f.ModifyAncients(func(op ethdb.AncientWriteOp) error {
|
||||
for _, item := range items {
|
||||
op.AppendRaw("test", item.id, item.blob)
|
||||
@@ -98,7 +98,7 @@ func TestFreezerCleanup(t *testing.T) {
|
||||
os.Rename(datadir, tmpName(datadir))
|
||||
|
||||
// Open the freezer again, trigger cleanup operation
|
||||
f, _ = NewResettableFreezer(datadir, "", false, 2048, freezerTestTableDef)
|
||||
f, _ = newResettableFreezer(datadir, "", false, 2048, freezerTestTableDef)
|
||||
f.Close()
|
||||
|
||||
if _, err := os.Lstat(tmpName(datadir)); !os.IsNotExist(err) {
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/rawdb/ancienttest"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -480,3 +481,22 @@ func TestFreezerCloseSync(t *testing.T) {
|
||||
t.Fatalf("want %v, have %v", have, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFreezerSuite(t *testing.T) {
|
||||
ancienttest.TestAncientSuite(t, func(kinds []string) ethdb.AncientStore {
|
||||
tables := make(map[string]bool)
|
||||
for _, kind := range kinds {
|
||||
tables[kind] = true
|
||||
}
|
||||
f, _ := newFreezerForTesting(t, tables)
|
||||
return f
|
||||
})
|
||||
ancienttest.TestResettableAncientSuite(t, func(kinds []string) ethdb.ResettableAncientStore {
|
||||
tables := make(map[string]bool)
|
||||
for _, kind := range kinds {
|
||||
tables[kind] = true
|
||||
}
|
||||
f, _ := newResettableFreezer(t.TempDir(), "", false, 2048, tables)
|
||||
return f
|
||||
})
|
||||
}
|
||||
|
||||
@@ -147,9 +147,9 @@ func (t *table) NewIterator(prefix []byte, start []byte) ethdb.Iterator {
|
||||
}
|
||||
}
|
||||
|
||||
// Stat returns a particular internal stat of the database.
|
||||
func (t *table) Stat(property string) (string, error) {
|
||||
return t.db.Stat(property)
|
||||
// Stat returns the statistic data of the database.
|
||||
func (t *table) Stat() (string, error) {
|
||||
return t.db.Stat()
|
||||
}
|
||||
|
||||
// Compact flattens the underlying data store for the given key range. In essence,
|
||||
|
||||
320
core/state/access_events.go
Normal file
320
core/state/access_events.go
Normal file
@@ -0,0 +1,320 @@
|
||||
// Copyright 2021 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"maps"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// mode specifies how a tree location has been accessed
|
||||
// for the byte value:
|
||||
// * the first bit is set if the branch has been edited
|
||||
// * the second bit is set if the branch has been read
|
||||
type mode byte
|
||||
|
||||
const (
|
||||
AccessWitnessReadFlag = mode(1)
|
||||
AccessWitnessWriteFlag = mode(2)
|
||||
)
|
||||
|
||||
var zeroTreeIndex uint256.Int
|
||||
|
||||
// AccessEvents lists the locations of the state that are being accessed
|
||||
// during the production of a block.
|
||||
type AccessEvents struct {
|
||||
branches map[branchAccessKey]mode
|
||||
chunks map[chunkAccessKey]mode
|
||||
|
||||
pointCache *utils.PointCache
|
||||
}
|
||||
|
||||
func NewAccessEvents(pointCache *utils.PointCache) *AccessEvents {
|
||||
return &AccessEvents{
|
||||
branches: make(map[branchAccessKey]mode),
|
||||
chunks: make(map[chunkAccessKey]mode),
|
||||
pointCache: pointCache,
|
||||
}
|
||||
}
|
||||
|
||||
// Merge is used to merge the access events that were generated during the
|
||||
// execution of a tx, with the accumulation of all access events that were
|
||||
// generated during the execution of all txs preceding this one in a block.
|
||||
func (ae *AccessEvents) Merge(other *AccessEvents) {
|
||||
for k := range other.branches {
|
||||
ae.branches[k] |= other.branches[k]
|
||||
}
|
||||
for k, chunk := range other.chunks {
|
||||
ae.chunks[k] |= chunk
|
||||
}
|
||||
}
|
||||
|
||||
// Keys returns, predictably, the list of keys that were touched during the
|
||||
// buildup of the access witness.
|
||||
func (ae *AccessEvents) Keys() [][]byte {
|
||||
// TODO: consider if parallelizing this is worth it, probably depending on len(ae.chunks).
|
||||
keys := make([][]byte, 0, len(ae.chunks))
|
||||
for chunk := range ae.chunks {
|
||||
basePoint := ae.pointCache.Get(chunk.addr[:])
|
||||
key := utils.GetTreeKeyWithEvaluatedAddress(basePoint, &chunk.treeIndex, chunk.leafKey)
|
||||
keys = append(keys, key)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
func (ae *AccessEvents) Copy() *AccessEvents {
|
||||
cpy := &AccessEvents{
|
||||
branches: maps.Clone(ae.branches),
|
||||
chunks: maps.Clone(ae.chunks),
|
||||
pointCache: ae.pointCache,
|
||||
}
|
||||
return cpy
|
||||
}
|
||||
|
||||
// AddAccount returns the gas to be charged for each of the currently cold
|
||||
// member fields of an account.
|
||||
func (ae *AccessEvents) AddAccount(addr common.Address, isWrite bool) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
return gas
|
||||
}
|
||||
|
||||
// MessageCallGas returns the gas to be charged for each of the currently
|
||||
// cold member fields of an account, that need to be touched when making a message
|
||||
// call to that account.
|
||||
func (ae *AccessEvents) MessageCallGas(destination common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
gas += ae.touchAddressAndChargeGas(destination, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ValueTransferGas returns the gas to be charged for each of the currently
|
||||
// cold balance member fields of the caller and the callee accounts.
|
||||
func (ae *AccessEvents) ValueTransferGas(callerAddr, targetAddr common.Address) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(callerAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(targetAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
return gas
|
||||
}
|
||||
|
||||
// ContractCreateInitGas returns the access gas costs for the initialization of
|
||||
// a contract creation.
|
||||
func (ae *AccessEvents) ContractCreateInitGas(addr common.Address, createSendsValue bool) uint64 {
|
||||
var gas uint64
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, true)
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
if createSendsValue {
|
||||
gas += ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
}
|
||||
return gas
|
||||
}
|
||||
|
||||
// AddTxOrigin adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxOrigin(originAddr common.Address) {
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.BalanceLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.NonceLeafKey, true)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(originAddr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
}
|
||||
|
||||
// AddTxDestination adds the member fields of the sender account to the access event list,
|
||||
// so that cold accesses are not charged, since they are covered by the 21000 gas.
|
||||
func (ae *AccessEvents) AddTxDestination(addr common.Address, sendsValue bool) {
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, sendsValue)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, false)
|
||||
ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, false)
|
||||
}
|
||||
|
||||
// SlotGas returns the amount of gas to be charged for a cold storage access.
|
||||
func (ae *AccessEvents) SlotGas(addr common.Address, slot common.Hash, isWrite bool) uint64 {
|
||||
treeIndex, subIndex := utils.StorageIndex(slot.Bytes())
|
||||
return ae.touchAddressAndChargeGas(addr, *treeIndex, subIndex, isWrite)
|
||||
}
|
||||
|
||||
// touchAddressAndChargeGas adds any missing access event to the access event list, and returns the cold
|
||||
// access cost to be charged, if need be.
|
||||
func (ae *AccessEvents) touchAddressAndChargeGas(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite bool) uint64 {
|
||||
stemRead, selectorRead, stemWrite, selectorWrite, selectorFill := ae.touchAddress(addr, treeIndex, subIndex, isWrite)
|
||||
|
||||
var gas uint64
|
||||
if stemRead {
|
||||
gas += params.WitnessBranchReadCost
|
||||
}
|
||||
if selectorRead {
|
||||
gas += params.WitnessChunkReadCost
|
||||
}
|
||||
if stemWrite {
|
||||
gas += params.WitnessBranchWriteCost
|
||||
}
|
||||
if selectorWrite {
|
||||
gas += params.WitnessChunkWriteCost
|
||||
}
|
||||
if selectorFill {
|
||||
gas += params.WitnessChunkFillCost
|
||||
}
|
||||
return gas
|
||||
}
|
||||
|
||||
// touchAddress adds any missing access event to the access event list.
|
||||
func (ae *AccessEvents) touchAddress(addr common.Address, treeIndex uint256.Int, subIndex byte, isWrite bool) (bool, bool, bool, bool, bool) {
|
||||
branchKey := newBranchAccessKey(addr, treeIndex)
|
||||
chunkKey := newChunkAccessKey(branchKey, subIndex)
|
||||
|
||||
// Read access.
|
||||
var branchRead, chunkRead bool
|
||||
if _, hasStem := ae.branches[branchKey]; !hasStem {
|
||||
branchRead = true
|
||||
ae.branches[branchKey] = AccessWitnessReadFlag
|
||||
}
|
||||
if _, hasSelector := ae.chunks[chunkKey]; !hasSelector {
|
||||
chunkRead = true
|
||||
ae.chunks[chunkKey] = AccessWitnessReadFlag
|
||||
}
|
||||
|
||||
// Write access.
|
||||
var branchWrite, chunkWrite, chunkFill bool
|
||||
if isWrite {
|
||||
if (ae.branches[branchKey] & AccessWitnessWriteFlag) == 0 {
|
||||
branchWrite = true
|
||||
ae.branches[branchKey] |= AccessWitnessWriteFlag
|
||||
}
|
||||
|
||||
chunkValue := ae.chunks[chunkKey]
|
||||
if (chunkValue & AccessWitnessWriteFlag) == 0 {
|
||||
chunkWrite = true
|
||||
ae.chunks[chunkKey] |= AccessWitnessWriteFlag
|
||||
}
|
||||
// TODO: charge chunk filling costs if the leaf was previously empty in the state
|
||||
}
|
||||
return branchRead, chunkRead, branchWrite, chunkWrite, chunkFill
|
||||
}
|
||||
|
||||
type branchAccessKey struct {
|
||||
addr common.Address
|
||||
treeIndex uint256.Int
|
||||
}
|
||||
|
||||
func newBranchAccessKey(addr common.Address, treeIndex uint256.Int) branchAccessKey {
|
||||
var sk branchAccessKey
|
||||
sk.addr = addr
|
||||
sk.treeIndex = treeIndex
|
||||
return sk
|
||||
}
|
||||
|
||||
type chunkAccessKey struct {
|
||||
branchAccessKey
|
||||
leafKey byte
|
||||
}
|
||||
|
||||
func newChunkAccessKey(branchKey branchAccessKey, leafKey byte) chunkAccessKey {
|
||||
var lk chunkAccessKey
|
||||
lk.branchAccessKey = branchKey
|
||||
lk.leafKey = leafKey
|
||||
return lk
|
||||
}
|
||||
|
||||
// CodeChunksRangeGas is a helper function to touch every chunk in a code range and charge witness gas costs
|
||||
func (ae *AccessEvents) CodeChunksRangeGas(contractAddr common.Address, startPC, size uint64, codeLen uint64, isWrite bool) uint64 {
|
||||
// note that in the case where the copied code is outside the range of the
|
||||
// contract code but touches the last leaf with contract code in it,
|
||||
// we don't include the last leaf of code in the AccessWitness. The
|
||||
// reason that we do not need the last leaf is the account's code size
|
||||
// is already in the AccessWitness so a stateless verifier can see that
|
||||
// the code from the last leaf is not needed.
|
||||
if (codeLen == 0 && size == 0) || startPC > codeLen {
|
||||
return 0
|
||||
}
|
||||
|
||||
endPC := startPC + size
|
||||
if endPC > codeLen {
|
||||
endPC = codeLen
|
||||
}
|
||||
if endPC > 0 {
|
||||
endPC -= 1 // endPC is the last bytecode that will be touched.
|
||||
}
|
||||
|
||||
var statelessGasCharged uint64
|
||||
for chunkNumber := startPC / 31; chunkNumber <= endPC/31; chunkNumber++ {
|
||||
treeIndex := *uint256.NewInt((chunkNumber + 128) / 256)
|
||||
subIndex := byte((chunkNumber + 128) % 256)
|
||||
gas := ae.touchAddressAndChargeGas(contractAddr, treeIndex, subIndex, isWrite)
|
||||
var overflow bool
|
||||
statelessGasCharged, overflow = math.SafeAdd(statelessGasCharged, gas)
|
||||
if overflow {
|
||||
panic("overflow when adding gas")
|
||||
}
|
||||
}
|
||||
return statelessGasCharged
|
||||
}
|
||||
|
||||
// VersionGas adds the account's version to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an
|
||||
// access in read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) VersionGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.VersionLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// BalanceGas adds the account's balance to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) BalanceGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.BalanceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// NonceGas adds the account's nonce to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) NonceGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.NonceLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// CodeSizeGas adds the account's code size to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) CodeSizeGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeSizeLeafKey, isWrite)
|
||||
}
|
||||
|
||||
// CodeHashGas adds the account's code hash to the accessed data, and returns the
|
||||
// amount of gas that it costs.
|
||||
// in write mode. If false, the charged gas corresponds to an access in read mode.
|
||||
// Note that an access in write mode implies an access in read mode, whereas an access in
|
||||
// read mode does not imply an access in write mode.
|
||||
func (ae *AccessEvents) CodeHashGas(addr common.Address, isWrite bool) uint64 {
|
||||
return ae.touchAddressAndChargeGas(addr, zeroTreeIndex, utils.CodeKeccakLeafKey, isWrite)
|
||||
}
|
||||
153
core/state/access_events_test.go
Normal file
153
core/state/access_events_test.go
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright 2021 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library 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 Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package state
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/trie/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
testAddr [20]byte
|
||||
testAddr2 [20]byte
|
||||
)
|
||||
|
||||
func init() {
|
||||
for i := byte(0); i < 20; i++ {
|
||||
testAddr[i] = i
|
||||
testAddr[2] = 2 * i
|
||||
}
|
||||
}
|
||||
|
||||
func TestAccountHeaderGas(t *testing.T) {
|
||||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
// Check cold read cost
|
||||
gas := ae.VersionGas(testAddr, false)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.VersionGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check cold read costs in the same group no longer incur the branch read cost
|
||||
gas = ae.BalanceGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.NonceGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
gas = ae.CodeHashGas(testAddr, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
|
||||
// Check cold write cost
|
||||
gas = ae.VersionGas(testAddr, true)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessChunkWriteCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm write cost
|
||||
gas = ae.VersionGas(testAddr, true)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check a write without a read charges both read and write costs
|
||||
gas = ae.BalanceGas(testAddr2, true)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessBranchWriteCost + params.WitnessChunkWriteCost + params.WitnessChunkReadCost; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that a write followed by a read charges nothing
|
||||
gas = ae.BalanceGas(testAddr2, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check that reading a slot from the account header only charges the
|
||||
// chunk read cost.
|
||||
gas = ae.SlotGas(testAddr, common.Hash{}, false)
|
||||
if gas != params.WitnessChunkReadCost {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, params.WitnessChunkReadCost)
|
||||
}
|
||||
}
|
||||
|
||||
// TestContractCreateInitGas checks that the gas cost of contract creation is correctly
|
||||
// calculated.
|
||||
func TestContractCreateInitGas(t *testing.T) {
|
||||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
var testAddr [20]byte
|
||||
for i := byte(0); i < 20; i++ {
|
||||
testAddr[i] = i
|
||||
}
|
||||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.ContractCreateInitGas(testAddr, false)
|
||||
if want := params.WitnessBranchWriteCost + params.WitnessBranchReadCost + params.WitnessChunkWriteCost*2 + params.WitnessChunkReadCost*2; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.ContractCreateInitGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// TestMessageCallGas checks that the gas cost of message calls is correctly
|
||||
// calculated.
|
||||
func TestMessageCallGas(t *testing.T) {
|
||||
ae := NewAccessEvents(utils.NewPointCache(1024))
|
||||
|
||||
// Check cold read cost, without a value
|
||||
gas := ae.MessageCallGas(testAddr)
|
||||
if want := params.WitnessBranchReadCost + params.WitnessChunkReadCost*2; gas != want {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, want)
|
||||
}
|
||||
|
||||
// Check that reading the version and code size of the same account does not incur the branch read cost
|
||||
gas = ae.VersionGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
gas = ae.CodeSizeGas(testAddr, false)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
|
||||
// Check warm read cost
|
||||
gas = ae.MessageCallGas(testAddr)
|
||||
if gas != 0 {
|
||||
t.Fatalf("incorrect gas computed, got %d, want %d", gas, 0)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,10 @@
|
||||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
@@ -57,11 +60,11 @@ func newAccessList() *accessList {
|
||||
}
|
||||
|
||||
// Copy creates an independent copy of an accessList.
|
||||
func (a *accessList) Copy() *accessList {
|
||||
func (al *accessList) Copy() *accessList {
|
||||
cp := newAccessList()
|
||||
cp.addresses = maps.Clone(a.addresses)
|
||||
cp.slots = make([]map[common.Hash]struct{}, len(a.slots))
|
||||
for i, slotMap := range a.slots {
|
||||
cp.addresses = maps.Clone(al.addresses)
|
||||
cp.slots = make([]map[common.Hash]struct{}, len(al.slots))
|
||||
for i, slotMap := range al.slots {
|
||||
cp.slots[i] = maps.Clone(slotMap)
|
||||
}
|
||||
return cp
|
||||
@@ -130,3 +133,35 @@ func (al *accessList) DeleteSlot(address common.Address, slot common.Hash) {
|
||||
func (al *accessList) DeleteAddress(address common.Address) {
|
||||
delete(al.addresses, address)
|
||||
}
|
||||
|
||||
// Equal returns true if the two access lists are identical
|
||||
func (al *accessList) Equal(other *accessList) bool {
|
||||
if !maps.Equal(al.addresses, other.addresses) {
|
||||
return false
|
||||
}
|
||||
return slices.EqualFunc(al.slots, other.slots,
|
||||
func(m map[common.Hash]struct{}, m2 map[common.Hash]struct{}) bool {
|
||||
return maps.Equal(m, m2)
|
||||
})
|
||||
}
|
||||
|
||||
// PrettyPrint prints the contents of the access list in a human-readable form
|
||||
func (al *accessList) PrettyPrint() string {
|
||||
out := new(strings.Builder)
|
||||
var sortedAddrs []common.Address
|
||||
for addr := range al.addresses {
|
||||
sortedAddrs = append(sortedAddrs, addr)
|
||||
}
|
||||
slices.SortFunc(sortedAddrs, common.Address.Cmp)
|
||||
for _, addr := range sortedAddrs {
|
||||
idx := al.addresses[addr]
|
||||
fmt.Fprintf(out, "%#x : (idx %d)\n", addr, idx)
|
||||
if idx >= 0 {
|
||||
slotmap := al.slots[idx]
|
||||
for h := range slotmap {
|
||||
fmt.Fprintf(out, " %#x\n", h)
|
||||
}
|
||||
}
|
||||
}
|
||||
return out.String()
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user