mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
fix:merge geth p2p change
Signed-off-by: Chen Kai <281165273grape@gmail.com>
This commit is contained in:
parent
4641a25656
commit
6088495691
166 changed files with 5175 additions and 4227 deletions
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
|
|
@ -10,6 +10,7 @@ core/ @karalabe @holiman @rjl493456442
|
|||
eth/ @karalabe @holiman @rjl493456442
|
||||
eth/catalyst/ @gballet
|
||||
eth/tracers/ @s1na
|
||||
core/tracing/ @s1na
|
||||
graphql/ @s1na
|
||||
les/ @zsfelfoldi @rjl493456442
|
||||
light/ @zsfelfoldi @rjl493456442
|
||||
|
|
|
|||
1
.github/workflows/go.yml
vendored
1
.github/workflows/go.yml
vendored
|
|
@ -16,6 +16,7 @@ jobs:
|
|||
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
|
||||
|
|
|
|||
23
Makefile
23
Makefile
|
|
@ -2,7 +2,7 @@
|
|||
# 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
|
||||
|
|
@ -20,24 +20,29 @@ shisui-image:
|
|||
docker build -t ghcr.io/optimism-java/shisui:latest -f Dockerfile.portal .
|
||||
|
||||
#? 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)/*
|
||||
|
|
@ -45,7 +50,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
|
||||
|
|
@ -56,5 +61,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/^/ /'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -326,6 +326,11 @@ func TestUpdatedKeyfileContents(t *testing.T) {
|
|||
|
||||
// Create a temporary keystore to test with
|
||||
dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-updatedkeyfilecontents-test-%d-%d", os.Getpid(), rand.Int()))
|
||||
|
||||
// Create the directory
|
||||
os.MkdirAll(dir, 0700)
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
ks := NewKeyStore(dir, LightScryptN, LightScryptP)
|
||||
|
||||
list := ks.Accounts()
|
||||
|
|
@ -335,9 +340,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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,11 +186,15 @@ func (s *serverWithTimeout) eventCallback(event Event) {
|
|||
// call will just do nothing
|
||||
timer.Stop()
|
||||
delete(s.timeouts, id)
|
||||
if s.childEventCb != nil {
|
||||
s.childEventCb(event)
|
||||
}
|
||||
}
|
||||
default:
|
||||
if s.childEventCb != nil {
|
||||
s.childEventCb(event)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// startTimeout starts a timeout timer for the given request.
|
||||
|
|
@ -211,25 +215,27 @@ func (s *serverWithTimeout) startTimeout(reqData RequestResponse) {
|
|||
delete(s.timeouts, id)
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
if childEventCb != nil {
|
||||
childEventCb(Event{Type: EvFail, Data: reqData})
|
||||
}
|
||||
})
|
||||
childEventCb := s.childEventCb
|
||||
s.lock.Unlock()
|
||||
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++
|
||||
}
|
||||
})
|
||||
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 }
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ func convertPayload[T payloadType](payload T, parentRoot *zrntcommon.Root) (*typ
|
|||
|
||||
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,79 +5,87 @@
|
|||
# https://github.com/ethereum/execution-spec-tests/releases/download/v2.1.0/
|
||||
ca89c76851b0900bfcc3cbb9a26cbece1f3d7c64a3bed38723e914713290df6c fixtures_develop.tar.gz
|
||||
|
||||
# version:golang 1.22.3
|
||||
# version:golang 1.22.4
|
||||
# https://go.dev/dl/
|
||||
80648ef34f903193d72a59c0dff019f5f98ae0c9aa13ade0b0ecbff991a76f68 go1.22.3.src.tar.gz
|
||||
adc9f5fee89cd53d907eb542d3b269d9d8a08a66bf1ab42175450ffbb58733fb go1.22.3.aix-ppc64.tar.gz
|
||||
610e48c1df4d2f852de8bc2e7fd2dc1521aac216f0c0026625db12f67f192024 go1.22.3.darwin-amd64.tar.gz
|
||||
02abeab3f4b8981232237ebd88f0a9bad933bc9621791cd7720a9ca29eacbe9d go1.22.3.darwin-arm64.tar.gz
|
||||
a5b3d54905f17af2ceaf7fcfe92edee67a5bd4eccd962dd89df719ace3e0894d go1.22.3.dragonfly-amd64.tar.gz
|
||||
b9989ca87695ae93bacde6f3aa7b13cde5f3825515eb9ed9bbef014273739889 go1.22.3.freebsd-386.tar.gz
|
||||
7483961fae29d7d768afd5c9c0f229354ca3263ab7119c20bc182761f87cbc74 go1.22.3.freebsd-amd64.tar.gz
|
||||
edf1f0b8ecf68b14faeedb4f5d868a58c4777a0282bd85e5115c39c010cd0130 go1.22.3.freebsd-arm.tar.gz
|
||||
572eb70e5e835fbff7d53ebf473f611d7eb458c428f8dbd98a49196883c3309e go1.22.3.freebsd-arm64.tar.gz
|
||||
ef94eb2b74402e436dce970584222c4e454eb3093908591149bd2ded6862b8af go1.22.3.freebsd-riscv64.tar.gz
|
||||
3c3f498c68334cbd11f72aadfb6bcb507eb8436cebc50f437a0523cd4c5e03d1 go1.22.3.illumos-amd64.tar.gz
|
||||
fefba30bb0d3dd1909823ee38c9f1930c3dc5337a2ac4701c2277a329a386b57 go1.22.3.linux-386.tar.gz
|
||||
8920ea521bad8f6b7bc377b4824982e011c19af27df88a815e3586ea895f1b36 go1.22.3.linux-amd64.tar.gz
|
||||
6c33e52a5b26e7aa021b94475587fce80043a727a54ceb0eee2f9fc160646434 go1.22.3.linux-arm64.tar.gz
|
||||
f2bacad20cd2b96f23a86d4826525d42b229fd431cc6d0dec61ff3bc448ef46e go1.22.3.linux-armv6l.tar.gz
|
||||
41e9328340544893482b2928ae18a9a88ba18b2fdd29ac77f4d33cf1815bbdc2 go1.22.3.linux-loong64.tar.gz
|
||||
cf4d5faff52e642492729eaf396968f43af179518be769075b90bc1bf650abf6 go1.22.3.linux-mips.tar.gz
|
||||
3bd009fe2e3d2bfd52433a11cb210d1dfa50b11b4c347a293951efd9e36de945 go1.22.3.linux-mips64.tar.gz
|
||||
5913b82a042188ef698f7f2dfd0cd0c71f0508a4739de9e41fceff3f4dc769b4 go1.22.3.linux-mips64le.tar.gz
|
||||
441afebca555be5313867b4577f237c7b5c0fff4386e22e47875b9f805abbec5 go1.22.3.linux-mipsle.tar.gz
|
||||
f3b53190a76f4a35283501ba6d94cbb72093be0c62ff735c6f9e586a1c983381 go1.22.3.linux-ppc64.tar.gz
|
||||
04b7b05283de30dd2da20bf3114b2e22cc727938aed3148babaf35cc951051ac go1.22.3.linux-ppc64le.tar.gz
|
||||
d4992d4a85696e3f1de06cefbfc2fd840c9c6695d77a0f35cfdc4e28b2121c20 go1.22.3.linux-riscv64.tar.gz
|
||||
2aba796417a69be5f3ed489076bac79c1c02b36e29422712f9f3bf51da9cf2d4 go1.22.3.linux-s390x.tar.gz
|
||||
d6e6113542dd9f23db899e177fe23772bac114a5ea5e8ee436b9da68628335a8 go1.22.3.netbsd-386.tar.gz
|
||||
c33cee3075bd18ceefddd75bafa8efb51fbdc17b5ee74275122e7a927a237a4c go1.22.3.netbsd-amd64.tar.gz
|
||||
1ab251df3c85f3b391a09565ca52fb6e1306527d72852d553e9ab74eabb4ecf8 go1.22.3.netbsd-arm.tar.gz
|
||||
1d194fe53f5d82f9a612f848950d8af8cab7cb40ccc03f10c4eb1c9808ff1a0c go1.22.3.netbsd-arm64.tar.gz
|
||||
91d6601727f08506e938640885d3ded784925045e3a4444fd9b4b936efe1b1e0 go1.22.3.openbsd-386.tar.gz
|
||||
09d0c91ae35a4eea92615426992062ca236cc2f66444fb0b0a24cd3b13bd5297 go1.22.3.openbsd-amd64.tar.gz
|
||||
338da30cc2c97b9458e0b4caa2509f67bba55d3de16fb7d31775baca82d2e3dc go1.22.3.openbsd-arm.tar.gz
|
||||
53eadfabd2b7dd09a64941421afee2a2888e2a4f94f353b27919b1dad1171a21 go1.22.3.openbsd-arm64.tar.gz
|
||||
8a1a2842ae8dcf2374bb05dff58074b368bb698dc9c211c794c1ff119cd9fdc7 go1.22.3.plan9-386.tar.gz
|
||||
f9816d3dd9e730cad55085ea08c1f0c925720728f9c945fff59cd24d2ac2db7b go1.22.3.plan9-amd64.tar.gz
|
||||
f4d3d7b17c9e1b1635fcb287b5b5ab5b60acc9db3ba6a27f2b2f5d6537a2ef95 go1.22.3.plan9-arm.tar.gz
|
||||
46b7999ee94d91b21ad6940b5a3131ff6fe53ef97be9a34e582e2a3ad7263e95 go1.22.3.solaris-amd64.tar.gz
|
||||
f60f63b8a0885e0d924f39fd284aee5438fe87d8c3d8545a312adf43e0d9edac go1.22.3.windows-386.zip
|
||||
cab2af6951a6e2115824263f6df13ff069c47270f5788714fa1d776f7f60cb39 go1.22.3.windows-amd64.zip
|
||||
40b37f4b068fc759f3a0dd61176a0f7570a4ba48bed8561c31d3967a3583981a go1.22.3.windows-arm.zip
|
||||
59b76ee22b9b1c3afbf7f50e3cb4edb954d6c0d25e5e029ab5483a6804d61e71 go1.22.3.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!
|
||||
#
|
||||
|
|
|
|||
|
|
@ -225,7 +225,7 @@ 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]
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)-.*)$"
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -605,6 +605,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{
|
||||
|
|
@ -1835,6 +1840,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)
|
||||
|
|
@ -2265,7 +2273,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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1809,7 +1809,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||
// 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()) {
|
||||
statedb.StartPrefetcher("chain")
|
||||
statedb.StartPrefetcher("chain", !bc.vmConfig.EnableWitnessCollection)
|
||||
}
|
||||
activeState = statedb
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -594,7 +594,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
|||
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: types.Account{Nonce: 1, Code: params.BeaconRootsCode},
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ type freezerOpenFunc = func() (*Freezer, error)
|
|||
// resettableFreezer is a wrapper of the freezer which makes the
|
||||
// freezer resettable.
|
||||
type resettableFreezer struct {
|
||||
readOnly bool
|
||||
freezer *Freezer
|
||||
opener freezerOpenFunc
|
||||
datadir string
|
||||
|
|
@ -60,6 +61,7 @@ func newResettableFreezer(datadir string, namespace string, readonly bool, maxTa
|
|||
return nil, err
|
||||
}
|
||||
return &resettableFreezer{
|
||||
readOnly: readonly,
|
||||
freezer: freezer,
|
||||
opener: opener,
|
||||
datadir: datadir,
|
||||
|
|
@ -74,6 +76,9 @@ 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,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
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ type Trie interface {
|
|||
// The returned nodeset can be nil if the trie is clean(nothing to commit).
|
||||
// Once the trie is committed, it's not usable anymore. A new trie must
|
||||
// be created with new root and updated trie database for following usage
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error)
|
||||
Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet)
|
||||
|
||||
// NodeIterator returns an iterator that returns nodes of the trie. Iteration
|
||||
// starts at the key after the given start key. And error will be returned
|
||||
|
|
|
|||
|
|
@ -360,10 +360,7 @@ func (dl *diskLayer) generateRange(ctx *generatorContext, trieId *trie.ID, prefi
|
|||
for i, key := range result.keys {
|
||||
snapTrie.Update(key, result.vals[i])
|
||||
}
|
||||
root, nodes, err := snapTrie.Commit(false)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
root, nodes := snapTrie.Commit(false)
|
||||
if nodes != nil {
|
||||
tdb.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
tdb.Commit(root, false)
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
|
|||
if !commit {
|
||||
return stTrie.Hash()
|
||||
}
|
||||
root, nodes, _ := stTrie.Commit(false)
|
||||
root, nodes := stTrie.Commit(false)
|
||||
if nodes != nil {
|
||||
t.nodes.Merge(nodes)
|
||||
}
|
||||
|
|
@ -218,7 +218,7 @@ func (t *testHelper) makeStorageTrie(owner common.Hash, keys []string, vals []st
|
|||
}
|
||||
|
||||
func (t *testHelper) Commit() common.Hash {
|
||||
root, nodes, _ := t.accTrie.Commit(true)
|
||||
root, nodes := t.accTrie.Commit(true)
|
||||
if nodes != nil {
|
||||
t.nodes.Merge(nodes)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -815,7 +815,7 @@ func TestStorageIteratorDeletions(t *testing.T) {
|
|||
verifyIterator(t, 2, snaps.Snapshot(common.HexToHash("0x06")).(*diffLayer).newBinaryStorageIterator(common.HexToHash("0xaa")), verifyStorage)
|
||||
}
|
||||
|
||||
// BenchmarkAccountIteratorTraversal is a bit a bit notorious -- all layers contain the
|
||||
// BenchmarkAccountIteratorTraversal is a bit notorious -- all layers contain the
|
||||
// exact same 200 accounts. That means that we need to process 2000 items, but
|
||||
// only spit out 200 values eventually.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@ package state
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -34,14 +32,6 @@ import (
|
|||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
// hasherPool holds a pool of hashers used by state objects during concurrent
|
||||
// trie updates.
|
||||
var hasherPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return crypto.NewKeccakState()
|
||||
},
|
||||
}
|
||||
|
||||
type Storage map[common.Hash]common.Hash
|
||||
|
||||
func (s Storage) Copy() Storage {
|
||||
|
|
@ -65,9 +55,20 @@ type stateObject struct {
|
|||
trie Trie // storage trie, which becomes non-nil on first access
|
||||
code []byte // contract bytecode, which gets set when code is loaded
|
||||
|
||||
originStorage Storage // Storage cache of original entries to dedup rewrites
|
||||
pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block
|
||||
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution, reset for every transaction
|
||||
originStorage Storage // Storage entries that have been accessed within the current block
|
||||
dirtyStorage Storage // Storage entries that have been modified within the current transaction
|
||||
pendingStorage Storage // Storage entries that have been modified within the current block
|
||||
|
||||
// uncommittedStorage tracks a set of storage entries that have been modified
|
||||
// but not yet committed since the "last commit operation", along with their
|
||||
// original values before mutation.
|
||||
//
|
||||
// Specifically, the commit will be performed after each transaction before
|
||||
// the byzantium fork, therefore the map is already reset at the transaction
|
||||
// boundary; however post the byzantium fork, the commit will only be performed
|
||||
// at the end of block, this set essentially tracks all the modifications
|
||||
// made within the block.
|
||||
uncommittedStorage Storage
|
||||
|
||||
// Cache flags.
|
||||
dirtyCode bool // true if the code was updated
|
||||
|
|
@ -102,16 +103,12 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
|
|||
origin: origin,
|
||||
data: *acct,
|
||||
originStorage: make(Storage),
|
||||
pendingStorage: make(Storage),
|
||||
dirtyStorage: make(Storage),
|
||||
pendingStorage: make(Storage),
|
||||
uncommittedStorage: make(Storage),
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeRLP implements rlp.Encoder.
|
||||
func (s *stateObject) EncodeRLP(w io.Writer) error {
|
||||
return rlp.Encode(w, &s.data)
|
||||
}
|
||||
|
||||
func (s *stateObject) markSelfdestructed() {
|
||||
s.selfDestructed = true
|
||||
}
|
||||
|
|
@ -127,7 +124,7 @@ func (s *stateObject) touch() {
|
|||
}
|
||||
}
|
||||
|
||||
// getTrie returns the associated storage trie. The trie will be opened if it'
|
||||
// getTrie returns the associated storage trie. The trie will be opened if it's
|
||||
// not loaded previously. An error will be returned if trie can't be loaded.
|
||||
//
|
||||
// If a new trie is opened, it will be cached within the state object to allow
|
||||
|
|
@ -150,17 +147,17 @@ func (s *stateObject) getTrie() (Trie, error) {
|
|||
// trie in the state object. The caller might want to do that, but it's cleaner
|
||||
// to break the hidden interdependency between retrieving tries from the db or
|
||||
// from the prefetcher.
|
||||
func (s *stateObject) getPrefetchedTrie() (Trie, error) {
|
||||
func (s *stateObject) getPrefetchedTrie() Trie {
|
||||
// If there's nothing to meaningfully return, let the user figure it out by
|
||||
// pulling the trie from disk.
|
||||
if s.data.Root == types.EmptyRootHash || s.db.prefetcher == nil {
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
// Attempt to retrieve the trie from the pretecher
|
||||
// Attempt to retrieve the trie from the prefetcher
|
||||
return s.db.prefetcher.trie(s.addrHash, s.data.Root)
|
||||
}
|
||||
|
||||
// GetState retrieves a value from the account storage trie.
|
||||
// GetState retrieves a value associated with the given storage key.
|
||||
func (s *stateObject) GetState(key common.Hash) common.Hash {
|
||||
value, _ := s.getState(key)
|
||||
return value
|
||||
|
|
@ -177,7 +174,8 @@ func (s *stateObject) getState(key common.Hash) (common.Hash, common.Hash) {
|
|||
return origin, origin
|
||||
}
|
||||
|
||||
// GetCommittedState retrieves a value from the committed account storage trie.
|
||||
// GetCommittedState retrieves the value associated with the specific key
|
||||
// without any mutations caused in the current execution.
|
||||
func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
||||
// If we have a pending write or clean cached, return that
|
||||
if value, pending := s.pendingStorage[key]; pending {
|
||||
|
|
@ -193,6 +191,7 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
|||
// have been handles via pendingStorage above.
|
||||
// 2) we don't have new values, and can deliver empty response back
|
||||
if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed {
|
||||
s.originStorage[key] = common.Hash{} // track the empty slot as origin value
|
||||
return common.Hash{}
|
||||
}
|
||||
// If no live objects are available, attempt to use snapshots
|
||||
|
|
@ -231,6 +230,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
|||
}
|
||||
value.SetBytes(val)
|
||||
}
|
||||
// Independent of where we loaded the data from, add it to the prefetcher.
|
||||
// Whilst this would be a bit weird if snapshots are disabled, but we still
|
||||
// want the trie nodes to end up in the prefetcher too, so just push through.
|
||||
if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash {
|
||||
if err = s.db.prefetcher.prefetch(s.addrHash, s.origin.Root, s.address, [][]byte{key[:]}, true); err != nil {
|
||||
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
|
||||
}
|
||||
}
|
||||
s.originStorage[key] = value
|
||||
return value
|
||||
}
|
||||
|
|
@ -272,20 +279,29 @@ func (s *stateObject) setState(key common.Hash, value common.Hash, origin common
|
|||
func (s *stateObject) finalise() {
|
||||
slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage))
|
||||
for key, value := range s.dirtyStorage {
|
||||
// If the slot is different from its original value, move it into the
|
||||
// pending area to be committed at the end of the block (and prefetch
|
||||
// the pathways).
|
||||
if value != s.originStorage[key] {
|
||||
s.pendingStorage[key] = value
|
||||
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure
|
||||
if origin, exist := s.uncommittedStorage[key]; exist && origin == value {
|
||||
// The slot is reverted to its original value, delete the entry
|
||||
// to avoid thrashing the data structures.
|
||||
delete(s.uncommittedStorage, key)
|
||||
} else if exist {
|
||||
// The slot is modified to another value and the slot has been
|
||||
// tracked for commit, do nothing here.
|
||||
} else {
|
||||
// Otherwise, the slot was reverted to its original value, remove it
|
||||
// from the pending area to avoid thrashing the data structure.
|
||||
delete(s.pendingStorage, key)
|
||||
// The slot is different from its original value and hasn't been
|
||||
// tracked for commit yet.
|
||||
s.uncommittedStorage[key] = s.GetCommittedState(key)
|
||||
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure
|
||||
}
|
||||
// Aggregate the dirty storage slots into the pending area. It might
|
||||
// be possible that the value of tracked slot here is same with the
|
||||
// one in originStorage (e.g. the slot was modified in tx_a and then
|
||||
// modified back in tx_b). We can't blindly remove it from pending
|
||||
// map as the dirty slot might have been committed already (before the
|
||||
// byzantium fork) and entry is necessary to modify the value back.
|
||||
s.pendingStorage[key] = value
|
||||
}
|
||||
if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
|
||||
if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch); err != nil {
|
||||
if err := s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch, false); err != nil {
|
||||
log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -308,40 +324,23 @@ func (s *stateObject) finalise() {
|
|||
// It assumes all the dirty storage slots have been finalized before.
|
||||
func (s *stateObject) updateTrie() (Trie, error) {
|
||||
// Short circuit if nothing changed, don't bother with hashing anything
|
||||
if len(s.pendingStorage) == 0 {
|
||||
if len(s.uncommittedStorage) == 0 {
|
||||
return s.trie, nil
|
||||
}
|
||||
// Retrieve a pretecher populated trie, or fall back to the database
|
||||
tr, err := s.getPrefetchedTrie()
|
||||
switch {
|
||||
case err != nil:
|
||||
// Fetcher retrieval failed, something's very wrong, abort
|
||||
s.db.setError(err)
|
||||
return nil, err
|
||||
|
||||
case tr == nil:
|
||||
tr := s.getPrefetchedTrie()
|
||||
if tr != nil {
|
||||
// Prefetcher returned a live trie, swap it out for the current one
|
||||
s.trie = tr
|
||||
} else {
|
||||
// Fetcher not running or empty trie, fallback to the database trie
|
||||
var err error
|
||||
tr, err = s.getTrie()
|
||||
if err != nil {
|
||||
s.db.setError(err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
default:
|
||||
// Prefetcher returned a live trie, swap it out for the current one
|
||||
s.trie = tr
|
||||
}
|
||||
// The snapshot storage map for the object
|
||||
var (
|
||||
storage map[common.Hash][]byte
|
||||
origin map[common.Hash][]byte
|
||||
)
|
||||
// Insert all the pending storage updates into the trie
|
||||
usedStorage := make([][]byte, 0, len(s.pendingStorage))
|
||||
|
||||
hasher := hasherPool.Get().(crypto.KeccakState)
|
||||
defer hasherPool.Put(hasher)
|
||||
|
||||
// Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes
|
||||
// in circumstances similar to the following:
|
||||
//
|
||||
|
|
@ -352,21 +351,23 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||
// If the deletion is handled first, then `P` would be left with only one child, thus collapsed
|
||||
// into a shortnode. This requires `B` to be resolved from disk.
|
||||
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
||||
var deletions []common.Hash
|
||||
for key, value := range s.pendingStorage {
|
||||
var (
|
||||
deletions []common.Hash
|
||||
used = make([][]byte, 0, len(s.uncommittedStorage))
|
||||
)
|
||||
for key, origin := range s.uncommittedStorage {
|
||||
// Skip noop changes, persist actual changes
|
||||
if value == s.originStorage[key] {
|
||||
value, exist := s.pendingStorage[key]
|
||||
if value == origin {
|
||||
log.Error("Storage update was noop", "address", s.address, "slot", key)
|
||||
continue
|
||||
}
|
||||
if !exist {
|
||||
log.Error("Storage slot is not found in pending area", s.address, "slot", key)
|
||||
continue
|
||||
}
|
||||
prev := s.originStorage[key]
|
||||
s.originStorage[key] = value
|
||||
|
||||
var encoded []byte // rlp-encoded value to be used by the snapshot
|
||||
if (value != common.Hash{}) {
|
||||
// Encoding []byte cannot fail, ok to ignore the error.
|
||||
trimmed := common.TrimLeftZeroes(value[:])
|
||||
encoded, _ = rlp.EncodeToBytes(trimmed)
|
||||
if err := tr.UpdateStorage(s.address, key[:], trimmed); err != nil {
|
||||
if err := tr.UpdateStorage(s.address, key[:], common.TrimLeftZeroes(value[:])); err != nil {
|
||||
s.db.setError(err)
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -374,39 +375,8 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||
} else {
|
||||
deletions = append(deletions, key)
|
||||
}
|
||||
// Cache the mutated storage slots until commit
|
||||
if storage == nil {
|
||||
s.db.storagesLock.Lock()
|
||||
if storage = s.db.storages[s.addrHash]; storage == nil {
|
||||
storage = make(map[common.Hash][]byte)
|
||||
s.db.storages[s.addrHash] = storage
|
||||
}
|
||||
s.db.storagesLock.Unlock()
|
||||
}
|
||||
khash := crypto.HashData(hasher, key[:])
|
||||
storage[khash] = encoded // encoded will be nil if it's deleted
|
||||
|
||||
// Cache the original value of mutated storage slots
|
||||
if origin == nil {
|
||||
s.db.storagesLock.Lock()
|
||||
if origin = s.db.storagesOrigin[s.address]; origin == nil {
|
||||
origin = make(map[common.Hash][]byte)
|
||||
s.db.storagesOrigin[s.address] = origin
|
||||
}
|
||||
s.db.storagesLock.Unlock()
|
||||
}
|
||||
// Track the original value of slot only if it's mutated first time
|
||||
if _, ok := origin[khash]; !ok {
|
||||
if prev == (common.Hash{}) {
|
||||
origin[khash] = nil // nil if it was not present previously
|
||||
} else {
|
||||
// Encoding []byte cannot fail, ok to ignore the error.
|
||||
b, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(prev[:]))
|
||||
origin[khash] = b
|
||||
}
|
||||
}
|
||||
// Cache the items for preloading
|
||||
usedStorage = append(usedStorage, common.CopyBytes(key[:])) // Copy needed for closure
|
||||
used = append(used, common.CopyBytes(key[:])) // Copy needed for closure
|
||||
}
|
||||
for _, key := range deletions {
|
||||
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
||||
|
|
@ -415,15 +385,10 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||
}
|
||||
s.db.StorageDeleted.Add(1)
|
||||
}
|
||||
// If no slots were touched, issue a warning as we shouldn't have done all
|
||||
// the above work in the first place
|
||||
if len(usedStorage) == 0 {
|
||||
log.Error("State object update was noop", "addr", s.address, "slots", len(s.pendingStorage))
|
||||
}
|
||||
if s.db.prefetcher != nil {
|
||||
s.db.prefetcher.used(s.addrHash, s.data.Root, usedStorage)
|
||||
s.db.prefetcher.used(s.addrHash, s.data.Root, used)
|
||||
}
|
||||
s.pendingStorage = make(Storage) // reset pending map
|
||||
s.uncommittedStorage = make(Storage) // empties the commit markers
|
||||
return tr, nil
|
||||
}
|
||||
|
||||
|
|
@ -439,30 +404,76 @@ func (s *stateObject) updateRoot() {
|
|||
s.data.Root = tr.Hash()
|
||||
}
|
||||
|
||||
// commit obtains a set of dirty storage trie nodes and updates the account data.
|
||||
// The returned set can be nil if nothing to commit. This function assumes all
|
||||
// storage mutations have already been flushed into trie by updateRoot.
|
||||
// commitStorage overwrites the clean storage with the storage changes and
|
||||
// fulfills the storage diffs into the given accountUpdate struct.
|
||||
func (s *stateObject) commitStorage(op *accountUpdate) {
|
||||
var (
|
||||
buf = crypto.NewKeccakState()
|
||||
encode = func(val common.Hash) []byte {
|
||||
if val == (common.Hash{}) {
|
||||
return nil
|
||||
}
|
||||
blob, _ := rlp.EncodeToBytes(common.TrimLeftZeroes(val[:]))
|
||||
return blob
|
||||
}
|
||||
)
|
||||
for key, val := range s.pendingStorage {
|
||||
// Skip the noop storage changes, it might be possible the value
|
||||
// of tracked slot is same in originStorage and pendingStorage
|
||||
// map, e.g. the storage slot is modified in tx_a and then reset
|
||||
// back in tx_b.
|
||||
if val == s.originStorage[key] {
|
||||
continue
|
||||
}
|
||||
hash := crypto.HashData(buf, key[:])
|
||||
if op.storages == nil {
|
||||
op.storages = make(map[common.Hash][]byte)
|
||||
}
|
||||
op.storages[hash] = encode(val)
|
||||
if op.storagesOrigin == nil {
|
||||
op.storagesOrigin = make(map[common.Hash][]byte)
|
||||
}
|
||||
op.storagesOrigin[hash] = encode(s.originStorage[key])
|
||||
|
||||
// Overwrite the clean value of storage slots
|
||||
s.originStorage[key] = val
|
||||
}
|
||||
s.pendingStorage = make(Storage)
|
||||
}
|
||||
|
||||
// commit obtains the account changes (metadata, storage slots, code) caused by
|
||||
// state execution along with the dirty storage trie nodes.
|
||||
//
|
||||
// Note, commit may run concurrently across all the state objects. Do not assume
|
||||
// thread-safe access to the statedb.
|
||||
func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
||||
// Short circuit if trie is not even loaded, don't bother with committing anything
|
||||
if s.trie == nil {
|
||||
func (s *stateObject) commit() (*accountUpdate, *trienode.NodeSet, error) {
|
||||
// commit the account metadata changes
|
||||
op := &accountUpdate{
|
||||
address: s.address,
|
||||
data: types.SlimAccountRLP(s.data),
|
||||
}
|
||||
if s.origin != nil {
|
||||
op.origin = types.SlimAccountRLP(*s.origin)
|
||||
}
|
||||
// commit the contract code if it's modified
|
||||
if s.dirtyCode {
|
||||
op.code = &contractCode{
|
||||
hash: common.BytesToHash(s.CodeHash()),
|
||||
blob: s.code,
|
||||
}
|
||||
s.dirtyCode = false // reset the dirty flag
|
||||
}
|
||||
// Commit storage changes and the associated storage trie
|
||||
s.commitStorage(op)
|
||||
if len(op.storages) == 0 {
|
||||
// nothing changed, don't bother to commit the trie
|
||||
s.origin = s.data.Copy()
|
||||
return nil, nil
|
||||
}
|
||||
// The trie is currently in an open state and could potentially contain
|
||||
// cached mutations. Call commit to acquire a set of nodes that have been
|
||||
// modified, the set can be nil if nothing to commit.
|
||||
root, nodes, err := s.trie.Commit(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return op, nil, nil
|
||||
}
|
||||
root, nodes := s.trie.Commit(false)
|
||||
s.data.Root = root
|
||||
|
||||
// Update original account data after commit
|
||||
s.origin = s.data.Copy()
|
||||
return nodes, nil
|
||||
return op, nodes, nil
|
||||
}
|
||||
|
||||
// AddBalance adds amount to s's balance.
|
||||
|
|
@ -514,6 +525,7 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
|||
originStorage: s.originStorage.Copy(),
|
||||
pendingStorage: s.pendingStorage.Copy(),
|
||||
dirtyStorage: s.dirtyStorage.Copy(),
|
||||
uncommittedStorage: s.uncommittedStorage.Copy(),
|
||||
dirtyCode: s.dirtyCode,
|
||||
selfDestructed: s.selfDestructed,
|
||||
newContract: s.newContract,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"maps"
|
||||
"math/big"
|
||||
|
|
@ -95,15 +96,6 @@ type StateDB struct {
|
|||
// It will be updated when the Commit is called.
|
||||
originalRoot common.Hash
|
||||
|
||||
// These maps hold the state changes (including the corresponding
|
||||
// original value) that occurred in this **block**.
|
||||
accounts map[common.Hash][]byte // The mutated accounts in 'slim RLP' encoding
|
||||
accountsOrigin map[common.Address][]byte // The original value of mutated accounts in 'slim RLP' encoding
|
||||
|
||||
storages map[common.Hash]map[common.Hash][]byte // The mutated slots in prefix-zero trimmed rlp format
|
||||
storagesOrigin map[common.Address]map[common.Hash][]byte // The original value of mutated slots in prefix-zero trimmed rlp format
|
||||
storagesLock sync.Mutex // Mutex protecting the maps during concurrent updates/commits
|
||||
|
||||
// This map holds 'live' objects, which will get modified while
|
||||
// processing a state transition.
|
||||
stateObjects map[common.Address]*stateObject
|
||||
|
|
@ -171,9 +163,6 @@ type StateDB struct {
|
|||
StorageUpdated atomic.Int64
|
||||
AccountDeleted int
|
||||
StorageDeleted atomic.Int64
|
||||
|
||||
// Testing hooks
|
||||
onCommit func(states *triestate.Set) // Hook invoked when commit is performed
|
||||
}
|
||||
|
||||
// New creates a new state from a given trie.
|
||||
|
|
@ -187,10 +176,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
|||
trie: tr,
|
||||
originalRoot: root,
|
||||
snaps: snaps,
|
||||
accounts: make(map[common.Hash][]byte),
|
||||
storages: make(map[common.Hash]map[common.Hash][]byte),
|
||||
accountsOrigin: make(map[common.Address][]byte),
|
||||
storagesOrigin: make(map[common.Address]map[common.Hash][]byte),
|
||||
stateObjects: make(map[common.Address]*stateObject),
|
||||
stateObjectsDestruct: make(map[common.Address]*types.StateAccount),
|
||||
mutations: make(map[common.Address]*mutation),
|
||||
|
|
@ -215,14 +200,27 @@ func (s *StateDB) SetLogger(l *tracing.Hooks) {
|
|||
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
|
||||
// state trie concurrently while the state is mutated so that when we reach the
|
||||
// commit phase, most of the needed data is already hot.
|
||||
func (s *StateDB) StartPrefetcher(namespace string) {
|
||||
func (s *StateDB) StartPrefetcher(namespace string, noreads bool) {
|
||||
if s.prefetcher != nil {
|
||||
s.prefetcher.terminate(false)
|
||||
s.prefetcher.report()
|
||||
s.prefetcher = nil
|
||||
}
|
||||
if s.snap != nil {
|
||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace)
|
||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, namespace, noreads)
|
||||
|
||||
// With the switch to the Proof-of-Stake consensus algorithm, block production
|
||||
// rewards are now handled at the consensus layer. Consequently, a block may
|
||||
// have no state transitions if it contains no transactions and no withdrawals.
|
||||
// In such cases, the account trie won't be scheduled for prefetching, leading
|
||||
// to unnecessary error logs.
|
||||
//
|
||||
// To prevent this, the account trie is always scheduled for prefetching once
|
||||
// the prefetcher is constructed. For more details, see:
|
||||
// https://github.com/ethereum/go-ethereum/issues/29880
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, nil, false); err != nil {
|
||||
log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +349,7 @@ func (s *StateDB) GetStorageRoot(addr common.Address) common.Hash {
|
|||
return common.Hash{}
|
||||
}
|
||||
|
||||
// TxIndex returns the current transaction index set by Prepare.
|
||||
// TxIndex returns the current transaction index set by SetTxContext.
|
||||
func (s *StateDB) TxIndex() int {
|
||||
return s.txIndex
|
||||
}
|
||||
|
|
@ -380,7 +378,7 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
|
|||
return common.Hash{}
|
||||
}
|
||||
|
||||
// GetState retrieves a value from the given account's storage trie.
|
||||
// GetState retrieves the value associated with the specific key.
|
||||
func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
|
||||
stateObject := s.getStateObject(addr)
|
||||
if stateObject != nil {
|
||||
|
|
@ -389,7 +387,8 @@ func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
|
|||
return common.Hash{}
|
||||
}
|
||||
|
||||
// GetCommittedState retrieves a value from the given account's committed storage trie.
|
||||
// GetCommittedState retrieves the value associated with the specific key
|
||||
// without any mutations caused in the current execution.
|
||||
func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
|
||||
stateObject := s.getStateObject(addr)
|
||||
if stateObject != nil {
|
||||
|
|
@ -557,22 +556,6 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
|
|||
if obj.dirtyCode {
|
||||
s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code)
|
||||
}
|
||||
// Cache the data until commit. Note, this update mechanism is not symmetric
|
||||
// to the deletion, because whereas it is enough to track account updates
|
||||
// at commit time, deletions need tracking at transaction boundary level to
|
||||
// ensure we capture state clearing.
|
||||
s.accounts[obj.addrHash] = types.SlimAccountRLP(obj.data)
|
||||
|
||||
// Track the original value of mutated account, nil means it was not present.
|
||||
// Skip if it has been tracked (because updateStateObject may be called
|
||||
// multiple times in a block).
|
||||
if _, ok := s.accountsOrigin[obj.address]; !ok {
|
||||
if obj.origin == nil {
|
||||
s.accountsOrigin[obj.address] = nil
|
||||
} else {
|
||||
s.accountsOrigin[obj.address] = types.SlimAccountRLP(*obj.origin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deleteStateObject removes the given object from the state trie.
|
||||
|
|
@ -633,6 +616,14 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
|||
return nil
|
||||
}
|
||||
}
|
||||
// Independent of where we loaded the data from, add it to the prefetcher.
|
||||
// Whilst this would be a bit weird if snapshots are disabled, but we still
|
||||
// want the trie nodes to end up in the prefetcher too, so just push through.
|
||||
if s.prefetcher != nil {
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, [][]byte{addr[:]}, true); err != nil {
|
||||
log.Error("Failed to prefetch account", "addr", addr, "err", err)
|
||||
}
|
||||
}
|
||||
// Insert into the live set
|
||||
obj := newObject(s, addr, data)
|
||||
s.setStateObject(obj)
|
||||
|
|
@ -691,10 +682,6 @@ func (s *StateDB) Copy() *StateDB {
|
|||
trie: s.db.CopyTrie(s.trie),
|
||||
hasher: crypto.NewKeccakState(),
|
||||
originalRoot: s.originalRoot,
|
||||
accounts: copySet(s.accounts),
|
||||
storages: copy2DSet(s.storages),
|
||||
accountsOrigin: copySet(s.accountsOrigin),
|
||||
storagesOrigin: copy2DSet(s.storagesOrigin),
|
||||
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
||||
stateObjectsDestruct: maps.Clone(s.stateObjectsDestruct),
|
||||
mutations: make(map[common.Address]*mutation, len(s.mutations)),
|
||||
|
|
@ -803,13 +790,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
|||
if _, ok := s.stateObjectsDestruct[obj.address]; !ok {
|
||||
s.stateObjectsDestruct[obj.address] = obj.origin
|
||||
}
|
||||
// Note, we can't do this only at the end of a block because multiple
|
||||
// transactions within the same block might self destruct and then
|
||||
// resurrect an account; but the snapshotter needs both events.
|
||||
delete(s.accounts, obj.addrHash) // Clear out any previously updated account data (may be recreated via a resurrect)
|
||||
delete(s.storages, obj.addrHash) // Clear out any previously updated storage data (may be recreated via a resurrect)
|
||||
delete(s.accountsOrigin, obj.address) // Clear out any previously updated account data (may be recreated via a resurrect)
|
||||
delete(s.storagesOrigin, obj.address) // Clear out any previously updated storage data (may be recreated via a resurrect)
|
||||
} else {
|
||||
obj.finalise()
|
||||
s.markUpdate(addr)
|
||||
|
|
@ -820,7 +800,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
|||
addressesToPrefetch = append(addressesToPrefetch, common.CopyBytes(addr[:])) // Copy needed for closure
|
||||
}
|
||||
if s.prefetcher != nil && len(addressesToPrefetch) > 0 {
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch); err != nil {
|
||||
if err := s.prefetcher.prefetch(common.Hash{}, s.originalRoot, common.Address{}, addressesToPrefetch, false); err != nil {
|
||||
log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -878,9 +858,9 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
|||
start = time.Now()
|
||||
|
||||
if s.prefetcher != nil {
|
||||
if trie, err := s.prefetcher.trie(common.Hash{}, s.originalRoot); err != nil {
|
||||
log.Error("Failed to retrieve account pre-fetcher trie", "err", err)
|
||||
} else if trie != nil {
|
||||
if trie := s.prefetcher.trie(common.Hash{}, s.originalRoot); trie == nil {
|
||||
log.Error("Failed to retrieve account pre-fetcher trie")
|
||||
} else {
|
||||
s.trie = trie
|
||||
}
|
||||
}
|
||||
|
|
@ -1020,10 +1000,9 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r
|
|||
}
|
||||
|
||||
// deleteStorage is designed to delete the storage trie of a designated account.
|
||||
// It could potentially be terminated if the storage size is excessively large,
|
||||
// potentially leading to an out-of-memory panic. The function will make an attempt
|
||||
// to utilize an efficient strategy if the associated state snapshot is reachable;
|
||||
// otherwise, it will resort to a less-efficient approach.
|
||||
// The function will make an attempt to utilize an efficient strategy if the
|
||||
// associated state snapshot is reachable; otherwise, it will resort to a less
|
||||
// efficient approach.
|
||||
func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root common.Hash) (map[common.Hash][]byte, *trienode.NodeSet, error) {
|
||||
var (
|
||||
start = time.Now()
|
||||
|
|
@ -1058,75 +1037,61 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
|
|||
}
|
||||
|
||||
// handleDestruction processes all destruction markers and deletes the account
|
||||
// and associated storage slots if necessary. There are four possible situations
|
||||
// here:
|
||||
// and associated storage slots if necessary. There are four potential scenarios
|
||||
// as following:
|
||||
//
|
||||
// - the account was not existent and be marked as destructed
|
||||
//
|
||||
// - the account was not existent and be marked as destructed,
|
||||
// (a) the account was not existent and be marked as destructed
|
||||
// (b) the account was not existent and be marked as destructed,
|
||||
// however, it's resurrected later in the same block.
|
||||
//
|
||||
// - the account was existent and be marked as destructed
|
||||
//
|
||||
// - the account was existent and be marked as destructed,
|
||||
// (c) the account was existent and be marked as destructed
|
||||
// (d) the account was existent and be marked as destructed,
|
||||
// however it's resurrected later in the same block.
|
||||
//
|
||||
// In case (a), nothing needs be deleted, nil to nil transition can be ignored.
|
||||
//
|
||||
// In case (b), nothing needs be deleted, nil is used as the original value for
|
||||
// newly created account and storages
|
||||
//
|
||||
// In case (c), **original** account along with its storages should be deleted,
|
||||
// with their values be tracked as original value.
|
||||
//
|
||||
// In case (d), **original** account along with its storages should be deleted,
|
||||
// with their values be tracked as original value.
|
||||
func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) error {
|
||||
// Short circuit if geth is running with hash mode. This procedure can consume
|
||||
// considerable time and storage deletion isn't supported in hash mode, thus
|
||||
// preemptively avoiding unnecessary expenses.
|
||||
if s.db.TrieDB().Scheme() == rawdb.HashScheme {
|
||||
return nil
|
||||
}
|
||||
func (s *StateDB) handleDestruction() (map[common.Hash]*accountDelete, []*trienode.NodeSet, error) {
|
||||
var (
|
||||
nodes []*trienode.NodeSet
|
||||
buf = crypto.NewKeccakState()
|
||||
deletes = make(map[common.Hash]*accountDelete)
|
||||
)
|
||||
for addr, prev := range s.stateObjectsDestruct {
|
||||
// The original account was non-existing, and it's marked as destructed
|
||||
// in the scope of block. It can be case (a) or (b).
|
||||
// - for (a), skip it without doing anything.
|
||||
// - for (b), track account's original value as nil. It may overwrite
|
||||
// the data cached in s.accountsOrigin set by 'updateStateObject'.
|
||||
addrHash := crypto.Keccak256Hash(addr[:])
|
||||
// The account was non-existent, and it's marked as destructed in the scope
|
||||
// of block. It can be either case (a) or (b) and will be interpreted as
|
||||
// null->null state transition.
|
||||
// - for (a), skip it without doing anything
|
||||
// - for (b), the resurrected account with nil as original will be handled afterwards
|
||||
if prev == nil {
|
||||
if _, ok := s.accounts[addrHash]; ok {
|
||||
s.accountsOrigin[addr] = nil // case (b)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// It can overwrite the data in s.accountsOrigin set by 'updateStateObject'.
|
||||
s.accountsOrigin[addr] = types.SlimAccountRLP(*prev) // case (c) or (d)
|
||||
// The account was existent, it can be either case (c) or (d).
|
||||
addrHash := crypto.HashData(buf, addr.Bytes())
|
||||
op := &accountDelete{
|
||||
address: addr,
|
||||
origin: types.SlimAccountRLP(*prev),
|
||||
}
|
||||
deletes[addrHash] = op
|
||||
|
||||
// Short circuit if the storage was empty.
|
||||
// Short circuit if the origin storage was empty.
|
||||
if prev.Root == types.EmptyRootHash {
|
||||
continue
|
||||
}
|
||||
// Remove storage slots belong to the account.
|
||||
// Remove storage slots belonging to the account.
|
||||
slots, set, err := s.deleteStorage(addr, addrHash, prev.Root)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete storage, err: %w", err)
|
||||
return nil, nil, fmt.Errorf("failed to delete storage, err: %w", err)
|
||||
}
|
||||
if s.storagesOrigin[addr] == nil {
|
||||
s.storagesOrigin[addr] = slots
|
||||
} else {
|
||||
// It can overwrite the data in s.storagesOrigin[addrHash] set by
|
||||
// 'object.updateTrie'.
|
||||
for key, val := range slots {
|
||||
s.storagesOrigin[addr][key] = val
|
||||
op.storagesOrigin = slots
|
||||
|
||||
// Aggregate the associated trie node changes.
|
||||
nodes = append(nodes, set)
|
||||
}
|
||||
}
|
||||
if err := nodes.Merge(set); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return deletes, nodes, nil
|
||||
}
|
||||
|
||||
// GetTrie returns the account trie.
|
||||
|
|
@ -1134,18 +1099,12 @@ func (s *StateDB) GetTrie() Trie {
|
|||
return s.trie
|
||||
}
|
||||
|
||||
// Commit writes the state to the underlying in-memory trie database.
|
||||
// Once the state is committed, tries cached in stateDB (including account
|
||||
// trie, storage tries) will no longer be functional. A new state instance
|
||||
// must be created with new root and updated database for accessing post-
|
||||
// commit states.
|
||||
//
|
||||
// The associated block number of the state transition is also provided
|
||||
// for more chain context.
|
||||
func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) {
|
||||
// commit gathers the state mutations accumulated along with the associated
|
||||
// trie changes, resetting all internal flags with the new state as the base.
|
||||
func (s *StateDB) commit(deleteEmptyObjects bool) (*stateUpdate, error) {
|
||||
// Short circuit in case any database failure occurred earlier.
|
||||
if s.dbErr != nil {
|
||||
return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
|
||||
return nil, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
|
||||
}
|
||||
// Finalize any pending changes and merge everything into the tries
|
||||
s.IntermediateRoot(deleteEmptyObjects)
|
||||
|
|
@ -1156,19 +1115,56 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
|
|||
accountTrieNodesDeleted int
|
||||
storageTrieNodesUpdated int
|
||||
storageTrieNodesDeleted int
|
||||
nodes = trienode.NewMergedNodeSet()
|
||||
|
||||
lock sync.Mutex // protect two maps below
|
||||
nodes = trienode.NewMergedNodeSet() // aggregated trie nodes
|
||||
updates = make(map[common.Hash]*accountUpdate, len(s.mutations)) // aggregated account updates
|
||||
|
||||
// merge aggregates the dirty trie nodes into the global set.
|
||||
//
|
||||
// Given that some accounts may be destroyed and then recreated within
|
||||
// the same block, it's possible that a node set with the same owner
|
||||
// may already exists. In such cases, these two sets are combined, with
|
||||
// the later one overwriting the previous one if any nodes are modified
|
||||
// or deleted in both sets.
|
||||
//
|
||||
// merge run concurrently across all the state objects and account trie.
|
||||
merge = func(set *trienode.NodeSet) error {
|
||||
if set == nil {
|
||||
return nil
|
||||
}
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
updates, deletes := set.Size()
|
||||
if set.Owner == (common.Hash{}) {
|
||||
accountTrieNodesUpdated += updates
|
||||
accountTrieNodesDeleted += deletes
|
||||
} else {
|
||||
storageTrieNodesUpdated += updates
|
||||
storageTrieNodesDeleted += deletes
|
||||
}
|
||||
return nodes.Merge(set)
|
||||
}
|
||||
)
|
||||
// Handle all state deletions first
|
||||
if err := s.handleDestruction(nodes); err != nil {
|
||||
return common.Hash{}, err
|
||||
// Given that some accounts could be destroyed and then recreated within
|
||||
// the same block, account deletions must be processed first. This ensures
|
||||
// that the storage trie nodes deleted during destruction and recreated
|
||||
// during subsequent resurrection can be combined correctly.
|
||||
deletes, delNodes, err := s.handleDestruction()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, set := range delNodes {
|
||||
if err := merge(set); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// Handle all state updates afterwards, concurrently to one another to shave
|
||||
// off some milliseconds from the commit operation. Also accumulate the code
|
||||
// writes to run in parallel with the computations.
|
||||
start := time.Now()
|
||||
var (
|
||||
code = s.db.DiskDB().NewBatch()
|
||||
lock sync.Mutex
|
||||
start = time.Now()
|
||||
root common.Hash
|
||||
workers errgroup.Group
|
||||
)
|
||||
|
|
@ -1183,22 +1179,12 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
|
|||
// code didn't anticipate for.
|
||||
workers.Go(func() error {
|
||||
// Write the account trie changes, measuring the amount of wasted time
|
||||
newroot, set, err := s.trie.Commit(true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newroot, set := s.trie.Commit(true)
|
||||
root = newroot
|
||||
|
||||
// Merge the dirty nodes of account trie into global set
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if set != nil {
|
||||
if err = nodes.Merge(set); err != nil {
|
||||
if err := merge(set); err != nil {
|
||||
return err
|
||||
}
|
||||
accountTrieNodesUpdated, accountTrieNodesDeleted = set.Size()
|
||||
}
|
||||
s.AccountCommits = time.Since(start)
|
||||
return nil
|
||||
})
|
||||
|
|
@ -1215,49 +1201,29 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
|
|||
}
|
||||
// Write any contract code associated with the state object
|
||||
obj := s.stateObjects[addr]
|
||||
if obj.code != nil && obj.dirtyCode {
|
||||
rawdb.WriteCode(code, common.BytesToHash(obj.CodeHash()), obj.code)
|
||||
obj.dirtyCode = false
|
||||
if obj == nil {
|
||||
return nil, errors.New("missing state object")
|
||||
}
|
||||
// Run the storage updates concurrently to one another
|
||||
workers.Go(func() error {
|
||||
// Write any storage changes in the state object to its storage trie
|
||||
set, err := obj.commit()
|
||||
update, set, err := obj.commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Merge the dirty nodes of storage trie into global set. It is possible
|
||||
// that the account was destructed and then resurrected in the same block.
|
||||
// In this case, the node set is shared by both accounts.
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if set != nil {
|
||||
if err = nodes.Merge(set); err != nil {
|
||||
if err := merge(set); err != nil {
|
||||
return err
|
||||
}
|
||||
updates, deleted := set.Size()
|
||||
storageTrieNodesUpdated += updates
|
||||
storageTrieNodesDeleted += deleted
|
||||
}
|
||||
lock.Lock()
|
||||
updates[obj.addrHash] = update
|
||||
s.StorageCommits = time.Since(start) // overwrite with the longest storage commit runtime
|
||||
lock.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
// Schedule the code commits to run concurrently too. This shouldn't really
|
||||
// take much since we don't often commit code, but since it's disk access,
|
||||
// it's always yolo.
|
||||
workers.Go(func() error {
|
||||
if code.ValueSize() > 0 {
|
||||
if err := code.Write(); err != nil {
|
||||
log.Crit("Failed to commit dirty codes", "error", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
// Wait for everything to finish and update the metrics
|
||||
if err := workers.Wait(); err != nil {
|
||||
return common.Hash{}, err
|
||||
return nil, err
|
||||
}
|
||||
accountUpdatedMeter.Mark(int64(s.AccountUpdated))
|
||||
storageUpdatedMeter.Mark(s.StorageUpdated.Load())
|
||||
|
|
@ -1271,53 +1237,78 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
|
|||
s.StorageUpdated.Store(0)
|
||||
s.StorageDeleted.Store(0)
|
||||
|
||||
// Clear all internal flags and update state root at the end.
|
||||
s.mutations = make(map[common.Address]*mutation)
|
||||
s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount)
|
||||
|
||||
origin := s.originalRoot
|
||||
s.originalRoot = root
|
||||
return newStateUpdate(origin, root, deletes, updates, nodes), nil
|
||||
}
|
||||
|
||||
// commitAndFlush is a wrapper of commit which also commits the state mutations
|
||||
// to the configured data stores.
|
||||
func (s *StateDB) commitAndFlush(block uint64, deleteEmptyObjects bool) (*stateUpdate, error) {
|
||||
ret, err := s.commit(deleteEmptyObjects)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Commit dirty contract code if any exists
|
||||
if db := s.db.DiskDB(); db != nil && len(ret.codes) > 0 {
|
||||
batch := db.NewBatch()
|
||||
for _, code := range ret.codes {
|
||||
rawdb.WriteCode(batch, code.hash, code.blob)
|
||||
}
|
||||
if err := batch.Write(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if !ret.empty() {
|
||||
// If snapshotting is enabled, update the snapshot tree with this new version
|
||||
if s.snap != nil {
|
||||
start = time.Now()
|
||||
// Only update if there's a state transition (skip empty Clique blocks)
|
||||
if parent := s.snap.Root(); parent != root {
|
||||
if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil {
|
||||
log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err)
|
||||
s.snap = nil
|
||||
|
||||
start := time.Now()
|
||||
if err := s.snaps.Update(ret.root, ret.originRoot, ret.destructs, ret.accounts, ret.storages); err != nil {
|
||||
log.Warn("Failed to update snapshot tree", "from", ret.originRoot, "to", ret.root, "err", err)
|
||||
}
|
||||
// Keep TriesInMemory diff layers in the memory, persistent layer is 129th.
|
||||
// Keep 128 diff layers in the memory, persistent layer is 129th.
|
||||
// - head layer is paired with HEAD state
|
||||
// - head-1 layer is paired with HEAD-1 state
|
||||
// - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state
|
||||
if err := s.snaps.Cap(root, TriesInMemory); err != nil {
|
||||
log.Warn("Failed to cap snapshot tree", "root", root, "layers", TriesInMemory, "err", err)
|
||||
}
|
||||
if err := s.snaps.Cap(ret.root, TriesInMemory); err != nil {
|
||||
log.Warn("Failed to cap snapshot tree", "root", ret.root, "layers", TriesInMemory, "err", err)
|
||||
}
|
||||
s.SnapshotCommits += time.Since(start)
|
||||
s.snap = nil
|
||||
}
|
||||
if root == (common.Hash{}) {
|
||||
root = types.EmptyRootHash
|
||||
// If trie database is enabled, commit the state update as a new layer
|
||||
if db := s.db.TrieDB(); db != nil {
|
||||
start := time.Now()
|
||||
set := triestate.New(ret.accountsOrigin, ret.storagesOrigin)
|
||||
if err := db.Update(ret.root, ret.originRoot, block, ret.nodes, set); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
origin := s.originalRoot
|
||||
if origin == (common.Hash{}) {
|
||||
origin = types.EmptyRootHash
|
||||
s.TrieDBCommits += time.Since(start)
|
||||
}
|
||||
if root != origin {
|
||||
start = time.Now()
|
||||
set := triestate.New(s.accountsOrigin, s.storagesOrigin)
|
||||
if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil {
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
|
||||
// Commit writes the state mutations into the configured data stores.
|
||||
//
|
||||
// Once the state is committed, tries cached in stateDB (including account
|
||||
// trie, storage tries) will no longer be functional. A new state instance
|
||||
// must be created with new root and updated database for accessing post-
|
||||
// commit states.
|
||||
//
|
||||
// The associated block number of the state transition is also provided
|
||||
// for more chain context.
|
||||
func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, error) {
|
||||
ret, err := s.commitAndFlush(block, deleteEmptyObjects)
|
||||
if err != nil {
|
||||
return common.Hash{}, err
|
||||
}
|
||||
s.originalRoot = root
|
||||
s.TrieDBCommits += time.Since(start)
|
||||
|
||||
if s.onCommit != nil {
|
||||
s.onCommit(set)
|
||||
}
|
||||
}
|
||||
// Clear all internal flags at the end of commit operation.
|
||||
s.accounts = make(map[common.Hash][]byte)
|
||||
s.storages = make(map[common.Hash]map[common.Hash][]byte)
|
||||
s.accountsOrigin = make(map[common.Address][]byte)
|
||||
s.storagesOrigin = make(map[common.Address]map[common.Hash][]byte)
|
||||
s.mutations = make(map[common.Address]*mutation)
|
||||
s.stateObjectsDestruct = make(map[common.Address]*types.StateAccount)
|
||||
return root, nil
|
||||
return ret.root, nil
|
||||
}
|
||||
|
||||
// Prepare handles the preparatory steps for executing a state transition with.
|
||||
|
|
@ -1399,41 +1390,9 @@ func (s *StateDB) SlotInAccessList(addr common.Address, slot common.Hash) (addre
|
|||
return s.accessList.Contains(addr, slot)
|
||||
}
|
||||
|
||||
// convertAccountSet converts a provided account set from address keyed to hash keyed.
|
||||
func (s *StateDB) convertAccountSet(set map[common.Address]*types.StateAccount) map[common.Hash]struct{} {
|
||||
ret := make(map[common.Hash]struct{}, len(set))
|
||||
for addr := range set {
|
||||
obj, exist := s.stateObjects[addr]
|
||||
if !exist {
|
||||
ret[crypto.Keccak256Hash(addr[:])] = struct{}{}
|
||||
} else {
|
||||
ret[obj.addrHash] = struct{}{}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// copySet returns a deep-copied set.
|
||||
func copySet[k comparable](set map[k][]byte) map[k][]byte {
|
||||
copied := make(map[k][]byte, len(set))
|
||||
for key, val := range set {
|
||||
copied[key] = common.CopyBytes(val)
|
||||
}
|
||||
return copied
|
||||
}
|
||||
|
||||
// copy2DSet returns a two-dimensional deep-copied set.
|
||||
func copy2DSet[k comparable](set map[k]map[common.Hash][]byte) map[k]map[common.Hash][]byte {
|
||||
copied := make(map[k]map[common.Hash][]byte, len(set))
|
||||
for addr, subset := range set {
|
||||
copied[addr] = make(map[common.Hash][]byte, len(subset))
|
||||
for key, val := range subset {
|
||||
copied[addr][key] = common.CopyBytes(val)
|
||||
}
|
||||
}
|
||||
return copied
|
||||
}
|
||||
|
||||
// markDelete is invoked when an account is deleted but the deletion is
|
||||
// not yet committed. The pending mutation is cached and will be applied
|
||||
// all together
|
||||
func (s *StateDB) markDelete(addr common.Address) {
|
||||
if _, ok := s.mutations[addr]; !ok {
|
||||
s.mutations[addr] = &mutation{}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
||||
"github.com/holiman/uint256"
|
||||
|
|
@ -180,9 +179,21 @@ func (test *stateTest) run() bool {
|
|||
roots []common.Hash
|
||||
accountList []map[common.Address][]byte
|
||||
storageList []map[common.Address]map[common.Hash][]byte
|
||||
onCommit = func(states *triestate.Set) {
|
||||
accountList = append(accountList, copySet(states.Accounts))
|
||||
storageList = append(storageList, copy2DSet(states.Storages))
|
||||
copyUpdate = func(update *stateUpdate) {
|
||||
accounts := make(map[common.Address][]byte, len(update.accountsOrigin))
|
||||
for key, val := range update.accountsOrigin {
|
||||
accounts[key] = common.CopyBytes(val)
|
||||
}
|
||||
accountList = append(accountList, accounts)
|
||||
|
||||
storages := make(map[common.Address]map[common.Hash][]byte, len(update.storagesOrigin))
|
||||
for addr, subset := range update.storagesOrigin {
|
||||
storages[addr] = make(map[common.Hash][]byte, len(subset))
|
||||
for key, val := range subset {
|
||||
storages[addr][key] = common.CopyBytes(val)
|
||||
}
|
||||
}
|
||||
storageList = append(storageList, storages)
|
||||
}
|
||||
disk = rawdb.NewMemoryDatabase()
|
||||
tdb = triedb.NewDatabase(disk, &triedb.Config{PathDB: pathdb.Defaults})
|
||||
|
|
@ -210,8 +221,6 @@ func (test *stateTest) run() bool {
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
state.onCommit = onCommit
|
||||
|
||||
for i, action := range actions {
|
||||
if i%test.chunk == 0 && i != 0 {
|
||||
if byzantium {
|
||||
|
|
@ -227,14 +236,15 @@ func (test *stateTest) run() bool {
|
|||
} else {
|
||||
state.IntermediateRoot(true) // call intermediateRoot at the transaction boundary
|
||||
}
|
||||
nroot, err := state.Commit(0, true) // call commit at the block boundary
|
||||
ret, err := state.commitAndFlush(0, true) // call commit at the block boundary
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if nroot == root {
|
||||
return true // filter out non-change state transition
|
||||
if ret.empty() {
|
||||
return true
|
||||
}
|
||||
roots = append(roots, nroot)
|
||||
copyUpdate(ret)
|
||||
roots = append(roots, ret.root)
|
||||
}
|
||||
for i := 0; i < len(test.actions); i++ {
|
||||
root := types.EmptyRootHash
|
||||
|
|
|
|||
133
core/state/stateupdate.go
Normal file
133
core/state/stateupdate.go
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
// 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 state
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
)
|
||||
|
||||
// contractCode represents a contract code with associated metadata.
|
||||
type contractCode struct {
|
||||
hash common.Hash // hash is the cryptographic hash of the contract code.
|
||||
blob []byte // blob is the binary representation of the contract code.
|
||||
}
|
||||
|
||||
// accountDelete represents an operation for deleting an Ethereum account.
|
||||
type accountDelete struct {
|
||||
address common.Address // address is the unique account identifier
|
||||
origin []byte // origin is the original value of account data in slim-RLP encoding.
|
||||
storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format.
|
||||
}
|
||||
|
||||
// accountUpdate represents an operation for updating an Ethereum account.
|
||||
type accountUpdate struct {
|
||||
address common.Address // address is the unique account identifier
|
||||
data []byte // data is the slim-RLP encoded account data.
|
||||
origin []byte // origin is the original value of account data in slim-RLP encoding.
|
||||
code *contractCode // code represents mutated contract code; nil means it's not modified.
|
||||
storages map[common.Hash][]byte // storages stores mutated slots in prefix-zero-trimmed RLP format.
|
||||
storagesOrigin map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in prefix-zero-trimmed RLP format.
|
||||
}
|
||||
|
||||
// stateUpdate represents the difference between two states resulting from state
|
||||
// execution. It contains information about mutated contract codes, accounts,
|
||||
// and storage slots, along with their original values.
|
||||
type stateUpdate struct {
|
||||
originRoot common.Hash // hash of the state before applying mutation
|
||||
root common.Hash // hash of the state after applying mutation
|
||||
destructs map[common.Hash]struct{} // destructs contains the list of destructed accounts
|
||||
accounts map[common.Hash][]byte // accounts stores mutated accounts in 'slim RLP' encoding
|
||||
accountsOrigin map[common.Address][]byte // accountsOrigin stores the original values of mutated accounts in 'slim RLP' encoding
|
||||
storages map[common.Hash]map[common.Hash][]byte // storages stores mutated slots in 'prefix-zero-trimmed' RLP format
|
||||
storagesOrigin map[common.Address]map[common.Hash][]byte // storagesOrigin stores the original values of mutated slots in 'prefix-zero-trimmed' RLP format
|
||||
codes map[common.Address]contractCode // codes contains the set of dirty codes
|
||||
nodes *trienode.MergedNodeSet // Aggregated dirty nodes caused by state changes
|
||||
}
|
||||
|
||||
// empty returns a flag indicating the state transition is empty or not.
|
||||
func (sc *stateUpdate) empty() bool {
|
||||
return sc.originRoot == sc.root
|
||||
}
|
||||
|
||||
// newStateUpdate constructs a state update object, representing the differences
|
||||
// between two states by performing state execution. It aggregates the given
|
||||
// account deletions and account updates to form a comprehensive state update.
|
||||
func newStateUpdate(originRoot common.Hash, root common.Hash, deletes map[common.Hash]*accountDelete, updates map[common.Hash]*accountUpdate, nodes *trienode.MergedNodeSet) *stateUpdate {
|
||||
var (
|
||||
destructs = make(map[common.Hash]struct{})
|
||||
accounts = make(map[common.Hash][]byte)
|
||||
accountsOrigin = make(map[common.Address][]byte)
|
||||
storages = make(map[common.Hash]map[common.Hash][]byte)
|
||||
storagesOrigin = make(map[common.Address]map[common.Hash][]byte)
|
||||
codes = make(map[common.Address]contractCode)
|
||||
)
|
||||
// Due to the fact that some accounts could be destructed and resurrected
|
||||
// within the same block, the deletions must be aggregated first.
|
||||
for addrHash, op := range deletes {
|
||||
addr := op.address
|
||||
destructs[addrHash] = struct{}{}
|
||||
accountsOrigin[addr] = op.origin
|
||||
if len(op.storagesOrigin) > 0 {
|
||||
storagesOrigin[addr] = op.storagesOrigin
|
||||
}
|
||||
}
|
||||
// Aggregate account updates then.
|
||||
for addrHash, op := range updates {
|
||||
// Aggregate dirty contract codes if they are available.
|
||||
addr := op.address
|
||||
if op.code != nil {
|
||||
codes[addr] = *op.code
|
||||
}
|
||||
// Aggregate the account changes. The original account value will only
|
||||
// be tracked if it's not present yet.
|
||||
accounts[addrHash] = op.data
|
||||
if _, found := accountsOrigin[addr]; !found {
|
||||
accountsOrigin[addr] = op.origin
|
||||
}
|
||||
// Aggregate the storage changes. The original storage slot value will
|
||||
// only be tracked if it's not present yet.
|
||||
if len(op.storages) > 0 {
|
||||
storages[addrHash] = op.storages
|
||||
}
|
||||
if len(op.storagesOrigin) > 0 {
|
||||
origin := storagesOrigin[addr]
|
||||
if origin == nil {
|
||||
storagesOrigin[addr] = op.storagesOrigin
|
||||
continue
|
||||
}
|
||||
for key, slot := range op.storagesOrigin {
|
||||
if _, found := origin[key]; !found {
|
||||
origin[key] = slot
|
||||
}
|
||||
}
|
||||
storagesOrigin[addr] = origin
|
||||
}
|
||||
}
|
||||
return &stateUpdate{
|
||||
originRoot: types.TrieRootHash(originRoot),
|
||||
root: types.TrieRootHash(root),
|
||||
destructs: destructs,
|
||||
accounts: accounts,
|
||||
accountsOrigin: accountsOrigin,
|
||||
storages: storages,
|
||||
storagesOrigin: storagesOrigin,
|
||||
codes: codes,
|
||||
nodes: nodes,
|
||||
}
|
||||
}
|
||||
|
|
@ -44,35 +44,53 @@ type triePrefetcher struct {
|
|||
root common.Hash // Root hash of the account trie for metrics
|
||||
fetchers map[string]*subfetcher // Subfetchers for each trie
|
||||
term chan struct{} // Channel to signal interruption
|
||||
noreads bool // Whether to ignore state-read-only prefetch requests
|
||||
|
||||
deliveryMissMeter metrics.Meter
|
||||
accountLoadMeter metrics.Meter
|
||||
accountDupMeter metrics.Meter
|
||||
|
||||
accountLoadReadMeter metrics.Meter
|
||||
accountLoadWriteMeter metrics.Meter
|
||||
accountDupReadMeter metrics.Meter
|
||||
accountDupWriteMeter metrics.Meter
|
||||
accountDupCrossMeter metrics.Meter
|
||||
accountWasteMeter metrics.Meter
|
||||
storageLoadMeter metrics.Meter
|
||||
storageDupMeter metrics.Meter
|
||||
|
||||
storageLoadReadMeter metrics.Meter
|
||||
storageLoadWriteMeter metrics.Meter
|
||||
storageDupReadMeter metrics.Meter
|
||||
storageDupWriteMeter metrics.Meter
|
||||
storageDupCrossMeter metrics.Meter
|
||||
storageWasteMeter metrics.Meter
|
||||
}
|
||||
|
||||
func newTriePrefetcher(db Database, root common.Hash, namespace string) *triePrefetcher {
|
||||
func newTriePrefetcher(db Database, root common.Hash, namespace string, noreads bool) *triePrefetcher {
|
||||
prefix := triePrefetchMetricsPrefix + namespace
|
||||
return &triePrefetcher{
|
||||
db: db,
|
||||
root: root,
|
||||
fetchers: make(map[string]*subfetcher), // Active prefetchers use the fetchers map
|
||||
term: make(chan struct{}),
|
||||
noreads: noreads,
|
||||
|
||||
deliveryMissMeter: metrics.GetOrRegisterMeter(prefix+"/deliverymiss", nil),
|
||||
accountLoadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load", nil),
|
||||
accountDupMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup", nil),
|
||||
|
||||
accountLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/read", nil),
|
||||
accountLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/load/write", nil),
|
||||
accountDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/read", nil),
|
||||
accountDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/write", nil),
|
||||
accountDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/account/dup/cross", nil),
|
||||
accountWasteMeter: metrics.GetOrRegisterMeter(prefix+"/account/waste", nil),
|
||||
storageLoadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load", nil),
|
||||
storageDupMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup", nil),
|
||||
|
||||
storageLoadReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/read", nil),
|
||||
storageLoadWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/load/write", nil),
|
||||
storageDupReadMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/read", nil),
|
||||
storageDupWriteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/write", nil),
|
||||
storageDupCrossMeter: metrics.GetOrRegisterMeter(prefix+"/storage/dup/cross", nil),
|
||||
storageWasteMeter: metrics.GetOrRegisterMeter(prefix+"/storage/waste", nil),
|
||||
}
|
||||
}
|
||||
|
||||
// terminate iterates over all the subfetchers and issues a terminateion request
|
||||
// terminate iterates over all the subfetchers and issues a termination request
|
||||
// to all of them. Depending on the async parameter, the method will either block
|
||||
// until all subfetchers spin down, or return immediately.
|
||||
func (p *triePrefetcher) terminate(async bool) {
|
||||
|
|
@ -82,7 +100,7 @@ func (p *triePrefetcher) terminate(async bool) {
|
|||
return
|
||||
default:
|
||||
}
|
||||
// Termiante all sub-fetchers, sync or async, depending on the request
|
||||
// Terminate all sub-fetchers, sync or async, depending on the request
|
||||
for _, fetcher := range p.fetchers {
|
||||
fetcher.terminate(async)
|
||||
}
|
||||
|
|
@ -98,19 +116,31 @@ func (p *triePrefetcher) report() {
|
|||
fetcher.wait() // ensure the fetcher's idle before poking in its internals
|
||||
|
||||
if fetcher.root == p.root {
|
||||
p.accountLoadMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.accountDupMeter.Mark(int64(fetcher.dups))
|
||||
p.accountLoadReadMeter.Mark(int64(len(fetcher.seenRead)))
|
||||
p.accountLoadWriteMeter.Mark(int64(len(fetcher.seenWrite)))
|
||||
|
||||
p.accountDupReadMeter.Mark(int64(fetcher.dupsRead))
|
||||
p.accountDupWriteMeter.Mark(int64(fetcher.dupsWrite))
|
||||
p.accountDupCrossMeter.Mark(int64(fetcher.dupsCross))
|
||||
|
||||
for _, key := range fetcher.used {
|
||||
delete(fetcher.seen, string(key))
|
||||
delete(fetcher.seenRead, string(key))
|
||||
delete(fetcher.seenWrite, string(key))
|
||||
}
|
||||
p.accountWasteMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.accountWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite)))
|
||||
} else {
|
||||
p.storageLoadMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.storageDupMeter.Mark(int64(fetcher.dups))
|
||||
p.storageLoadReadMeter.Mark(int64(len(fetcher.seenRead)))
|
||||
p.storageLoadWriteMeter.Mark(int64(len(fetcher.seenWrite)))
|
||||
|
||||
p.storageDupReadMeter.Mark(int64(fetcher.dupsRead))
|
||||
p.storageDupWriteMeter.Mark(int64(fetcher.dupsWrite))
|
||||
p.storageDupCrossMeter.Mark(int64(fetcher.dupsCross))
|
||||
|
||||
for _, key := range fetcher.used {
|
||||
delete(fetcher.seen, string(key))
|
||||
delete(fetcher.seenRead, string(key))
|
||||
delete(fetcher.seenWrite, string(key))
|
||||
}
|
||||
p.storageWasteMeter.Mark(int64(len(fetcher.seen)))
|
||||
p.storageWasteMeter.Mark(int64(len(fetcher.seenRead) + len(fetcher.seenWrite)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +156,11 @@ func (p *triePrefetcher) report() {
|
|||
// upon the same contract, the parameters invoking this method may be
|
||||
// repeated.
|
||||
// 2. Finalize of the main account trie. This happens only once per block.
|
||||
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte) error {
|
||||
func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr common.Address, keys [][]byte, read bool) error {
|
||||
// If the state item is only being read, but reads are disabled, return
|
||||
if read && p.noreads {
|
||||
return nil
|
||||
}
|
||||
// Ensure the subfetcher is still alive
|
||||
select {
|
||||
case <-p.term:
|
||||
|
|
@ -139,22 +173,22 @@ func (p *triePrefetcher) prefetch(owner common.Hash, root common.Hash, addr comm
|
|||
fetcher = newSubfetcher(p.db, p.root, owner, root, addr)
|
||||
p.fetchers[id] = fetcher
|
||||
}
|
||||
return fetcher.schedule(keys)
|
||||
return fetcher.schedule(keys, read)
|
||||
}
|
||||
|
||||
// trie returns the trie matching the root hash, blocking until the fetcher of
|
||||
// the given trie terminates. If no fetcher exists for the request, nil will be
|
||||
// returned.
|
||||
func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) (Trie, error) {
|
||||
func (p *triePrefetcher) trie(owner common.Hash, root common.Hash) Trie {
|
||||
// Bail if no trie was prefetched for this root
|
||||
fetcher := p.fetchers[p.trieID(owner, root)]
|
||||
if fetcher == nil {
|
||||
log.Error("Prefetcher missed to load trie", "owner", owner, "root", root)
|
||||
p.deliveryMissMeter.Mark(1)
|
||||
return nil, nil
|
||||
return nil
|
||||
}
|
||||
// Subfetcher exists, retrieve its trie
|
||||
return fetcher.peek(), nil
|
||||
return fetcher.peek()
|
||||
}
|
||||
|
||||
// used marks a batch of state items used to allow creating statistics as to
|
||||
|
|
@ -186,18 +220,30 @@ type subfetcher struct {
|
|||
addr common.Address // Address of the account that the trie belongs to
|
||||
trie Trie // Trie being populated with nodes
|
||||
|
||||
tasks [][]byte // Items queued up for retrieval
|
||||
tasks []*subfetcherTask // Items queued up for retrieval
|
||||
lock sync.Mutex // Lock protecting the task queue
|
||||
|
||||
wake chan struct{} // Wake channel if a new task is scheduled
|
||||
stop chan struct{} // Channel to interrupt processing
|
||||
term chan struct{} // Channel to signal interruption
|
||||
|
||||
seen map[string]struct{} // Tracks the entries already loaded
|
||||
dups int // Number of duplicate preload tasks
|
||||
seenRead map[string]struct{} // Tracks the entries already loaded via read operations
|
||||
seenWrite map[string]struct{} // Tracks the entries already loaded via write operations
|
||||
|
||||
dupsRead int // Number of duplicate preload tasks via reads only
|
||||
dupsWrite int // Number of duplicate preload tasks via writes only
|
||||
dupsCross int // Number of duplicate preload tasks via read-write-crosses
|
||||
|
||||
used [][]byte // Tracks the entries used in the end
|
||||
}
|
||||
|
||||
// subfetcherTask is a trie path to prefetch, tagged with whether it originates
|
||||
// from a read or a write request.
|
||||
type subfetcherTask struct {
|
||||
read bool
|
||||
key []byte
|
||||
}
|
||||
|
||||
// newSubfetcher creates a goroutine to prefetch state items belonging to a
|
||||
// particular root hash.
|
||||
func newSubfetcher(db Database, state common.Hash, owner common.Hash, root common.Hash, addr common.Address) *subfetcher {
|
||||
|
|
@ -210,14 +256,15 @@ func newSubfetcher(db Database, state common.Hash, owner common.Hash, root commo
|
|||
wake: make(chan struct{}, 1),
|
||||
stop: make(chan struct{}),
|
||||
term: make(chan struct{}),
|
||||
seen: make(map[string]struct{}),
|
||||
seenRead: make(map[string]struct{}),
|
||||
seenWrite: make(map[string]struct{}),
|
||||
}
|
||||
go sf.loop()
|
||||
return sf
|
||||
}
|
||||
|
||||
// schedule adds a batch of trie keys to the queue to prefetch.
|
||||
func (sf *subfetcher) schedule(keys [][]byte) error {
|
||||
func (sf *subfetcher) schedule(keys [][]byte, read bool) error {
|
||||
// Ensure the subfetcher is still alive
|
||||
select {
|
||||
case <-sf.term:
|
||||
|
|
@ -226,7 +273,10 @@ func (sf *subfetcher) schedule(keys [][]byte) error {
|
|||
}
|
||||
// Append the tasks to the current queue
|
||||
sf.lock.Lock()
|
||||
sf.tasks = append(sf.tasks, keys...)
|
||||
for _, key := range keys {
|
||||
key := key // closure for the append below
|
||||
sf.tasks = append(sf.tasks, &subfetcherTask{read: read, key: key})
|
||||
}
|
||||
sf.lock.Unlock()
|
||||
|
||||
// Notify the background thread to execute scheduled tasks
|
||||
|
|
@ -234,7 +284,7 @@ func (sf *subfetcher) schedule(keys [][]byte) error {
|
|||
case sf.wake <- struct{}{}:
|
||||
// Wake signal sent
|
||||
default:
|
||||
// Wake signal not sent as a previous is already queued
|
||||
// Wake signal not sent as a previous one is already queued
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -250,7 +300,7 @@ func (sf *subfetcher) wait() {
|
|||
// peeks for the original data. The method will block until all the scheduled
|
||||
// data has been loaded and the fethcer terminated.
|
||||
func (sf *subfetcher) peek() Trie {
|
||||
// Block until the fertcher terminates, then retrieve the trie
|
||||
// Block until the fetcher terminates, then retrieve the trie
|
||||
sf.wait()
|
||||
return sf.trie
|
||||
}
|
||||
|
|
@ -296,23 +346,43 @@ func (sf *subfetcher) loop() {
|
|||
for {
|
||||
select {
|
||||
case <-sf.wake:
|
||||
// Execute all remaining tasks in single run
|
||||
// Execute all remaining tasks in a single run
|
||||
sf.lock.Lock()
|
||||
tasks := sf.tasks
|
||||
sf.tasks = nil
|
||||
sf.lock.Unlock()
|
||||
|
||||
for _, task := range tasks {
|
||||
if _, ok := sf.seen[string(task)]; ok {
|
||||
sf.dups++
|
||||
key := string(task.key)
|
||||
if task.read {
|
||||
if _, ok := sf.seenRead[key]; ok {
|
||||
sf.dupsRead++
|
||||
continue
|
||||
}
|
||||
if len(task) == common.AddressLength {
|
||||
sf.trie.GetAccount(common.BytesToAddress(task))
|
||||
} else {
|
||||
sf.trie.GetStorage(sf.addr, task)
|
||||
if _, ok := sf.seenWrite[key]; ok {
|
||||
sf.dupsCross++
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
if _, ok := sf.seenRead[key]; ok {
|
||||
sf.dupsCross++
|
||||
continue
|
||||
}
|
||||
if _, ok := sf.seenWrite[key]; ok {
|
||||
sf.dupsWrite++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if len(task.key) == common.AddressLength {
|
||||
sf.trie.GetAccount(common.BytesToAddress(task.key))
|
||||
} else {
|
||||
sf.trie.GetStorage(sf.addr, task.key)
|
||||
}
|
||||
if task.read {
|
||||
sf.seenRead[key] = struct{}{}
|
||||
} else {
|
||||
sf.seenWrite[key] = struct{}{}
|
||||
}
|
||||
sf.seen[string(task)] = struct{}{}
|
||||
}
|
||||
|
||||
case <-sf.stop:
|
||||
|
|
|
|||
|
|
@ -47,18 +47,18 @@ func filledStateDB() *StateDB {
|
|||
|
||||
func TestUseAfterTerminate(t *testing.T) {
|
||||
db := filledStateDB()
|
||||
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "")
|
||||
prefetcher := newTriePrefetcher(db.db, db.originalRoot, "", true)
|
||||
skey := common.HexToHash("aaa")
|
||||
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err != nil {
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err != nil {
|
||||
t.Errorf("Prefetch failed before terminate: %v", err)
|
||||
}
|
||||
prefetcher.terminate(false)
|
||||
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}); err == nil {
|
||||
if err := prefetcher.prefetch(common.Hash{}, db.originalRoot, common.Address{}, [][]byte{skey.Bytes()}, false); err == nil {
|
||||
t.Errorf("Prefetch succeeded after terminate: %v", err)
|
||||
}
|
||||
if _, err := prefetcher.trie(common.Hash{}, db.originalRoot); err != nil {
|
||||
t.Errorf("Trie retrieval failed after terminate: %v", err)
|
||||
if tr := prefetcher.trie(common.Hash{}, db.originalRoot); tr == nil {
|
||||
t.Errorf("Prefetcher returned nil trie after terminate")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
37
core/tracing/gen_balance_change_reason_stringer.go
Normal file
37
core/tracing/gen_balance_change_reason_stringer.go
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Code generated by "stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go"; DO NOT EDIT.
|
||||
|
||||
package tracing
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[BalanceChangeUnspecified-0]
|
||||
_ = x[BalanceIncreaseRewardMineUncle-1]
|
||||
_ = x[BalanceIncreaseRewardMineBlock-2]
|
||||
_ = x[BalanceIncreaseWithdrawal-3]
|
||||
_ = x[BalanceIncreaseGenesisBalance-4]
|
||||
_ = x[BalanceIncreaseRewardTransactionFee-5]
|
||||
_ = x[BalanceDecreaseGasBuy-6]
|
||||
_ = x[BalanceIncreaseGasReturn-7]
|
||||
_ = x[BalanceIncreaseDaoContract-8]
|
||||
_ = x[BalanceDecreaseDaoAccount-9]
|
||||
_ = x[BalanceChangeTransfer-10]
|
||||
_ = x[BalanceChangeTouchAccount-11]
|
||||
_ = x[BalanceIncreaseSelfdestruct-12]
|
||||
_ = x[BalanceDecreaseSelfdestruct-13]
|
||||
_ = x[BalanceDecreaseSelfdestructBurn-14]
|
||||
}
|
||||
|
||||
const _BalanceChangeReason_name = "BalanceChangeUnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountBalanceChangeTransferBalanceChangeTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurn"
|
||||
|
||||
var _BalanceChangeReason_index = [...]uint16{0, 24, 54, 84, 109, 138, 173, 194, 218, 244, 269, 290, 315, 342, 369, 400}
|
||||
|
||||
func (i BalanceChangeReason) String() string {
|
||||
if i >= BalanceChangeReason(len(_BalanceChangeReason_index)-1) {
|
||||
return "BalanceChangeReason(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _BalanceChangeReason_name[_BalanceChangeReason_index[i]:_BalanceChangeReason_index[i+1]]
|
||||
}
|
||||
|
|
@ -199,6 +199,8 @@ type Hooks struct {
|
|||
// for tracing and reporting.
|
||||
type BalanceChangeReason byte
|
||||
|
||||
//go:generate stringer -type=BalanceChangeReason -output gen_balance_change_reason_stringer.go
|
||||
|
||||
const (
|
||||
BalanceChangeUnspecified BalanceChangeReason = 0
|
||||
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ func (bc *testBlockChain) CurrentFinalBlock() *types.Header {
|
|||
}
|
||||
}
|
||||
|
||||
func (bt *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ func (s Transactions) EncodeIndex(i int, w *bytes.Buffer) {
|
|||
}
|
||||
}
|
||||
|
||||
// TxDifference returns a new set which is the difference between a and b.
|
||||
// TxDifference returns a new set of transactions that are present in a but not in b.
|
||||
func TxDifference(a, b Transactions) Transactions {
|
||||
keep := make(Transactions, 0, len(a))
|
||||
|
||||
|
|
@ -574,7 +574,7 @@ func TxDifference(a, b Transactions) Transactions {
|
|||
return keep
|
||||
}
|
||||
|
||||
// HashDifference returns a new set which is the difference between a and b.
|
||||
// HashDifference returns a new set of hashes that are present in a but not in b.
|
||||
func HashDifference(a, b []common.Hash) []common.Hash {
|
||||
keep := make([]common.Hash, 0, len(a))
|
||||
|
||||
|
|
|
|||
|
|
@ -459,11 +459,11 @@ func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
|
|||
// homestead rules.
|
||||
type HomesteadSigner struct{ FrontierSigner }
|
||||
|
||||
func (s HomesteadSigner) ChainID() *big.Int {
|
||||
func (hs HomesteadSigner) ChainID() *big.Int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s HomesteadSigner) Equal(s2 Signer) bool {
|
||||
func (hs HomesteadSigner) Equal(s2 Signer) bool {
|
||||
_, ok := s2.(HomesteadSigner)
|
||||
return ok
|
||||
}
|
||||
|
|
@ -486,11 +486,11 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
|
|||
// frontier rules.
|
||||
type FrontierSigner struct{}
|
||||
|
||||
func (s FrontierSigner) ChainID() *big.Int {
|
||||
func (fs FrontierSigner) ChainID() *big.Int {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s FrontierSigner) Equal(s2 Signer) bool {
|
||||
func (fs FrontierSigner) Equal(s2 Signer) bool {
|
||||
_, ok := s2.(FrontierSigner)
|
||||
return ok
|
||||
}
|
||||
|
|
|
|||
|
|
@ -379,7 +379,7 @@ func assertEqual(orig *Transaction, cpy *Transaction) error {
|
|||
}
|
||||
if orig.AccessList() != nil {
|
||||
if !reflect.DeepEqual(orig.AccessList(), cpy.AccessList()) {
|
||||
return errors.New("access list wrong!")
|
||||
return errors.New("access list wrong")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ type Config struct {
|
|||
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
||||
ExtraEips []int // Additional EIPS that are to be enabled
|
||||
EnableWitnessCollection bool // true if witness collection is enabled
|
||||
}
|
||||
|
||||
// ScopeContext contains the things that are per-call, such as stack and memory,
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ type Config struct {
|
|||
// sets defaults on the config
|
||||
func setDefaults(cfg *Config) {
|
||||
if cfg.ChainConfig == nil {
|
||||
var (
|
||||
shanghaiTime = uint64(0)
|
||||
cancunTime = uint64(0)
|
||||
)
|
||||
cfg.ChainConfig = ¶ms.ChainConfig{
|
||||
ChainID: big.NewInt(1),
|
||||
HomesteadBlock: new(big.Int),
|
||||
|
|
@ -72,9 +76,14 @@ func setDefaults(cfg *Config) {
|
|||
MuirGlacierBlock: new(big.Int),
|
||||
BerlinBlock: new(big.Int),
|
||||
LondonBlock: new(big.Int),
|
||||
ArrowGlacierBlock: nil,
|
||||
GrayGlacierBlock: nil,
|
||||
TerminalTotalDifficulty: big.NewInt(0),
|
||||
TerminalTotalDifficultyPassed: true,
|
||||
MergeNetsplitBlock: nil,
|
||||
ShanghaiTime: &shanghaiTime,
|
||||
CancunTime: &cancunTime}
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.Difficulty == nil {
|
||||
cfg.Difficulty = new(big.Int)
|
||||
}
|
||||
|
|
@ -101,6 +110,10 @@ func setDefaults(cfg *Config) {
|
|||
if cfg.BlobBaseFee == nil {
|
||||
cfg.BlobBaseFee = big.NewInt(params.BlobTxMinBlobGasprice)
|
||||
}
|
||||
// Merge indicators
|
||||
if t := cfg.ChainConfig.ShanghaiTime; cfg.ChainConfig.TerminalTotalDifficultyPassed || (t != nil && *t == 0) {
|
||||
cfg.Random = &(common.Hash{})
|
||||
}
|
||||
}
|
||||
|
||||
// Execute executes the code using the input as call data during the execution.
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ func TestExecute(t *testing.T) {
|
|||
|
||||
func TestCall(t *testing.T) {
|
||||
state, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||
address := common.HexToAddress("0x0a")
|
||||
address := common.HexToAddress("0xaa")
|
||||
state.SetCode(address, []byte{
|
||||
byte(vm.PUSH1), 10,
|
||||
byte(vm.PUSH1), 0,
|
||||
|
|
@ -725,7 +725,7 @@ func TestRuntimeJSTracer(t *testing.T) {
|
|||
byte(vm.CREATE),
|
||||
byte(vm.POP),
|
||||
},
|
||||
results: []string{`"1,1,952855,6,12"`, `"1,1,952855,6,0"`},
|
||||
results: []string{`"1,1,952853,6,12"`, `"1,1,952853,6,0"`},
|
||||
},
|
||||
{
|
||||
// CREATE2
|
||||
|
|
@ -741,7 +741,7 @@ func TestRuntimeJSTracer(t *testing.T) {
|
|||
byte(vm.CREATE2),
|
||||
byte(vm.POP),
|
||||
},
|
||||
results: []string{`"1,1,952846,6,13"`, `"1,1,952846,6,0"`},
|
||||
results: []string{`"1,1,952844,6,13"`, `"1,1,952844,6,0"`},
|
||||
},
|
||||
{
|
||||
// CALL
|
||||
|
|
|
|||
|
|
@ -79,52 +79,52 @@ type BitCurve struct {
|
|||
BitSize int // the size of the underlying field
|
||||
}
|
||||
|
||||
func (BitCurve *BitCurve) Params() *elliptic.CurveParams {
|
||||
func (bitCurve *BitCurve) Params() *elliptic.CurveParams {
|
||||
return &elliptic.CurveParams{
|
||||
P: BitCurve.P,
|
||||
N: BitCurve.N,
|
||||
B: BitCurve.B,
|
||||
Gx: BitCurve.Gx,
|
||||
Gy: BitCurve.Gy,
|
||||
BitSize: BitCurve.BitSize,
|
||||
P: bitCurve.P,
|
||||
N: bitCurve.N,
|
||||
B: bitCurve.B,
|
||||
Gx: bitCurve.Gx,
|
||||
Gy: bitCurve.Gy,
|
||||
BitSize: bitCurve.BitSize,
|
||||
}
|
||||
}
|
||||
|
||||
// IsOnCurve returns true if the given (x,y) lies on the BitCurve.
|
||||
func (BitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool {
|
||||
func (bitCurve *BitCurve) IsOnCurve(x, y *big.Int) bool {
|
||||
// y² = x³ + b
|
||||
y2 := new(big.Int).Mul(y, y) //y²
|
||||
y2.Mod(y2, BitCurve.P) //y²%P
|
||||
y2.Mod(y2, bitCurve.P) //y²%P
|
||||
|
||||
x3 := new(big.Int).Mul(x, x) //x²
|
||||
x3.Mul(x3, x) //x³
|
||||
|
||||
x3.Add(x3, BitCurve.B) //x³+B
|
||||
x3.Mod(x3, BitCurve.P) //(x³+B)%P
|
||||
x3.Add(x3, bitCurve.B) //x³+B
|
||||
x3.Mod(x3, bitCurve.P) //(x³+B)%P
|
||||
|
||||
return x3.Cmp(y2) == 0
|
||||
}
|
||||
|
||||
// affineFromJacobian reverses the Jacobian transform. See the comment at the
|
||||
// top of the file.
|
||||
func (BitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
|
||||
func (bitCurve *BitCurve) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
|
||||
if z.Sign() == 0 {
|
||||
return new(big.Int), new(big.Int)
|
||||
}
|
||||
|
||||
zinv := new(big.Int).ModInverse(z, BitCurve.P)
|
||||
zinv := new(big.Int).ModInverse(z, bitCurve.P)
|
||||
zinvsq := new(big.Int).Mul(zinv, zinv)
|
||||
|
||||
xOut = new(big.Int).Mul(x, zinvsq)
|
||||
xOut.Mod(xOut, BitCurve.P)
|
||||
xOut.Mod(xOut, bitCurve.P)
|
||||
zinvsq.Mul(zinvsq, zinv)
|
||||
yOut = new(big.Int).Mul(y, zinvsq)
|
||||
yOut.Mod(yOut, BitCurve.P)
|
||||
yOut.Mod(yOut, bitCurve.P)
|
||||
return
|
||||
}
|
||||
|
||||
// Add returns the sum of (x1,y1) and (x2,y2)
|
||||
func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
||||
func (bitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
||||
// If one point is at infinity, return the other point.
|
||||
// Adding the point at infinity to any point will preserve the other point.
|
||||
if x1.Sign() == 0 && y1.Sign() == 0 {
|
||||
|
|
@ -135,27 +135,27 @@ func (BitCurve *BitCurve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
|||
}
|
||||
z := new(big.Int).SetInt64(1)
|
||||
if x1.Cmp(x2) == 0 && y1.Cmp(y2) == 0 {
|
||||
return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z))
|
||||
return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z))
|
||||
}
|
||||
return BitCurve.affineFromJacobian(BitCurve.addJacobian(x1, y1, z, x2, y2, z))
|
||||
return bitCurve.affineFromJacobian(bitCurve.addJacobian(x1, y1, z, x2, y2, z))
|
||||
}
|
||||
|
||||
// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
|
||||
// (x2, y2, z2) and returns their sum, also in Jacobian form.
|
||||
func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
|
||||
func (bitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-add-2007-bl
|
||||
z1z1 := new(big.Int).Mul(z1, z1)
|
||||
z1z1.Mod(z1z1, BitCurve.P)
|
||||
z1z1.Mod(z1z1, bitCurve.P)
|
||||
z2z2 := new(big.Int).Mul(z2, z2)
|
||||
z2z2.Mod(z2z2, BitCurve.P)
|
||||
z2z2.Mod(z2z2, bitCurve.P)
|
||||
|
||||
u1 := new(big.Int).Mul(x1, z2z2)
|
||||
u1.Mod(u1, BitCurve.P)
|
||||
u1.Mod(u1, bitCurve.P)
|
||||
u2 := new(big.Int).Mul(x2, z1z1)
|
||||
u2.Mod(u2, BitCurve.P)
|
||||
u2.Mod(u2, bitCurve.P)
|
||||
h := new(big.Int).Sub(u2, u1)
|
||||
if h.Sign() == -1 {
|
||||
h.Add(h, BitCurve.P)
|
||||
h.Add(h, bitCurve.P)
|
||||
}
|
||||
i := new(big.Int).Lsh(h, 1)
|
||||
i.Mul(i, i)
|
||||
|
|
@ -163,13 +163,13 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int
|
|||
|
||||
s1 := new(big.Int).Mul(y1, z2)
|
||||
s1.Mul(s1, z2z2)
|
||||
s1.Mod(s1, BitCurve.P)
|
||||
s1.Mod(s1, bitCurve.P)
|
||||
s2 := new(big.Int).Mul(y2, z1)
|
||||
s2.Mul(s2, z1z1)
|
||||
s2.Mod(s2, BitCurve.P)
|
||||
s2.Mod(s2, bitCurve.P)
|
||||
r := new(big.Int).Sub(s2, s1)
|
||||
if r.Sign() == -1 {
|
||||
r.Add(r, BitCurve.P)
|
||||
r.Add(r, bitCurve.P)
|
||||
}
|
||||
r.Lsh(r, 1)
|
||||
v := new(big.Int).Mul(u1, i)
|
||||
|
|
@ -179,7 +179,7 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int
|
|||
x3.Sub(x3, j)
|
||||
x3.Sub(x3, v)
|
||||
x3.Sub(x3, v)
|
||||
x3.Mod(x3, BitCurve.P)
|
||||
x3.Mod(x3, bitCurve.P)
|
||||
|
||||
y3 := new(big.Int).Set(r)
|
||||
v.Sub(v, x3)
|
||||
|
|
@ -187,33 +187,33 @@ func (BitCurve *BitCurve) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int
|
|||
s1.Mul(s1, j)
|
||||
s1.Lsh(s1, 1)
|
||||
y3.Sub(y3, s1)
|
||||
y3.Mod(y3, BitCurve.P)
|
||||
y3.Mod(y3, bitCurve.P)
|
||||
|
||||
z3 := new(big.Int).Add(z1, z2)
|
||||
z3.Mul(z3, z3)
|
||||
z3.Sub(z3, z1z1)
|
||||
if z3.Sign() == -1 {
|
||||
z3.Add(z3, BitCurve.P)
|
||||
z3.Add(z3, bitCurve.P)
|
||||
}
|
||||
z3.Sub(z3, z2z2)
|
||||
if z3.Sign() == -1 {
|
||||
z3.Add(z3, BitCurve.P)
|
||||
z3.Add(z3, bitCurve.P)
|
||||
}
|
||||
z3.Mul(z3, h)
|
||||
z3.Mod(z3, BitCurve.P)
|
||||
z3.Mod(z3, bitCurve.P)
|
||||
|
||||
return x3, y3, z3
|
||||
}
|
||||
|
||||
// Double returns 2*(x,y)
|
||||
func (BitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
|
||||
func (bitCurve *BitCurve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
|
||||
z1 := new(big.Int).SetInt64(1)
|
||||
return BitCurve.affineFromJacobian(BitCurve.doubleJacobian(x1, y1, z1))
|
||||
return bitCurve.affineFromJacobian(bitCurve.doubleJacobian(x1, y1, z1))
|
||||
}
|
||||
|
||||
// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
|
||||
// returns its double, also in Jacobian form.
|
||||
func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
|
||||
func (bitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
|
||||
// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
|
||||
|
||||
a := new(big.Int).Mul(x, x) //X1²
|
||||
|
|
@ -231,30 +231,30 @@ func (BitCurve *BitCurve) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,
|
|||
|
||||
x3 := new(big.Int).Mul(big.NewInt(2), d) //2*D
|
||||
x3.Sub(f, x3) //F-2*D
|
||||
x3.Mod(x3, BitCurve.P)
|
||||
x3.Mod(x3, bitCurve.P)
|
||||
|
||||
y3 := new(big.Int).Sub(d, x3) //D-X3
|
||||
y3.Mul(e, y3) //E*(D-X3)
|
||||
y3.Sub(y3, new(big.Int).Mul(big.NewInt(8), c)) //E*(D-X3)-8*C
|
||||
y3.Mod(y3, BitCurve.P)
|
||||
y3.Mod(y3, bitCurve.P)
|
||||
|
||||
z3 := new(big.Int).Mul(y, z) //Y1*Z1
|
||||
z3.Mul(big.NewInt(2), z3) //3*Y1*Z1
|
||||
z3.Mod(z3, BitCurve.P)
|
||||
z3.Mod(z3, bitCurve.P)
|
||||
|
||||
return x3, y3, z3
|
||||
}
|
||||
|
||||
// ScalarBaseMult returns k*G, where G is the base point of the group and k is
|
||||
// an integer in big-endian form.
|
||||
func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
|
||||
return BitCurve.ScalarMult(BitCurve.Gx, BitCurve.Gy, k)
|
||||
func (bitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
|
||||
return bitCurve.ScalarMult(bitCurve.Gx, bitCurve.Gy, k)
|
||||
}
|
||||
|
||||
// Marshal converts a point into the form specified in section 4.3.6 of ANSI
|
||||
// X9.62.
|
||||
func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
|
||||
byteLen := (BitCurve.BitSize + 7) >> 3
|
||||
func (bitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
|
||||
byteLen := (bitCurve.BitSize + 7) >> 3
|
||||
ret := make([]byte, 1+2*byteLen)
|
||||
ret[0] = 4 // uncompressed point flag
|
||||
readBits(x, ret[1:1+byteLen])
|
||||
|
|
@ -264,8 +264,8 @@ func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
|
|||
|
||||
// Unmarshal converts a point, serialised by Marshal, into an x, y pair. On
|
||||
// error, x = nil.
|
||||
func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
|
||||
byteLen := (BitCurve.BitSize + 7) >> 3
|
||||
func (bitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
|
||||
byteLen := (bitCurve.BitSize + 7) >> 3
|
||||
if len(data) != 1+2*byteLen {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned
|
|||
*/
|
||||
import "C"
|
||||
|
||||
func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
|
||||
func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
|
||||
// Ensure scalar is exactly 32 bytes. We pad always, even if
|
||||
// scalar is 32 bytes long, to avoid a timing side channel.
|
||||
if len(scalar) > 32 {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,6 @@ package secp256k1
|
|||
|
||||
import "math/big"
|
||||
|
||||
func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
|
||||
func (bitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
|
||||
panic("ScalarMult is not available when secp256k1 is built without cgo")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package eth
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"runtime"
|
||||
|
|
@ -105,9 +104,6 @@ type Ethereum struct {
|
|||
// whose lifecycle will be managed by the provided node.
|
||||
func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
// Ensure configuration values are compatible and sane
|
||||
if config.SyncMode == downloader.LightSync {
|
||||
return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated")
|
||||
}
|
||||
if !config.SyncMode.IsValid() {
|
||||
return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode)
|
||||
}
|
||||
|
|
@ -188,6 +184,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
var (
|
||||
vmConfig = vm.Config{
|
||||
EnablePreimageRecording: config.EnablePreimageRecording,
|
||||
EnableWitnessCollection: config.EnableWitnessCollection,
|
||||
}
|
||||
cacheConfig = &core.CacheConfig{
|
||||
TrieCleanLimit: config.TrieCleanCache,
|
||||
|
|
@ -208,7 +205,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
}
|
||||
t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to create tracer %s: %v", config.VMTrace, err)
|
||||
return nil, fmt.Errorf("failed to create tracer %s: %v", config.VMTrace, err)
|
||||
}
|
||||
vmConfig.Tracer = t
|
||||
}
|
||||
|
|
|
|||
|
|
@ -979,11 +979,11 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
|||
defer wg.Done()
|
||||
if newResp, err := api.NewPayloadV1(*execData); err != nil {
|
||||
errMu.Lock()
|
||||
testErr = fmt.Errorf("Failed to insert block: %w", err)
|
||||
testErr = fmt.Errorf("failed to insert block: %w", err)
|
||||
errMu.Unlock()
|
||||
} else if newResp.Status != "VALID" {
|
||||
errMu.Lock()
|
||||
testErr = fmt.Errorf("Failed to insert block: %v", newResp.Status)
|
||||
testErr = fmt.Errorf("failed to insert block: %v", newResp.Status)
|
||||
errMu.Unlock()
|
||||
}
|
||||
}()
|
||||
|
|
@ -1018,7 +1018,7 @@ func TestSimultaneousNewBlock(t *testing.T) {
|
|||
defer wg.Done()
|
||||
if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
|
||||
errMu.Lock()
|
||||
testErr = fmt.Errorf("Failed to insert block: %w", err)
|
||||
testErr = fmt.Errorf("failed to insert block: %w", err)
|
||||
errMu.Unlock()
|
||||
}
|
||||
}()
|
||||
|
|
|
|||
|
|
@ -279,9 +279,12 @@ func (c *SimulatedBeacon) Rollback() {
|
|||
|
||||
// Fork sets the head to the provided hash.
|
||||
func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
|
||||
// Ensure no pending transactions.
|
||||
c.eth.TxPool().Sync()
|
||||
if len(c.eth.TxPool().Pending(txpool.PendingFilter{})) != 0 {
|
||||
return errors.New("pending block dirty")
|
||||
}
|
||||
|
||||
parent := c.eth.BlockChain().GetBlockByHash(parentHash)
|
||||
if parent == nil {
|
||||
return errors.New("parent not found")
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ func (api *DownloaderAPI) eventLoop() {
|
|||
}
|
||||
}
|
||||
|
||||
// Syncing provides information when this nodes starts synchronising with the Ethereum network and when it's finished.
|
||||
// Syncing provides information when this node starts synchronising with the Ethereum network and when it's finished.
|
||||
func (api *DownloaderAPI) Syncing(ctx context.Context) (*rpc.Subscription, error) {
|
||||
notifier, supported := rpc.NotifierFromContext(ctx)
|
||||
if !supported {
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
|||
case SnapSync:
|
||||
chainHead = d.blockchain.CurrentSnapBlock()
|
||||
default:
|
||||
chainHead = d.lightchain.CurrentHeader()
|
||||
panic("unknown sync mode")
|
||||
}
|
||||
number := chainHead.Number.Uint64()
|
||||
|
||||
|
|
@ -222,7 +222,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
|||
case SnapSync:
|
||||
linked = d.blockchain.HasFastBlock(beaconTail.ParentHash, beaconTail.Number.Uint64()-1)
|
||||
default:
|
||||
linked = d.blockchain.HasHeader(beaconTail.ParentHash, beaconTail.Number.Uint64()-1)
|
||||
panic("unknown sync mode")
|
||||
}
|
||||
if !linked {
|
||||
// This is a programming error. The chain backfiller was called with a
|
||||
|
|
@ -257,7 +257,7 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
|||
case SnapSync:
|
||||
known = d.blockchain.HasFastBlock(h.Hash(), n)
|
||||
default:
|
||||
known = d.lightchain.HasHeader(h.Hash(), n)
|
||||
panic("unknown sync mode")
|
||||
}
|
||||
if !known {
|
||||
end = check
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ var (
|
|||
errCancelContentProcessing = errors.New("content processing canceled (requested)")
|
||||
errCanceled = errors.New("syncing canceled (requested)")
|
||||
errNoPivotHeader = errors.New("pivot header is not found")
|
||||
ErrMergeTransition = errors.New("legacy sync reached the merge")
|
||||
)
|
||||
|
||||
// peerDropFn is a callback type for dropping a peer detected as malicious.
|
||||
|
|
@ -98,7 +97,6 @@ type Downloader struct {
|
|||
syncStatsChainHeight uint64 // Highest block number known when syncing started
|
||||
syncStatsLock sync.RWMutex // Lock protecting the sync stats fields
|
||||
|
||||
lightchain LightChain
|
||||
blockchain BlockChain
|
||||
|
||||
// Callbacks
|
||||
|
|
@ -143,8 +141,8 @@ type Downloader struct {
|
|||
syncLogTime time.Time // Time instance when status was last reported
|
||||
}
|
||||
|
||||
// LightChain encapsulates functions required to synchronise a light chain.
|
||||
type LightChain interface {
|
||||
// BlockChain encapsulates functions required to sync a (full or snap) blockchain.
|
||||
type BlockChain interface {
|
||||
// HasHeader verifies a header's presence in the local chain.
|
||||
HasHeader(common.Hash, uint64) bool
|
||||
|
||||
|
|
@ -162,11 +160,6 @@ type LightChain interface {
|
|||
|
||||
// SetHead rewinds the local chain to a new head.
|
||||
SetHead(uint64) error
|
||||
}
|
||||
|
||||
// BlockChain encapsulates functions required to sync a (full or snap) blockchain.
|
||||
type BlockChain interface {
|
||||
LightChain
|
||||
|
||||
// HasBlock verifies a block's presence in the local chain.
|
||||
HasBlock(common.Hash, uint64) bool
|
||||
|
|
@ -201,17 +194,13 @@ type BlockChain interface {
|
|||
}
|
||||
|
||||
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
||||
func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn, success func()) *Downloader {
|
||||
if lightchain == nil {
|
||||
lightchain = chain
|
||||
}
|
||||
func New(stateDb ethdb.Database, mux *event.TypeMux, chain BlockChain, dropPeer peerDropFn, success func()) *Downloader {
|
||||
dl := &Downloader{
|
||||
stateDB: stateDb,
|
||||
mux: mux,
|
||||
queue: newQueue(blockCacheMaxItems, blockCacheInitialItems),
|
||||
peers: newPeerSet(),
|
||||
blockchain: chain,
|
||||
lightchain: lightchain,
|
||||
dropPeer: dropPeer,
|
||||
headerProcCh: make(chan *headerTask, 1),
|
||||
quitCh: make(chan struct{}),
|
||||
|
|
@ -240,15 +229,13 @@ func (d *Downloader) Progress() ethereum.SyncProgress {
|
|||
|
||||
current := uint64(0)
|
||||
mode := d.getMode()
|
||||
switch {
|
||||
case d.blockchain != nil && mode == FullSync:
|
||||
switch mode {
|
||||
case FullSync:
|
||||
current = d.blockchain.CurrentBlock().Number.Uint64()
|
||||
case d.blockchain != nil && mode == SnapSync:
|
||||
case SnapSync:
|
||||
current = d.blockchain.CurrentSnapBlock().Number.Uint64()
|
||||
case d.lightchain != nil:
|
||||
current = d.lightchain.CurrentHeader().Number.Uint64()
|
||||
default:
|
||||
log.Error("Unknown downloader chain/mode combo", "light", d.lightchain != nil, "full", d.blockchain != nil, "mode", mode)
|
||||
log.Error("Unknown downloader mode", "mode", mode)
|
||||
}
|
||||
progress, pending := d.SnapSyncer.Progress()
|
||||
|
||||
|
|
@ -402,7 +389,7 @@ func (d *Downloader) syncToHead() (err error) {
|
|||
if err != nil {
|
||||
d.mux.Post(FailedEvent{err})
|
||||
} else {
|
||||
latest := d.lightchain.CurrentHeader()
|
||||
latest := d.blockchain.CurrentHeader()
|
||||
d.mux.Post(DoneEvent{latest})
|
||||
}
|
||||
}()
|
||||
|
|
@ -520,7 +507,7 @@ func (d *Downloader) syncToHead() (err error) {
|
|||
}
|
||||
// Rewind the ancient store and blockchain if reorg happens.
|
||||
if origin+1 < frozen {
|
||||
if err := d.lightchain.SetHead(origin); err != nil {
|
||||
if err := d.blockchain.SetHead(origin); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Truncated excess ancient chain segment", "oldhead", frozen-1, "newhead", origin)
|
||||
|
|
@ -690,19 +677,17 @@ func (d *Downloader) processHeaders(origin uint64) error {
|
|||
chunkHashes := hashes[:limit]
|
||||
|
||||
// In case of header only syncing, validate the chunk immediately
|
||||
if mode == SnapSync || mode == LightSync {
|
||||
if mode == SnapSync {
|
||||
// Although the received headers might be all valid, a legacy
|
||||
// PoW/PoA sync must not accept post-merge headers. Make sure
|
||||
// that any transition is rejected at this point.
|
||||
if len(chunkHeaders) > 0 {
|
||||
if n, err := d.lightchain.InsertHeaderChain(chunkHeaders); err != nil {
|
||||
if n, err := d.blockchain.InsertHeaderChain(chunkHeaders); err != nil {
|
||||
log.Warn("Invalid header encountered", "number", chunkHeaders[n].Number, "hash", chunkHashes[n], "parent", chunkHeaders[n].ParentHash, "err", err)
|
||||
return fmt.Errorf("%w: %v", errInvalidChain, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Unless we're doing light chains, schedule the headers for associated content retrieval
|
||||
if mode == FullSync || mode == SnapSync {
|
||||
// If we've reached the allowed number of pending headers, stall a bit
|
||||
for d.queue.PendingBodies() >= maxQueuedHeaders || d.queue.PendingReceipts() >= maxQueuedHeaders {
|
||||
timer.Reset(time.Second)
|
||||
|
|
@ -717,7 +702,7 @@ func (d *Downloader) processHeaders(origin uint64) error {
|
|||
if len(inserts) != len(chunkHeaders) {
|
||||
return fmt.Errorf("%w: stale headers", errBadPeer)
|
||||
}
|
||||
}
|
||||
|
||||
headers = headers[limit:]
|
||||
hashes = hashes[limit:]
|
||||
origin += uint64(limit)
|
||||
|
|
@ -1056,7 +1041,7 @@ func (d *Downloader) readHeaderRange(last *types.Header, count int) []*types.Hea
|
|||
headers []*types.Header
|
||||
)
|
||||
for {
|
||||
parent := d.lightchain.GetHeaderByHash(current.ParentHash)
|
||||
parent := d.blockchain.GetHeaderByHash(current.ParentHash)
|
||||
if parent == nil {
|
||||
break // The chain is not continuous, or the chain is exhausted
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
|
|||
chain: chain,
|
||||
peers: make(map[string]*downloadTesterPeer),
|
||||
}
|
||||
tester.downloader = New(db, new(event.TypeMux), tester.chain, nil, tester.dropPeer, success)
|
||||
tester.downloader = New(db, new(event.TypeMux), tester.chain, tester.dropPeer, success)
|
||||
return tester
|
||||
}
|
||||
|
||||
|
|
@ -384,9 +384,6 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) {
|
|||
t.Helper()
|
||||
|
||||
headers, blocks, receipts := length, length, length
|
||||
if tester.downloader.getMode() == LightSync {
|
||||
blocks, receipts = 1, 1
|
||||
}
|
||||
if hs := int(tester.chain.CurrentHeader().Number.Uint64()) + 1; hs != headers {
|
||||
t.Fatalf("synchronised headers mismatch: have %v, want %v", hs, headers)
|
||||
}
|
||||
|
|
@ -400,7 +397,6 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) {
|
|||
|
||||
func TestCanonicalSynchronisation68Full(t *testing.T) { testCanonSync(t, eth.ETH68, FullSync) }
|
||||
func TestCanonicalSynchronisation68Snap(t *testing.T) { testCanonSync(t, eth.ETH68, SnapSync) }
|
||||
func TestCanonicalSynchronisation68Light(t *testing.T) { testCanonSync(t, eth.ETH68, LightSync) }
|
||||
|
||||
func testCanonSync(t *testing.T, protocol uint, mode SyncMode) {
|
||||
success := make(chan struct{})
|
||||
|
|
@ -507,7 +503,6 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) {
|
|||
// Tests that a canceled download wipes all previously accumulated state.
|
||||
func TestCancel68Full(t *testing.T) { testCancel(t, eth.ETH68, FullSync) }
|
||||
func TestCancel68Snap(t *testing.T) { testCancel(t, eth.ETH68, SnapSync) }
|
||||
func TestCancel68Light(t *testing.T) { testCancel(t, eth.ETH68, LightSync) }
|
||||
|
||||
func testCancel(t *testing.T, protocol uint, mode SyncMode) {
|
||||
complete := make(chan struct{})
|
||||
|
|
@ -540,7 +535,6 @@ func testCancel(t *testing.T, protocol uint, mode SyncMode) {
|
|||
// and not wreak havoc on other nodes in the network.
|
||||
func TestMultiProtoSynchronisation68Full(t *testing.T) { testMultiProtoSync(t, eth.ETH68, FullSync) }
|
||||
func TestMultiProtoSynchronisation68Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH68, SnapSync) }
|
||||
func TestMultiProtoSynchronisation68Light(t *testing.T) { testMultiProtoSync(t, eth.ETH68, LightSync) }
|
||||
|
||||
func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) {
|
||||
complete := make(chan struct{})
|
||||
|
|
@ -580,7 +574,6 @@ func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) {
|
|||
// made, and instead the header should be assembled into a whole block in itself.
|
||||
func TestEmptyShortCircuit68Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, FullSync) }
|
||||
func TestEmptyShortCircuit68Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, SnapSync) }
|
||||
func TestEmptyShortCircuit68Light(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, LightSync) }
|
||||
|
||||
func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) {
|
||||
success := make(chan struct{})
|
||||
|
|
@ -619,7 +612,7 @@ func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) {
|
|||
// Validate the number of block bodies that should have been requested
|
||||
bodiesNeeded, receiptsNeeded := 0, 0
|
||||
for _, block := range chain.blocks[1:] {
|
||||
if mode != LightSync && (len(block.Transactions()) > 0 || len(block.Uncles()) > 0) {
|
||||
if len(block.Transactions()) > 0 || len(block.Uncles()) > 0 {
|
||||
bodiesNeeded++
|
||||
}
|
||||
}
|
||||
|
|
@ -696,7 +689,6 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) {
|
|||
// and highest block number) is tracked and updated correctly.
|
||||
func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) }
|
||||
func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) }
|
||||
func TestSyncProgress68Light(t *testing.T) { testSyncProgress(t, eth.ETH68, LightSync) }
|
||||
|
||||
func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) {
|
||||
success := make(chan struct{})
|
||||
|
|
@ -734,17 +726,7 @@ func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) {
|
|||
if err := tester.downloader.BeaconSync(mode, chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil {
|
||||
t.Fatalf("failed to beacon-sync chain: %v", err)
|
||||
}
|
||||
var startingBlock uint64
|
||||
if mode == LightSync {
|
||||
// in light-sync mode:
|
||||
// * the starting block is 0 on the second sync cycle because blocks
|
||||
// are never downloaded.
|
||||
// * The current/highest blocks reported in the progress reflect the
|
||||
// current/highest header.
|
||||
startingBlock = 0
|
||||
} else {
|
||||
startingBlock = uint64(len(chain.blocks)/2 - 1)
|
||||
}
|
||||
startingBlock := uint64(len(chain.blocks)/2 - 1)
|
||||
|
||||
select {
|
||||
case <-success:
|
||||
|
|
|
|||
|
|
@ -25,11 +25,10 @@ type SyncMode uint32
|
|||
const (
|
||||
FullSync SyncMode = iota // Synchronise the entire blockchain history from full blocks
|
||||
SnapSync // Download the chain and the state via compact snapshots
|
||||
LightSync // Download only the headers and terminate afterwards
|
||||
)
|
||||
|
||||
func (mode SyncMode) IsValid() bool {
|
||||
return mode >= FullSync && mode <= LightSync
|
||||
return mode == FullSync || mode == SnapSync
|
||||
}
|
||||
|
||||
// String implements the stringer interface.
|
||||
|
|
@ -39,8 +38,6 @@ func (mode SyncMode) String() string {
|
|||
return "full"
|
||||
case SnapSync:
|
||||
return "snap"
|
||||
case LightSync:
|
||||
return "light"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
|
|
@ -52,8 +49,6 @@ func (mode SyncMode) MarshalText() ([]byte, error) {
|
|||
return []byte("full"), nil
|
||||
case SnapSync:
|
||||
return []byte("snap"), nil
|
||||
case LightSync:
|
||||
return []byte("light"), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown sync mode %d", mode)
|
||||
}
|
||||
|
|
@ -65,10 +60,8 @@ func (mode *SyncMode) UnmarshalText(text []byte) error {
|
|||
*mode = FullSync
|
||||
case "snap":
|
||||
*mode = SnapSync
|
||||
case "light":
|
||||
*mode = LightSync
|
||||
default:
|
||||
return fmt.Errorf(`unknown sync mode %q, want "full", "snap" or "light"`, text)
|
||||
return fmt.Errorf(`unknown sync mode %q, want "full" or "snap"`, text)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
)
|
||||
|
||||
|
|
@ -376,20 +377,9 @@ func TestSkeletonSyncInit(t *testing.T) {
|
|||
skeleton.Terminate()
|
||||
|
||||
// Ensure the correct resulting sync status
|
||||
var progress skeletonProgress
|
||||
json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress)
|
||||
|
||||
if len(progress.Subchains) != len(tt.newstate) {
|
||||
t.Errorf("test %d: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.newstate))
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(progress.Subchains); j++ {
|
||||
if progress.Subchains[j].Head != tt.newstate[j].Head {
|
||||
t.Errorf("test %d: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.newstate[j].Head)
|
||||
}
|
||||
if progress.Subchains[j].Tail != tt.newstate[j].Tail {
|
||||
t.Errorf("test %d: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.newstate[j].Tail)
|
||||
}
|
||||
expect := skeletonExpect{state: tt.newstate}
|
||||
if err := checkSkeletonProgress(db, false, nil, expect); err != nil {
|
||||
t.Errorf("test %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -493,28 +483,36 @@ func TestSkeletonSyncExtend(t *testing.T) {
|
|||
skeleton.Terminate()
|
||||
|
||||
// Ensure the correct resulting sync status
|
||||
var progress skeletonProgress
|
||||
json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress)
|
||||
expect := skeletonExpect{state: tt.newstate}
|
||||
if err := checkSkeletonProgress(db, false, nil, expect); err != nil {
|
||||
t.Errorf("test %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(progress.Subchains) != len(tt.newstate) {
|
||||
t.Errorf("test %d: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.newstate))
|
||||
continue
|
||||
}
|
||||
for j := 0; j < len(progress.Subchains); j++ {
|
||||
if progress.Subchains[j].Head != tt.newstate[j].Head {
|
||||
t.Errorf("test %d: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.newstate[j].Head)
|
||||
}
|
||||
if progress.Subchains[j].Tail != tt.newstate[j].Tail {
|
||||
t.Errorf("test %d: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.newstate[j].Tail)
|
||||
}
|
||||
}
|
||||
}
|
||||
type skeletonExpect struct {
|
||||
state []*subchain // Expected sync state after the post-init event
|
||||
serve uint64 // Expected number of header retrievals after initial cycle
|
||||
drop uint64 // Expected number of peers dropped after initial cycle
|
||||
}
|
||||
|
||||
type skeletonTest struct {
|
||||
fill bool // Whether to run a real backfiller in this test case
|
||||
unpredictable bool // Whether to ignore drops/serves due to uncertain packet assignments
|
||||
|
||||
head *types.Header // New head header to announce to reorg to
|
||||
peers []*skeletonTestPeer // Initial peer set to start the sync with
|
||||
mid skeletonExpect
|
||||
|
||||
newHead *types.Header // New header to anoint on top of the old one
|
||||
newPeer *skeletonTestPeer // New peer to join the skeleton syncer
|
||||
end skeletonExpect
|
||||
}
|
||||
|
||||
// Tests that the skeleton sync correctly retrieves headers from one or more
|
||||
// peers without duplicates or other strange side effects.
|
||||
func TestSkeletonSyncRetrievals(t *testing.T) {
|
||||
//log.Root().SetHandler(log.LvlFilterHandler(log.LvlTrace, log.StreamHandler(os.Stderr, log.TerminalFormat(true))))
|
||||
//log.SetDefault(log.NewLogger(log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))))
|
||||
|
||||
// Since skeleton headers don't need to be meaningful, beyond a parent hash
|
||||
// progression, create a long fake chain to test with.
|
||||
|
|
@ -537,22 +535,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
Extra: []byte("B"), // force a different hash
|
||||
})
|
||||
}
|
||||
tests := []struct {
|
||||
fill bool // Whether to run a real backfiller in this test case
|
||||
unpredictable bool // Whether to ignore drops/serves due to uncertain packet assignments
|
||||
|
||||
head *types.Header // New head header to announce to reorg to
|
||||
peers []*skeletonTestPeer // Initial peer set to start the sync with
|
||||
midstate []*subchain // Expected sync state after initial cycle
|
||||
midserve uint64 // Expected number of header retrievals after initial cycle
|
||||
middrop uint64 // Expected number of peers dropped after initial cycle
|
||||
|
||||
newHead *types.Header // New header to anoint on top of the old one
|
||||
newPeer *skeletonTestPeer // New peer to join the skeleton syncer
|
||||
endstate []*subchain // Expected sync state after the post-init event
|
||||
endserve uint64 // Expected number of header retrievals after the post-init event
|
||||
enddrop uint64 // Expected number of peers dropped after the post-init event
|
||||
}{
|
||||
tests := []skeletonTest{
|
||||
// Completely empty database with only the genesis set. The sync is expected
|
||||
// to create a single subchain with the requested head. No peers however, so
|
||||
// the sync should be stuck without any progression.
|
||||
|
|
@ -561,11 +544,15 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
// to the genesis block.
|
||||
{
|
||||
head: chain[len(chain)-1],
|
||||
midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: uint64(len(chain) - 1)}},
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(chain) - 1), Tail: uint64(len(chain) - 1)}},
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("test-peer", chain),
|
||||
endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
endserve: uint64(len(chain) - 2), // len - head - genesis
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
serve: uint64(len(chain) - 2), // len - head - genesis
|
||||
},
|
||||
},
|
||||
// Completely empty database with only the genesis set. The sync is expected
|
||||
// to create a single subchain with the requested head. With one valid peer,
|
||||
|
|
@ -575,12 +562,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
{
|
||||
head: chain[len(chain)-1],
|
||||
peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-1", chain)},
|
||||
midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
midserve: uint64(len(chain) - 2), // len - head - genesis
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
serve: uint64(len(chain) - 2), // len - head - genesis
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("test-peer-2", chain),
|
||||
endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
endserve: uint64(len(chain) - 2), // len - head - genesis
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
serve: uint64(len(chain) - 2), // len - head - genesis
|
||||
},
|
||||
},
|
||||
// Completely empty database with only the genesis set. The sync is expected
|
||||
// to create a single subchain with the requested head. With many valid peers,
|
||||
|
|
@ -594,12 +585,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
newSkeletonTestPeer("test-peer-2", chain),
|
||||
newSkeletonTestPeer("test-peer-3", chain),
|
||||
},
|
||||
midstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
midserve: uint64(len(chain) - 2), // len - head - genesis
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
serve: uint64(len(chain) - 2), // len - head - genesis
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("test-peer-4", chain),
|
||||
endstate: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
endserve: uint64(len(chain) - 2), // len - head - genesis
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(chain) - 1), Tail: 1}},
|
||||
serve: uint64(len(chain) - 2), // len - head - genesis
|
||||
},
|
||||
},
|
||||
// This test checks if a peer tries to withhold a header - *on* the sync
|
||||
// boundary - instead of sending the requested amount. The malicious short
|
||||
|
|
@ -611,14 +606,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
peers: []*skeletonTestPeer{
|
||||
newSkeletonTestPeer("header-skipper", append(append(append([]*types.Header{}, chain[:99]...), nil), chain[100:]...)),
|
||||
},
|
||||
midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
midserve: requestHeaders + 101 - 3, // len - head - genesis - missing
|
||||
middrop: 1, // penalize shortened header deliveries
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
serve: requestHeaders + 101 - 3, // len - head - genesis - missing
|
||||
drop: 1, // penalize shortened header deliveries
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("good-peer", chain),
|
||||
endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
endserve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis
|
||||
enddrop: 1, // no new drops
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
serve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis
|
||||
drop: 1, // no new drops
|
||||
},
|
||||
},
|
||||
// This test checks if a peer tries to withhold a header - *off* the sync
|
||||
// boundary - instead of sending the requested amount. The malicious short
|
||||
|
|
@ -630,14 +629,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
peers: []*skeletonTestPeer{
|
||||
newSkeletonTestPeer("header-skipper", append(append(append([]*types.Header{}, chain[:50]...), nil), chain[51:]...)),
|
||||
},
|
||||
midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
midserve: requestHeaders + 101 - 3, // len - head - genesis - missing
|
||||
middrop: 1, // penalize shortened header deliveries
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
serve: requestHeaders + 101 - 3, // len - head - genesis - missing
|
||||
drop: 1, // penalize shortened header deliveries
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("good-peer", chain),
|
||||
endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
endserve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis
|
||||
enddrop: 1, // no new drops
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
serve: (requestHeaders + 101 - 3) + (100 - 1), // midserve + lenrest - genesis
|
||||
drop: 1, // no new drops
|
||||
},
|
||||
},
|
||||
// This test checks if a peer tries to duplicate a header - *on* the sync
|
||||
// boundary - instead of sending the correct sequence. The malicious duped
|
||||
|
|
@ -649,14 +652,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
peers: []*skeletonTestPeer{
|
||||
newSkeletonTestPeer("header-duper", append(append(append([]*types.Header{}, chain[:99]...), chain[98]), chain[100:]...)),
|
||||
},
|
||||
midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
midserve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
middrop: 1, // penalize invalid header sequences
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
serve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
drop: 1, // penalize invalid header sequences
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("good-peer", chain),
|
||||
endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
enddrop: 1, // no new drops
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
drop: 1, // no new drops
|
||||
},
|
||||
},
|
||||
// This test checks if a peer tries to duplicate a header - *off* the sync
|
||||
// boundary - instead of sending the correct sequence. The malicious duped
|
||||
|
|
@ -668,14 +675,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
peers: []*skeletonTestPeer{
|
||||
newSkeletonTestPeer("header-duper", append(append(append([]*types.Header{}, chain[:50]...), chain[49]), chain[51:]...)),
|
||||
},
|
||||
midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
midserve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
middrop: 1, // penalize invalid header sequences
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
serve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
drop: 1, // penalize invalid header sequences
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("good-peer", chain),
|
||||
endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
enddrop: 1, // no new drops
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
drop: 1, // no new drops
|
||||
},
|
||||
},
|
||||
// This test checks if a peer tries to inject a different header - *on*
|
||||
// the sync boundary - instead of sending the correct sequence. The bad
|
||||
|
|
@ -698,14 +709,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
),
|
||||
),
|
||||
},
|
||||
midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
midserve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
middrop: 1, // different set of headers, drop // TODO(karalabe): maybe just diff sync?
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
serve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
drop: 1, // different set of headers, drop // TODO(karalabe): maybe just diff sync?
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("good-peer", chain),
|
||||
endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
enddrop: 1, // no new drops
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
drop: 1, // no new drops
|
||||
},
|
||||
},
|
||||
// This test checks if a peer tries to inject a different header - *off*
|
||||
// the sync boundary - instead of sending the correct sequence. The bad
|
||||
|
|
@ -728,14 +743,18 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
),
|
||||
),
|
||||
},
|
||||
midstate: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
midserve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
middrop: 1, // different set of headers, drop
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 100}},
|
||||
serve: requestHeaders + 101 - 2, // len - head - genesis
|
||||
drop: 1, // different set of headers, drop
|
||||
},
|
||||
|
||||
newPeer: newSkeletonTestPeer("good-peer", chain),
|
||||
endstate: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
endserve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
enddrop: 1, // no new drops
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: requestHeaders + 100, Tail: 1}},
|
||||
serve: (requestHeaders + 101 - 2) + (100 - 1), // midserve + lenrest - genesis
|
||||
drop: 1, // no new drops
|
||||
},
|
||||
},
|
||||
// This test reproduces a bug caught during review (kudos to @holiman)
|
||||
// where a subchain is merged with a previously interrupted one, causing
|
||||
|
|
@ -765,12 +784,16 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
return nil // Fallback to default behavior, just delayed
|
||||
}),
|
||||
},
|
||||
midstate: []*subchain{{Head: 2 * requestHeaders, Tail: 1}},
|
||||
midserve: 2*requestHeaders - 1, // len - head - genesis
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: 2 * requestHeaders, Tail: 1}},
|
||||
serve: 2*requestHeaders - 1, // len - head - genesis
|
||||
},
|
||||
|
||||
newHead: chain[2*requestHeaders+2],
|
||||
endstate: []*subchain{{Head: 2*requestHeaders + 2, Tail: 1}},
|
||||
endserve: 4 * requestHeaders,
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: 2*requestHeaders + 2, Tail: 1}},
|
||||
serve: 4 * requestHeaders,
|
||||
},
|
||||
},
|
||||
// This test reproduces a bug caught by (@rjl493456442) where a skeleton
|
||||
// header goes missing, causing the sync to get stuck and/or panic.
|
||||
|
|
@ -794,11 +817,15 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
|
||||
head: chain[len(chain)/2+1], // Sync up until the sidechain common ancestor + 2
|
||||
peers: []*skeletonTestPeer{newSkeletonTestPeer("test-peer-oldchain", chain)},
|
||||
midstate: []*subchain{{Head: uint64(len(chain)/2 + 1), Tail: 1}},
|
||||
mid: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(chain)/2 + 1), Tail: 1}},
|
||||
},
|
||||
|
||||
newHead: sidechain[len(sidechain)/2+3], // Sync up until the sidechain common ancestor + 4
|
||||
newPeer: newSkeletonTestPeer("test-peer-newchain", sidechain),
|
||||
endstate: []*subchain{{Head: uint64(len(sidechain)/2 + 3), Tail: uint64(len(chain) / 2)}},
|
||||
end: skeletonExpect{
|
||||
state: []*subchain{{Head: uint64(len(sidechain)/2 + 3), Tail: uint64(len(chain) / 2)}},
|
||||
},
|
||||
},
|
||||
}
|
||||
for i, tt := range tests {
|
||||
|
|
@ -861,115 +888,83 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
|
|||
skeleton := newSkeleton(db, peerset, drop, filler)
|
||||
skeleton.Sync(tt.head, nil, true)
|
||||
|
||||
var progress skeletonProgress
|
||||
// Wait a bit (bleah) for the initial sync loop to go to idle. This might
|
||||
// be either a finish or a never-start hence why there's no event to hook.
|
||||
check := func() error {
|
||||
if len(progress.Subchains) != len(tt.midstate) {
|
||||
return fmt.Errorf("test %d, mid state: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.midstate))
|
||||
}
|
||||
for j := 0; j < len(progress.Subchains); j++ {
|
||||
if progress.Subchains[j].Head != tt.midstate[j].Head {
|
||||
return fmt.Errorf("test %d, mid state: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.midstate[j].Head)
|
||||
}
|
||||
if progress.Subchains[j].Tail != tt.midstate[j].Tail {
|
||||
return fmt.Errorf("test %d, mid state: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.midstate[j].Tail)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
waitStart := time.Now()
|
||||
for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 {
|
||||
time.Sleep(waitTime)
|
||||
// Check the post-init end state if it matches the required results
|
||||
json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress)
|
||||
if err := check(); err == nil {
|
||||
if err := checkSkeletonProgress(db, tt.unpredictable, tt.peers, tt.mid); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err := check(); err != nil {
|
||||
t.Error(err)
|
||||
if err := checkSkeletonProgress(db, tt.unpredictable, tt.peers, tt.mid); err != nil {
|
||||
t.Errorf("test %d, mid: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if !tt.unpredictable {
|
||||
var served uint64
|
||||
for _, peer := range tt.peers {
|
||||
served += peer.served.Load()
|
||||
}
|
||||
if served != tt.midserve {
|
||||
t.Errorf("test %d, mid state: served headers mismatch: have %d, want %d", i, served, tt.midserve)
|
||||
}
|
||||
var drops uint64
|
||||
for _, peer := range tt.peers {
|
||||
drops += peer.dropped.Load()
|
||||
}
|
||||
if drops != tt.middrop {
|
||||
t.Errorf("test %d, mid state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop)
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the post-init events if there's any
|
||||
if tt.newHead != nil {
|
||||
skeleton.Sync(tt.newHead, nil, true)
|
||||
}
|
||||
endpeers := tt.peers
|
||||
if tt.newPeer != nil {
|
||||
if err := peerset.Register(newPeerConnection(tt.newPeer.id, eth.ETH68, tt.newPeer, log.New("id", tt.newPeer.id))); err != nil {
|
||||
t.Errorf("test %d: failed to register new peer: %v", i, err)
|
||||
}
|
||||
time.Sleep(time.Millisecond * 50) // given time for peer registration
|
||||
endpeers = append(tt.peers, tt.newPeer)
|
||||
}
|
||||
if tt.newHead != nil {
|
||||
skeleton.Sync(tt.newHead, nil, true)
|
||||
}
|
||||
|
||||
// Wait a bit (bleah) for the second sync loop to go to idle. This might
|
||||
// be either a finish or a never-start hence why there's no event to hook.
|
||||
check = func() error {
|
||||
if len(progress.Subchains) != len(tt.endstate) {
|
||||
return fmt.Errorf("test %d, end state: subchain count mismatch: have %d, want %d", i, len(progress.Subchains), len(tt.endstate))
|
||||
}
|
||||
for j := 0; j < len(progress.Subchains); j++ {
|
||||
if progress.Subchains[j].Head != tt.endstate[j].Head {
|
||||
return fmt.Errorf("test %d, end state: subchain %d head mismatch: have %d, want %d", i, j, progress.Subchains[j].Head, tt.endstate[j].Head)
|
||||
}
|
||||
if progress.Subchains[j].Tail != tt.endstate[j].Tail {
|
||||
return fmt.Errorf("test %d, end state: subchain %d tail mismatch: have %d, want %d", i, j, progress.Subchains[j].Tail, tt.endstate[j].Tail)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
waitStart = time.Now()
|
||||
for waitTime := 20 * time.Millisecond; time.Since(waitStart) < 2*time.Second; waitTime = waitTime * 2 {
|
||||
time.Sleep(waitTime)
|
||||
// Check the post-init end state if it matches the required results
|
||||
json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress)
|
||||
if err := check(); err == nil {
|
||||
if err := checkSkeletonProgress(db, tt.unpredictable, endpeers, tt.end); err == nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err := check(); err != nil {
|
||||
t.Error(err)
|
||||
if err := checkSkeletonProgress(db, tt.unpredictable, endpeers, tt.end); err != nil {
|
||||
t.Errorf("test %d, end: %v", i, err)
|
||||
continue
|
||||
}
|
||||
// Check that the peers served no more headers than we actually needed
|
||||
if !tt.unpredictable {
|
||||
served := uint64(0)
|
||||
for _, peer := range tt.peers {
|
||||
served += peer.served.Load()
|
||||
}
|
||||
if tt.newPeer != nil {
|
||||
served += tt.newPeer.served.Load()
|
||||
}
|
||||
if served != tt.endserve {
|
||||
t.Errorf("test %d, end state: served headers mismatch: have %d, want %d", i, served, tt.endserve)
|
||||
}
|
||||
drops := uint64(0)
|
||||
for _, peer := range tt.peers {
|
||||
drops += peer.dropped.Load()
|
||||
}
|
||||
if tt.newPeer != nil {
|
||||
drops += tt.newPeer.dropped.Load()
|
||||
}
|
||||
if drops != tt.enddrop {
|
||||
t.Errorf("test %d, end state: dropped peers mismatch: have %d, want %d", i, drops, tt.middrop)
|
||||
}
|
||||
}
|
||||
// Clean up any leftover skeleton sync resources
|
||||
skeleton.Terminate()
|
||||
}
|
||||
}
|
||||
|
||||
func checkSkeletonProgress(db ethdb.KeyValueReader, unpredictable bool, peers []*skeletonTestPeer, expected skeletonExpect) error {
|
||||
var progress skeletonProgress
|
||||
// Check the post-init end state if it matches the required results
|
||||
json.Unmarshal(rawdb.ReadSkeletonSyncStatus(db), &progress)
|
||||
|
||||
if len(progress.Subchains) != len(expected.state) {
|
||||
return fmt.Errorf("subchain count mismatch: have %d, want %d", len(progress.Subchains), len(expected.state))
|
||||
}
|
||||
for j := 0; j < len(progress.Subchains); j++ {
|
||||
if progress.Subchains[j].Head != expected.state[j].Head {
|
||||
return fmt.Errorf("subchain %d head mismatch: have %d, want %d", j, progress.Subchains[j].Head, expected.state[j].Head)
|
||||
}
|
||||
if progress.Subchains[j].Tail != expected.state[j].Tail {
|
||||
return fmt.Errorf("subchain %d tail mismatch: have %d, want %d", j, progress.Subchains[j].Tail, expected.state[j].Tail)
|
||||
}
|
||||
}
|
||||
if !unpredictable {
|
||||
var served uint64
|
||||
for _, peer := range peers {
|
||||
served += peer.served.Load()
|
||||
}
|
||||
if served != expected.serve {
|
||||
return fmt.Errorf("served headers mismatch: have %d, want %d", served, expected.serve)
|
||||
}
|
||||
var drops uint64
|
||||
for _, peer := range peers {
|
||||
drops += peer.dropped.Load()
|
||||
}
|
||||
if drops != expected.drop {
|
||||
return fmt.Errorf("dropped peers mismatch: have %d, want %d", drops, expected.drop)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -141,6 +141,9 @@ type Config struct {
|
|||
// Enables tracking of SHA3 preimages in the VM
|
||||
EnablePreimageRecording bool
|
||||
|
||||
// Enables prefetching trie nodes for read operations too
|
||||
EnableWitnessCollection bool `toml:"-"`
|
||||
|
||||
// Enables VM tracing
|
||||
VMTrace string
|
||||
VMTraceJsonConfig string
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
BlobPool blobpool.Config
|
||||
GPO gasprice.Config
|
||||
EnablePreimageRecording bool
|
||||
EnableWitnessCollection bool `toml:"-"`
|
||||
VMTrace string
|
||||
VMTraceJsonConfig string
|
||||
DocRoot string `toml:"-"`
|
||||
|
|
@ -93,6 +94,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||
enc.BlobPool = c.BlobPool
|
||||
enc.GPO = c.GPO
|
||||
enc.EnablePreimageRecording = c.EnablePreimageRecording
|
||||
enc.EnableWitnessCollection = c.EnableWitnessCollection
|
||||
enc.VMTrace = c.VMTrace
|
||||
enc.VMTraceJsonConfig = c.VMTraceJsonConfig
|
||||
enc.DocRoot = c.DocRoot
|
||||
|
|
@ -140,6 +142,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
BlobPool *blobpool.Config
|
||||
GPO *gasprice.Config
|
||||
EnablePreimageRecording *bool
|
||||
EnableWitnessCollection *bool `toml:"-"`
|
||||
VMTrace *string
|
||||
VMTraceJsonConfig *string
|
||||
DocRoot *string `toml:"-"`
|
||||
|
|
@ -252,6 +255,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||
if dec.EnablePreimageRecording != nil {
|
||||
c.EnablePreimageRecording = *dec.EnablePreimageRecording
|
||||
}
|
||||
if dec.EnableWitnessCollection != nil {
|
||||
c.EnableWitnessCollection = *dec.EnableWitnessCollection
|
||||
}
|
||||
if dec.VMTrace != nil {
|
||||
c.VMTrace = *dec.VMTrace
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ const (
|
|||
// maxBlockFetchers is the max number of goroutines to spin up to pull blocks
|
||||
// for the fee history calculation (mostly relevant for LES).
|
||||
maxBlockFetchers = 4
|
||||
// maxQueryLimit is the max number of requested percentiles.
|
||||
maxQueryLimit = 100
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
|||
return nil, errors.New("snap sync not supported with snapshots disabled")
|
||||
}
|
||||
// Construct the downloader (long sync)
|
||||
h.downloader = downloader.New(config.Database, h.eventMux, h.chain, nil, h.removePeer, h.enableSyncedFeatures)
|
||||
h.downloader = downloader.New(config.Database, h.eventMux, h.chain, h.removePeer, h.enableSyncedFeatures)
|
||||
|
||||
fetchTx := func(peer string, hashes []common.Hash) error {
|
||||
p := h.peers.peer(peer)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ func makeLegacyProgress() legacyProgress {
|
|||
Next: common.Hash{},
|
||||
Last: common.Hash{0x77},
|
||||
SubTasks: map[common.Hash][]*legacyStorageTask{
|
||||
common.Hash{0x1}: {
|
||||
{0x1}: {
|
||||
{
|
||||
Next: common.Hash{},
|
||||
Last: common.Hash{0xff},
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ var (
|
|||
// to allow concurrent retrievals.
|
||||
accountConcurrency = 16
|
||||
|
||||
// storageConcurrency is the number of chunks to split the a large contract
|
||||
// storageConcurrency is the number of chunks to split a large contract
|
||||
// storage trie into to allow concurrent retrievals.
|
||||
storageConcurrency = 16
|
||||
)
|
||||
|
|
@ -3250,9 +3250,9 @@ func (t *healRequestSort) Merge() []TrieNodePathSet {
|
|||
// sortByAccountPath takes hashes and paths, and sorts them. After that, it generates
|
||||
// the TrieNodePaths and merges paths which belongs to the same account path.
|
||||
func sortByAccountPath(paths []string, hashes []common.Hash) ([]string, []common.Hash, []trie.SyncPath, []TrieNodePathSet) {
|
||||
var syncPaths []trie.SyncPath
|
||||
for _, path := range paths {
|
||||
syncPaths = append(syncPaths, trie.NewSyncPath([]byte(path)))
|
||||
syncPaths := make([]trie.SyncPath, len(paths))
|
||||
for i, path := range paths {
|
||||
syncPaths[i] = trie.NewSyncPath([]byte(path))
|
||||
}
|
||||
n := &healRequestSort{paths, hashes, syncPaths}
|
||||
sort.Sort(n)
|
||||
|
|
|
|||
|
|
@ -1525,7 +1525,7 @@ func makeAccountTrieNoStorage(n int, scheme string) (string, *trie.Trie, []*kv)
|
|||
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes, _ := accTrie.Commit(false)
|
||||
root, nodes := accTrie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
|
|
@ -1587,7 +1587,7 @@ func makeBoundaryAccountTrie(scheme string, n int) (string, *trie.Trie, []*kv) {
|
|||
|
||||
// Commit the state changes into db and re-create the trie
|
||||
// for accessing later.
|
||||
root, nodes, _ := accTrie.Commit(false)
|
||||
root, nodes := accTrie.Commit(false)
|
||||
db.Update(root, types.EmptyRootHash, 0, trienode.NewWithNodeSet(nodes), nil)
|
||||
|
||||
accTrie, _ = trie.New(trie.StateTrieID(root), db)
|
||||
|
|
@ -1633,7 +1633,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(scheme string, accounts, slots
|
|||
slices.SortFunc(entries, (*kv).cmp)
|
||||
|
||||
// Commit account trie
|
||||
root, set, _ := accTrie.Commit(true)
|
||||
root, set := accTrie.Commit(true)
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
|
|
@ -1700,7 +1700,7 @@ func makeAccountTrieWithStorage(scheme string, accounts, slots int, code, bounda
|
|||
slices.SortFunc(entries, (*kv).cmp)
|
||||
|
||||
// Commit account trie
|
||||
root, set, _ := accTrie.Commit(true)
|
||||
root, set := accTrie.Commit(true)
|
||||
nodes.Merge(set)
|
||||
|
||||
// Commit gathered dirty nodes into database
|
||||
|
|
@ -1742,7 +1742,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *triedb.Datab
|
|||
entries = append(entries, elem)
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes := trie.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
@ -1793,7 +1793,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *triedb.Database) (com
|
|||
entries = append(entries, elem)
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := trie.Commit(false)
|
||||
root, nodes := trie.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
@ -1825,7 +1825,7 @@ func makeUnevenStorageTrie(owner common.Hash, slots int, db *triedb.Database) (c
|
|||
}
|
||||
}
|
||||
slices.SortFunc(entries, (*kv).cmp)
|
||||
root, nodes, _ := tr.Commit(false)
|
||||
root, nodes := tr.Commit(false)
|
||||
return root, nodes, entries
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -804,9 +804,13 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
|||
// Execute the transaction and flush any traces to disk
|
||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
if vmConf.Tracer.OnTxStart != nil {
|
||||
vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From)
|
||||
}
|
||||
vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||
if vmConf.Tracer.OnTxEnd != nil {
|
||||
vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err)
|
||||
}
|
||||
if writer != nil {
|
||||
writer.Flush()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -312,7 +312,7 @@ func TestTraceCall(t *testing.T) {
|
|||
config: &TraceCallConfig{TxIndex: uintPtr(1)},
|
||||
expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr),
|
||||
},
|
||||
// After the target transaction, should be succeed
|
||||
// After the target transaction, should be succeeded
|
||||
{
|
||||
blockNumber: rpc.BlockNumber(genBlocks - 1),
|
||||
call: ethapi.TransactionArgs{
|
||||
|
|
|
|||
613
eth/tracers/internal/tracetest/supply_test.go
Normal file
613
eth/tracers/internal/tracetest/supply_test.go
Normal file
|
|
@ -0,0 +1,613 @@
|
|||
// 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 tracetest
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
// Force-load live packages, to trigger registration
|
||||
_ "github.com/ethereum/go-ethereum/eth/tracers/live"
|
||||
)
|
||||
|
||||
type supplyInfoIssuance struct {
|
||||
GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"`
|
||||
Reward *hexutil.Big `json:"reward,omitempty"`
|
||||
Withdrawals *hexutil.Big `json:"withdrawals,omitempty"`
|
||||
}
|
||||
|
||||
type supplyInfoBurn struct {
|
||||
EIP1559 *hexutil.Big `json:"1559,omitempty"`
|
||||
Blob *hexutil.Big `json:"blob,omitempty"`
|
||||
Misc *hexutil.Big `json:"misc,omitempty"`
|
||||
}
|
||||
|
||||
type supplyInfo struct {
|
||||
Issuance *supplyInfoIssuance `json:"issuance,omitempty"`
|
||||
Burn *supplyInfoBurn `json:"burn,omitempty"`
|
||||
|
||||
// Block info
|
||||
Number uint64 `json:"blockNumber"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
}
|
||||
|
||||
func emptyBlockGenerationFunc(b *core.BlockGen) {}
|
||||
|
||||
func TestSupplyOmittedFields(t *testing.T) {
|
||||
var (
|
||||
config = *params.MergedTestChainConfig
|
||||
gspec = &core.Genesis{
|
||||
Config: &config,
|
||||
}
|
||||
)
|
||||
|
||||
gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
|
||||
|
||||
out, _, err := testSupplyTracer(t, gspec, func(b *core.BlockGen) {
|
||||
b.SetPoS()
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to test supply tracer: %v", err)
|
||||
}
|
||||
|
||||
expected := supplyInfo{
|
||||
Number: 0,
|
||||
Hash: common.HexToHash("0x52f276d96f0afaaf2c3cb358868bdc2779c4b0cb8de3e7e5302e247c0b66a703"),
|
||||
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
}
|
||||
actual := out[expected.Number]
|
||||
|
||||
compareAsJSON(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestSupplyGenesisAlloc(t *testing.T) {
|
||||
var (
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||
eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
|
||||
config = *params.AllEthashProtocolChanges
|
||||
|
||||
gspec = &core.Genesis{
|
||||
Config: &config,
|
||||
Alloc: types.GenesisAlloc{
|
||||
addr1: {Balance: eth1},
|
||||
addr2: {Balance: eth1},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expected := supplyInfo{
|
||||
Issuance: &supplyInfoIssuance{
|
||||
GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
|
||||
},
|
||||
Number: 0,
|
||||
Hash: common.HexToHash("0xbcc9466e9fc6a8b56f4b29ca353a421ff8b51a0c1a58ca4743b427605b08f2ca"),
|
||||
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||
}
|
||||
|
||||
out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to test supply tracer: %v", err)
|
||||
}
|
||||
|
||||
actual := out[expected.Number]
|
||||
|
||||
compareAsJSON(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestSupplyRewards(t *testing.T) {
|
||||
var (
|
||||
config = *params.AllEthashProtocolChanges
|
||||
|
||||
gspec = &core.Genesis{
|
||||
Config: &config,
|
||||
}
|
||||
)
|
||||
|
||||
expected := supplyInfo{
|
||||
Issuance: &supplyInfoIssuance{
|
||||
Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
|
||||
},
|
||||
Number: 1,
|
||||
Hash: common.HexToHash("0xcbb08370505be503dafedc4e96d139ea27aba3cbc580148568b8a307b3f51052"),
|
||||
ParentHash: common.HexToHash("0xadeda0a83e337b6c073e3f0e9a17531a04009b397a9588c093b628f21b8bc5a3"),
|
||||
}
|
||||
|
||||
out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to test supply tracer: %v", err)
|
||||
}
|
||||
|
||||
actual := out[expected.Number]
|
||||
|
||||
compareAsJSON(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestSupplyEip1559Burn(t *testing.T) {
|
||||
var (
|
||||
config = *params.AllEthashProtocolChanges
|
||||
|
||||
aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
|
||||
// A sender who makes transactions, has some eth1
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei))
|
||||
eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
|
||||
gspec = &core.Genesis{
|
||||
Config: &config,
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Alloc: types.GenesisAlloc{
|
||||
addr1: {Balance: eth1},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
signer := types.LatestSigner(gspec.Config)
|
||||
|
||||
eip1559BlockGenerationFunc := func(b *core.BlockGen) {
|
||||
txdata := &types.DynamicFeeTx{
|
||||
ChainID: gspec.Config.ChainID,
|
||||
Nonce: 0,
|
||||
To: &aa,
|
||||
Gas: 21000,
|
||||
GasFeeCap: gwei5,
|
||||
GasTipCap: big.NewInt(2),
|
||||
}
|
||||
tx := types.NewTx(txdata)
|
||||
tx, _ = types.SignTx(tx, signer, key1)
|
||||
|
||||
b.AddTx(tx)
|
||||
}
|
||||
|
||||
out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to test supply tracer: %v", err)
|
||||
}
|
||||
var (
|
||||
head = chain.CurrentBlock()
|
||||
reward = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))
|
||||
burn = new(big.Int).Mul(big.NewInt(21000), head.BaseFee)
|
||||
expected = supplyInfo{
|
||||
Issuance: &supplyInfoIssuance{
|
||||
Reward: (*hexutil.Big)(reward),
|
||||
},
|
||||
Burn: &supplyInfoBurn{
|
||||
EIP1559: (*hexutil.Big)(burn),
|
||||
},
|
||||
Number: 1,
|
||||
Hash: head.Hash(),
|
||||
ParentHash: head.ParentHash,
|
||||
}
|
||||
)
|
||||
|
||||
actual := out[expected.Number]
|
||||
compareAsJSON(t, expected, actual)
|
||||
}
|
||||
|
||||
func TestSupplyWithdrawals(t *testing.T) {
|
||||
var (
|
||||
config = *params.MergedTestChainConfig
|
||||
gspec = &core.Genesis{
|
||||
Config: &config,
|
||||
}
|
||||
)
|
||||
|
||||
withdrawalsBlockGenerationFunc := func(b *core.BlockGen) {
|
||||
b.SetPoS()
|
||||
|
||||
b.AddWithdrawal(&types.Withdrawal{
|
||||
Validator: 42,
|
||||
Address: common.Address{0xee},
|
||||
Amount: 1337,
|
||||
})
|
||||
}
|
||||
|
||||
out, chain, err := testSupplyTracer(t, gspec, withdrawalsBlockGenerationFunc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to test supply tracer: %v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
head = chain.CurrentBlock()
|
||||
expected = supplyInfo{
|
||||
Issuance: &supplyInfoIssuance{
|
||||
Withdrawals: (*hexutil.Big)(big.NewInt(1337000000000)),
|
||||
},
|
||||
Number: 1,
|
||||
Hash: head.Hash(),
|
||||
ParentHash: head.ParentHash,
|
||||
}
|
||||
actual = out[expected.Number]
|
||||
)
|
||||
|
||||
compareAsJSON(t, expected, actual)
|
||||
}
|
||||
|
||||
// Tests fund retrieval after contract's selfdestruct.
|
||||
// Contract A calls contract B which selfdestructs, but B receives eth1
|
||||
// after the selfdestruct opcode executes from Contract A.
|
||||
// Because Contract B is removed only at the end of the transaction
|
||||
// the ether sent in between is burnt before Cancun hard fork.
|
||||
func TestSupplySelfdestruct(t *testing.T) {
|
||||
var (
|
||||
config = *params.TestChainConfig
|
||||
|
||||
aa = common.HexToAddress("0x1111111111111111111111111111111111111111")
|
||||
bb = common.HexToAddress("0x2222222222222222222222222222222222222222")
|
||||
dad = common.HexToAddress("0x0000000000000000000000000000000000000dad")
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei))
|
||||
eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
|
||||
gspec = &core.Genesis{
|
||||
Config: &config,
|
||||
BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Alloc: types.GenesisAlloc{
|
||||
addr1: {Balance: eth1},
|
||||
aa: {
|
||||
Code: common.FromHex("0x61face60f01b6000527322222222222222222222222222222222222222226000806002600080855af160008103603457600080fd5b60008060008034865af1905060008103604c57600080fd5b5050"),
|
||||
// Nonce: 0,
|
||||
Balance: big.NewInt(0),
|
||||
},
|
||||
bb: {
|
||||
Code: common.FromHex("0x6000357fface000000000000000000000000000000000000000000000000000000000000808203602f57610dad80ff5b5050"),
|
||||
Nonce: 0,
|
||||
Balance: eth1,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
|
||||
|
||||
signer := types.LatestSigner(gspec.Config)
|
||||
|
||||
testBlockGenerationFunc := func(b *core.BlockGen) {
|
||||
b.SetPoS()
|
||||
|
||||
txdata := &types.LegacyTx{
|
||||
Nonce: 0,
|
||||
To: &aa,
|
||||
Value: gwei5,
|
||||
Gas: 150000,
|
||||
GasPrice: gwei5,
|
||||
Data: []byte{},
|
||||
}
|
||||
|
||||
tx := types.NewTx(txdata)
|
||||
tx, _ = types.SignTx(tx, signer, key1)
|
||||
|
||||
b.AddTx(tx)
|
||||
}
|
||||
|
||||
// 1. Test pre Cancun
|
||||
preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
|
||||
if err != nil {
|
||||
t.Fatalf("Pre-cancun failed to test supply tracer: %v", err)
|
||||
}
|
||||
|
||||
// Check balance at state:
|
||||
// 1. 0x0000...000dad has 1 ether
|
||||
// 2. A has 0 ether
|
||||
// 3. B has 0 ether
|
||||
statedb, _ := preCancunChain.State()
|
||||
if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", dad, got, exp)
|
||||
}
|
||||
if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", aa, got, exp)
|
||||
}
|
||||
if got, exp := statedb.GetBalance(bb), big.NewInt(0); got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", bb, got, exp)
|
||||
}
|
||||
|
||||
head := preCancunChain.CurrentBlock()
|
||||
// Check live trace output
|
||||
expected := supplyInfo{
|
||||
Burn: &supplyInfoBurn{
|
||||
EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)),
|
||||
Misc: (*hexutil.Big)(big.NewInt(5000000000)),
|
||||
},
|
||||
Number: 1,
|
||||
Hash: head.Hash(),
|
||||
ParentHash: head.ParentHash,
|
||||
}
|
||||
|
||||
actual := preCancunOutput[expected.Number]
|
||||
|
||||
compareAsJSON(t, expected, actual)
|
||||
|
||||
// 2. Test post Cancun
|
||||
cancunTime := uint64(0)
|
||||
gspec.Config.ShanghaiTime = &cancunTime
|
||||
gspec.Config.CancunTime = &cancunTime
|
||||
|
||||
postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
|
||||
if err != nil {
|
||||
t.Fatalf("Post-cancun failed to test supply tracer: %v", err)
|
||||
}
|
||||
|
||||
// Check balance at state:
|
||||
// 1. 0x0000...000dad has 1 ether
|
||||
// 3. A has 0 ether
|
||||
// 3. B has 5 gwei
|
||||
statedb, _ = postCancunChain.State()
|
||||
if got, exp := statedb.GetBalance(dad), eth1; got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", dad, got, exp)
|
||||
}
|
||||
if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", aa, got, exp)
|
||||
}
|
||||
if got, exp := statedb.GetBalance(bb), gwei5; got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", bb, got, exp)
|
||||
}
|
||||
|
||||
// Check live trace output
|
||||
head = postCancunChain.CurrentBlock()
|
||||
expected = supplyInfo{
|
||||
Burn: &supplyInfoBurn{
|
||||
EIP1559: (*hexutil.Big)(big.NewInt(55289500000000)),
|
||||
},
|
||||
Number: 1,
|
||||
Hash: head.Hash(),
|
||||
ParentHash: head.ParentHash,
|
||||
}
|
||||
|
||||
actual = postCancunOutput[expected.Number]
|
||||
|
||||
compareAsJSON(t, expected, actual)
|
||||
}
|
||||
|
||||
// Tests selfdestructing contract to send its balance to itself (burn).
|
||||
// It tests both cases of selfdestructing succeeding and being reverted.
|
||||
// - Contract A calls B and D.
|
||||
// - Contract B selfdestructs and sends the eth1 to itself (Burn amount to be counted).
|
||||
// - Contract C selfdestructs and sends the eth1 to itself.
|
||||
// - Contract D calls C and reverts (Burn amount of C
|
||||
// has to be reverted as well).
|
||||
func TestSupplySelfdestructItselfAndRevert(t *testing.T) {
|
||||
var (
|
||||
config = *params.TestChainConfig
|
||||
|
||||
aa = common.HexToAddress("0x1111111111111111111111111111111111111111")
|
||||
bb = common.HexToAddress("0x2222222222222222222222222222222222222222")
|
||||
cc = common.HexToAddress("0x3333333333333333333333333333333333333333")
|
||||
dd = common.HexToAddress("0x4444444444444444444444444444444444444444")
|
||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||
gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei))
|
||||
eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
|
||||
eth2 = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))
|
||||
eth5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.Ether))
|
||||
|
||||
gspec = &core.Genesis{
|
||||
Config: &config,
|
||||
// BaseFee: big.NewInt(params.InitialBaseFee),
|
||||
Alloc: types.GenesisAlloc{
|
||||
addr1: {Balance: eth1},
|
||||
aa: {
|
||||
// Contract code in YUL:
|
||||
//
|
||||
// object "ContractA" {
|
||||
// code {
|
||||
// let B := 0x2222222222222222222222222222222222222222
|
||||
// let D := 0x4444444444444444444444444444444444444444
|
||||
|
||||
// // Call to Contract B
|
||||
// let resB:= call(gas(), B, 0, 0x0, 0x0, 0, 0)
|
||||
|
||||
// // Call to Contract D
|
||||
// let resD := call(gas(), D, 0, 0x0, 0x0, 0, 0)
|
||||
// }
|
||||
// }
|
||||
Code: common.FromHex("0x73222222222222222222222222222222222222222273444444444444444444444444444444444444444460006000600060006000865af160006000600060006000865af150505050"),
|
||||
Balance: common.Big0,
|
||||
},
|
||||
bb: {
|
||||
// Contract code in YUL:
|
||||
//
|
||||
// object "ContractB" {
|
||||
// code {
|
||||
// let self := address()
|
||||
// selfdestruct(self)
|
||||
// }
|
||||
// }
|
||||
Code: common.FromHex("0x3080ff50"),
|
||||
Balance: eth5,
|
||||
},
|
||||
cc: {
|
||||
Code: common.FromHex("0x3080ff50"),
|
||||
Balance: eth1,
|
||||
},
|
||||
dd: {
|
||||
// Contract code in YUL:
|
||||
//
|
||||
// object "ContractD" {
|
||||
// code {
|
||||
// let C := 0x3333333333333333333333333333333333333333
|
||||
|
||||
// // Call to Contract C
|
||||
// let resC := call(gas(), C, 0, 0x0, 0x0, 0, 0)
|
||||
|
||||
// // Revert
|
||||
// revert(0, 0)
|
||||
// }
|
||||
// }
|
||||
Code: common.FromHex("0x73333333333333333333333333333333333333333360006000600060006000855af160006000fd5050"),
|
||||
Balance: eth2,
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
|
||||
|
||||
signer := types.LatestSigner(gspec.Config)
|
||||
|
||||
testBlockGenerationFunc := func(b *core.BlockGen) {
|
||||
b.SetPoS()
|
||||
|
||||
txdata := &types.LegacyTx{
|
||||
Nonce: 0,
|
||||
To: &aa,
|
||||
Value: common.Big0,
|
||||
Gas: 150000,
|
||||
GasPrice: gwei5,
|
||||
Data: []byte{},
|
||||
}
|
||||
|
||||
tx := types.NewTx(txdata)
|
||||
tx, _ = types.SignTx(tx, signer, key1)
|
||||
|
||||
b.AddTx(tx)
|
||||
}
|
||||
|
||||
output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to test supply tracer: %v", err)
|
||||
}
|
||||
|
||||
// Check balance at state:
|
||||
// 1. A has 0 ether
|
||||
// 2. B has 0 ether, burned
|
||||
// 3. C has 2 ether, selfdestructed but parent D reverted
|
||||
// 4. D has 1 ether, reverted
|
||||
statedb, _ := chain.State()
|
||||
if got, exp := statedb.GetBalance(aa), common.Big0; got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("address \"%v\" balance, got %v exp %v\n", aa, got, exp)
|
||||
}
|
||||
if got, exp := statedb.GetBalance(bb), common.Big0; got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp)
|
||||
}
|
||||
if got, exp := statedb.GetBalance(cc), eth1; got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp)
|
||||
}
|
||||
if got, exp := statedb.GetBalance(dd), eth2; got.CmpBig(exp) != 0 {
|
||||
t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp)
|
||||
}
|
||||
|
||||
// Check live trace output
|
||||
block := chain.GetBlockByNumber(1)
|
||||
|
||||
expected := supplyInfo{
|
||||
Burn: &supplyInfoBurn{
|
||||
EIP1559: (*hexutil.Big)(new(big.Int).Mul(block.BaseFee(), big.NewInt(int64(block.GasUsed())))),
|
||||
Misc: (*hexutil.Big)(eth5), // 5ETH burned from contract B
|
||||
},
|
||||
Number: 1,
|
||||
Hash: block.Hash(),
|
||||
ParentHash: block.ParentHash(),
|
||||
}
|
||||
|
||||
actual := output[expected.Number]
|
||||
|
||||
compareAsJSON(t, expected, actual)
|
||||
}
|
||||
|
||||
func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) {
|
||||
var (
|
||||
engine = beacon.New(ethash.NewFaker())
|
||||
)
|
||||
|
||||
traceOutputPath := filepath.ToSlash(t.TempDir())
|
||||
traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl")
|
||||
|
||||
// Load supply tracer
|
||||
tracer, err := tracers.LiveDirectory.New("supply", json.RawMessage(fmt.Sprintf(`{"path":"%s"}`, traceOutputPath)))
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create call tracer: %v", err)
|
||||
}
|
||||
|
||||
chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil, nil)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
||||
}
|
||||
defer chain.Stop()
|
||||
|
||||
_, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, 1, func(i int, b *core.BlockGen) {
|
||||
b.SetCoinbase(common.Address{1})
|
||||
gen(b)
|
||||
})
|
||||
|
||||
if n, err := chain.InsertChain(blocks); err != nil {
|
||||
return nil, chain, fmt.Errorf("block %d: failed to insert into chain: %v", n, err)
|
||||
}
|
||||
|
||||
// Check and compare the results
|
||||
file, err := os.OpenFile(traceOutputFilename, os.O_RDONLY, 0666)
|
||||
if err != nil {
|
||||
return nil, chain, fmt.Errorf("failed to open output file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var output []supplyInfo
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
blockBytes := scanner.Bytes()
|
||||
|
||||
var info supplyInfo
|
||||
if err := json.Unmarshal(blockBytes, &info); err != nil {
|
||||
return nil, chain, fmt.Errorf("failed to unmarshal result: %v", err)
|
||||
}
|
||||
|
||||
output = append(output, info)
|
||||
}
|
||||
|
||||
return output, chain, nil
|
||||
}
|
||||
|
||||
func compareAsJSON(t *testing.T, expected interface{}, actual interface{}) {
|
||||
want, err := json.Marshal(expected)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal expected value to JSON: %v", err)
|
||||
}
|
||||
|
||||
have, err := json.Marshal(actual)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to marshal actual value to JSON: %v", err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(want, have) {
|
||||
t.Fatalf("incorrect supply info: expected %s, got %s", string(want), string(have))
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
49
eth/tracers/live/gen_supplyinfoburn.go
Normal file
49
eth/tracers/live/gen_supplyinfoburn.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package live
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
var _ = (*supplyInfoBurnMarshaling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (s supplyInfoBurn) MarshalJSON() ([]byte, error) {
|
||||
type supplyInfoBurn struct {
|
||||
EIP1559 *hexutil.Big `json:"1559,omitempty"`
|
||||
Blob *hexutil.Big `json:"blob,omitempty"`
|
||||
Misc *hexutil.Big `json:"misc,omitempty"`
|
||||
}
|
||||
var enc supplyInfoBurn
|
||||
enc.EIP1559 = (*hexutil.Big)(s.EIP1559)
|
||||
enc.Blob = (*hexutil.Big)(s.Blob)
|
||||
enc.Misc = (*hexutil.Big)(s.Misc)
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (s *supplyInfoBurn) UnmarshalJSON(input []byte) error {
|
||||
type supplyInfoBurn struct {
|
||||
EIP1559 *hexutil.Big `json:"1559,omitempty"`
|
||||
Blob *hexutil.Big `json:"blob,omitempty"`
|
||||
Misc *hexutil.Big `json:"misc,omitempty"`
|
||||
}
|
||||
var dec supplyInfoBurn
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.EIP1559 != nil {
|
||||
s.EIP1559 = (*big.Int)(dec.EIP1559)
|
||||
}
|
||||
if dec.Blob != nil {
|
||||
s.Blob = (*big.Int)(dec.Blob)
|
||||
}
|
||||
if dec.Misc != nil {
|
||||
s.Misc = (*big.Int)(dec.Misc)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
49
eth/tracers/live/gen_supplyinfoissuance.go
Normal file
49
eth/tracers/live/gen_supplyinfoissuance.go
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
|
||||
|
||||
package live
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
var _ = (*supplyInfoIssuanceMarshaling)(nil)
|
||||
|
||||
// MarshalJSON marshals as JSON.
|
||||
func (s supplyInfoIssuance) MarshalJSON() ([]byte, error) {
|
||||
type supplyInfoIssuance struct {
|
||||
GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"`
|
||||
Reward *hexutil.Big `json:"reward,omitempty"`
|
||||
Withdrawals *hexutil.Big `json:"withdrawals,omitempty"`
|
||||
}
|
||||
var enc supplyInfoIssuance
|
||||
enc.GenesisAlloc = (*hexutil.Big)(s.GenesisAlloc)
|
||||
enc.Reward = (*hexutil.Big)(s.Reward)
|
||||
enc.Withdrawals = (*hexutil.Big)(s.Withdrawals)
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (s *supplyInfoIssuance) UnmarshalJSON(input []byte) error {
|
||||
type supplyInfoIssuance struct {
|
||||
GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"`
|
||||
Reward *hexutil.Big `json:"reward,omitempty"`
|
||||
Withdrawals *hexutil.Big `json:"withdrawals,omitempty"`
|
||||
}
|
||||
var dec supplyInfoIssuance
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
return err
|
||||
}
|
||||
if dec.GenesisAlloc != nil {
|
||||
s.GenesisAlloc = (*big.Int)(dec.GenesisAlloc)
|
||||
}
|
||||
if dec.Reward != nil {
|
||||
s.Reward = (*big.Int)(dec.Reward)
|
||||
}
|
||||
if dec.Withdrawals != nil {
|
||||
s.Withdrawals = (*big.Int)(dec.Withdrawals)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
310
eth/tracers/live/supply.go
Normal file
310
eth/tracers/live/supply.go
Normal file
|
|
@ -0,0 +1,310 @@
|
|||
package live
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"gopkg.in/natefinch/lumberjack.v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
tracers.LiveDirectory.Register("supply", newSupply)
|
||||
}
|
||||
|
||||
type supplyInfoIssuance struct {
|
||||
GenesisAlloc *big.Int `json:"genesisAlloc,omitempty"`
|
||||
Reward *big.Int `json:"reward,omitempty"`
|
||||
Withdrawals *big.Int `json:"withdrawals,omitempty"`
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type supplyInfoIssuance -field-override supplyInfoIssuanceMarshaling -out gen_supplyinfoissuance.go
|
||||
type supplyInfoIssuanceMarshaling struct {
|
||||
GenesisAlloc *hexutil.Big
|
||||
Reward *hexutil.Big
|
||||
Withdrawals *hexutil.Big
|
||||
}
|
||||
|
||||
type supplyInfoBurn struct {
|
||||
EIP1559 *big.Int `json:"1559,omitempty"`
|
||||
Blob *big.Int `json:"blob,omitempty"`
|
||||
Misc *big.Int `json:"misc,omitempty"`
|
||||
}
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type supplyInfoBurn -field-override supplyInfoBurnMarshaling -out gen_supplyinfoburn.go
|
||||
type supplyInfoBurnMarshaling struct {
|
||||
EIP1559 *hexutil.Big
|
||||
Blob *hexutil.Big
|
||||
Misc *hexutil.Big
|
||||
}
|
||||
|
||||
type supplyInfo struct {
|
||||
Issuance *supplyInfoIssuance `json:"issuance,omitempty"`
|
||||
Burn *supplyInfoBurn `json:"burn,omitempty"`
|
||||
|
||||
// Block info
|
||||
Number uint64 `json:"blockNumber"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
}
|
||||
|
||||
type supplyTxCallstack struct {
|
||||
calls []supplyTxCallstack
|
||||
burn *big.Int
|
||||
}
|
||||
|
||||
type supply struct {
|
||||
delta supplyInfo
|
||||
txCallstack []supplyTxCallstack // Callstack for current transaction
|
||||
logger *lumberjack.Logger
|
||||
}
|
||||
|
||||
type supplyTracerConfig struct {
|
||||
Path string `json:"path"` // Path to the directory where the tracer logs will be stored
|
||||
MaxSize int `json:"maxSize"` // MaxSize is the maximum size in megabytes of the tracer log file before it gets rotated. It defaults to 100 megabytes.
|
||||
}
|
||||
|
||||
func newSupply(cfg json.RawMessage) (*tracing.Hooks, error) {
|
||||
var config supplyTracerConfig
|
||||
if cfg != nil {
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config: %v", err)
|
||||
}
|
||||
}
|
||||
if config.Path == "" {
|
||||
return nil, errors.New("supply tracer output path is required")
|
||||
}
|
||||
|
||||
// Store traces in a rotating file
|
||||
logger := &lumberjack.Logger{
|
||||
Filename: filepath.Join(config.Path, "supply.jsonl"),
|
||||
}
|
||||
if config.MaxSize > 0 {
|
||||
logger.MaxSize = config.MaxSize
|
||||
}
|
||||
|
||||
t := &supply{
|
||||
delta: newSupplyInfo(),
|
||||
logger: logger,
|
||||
}
|
||||
return &tracing.Hooks{
|
||||
OnBlockStart: t.OnBlockStart,
|
||||
OnBlockEnd: t.OnBlockEnd,
|
||||
OnGenesisBlock: t.OnGenesisBlock,
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnBalanceChange: t.OnBalanceChange,
|
||||
OnEnter: t.OnEnter,
|
||||
OnExit: t.OnExit,
|
||||
OnClose: t.OnClose,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func newSupplyInfo() supplyInfo {
|
||||
return supplyInfo{
|
||||
Issuance: &supplyInfoIssuance{
|
||||
GenesisAlloc: big.NewInt(0),
|
||||
Reward: big.NewInt(0),
|
||||
Withdrawals: big.NewInt(0),
|
||||
},
|
||||
Burn: &supplyInfoBurn{
|
||||
EIP1559: big.NewInt(0),
|
||||
Blob: big.NewInt(0),
|
||||
Misc: big.NewInt(0),
|
||||
},
|
||||
|
||||
Number: 0,
|
||||
Hash: common.Hash{},
|
||||
ParentHash: common.Hash{},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *supply) resetDelta() {
|
||||
s.delta = newSupplyInfo()
|
||||
}
|
||||
|
||||
func (s *supply) OnBlockStart(ev tracing.BlockEvent) {
|
||||
s.resetDelta()
|
||||
|
||||
s.delta.Number = ev.Block.NumberU64()
|
||||
s.delta.Hash = ev.Block.Hash()
|
||||
s.delta.ParentHash = ev.Block.ParentHash()
|
||||
|
||||
// Calculate Burn for this block
|
||||
if ev.Block.BaseFee() != nil {
|
||||
burn := new(big.Int).Mul(new(big.Int).SetUint64(ev.Block.GasUsed()), ev.Block.BaseFee())
|
||||
s.delta.Burn.EIP1559 = burn
|
||||
}
|
||||
// Blob burnt gas
|
||||
if blobGas := ev.Block.BlobGasUsed(); blobGas != nil && *blobGas > 0 && ev.Block.ExcessBlobGas() != nil {
|
||||
var (
|
||||
excess = *ev.Block.ExcessBlobGas()
|
||||
baseFee = eip4844.CalcBlobFee(excess)
|
||||
burn = new(big.Int).Mul(new(big.Int).SetUint64(*blobGas), baseFee)
|
||||
)
|
||||
s.delta.Burn.Blob = burn
|
||||
}
|
||||
}
|
||||
|
||||
func (s *supply) OnBlockEnd(err error) {
|
||||
s.write(s.delta)
|
||||
}
|
||||
|
||||
func (s *supply) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) {
|
||||
s.resetDelta()
|
||||
|
||||
s.delta.Number = b.NumberU64()
|
||||
s.delta.Hash = b.Hash()
|
||||
s.delta.ParentHash = b.ParentHash()
|
||||
|
||||
// Initialize supply with total allocation in genesis block
|
||||
for _, account := range alloc {
|
||||
s.delta.Issuance.GenesisAlloc.Add(s.delta.Issuance.GenesisAlloc, account.Balance)
|
||||
}
|
||||
|
||||
s.write(s.delta)
|
||||
}
|
||||
|
||||
func (s *supply) OnBalanceChange(a common.Address, prevBalance, newBalance *big.Int, reason tracing.BalanceChangeReason) {
|
||||
diff := new(big.Int).Sub(newBalance, prevBalance)
|
||||
|
||||
// NOTE: don't handle "BalanceIncreaseGenesisBalance" because it is handled in OnGenesisBlock
|
||||
switch reason {
|
||||
case tracing.BalanceIncreaseRewardMineUncle:
|
||||
case tracing.BalanceIncreaseRewardMineBlock:
|
||||
s.delta.Issuance.Reward.Add(s.delta.Issuance.Reward, diff)
|
||||
case tracing.BalanceIncreaseWithdrawal:
|
||||
s.delta.Issuance.Withdrawals.Add(s.delta.Issuance.Withdrawals, diff)
|
||||
case tracing.BalanceDecreaseSelfdestructBurn:
|
||||
// BalanceDecreaseSelfdestructBurn is non-reversible as it happens
|
||||
// at the end of the transaction.
|
||||
s.delta.Burn.Misc.Sub(s.delta.Burn.Misc, diff)
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (s *supply) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||
s.txCallstack = make([]supplyTxCallstack, 0, 1)
|
||||
}
|
||||
|
||||
// internalTxsHandler handles internal transactions burned amount
|
||||
func (s *supply) internalTxsHandler(call *supplyTxCallstack) {
|
||||
// Handle Burned amount
|
||||
if call.burn != nil {
|
||||
s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn)
|
||||
}
|
||||
|
||||
if len(call.calls) > 0 {
|
||||
// Recursively handle internal calls
|
||||
for _, call := range call.calls {
|
||||
callCopy := call
|
||||
s.internalTxsHandler(&callCopy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *supply) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
call := supplyTxCallstack{
|
||||
calls: make([]supplyTxCallstack, 0),
|
||||
}
|
||||
|
||||
// This is a special case of burned amount which has to be handled here
|
||||
// which happens when type == selfdestruct and from == to.
|
||||
if vm.OpCode(typ) == vm.SELFDESTRUCT && from == to && value.Cmp(common.Big0) == 1 {
|
||||
call.burn = value
|
||||
}
|
||||
|
||||
// Append call to the callstack, so we can fill the details in CaptureExit
|
||||
s.txCallstack = append(s.txCallstack, call)
|
||||
}
|
||||
|
||||
func (s *supply) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if depth == 0 {
|
||||
// No need to handle Burned amount if transaction is reverted
|
||||
if !reverted {
|
||||
s.internalTxsHandler(&s.txCallstack[0])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
size := len(s.txCallstack)
|
||||
if size <= 1 {
|
||||
return
|
||||
}
|
||||
// Pop call
|
||||
call := s.txCallstack[size-1]
|
||||
s.txCallstack = s.txCallstack[:size-1]
|
||||
size -= 1
|
||||
|
||||
// In case of a revert, we can drop the call and all its subcalls.
|
||||
// Caution, that this has to happen after popping the call from the stack.
|
||||
if reverted {
|
||||
return
|
||||
}
|
||||
s.txCallstack[size-1].calls = append(s.txCallstack[size-1].calls, call)
|
||||
}
|
||||
|
||||
func (s *supply) OnClose() {
|
||||
if err := s.logger.Close(); err != nil {
|
||||
log.Warn("failed to close supply tracer log file", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *supply) write(data any) {
|
||||
supply, ok := data.(supplyInfo)
|
||||
if !ok {
|
||||
log.Warn("failed to cast supply tracer data on write to log file")
|
||||
return
|
||||
}
|
||||
|
||||
// Remove empty fields
|
||||
if supply.Issuance.GenesisAlloc.Sign() == 0 {
|
||||
supply.Issuance.GenesisAlloc = nil
|
||||
}
|
||||
|
||||
if supply.Issuance.Reward.Sign() == 0 {
|
||||
supply.Issuance.Reward = nil
|
||||
}
|
||||
|
||||
if supply.Issuance.Withdrawals.Sign() == 0 {
|
||||
supply.Issuance.Withdrawals = nil
|
||||
}
|
||||
|
||||
if supply.Issuance.GenesisAlloc == nil && supply.Issuance.Reward == nil && supply.Issuance.Withdrawals == nil {
|
||||
supply.Issuance = nil
|
||||
}
|
||||
|
||||
if supply.Burn.EIP1559.Sign() == 0 {
|
||||
supply.Burn.EIP1559 = nil
|
||||
}
|
||||
|
||||
if supply.Burn.Blob.Sign() == 0 {
|
||||
supply.Burn.Blob = nil
|
||||
}
|
||||
|
||||
if supply.Burn.Misc.Sign() == 0 {
|
||||
supply.Burn.Misc = nil
|
||||
}
|
||||
|
||||
if supply.Burn.EIP1559 == nil && supply.Burn.Blob == nil && supply.Burn.Misc == nil {
|
||||
supply.Burn = nil
|
||||
}
|
||||
|
||||
out, _ := json.Marshal(supply)
|
||||
if _, err := s.logger.Write(out); err != nil {
|
||||
log.Warn("failed to write to supply tracer log file", "error", err)
|
||||
}
|
||||
if _, err := s.logger.Write([]byte{'\n'}); err != nil {
|
||||
log.Warn("failed to write to supply tracer log file", "error", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -58,6 +58,7 @@ type jsonLogger struct {
|
|||
encoder *json.Encoder
|
||||
cfg *Config
|
||||
env *tracing.VMContext
|
||||
hooks *tracing.Hooks
|
||||
}
|
||||
|
||||
// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects
|
||||
|
|
@ -67,12 +68,14 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks {
|
|||
if l.cfg == nil {
|
||||
l.cfg = &Config{}
|
||||
}
|
||||
return &tracing.Hooks{
|
||||
l.hooks = &tracing.Hooks{
|
||||
OnTxStart: l.OnTxStart,
|
||||
OnExit: l.OnExit,
|
||||
OnSystemCallStart: l.onSystemCallStart,
|
||||
OnExit: l.OnEnd,
|
||||
OnOpcode: l.OnOpcode,
|
||||
OnFault: l.OnFault,
|
||||
}
|
||||
return l.hooks
|
||||
}
|
||||
|
||||
// NewJSONLoggerWithCallFrames creates a new EVM tracer that prints execution steps as JSON objects
|
||||
|
|
@ -82,13 +85,15 @@ func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks {
|
|||
if l.cfg == nil {
|
||||
l.cfg = &Config{}
|
||||
}
|
||||
return &tracing.Hooks{
|
||||
l.hooks = &tracing.Hooks{
|
||||
OnTxStart: l.OnTxStart,
|
||||
OnSystemCallStart: l.onSystemCallStart,
|
||||
OnEnter: l.OnEnter,
|
||||
OnExit: l.OnExit,
|
||||
OnOpcode: l.OnOpcode,
|
||||
OnFault: l.OnFault,
|
||||
}
|
||||
return l.hooks
|
||||
}
|
||||
|
||||
func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) {
|
||||
|
|
@ -122,6 +127,16 @@ func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracin
|
|||
l.encoder.Encode(log)
|
||||
}
|
||||
|
||||
func (l *jsonLogger) onSystemCallStart() {
|
||||
// Process no events while in system call.
|
||||
hooks := *l.hooks
|
||||
*l.hooks = tracing.Hooks{
|
||||
OnSystemCallEnd: func() {
|
||||
*l.hooks = hooks
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// OnEnter is not enabled by default.
|
||||
func (l *jsonLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
frame := callFrame{
|
||||
|
|
|
|||
|
|
@ -74,6 +74,11 @@ func (f callFrame) failed() bool {
|
|||
|
||||
func (f *callFrame) processOutput(output []byte, err error, reverted bool) {
|
||||
output = common.CopyBytes(output)
|
||||
// Clear error if tx wasn't reverted. This happened
|
||||
// for pre-homestead contract storage OOG.
|
||||
if err != nil && !reverted {
|
||||
err = nil
|
||||
}
|
||||
if err == nil {
|
||||
f.Output = output
|
||||
return
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ func makeDataset(size, ksize, vsize int, order bool) ([][]byte, [][]byte) {
|
|||
vals = append(vals, randBytes(vsize))
|
||||
}
|
||||
if order {
|
||||
slices.SortFunc(keys, func(a, b []byte) int { return bytes.Compare(a, b) })
|
||||
slices.SortFunc(keys, bytes.Compare)
|
||||
}
|
||||
return keys, vals
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,7 +400,7 @@ func (b *batch) Put(key, value []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Delete inserts the a key removal into the batch for later committing.
|
||||
// Delete inserts the key removal into the batch for later committing.
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.b.Delete(key)
|
||||
b.size += len(key)
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ func (b *batch) Put(key, value []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Delete inserts the a key removal into the batch for later committing.
|
||||
// Delete inserts the key removal into the batch for later committing.
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.writes = append(b.writes, keyvalue{string(key), nil, true})
|
||||
b.size += len(key)
|
||||
|
|
|
|||
|
|
@ -207,7 +207,7 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
|
|||
|
||||
// The default compaction concurrency(1 thread),
|
||||
// Here use all available CPUs for faster compaction.
|
||||
MaxConcurrentCompactions: func() int { return runtime.NumCPU() },
|
||||
MaxConcurrentCompactions: runtime.NumCPU,
|
||||
|
||||
// Per-level options. Options for at least one level must be specified. The
|
||||
// options for the last level are used for all subsequent levels.
|
||||
|
|
@ -575,7 +575,7 @@ func (b *batch) Put(key, value []byte) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Delete inserts the a key removal into the batch for later committing.
|
||||
// Delete inserts the key removal into the batch for later committing.
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.b.Delete(key, nil)
|
||||
b.size += len(key)
|
||||
|
|
|
|||
16
go.mod
16
go.mod
|
|
@ -4,8 +4,8 @@ go 1.21
|
|||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
|
||||
github.com/Microsoft/go-winio v0.6.1
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1
|
||||
github.com/Microsoft/go-winio v0.6.2
|
||||
github.com/VictoriaMetrics/fastcache v1.12.2
|
||||
github.com/aws/aws-sdk-go-v2 v1.21.2
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.45
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.43
|
||||
|
|
@ -18,13 +18,13 @@ require (
|
|||
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c
|
||||
github.com/crate-crypto/go-kzg-4844 v1.0.0
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set/v2 v2.1.0
|
||||
github.com/deckarep/golang-set/v2 v2.6.0
|
||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
||||
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
||||
github.com/ethereum/c-kzg-4844 v1.0.0
|
||||
github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0
|
||||
github.com/fatih/color v1.13.0
|
||||
github.com/ferranbt/fastssz v0.1.3
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/ferranbt/fastssz v0.1.2
|
||||
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
|
||||
github.com/fjl/memsize v0.0.2
|
||||
github.com/fsnotify/fsnotify v1.6.0
|
||||
|
|
@ -51,7 +51,7 @@ require (
|
|||
github.com/kilic/bls12-381 v0.1.0
|
||||
github.com/kylelemons/godebug v1.1.0
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-isatty v0.0.17
|
||||
github.com/mattn/go-isatty v0.0.20
|
||||
github.com/mattn/go-sqlite3 v1.14.18
|
||||
github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
|
|
@ -79,7 +79,7 @@ require (
|
|||
golang.org/x/text v0.14.0
|
||||
golang.org/x/time v0.5.0
|
||||
golang.org/x/tools v0.20.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ require (
|
|||
github.com/aws/smithy-go v1.15.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.10.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||
|
|
|
|||
41
go.sum
41
go.sum
|
|
@ -44,17 +44,15 @@ github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0/go.mod h1:+6KLcKIVgx
|
|||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0 h1:OBhqkivkhkMqLPymWEppkm7vgPQY2XsHoEkaMQ0AdZY=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.0.0/go.mod h1:kgDmCTgBzIEPFElEF+FK0SdjAor06dRq2Go927dnQ6o=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ=
|
||||
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
|
||||
github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1 h1:i0mICQuojGDL3KblA7wUNlY5lOK6a4bwt3uRKnkZU40=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.1/go.mod h1:tX04vaqcNoQeGLD+ra5pU5sWkuxnzWhEzLwhP9w653o=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.2 h1:N0y9ASrJ0F6h0QaC3o6uJb3NIZ9VKLjCM7NQbSmF7WI=
|
||||
github.com/VictoriaMetrics/fastcache v1.12.2/go.mod h1:AmC+Nzz1+3G2eCPapF6UcsnkThDcMsQicp4xDukwJYI=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
|
|
@ -103,8 +101,9 @@ github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
|||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
|
|
@ -142,8 +141,8 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV
|
|||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/deckarep/golang-set/v2 v2.1.0 h1:g47V4Or+DUdzbs8FxCCmgb6VYd+ptPAngjM6dtGktsI=
|
||||
github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM=
|
||||
github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
|
||||
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc=
|
||||
|
|
@ -171,10 +170,10 @@ github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHE
|
|||
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
|
||||
github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0 h1:KrE8I4reeVvf7C1tm8elRjj4BdscTYzz/WAbYyf/JI4=
|
||||
github.com/ethereum/go-verkle v0.1.1-0.20240306133620-7d920df305f0/go.mod h1:D9AJLVXSyZQXJQVk8oh1EwjISE+sJTn2duYIZC0dy3w=
|
||||
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/ferranbt/fastssz v0.1.3 h1:ZI+z3JH05h4kgmFXdHuR1aWYsgrg7o+Fw7/NCzM16Mo=
|
||||
github.com/ferranbt/fastssz v0.1.3/go.mod h1:0Y9TEd/9XuFlh7mskMPfXiI2Dkw4Ddg9EyXt1W7MRvE=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
|
||||
github.com/ferranbt/fastssz v0.1.2/go.mod h1:X5UPrE2u1UJjxHA8X54u04SBwdAQjG2sFtWs39YxyWs=
|
||||
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e h1:bBLctRc7kr01YGvaDfgLbTwjFNW5jdp5y5rj8XXBHfY=
|
||||
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e/go.mod h1:AzA8Lj6YtixmJWL+wkKoBGsLWy9gFrAzi4g+5bCKwpY=
|
||||
github.com/fjl/memsize v0.0.2 h1:27txuSD9or+NZlnOWdKUxeBzTAUkWCVh+4Gf2dWFOzA=
|
||||
|
|
@ -377,16 +376,14 @@ github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIG
|
|||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
|
|
@ -698,7 +695,6 @@ golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
@ -706,9 +702,12 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
|
|
@ -867,8 +866,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -751,7 +751,7 @@ func TestEstimateGas(t *testing.T) {
|
|||
From: &accounts[0].addr,
|
||||
To: &accounts[1].addr,
|
||||
Value: (*hexutil.Big)(big.NewInt(1)),
|
||||
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
|
||||
BlobHashes: []common.Hash{{0x01, 0x22}},
|
||||
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
||||
},
|
||||
want: 21000,
|
||||
|
|
@ -939,7 +939,7 @@ func TestCall(t *testing.T) {
|
|||
call: TransactionArgs{
|
||||
From: &accounts[1].addr,
|
||||
To: &randomAccounts[2].addr,
|
||||
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
|
||||
BlobHashes: []common.Hash{{0x01, 0x22}},
|
||||
BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
|
||||
},
|
||||
overrides: StateOverride{
|
||||
|
|
@ -1063,7 +1063,7 @@ func TestSendBlobTransaction(t *testing.T) {
|
|||
From: &b.acc.Address,
|
||||
To: &to,
|
||||
Value: (*hexutil.Big)(big.NewInt(1)),
|
||||
BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
|
||||
BlobHashes: []common.Hash{{0x01, 0x22}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to fill tx defaults: %v\n", err)
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ func (h *bufHandler) Handle(_ context.Context, r slog.Record) error {
|
|||
}
|
||||
|
||||
func (h *bufHandler) Enabled(_ context.Context, lvl slog.Level) bool {
|
||||
return lvl <= h.level
|
||||
return lvl >= h.level
|
||||
}
|
||||
|
||||
func (h *bufHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
||||
|
|
|
|||
|
|
@ -101,10 +101,10 @@ func (h *TerminalHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
|
|||
}
|
||||
|
||||
// ResetFieldPadding zeroes the field-padding for all attribute pairs.
|
||||
func (t *TerminalHandler) ResetFieldPadding() {
|
||||
t.mu.Lock()
|
||||
t.fieldPadding = make(map[string]int)
|
||||
t.mu.Unlock()
|
||||
func (h *TerminalHandler) ResetFieldPadding() {
|
||||
h.mu.Lock()
|
||||
h.fieldPadding = make(map[string]int)
|
||||
h.mu.Unlock()
|
||||
}
|
||||
|
||||
type leveler struct{ minLevel slog.Level }
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ func TestLoggingWithVmodule(t *testing.T) {
|
|||
logger.Trace("a message", "foo", "bar")
|
||||
have := out.String()
|
||||
// The timestamp is locale-dependent, so we want to trim that off
|
||||
// "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..."
|
||||
// "INFO [01-01|00:00:00.000] a message ..." -> "a message..."
|
||||
have = strings.Split(have, "]")[1]
|
||||
want := " a message foo=bar\n"
|
||||
if have != want {
|
||||
|
|
@ -42,7 +42,7 @@ func TestTerminalHandlerWithAttrs(t *testing.T) {
|
|||
logger.Trace("a message", "foo", "bar")
|
||||
have := out.String()
|
||||
// The timestamp is locale-dependent, so we want to trim that off
|
||||
// "INFO [01-01|00:00:00.000] a messag ..." -> "a messag..."
|
||||
// "INFO [01-01|00:00:00.000] a message ..." -> "a message..."
|
||||
have = strings.Split(have, "]")[1]
|
||||
want := " a message baz=bat foo=bar\n"
|
||||
if have != want {
|
||||
|
|
@ -97,7 +97,7 @@ func benchmarkLogger(b *testing.B, l Logger) {
|
|||
tt = time.Now()
|
||||
bigint = big.NewInt(100)
|
||||
nilbig *big.Int
|
||||
err = errors.New("Oh nooes it's crap")
|
||||
err = errors.New("oh nooes it's crap")
|
||||
)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
|
@ -126,7 +126,7 @@ func TestLoggerOutput(t *testing.T) {
|
|||
tt = time.Time{}
|
||||
bigint = big.NewInt(100)
|
||||
nilbig *big.Int
|
||||
err = errors.New("Oh nooes it's crap")
|
||||
err = errors.New("oh nooes it's crap")
|
||||
smallUint = uint256.NewInt(500_000)
|
||||
bigUint = &uint256.Int{0xff, 0xff, 0xff, 0xff}
|
||||
)
|
||||
|
|
@ -150,7 +150,7 @@ func TestLoggerOutput(t *testing.T) {
|
|||
|
||||
have := out.String()
|
||||
t.Logf("output %v", out.String())
|
||||
want := `INFO [11-07|19:14:33.821] This is a message foo=123 bytes="[0 0 0 0 0 0 0 0 0 0]" bonk="a string with text" time=0001-01-01T00:00:00+0000 bigint=100 nilbig=<nil> err="Oh nooes it's crap" struct="{A:Foo B:12}" struct="{A:Foo\nLinebreak B:122}" ptrstruct="&{A:Foo B:12}" smalluint=500,000 bigUint=1,600,660,942,523,603,594,864,898,306,482,794,244,293,965,082,972,225,630,372,095
|
||||
want := `INFO [11-07|19:14:33.821] This is a message foo=123 bytes="[0 0 0 0 0 0 0 0 0 0]" bonk="a string with text" time=0001-01-01T00:00:00+0000 bigint=100 nilbig=<nil> err="oh nooes it's crap" struct="{A:Foo B:12}" struct="{A:Foo\nLinebreak B:122}" ptrstruct="&{A:Foo B:12}" smalluint=500,000 bigUint=1,600,660,942,523,603,594,864,898,306,482,794,244,293,965,082,972,225,630,372,095
|
||||
`
|
||||
if !bytes.Equal([]byte(have)[25:], []byte(want)[25:]) {
|
||||
t.Errorf("Error\nhave: %q\nwant: %q", have, want)
|
||||
|
|
|
|||
|
|
@ -19,18 +19,18 @@ var (
|
|||
gcStats debug.GCStats
|
||||
)
|
||||
|
||||
// Capture new values for the Go garbage collector statistics exported in
|
||||
// debug.GCStats. This is designed to be called as a goroutine.
|
||||
// CaptureDebugGCStats captures new values for the Go garbage collector statistics
|
||||
// exported in debug.GCStats. This is designed to be called as a goroutine.
|
||||
func CaptureDebugGCStats(r Registry, d time.Duration) {
|
||||
for range time.Tick(d) {
|
||||
CaptureDebugGCStatsOnce(r)
|
||||
}
|
||||
}
|
||||
|
||||
// Capture new values for the Go garbage collector statistics exported in
|
||||
// debug.GCStats. This is designed to be called in a background goroutine.
|
||||
// Giving a registry which has not been given to RegisterDebugGCStats will
|
||||
// panic.
|
||||
// CaptureDebugGCStatsOnce captures new values for the Go garbage collector
|
||||
// statistics exported in debug.GCStats. This is designed to be called in
|
||||
// a background goroutine. Giving a registry which has not been given to
|
||||
// RegisterDebugGCStats will panic.
|
||||
//
|
||||
// Be careful (but much less so) with this because debug.ReadGCStats calls
|
||||
// the C function runtime·lock(runtime·mheap) which, while not a stop-the-world
|
||||
|
|
@ -50,9 +50,9 @@ func CaptureDebugGCStatsOnce(r Registry) {
|
|||
debugMetrics.GCStats.PauseTotal.Update(int64(gcStats.PauseTotal))
|
||||
}
|
||||
|
||||
// Register metrics for the Go garbage collector statistics exported in
|
||||
// debug.GCStats. The metrics are named by their fully-qualified Go symbols,
|
||||
// i.e. debug.GCStats.PauseTotal.
|
||||
// RegisterDebugGCStats registers metrics for the Go garbage collector statistics
|
||||
// exported in debug.GCStats. The metrics are named by their fully-qualified Go
|
||||
// symbols, i.e. debug.GCStats.PauseTotal.
|
||||
func RegisterDebugGCStats(r Registry) {
|
||||
debugMetrics.GCStats.LastGC = NewGauge()
|
||||
debugMetrics.GCStats.NumGC = NewGauge()
|
||||
|
|
|
|||
|
|
@ -103,18 +103,18 @@ func TestExpDecaySample(t *testing.T) {
|
|||
}
|
||||
snap := sample.Snapshot()
|
||||
if have, want := int(snap.Count()), tc.updates; have != want {
|
||||
t.Errorf("have %d want %d", have, want)
|
||||
t.Errorf("unexpected count: have %d want %d", have, want)
|
||||
}
|
||||
if have, want := snap.Size(), min(tc.updates, tc.reservoirSize); have != want {
|
||||
t.Errorf("have %d want %d", have, want)
|
||||
t.Errorf("unexpected size: have %d want %d", have, want)
|
||||
}
|
||||
values := snap.(*sampleSnapshot).values
|
||||
if have, want := len(values), min(tc.updates, tc.reservoirSize); have != want {
|
||||
t.Errorf("have %d want %d", have, want)
|
||||
t.Errorf("unexpected values length: have %d want %d", have, want)
|
||||
}
|
||||
for _, v := range values {
|
||||
if v > int64(tc.updates) || v < 0 {
|
||||
t.Errorf("out of range [0, %d): %v", tc.updates, v)
|
||||
t.Errorf("out of range [0, %d]: %v", tc.updates, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -125,12 +125,12 @@ func TestExpDecaySample(t *testing.T) {
|
|||
// The priority becomes +Inf quickly after starting if this is done,
|
||||
// effectively freezing the set of samples until a rescale step happens.
|
||||
func TestExpDecaySampleNanosecondRegression(t *testing.T) {
|
||||
sw := NewExpDecaySample(100, 0.99)
|
||||
for i := 0; i < 100; i++ {
|
||||
sw := NewExpDecaySample(1000, 0.99)
|
||||
for i := 0; i < 1000; i++ {
|
||||
sw.Update(10)
|
||||
}
|
||||
time.Sleep(1 * time.Millisecond)
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := 0; i < 1000; i++ {
|
||||
sw.Update(20)
|
||||
}
|
||||
s := sw.Snapshot()
|
||||
|
|
@ -195,7 +195,7 @@ func TestUniformSample(t *testing.T) {
|
|||
}
|
||||
for _, v := range values {
|
||||
if v > 1000 || v < 0 {
|
||||
t.Errorf("out of range [0, 100): %v\n", v)
|
||||
t.Errorf("out of range [0, 1000]: %v\n", v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -251,6 +251,9 @@ func benchmarkSample(b *testing.B, s Sample) {
|
|||
}
|
||||
|
||||
func testExpDecaySampleStatistics(t *testing.T, s SampleSnapshot) {
|
||||
if sum := s.Sum(); sum != 496598 {
|
||||
t.Errorf("s.Sum(): 496598 != %v\n", sum)
|
||||
}
|
||||
if count := s.Count(); count != 10000 {
|
||||
t.Errorf("s.Count(): 10000 != %v\n", count)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ type Config struct {
|
|||
// DefaultConfig contains default settings for miner.
|
||||
var DefaultConfig = Config{
|
||||
GasCeil: 30_000_000,
|
||||
GasPrice: big.NewInt(params.GWei),
|
||||
GasPrice: big.NewInt(params.GWei / 1000),
|
||||
|
||||
// The default recommit time is chosen as two seconds since
|
||||
// consensus-layer usually will wait a half slot of time(6s)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue