Merge remote-tracking branch 'origin/master' into fix/freezer-incorrect-fsync-ordering

This commit is contained in:
Snehendu Roy 2026-04-16 18:10:11 +05:30
commit b269abadc9
No known key found for this signature in database
7 changed files with 266 additions and 85 deletions

View file

@ -115,7 +115,7 @@ var (
Name: "trace.noreturndata",
Aliases: []string{"noreturndata"},
Value: true,
Usage: "enable return data output",
Usage: "disable return data output",
Category: traceCategory,
}

View file

@ -1899,7 +1899,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
cfg.StatelessSelfValidation = ctx.Bool(VMStatelessSelfValidationFlag.Name)
}
// Auto-enable StatelessSelfValidation when witness stats are enabled
if ctx.Bool(VMWitnessStatsFlag.Name) {
if cfg.EnableWitnessStats {
cfg.StatelessSelfValidation = true
}

View file

@ -0,0 +1,98 @@
{
"genesis": {
"blobGasUsed": "0",
"difficulty": "0",
"excessBlobGas": "0",
"extraData": "0x",
"gasLimit": "11511229",
"hash": "0x455b93a512baa4ed5e117508b184a6bb03904b94d665ce38931728eca9cdd8fe",
"miner": "0x71562b71999873db5b286df957af199ec94617f7",
"mixHash": "0x042877c4fab9f022d29590ae83bad89d6181afb1d6e107619911ea52e5901364",
"nonce": "0x0000000000000000",
"number": "1",
"parentBeaconBlockRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
"stateRoot": "0xc8688ad6433e6b9f4edeb82360d2b99c8e919f493a01cacbe7c4a97184f5d043",
"timestamp": "1775654796",
"alloc": {
"0x71562b71999873db5b286df957af199ec94617f7": {
"balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffdb64910c3bf7",
"nonce": "1"
},
"0xe85a1c0e9d5b1c9b417c6c1b34c22cd77f623f50": {
"balance": "0x0",
"code": "0xef0100d313d93607c016a85e63e557a11ca5ab0b53ad83",
"codeHash": "0x9eea9f41ed2b35e6234d1e1c14e88c1136f85d56ed1f32a7efc0096d998dad3d",
"nonce": "1"
}
},
"config": {
"chainId": 1337,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
"istanbulBlock": 0,
"muirGlacierBlock": 0,
"berlinBlock": 0,
"londonBlock": 0,
"arrowGlacierBlock": 0,
"grayGlacierBlock": 0,
"shanghaiTime": 0,
"cancunTime": 0,
"pragueTime": 0,
"terminalTotalDifficulty": 0,
"blobSchedule": {
"cancun": {
"target": 3,
"max": 6,
"baseFeeUpdateFraction": 3338477
},
"prague": {
"target": 6,
"max": 9,
"baseFeeUpdateFraction": 5007716
}
}
}
},
"context": {
"number": "2",
"difficulty": "0",
"timestamp": "1775654797",
"gasLimit": "11522469",
"miner": "0x71562b71999873db5b286df957af199ec94617f7",
"baseFeePerGas": "766499147"
},
"input": "0x04f8cd82053901843b9aca008477359400830186a09471562b71999873db5b286df957af199ec94617f78080c0f85ef85c8205399400000000000000000000000000000000000000000101a011fc0271f2566e7ebe5ddbff6d48ea97a19afa248452a392781096b7e3b89177a0020107ecefe99c90429b416fe4d1eead5a7fa253761e85cd7cdc7df6e5032d7f80a098495fb16c904f0b67b49afe868b28b0159c8df07522bed99ef6ff2cc2ac2935a048857a9c385d91735a9fdccabc66de7a5ea1897f523a5b9a352e281642a76e6b",
"tracerConfig": {
"diffMode": true
},
"result": {
"post": {
"0x71562b71999873db5b286df957af199ec94617f7": {
"balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffc1bd12c85eb7",
"nonce": 2
},
"0xe85a1c0e9d5b1c9b417c6c1b34c22cd77f623f50": {
"code": "0x",
"codeHash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470",
"nonce": 2
}
},
"pre": {
"0x71562b71999873db5b286df957af199ec94617f7": {
"balance": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffdb64910c3bf7",
"nonce": 1
},
"0xe85a1c0e9d5b1c9b417c6c1b34c22cd77f623f50": {
"balance": "0x0",
"code": "0xef0100d313d93607c016a85e63e557a11ca5ab0b53ad83",
"codeHash": "0x9eea9f41ed2b35e6234d1e1c14e88c1136f85d56ed1f32a7efc0096d998dad3d",
"nonce": 1
}
}
}
}

View file

@ -16,14 +16,14 @@ var _ = (*accountMarshaling)(nil)
func (a account) MarshalJSON() ([]byte, error) {
type account struct {
Balance *hexutil.Big `json:"balance,omitempty"`
Code hexutil.Bytes `json:"code,omitempty"`
Code *hexutil.Bytes `json:"code,omitempty"`
CodeHash *common.Hash `json:"codeHash,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
}
var enc account
enc.Balance = (*hexutil.Big)(a.Balance)
enc.Code = a.Code
enc.Code = (*hexutil.Bytes)(a.Code)
enc.CodeHash = a.CodeHash
enc.Nonce = a.Nonce
enc.Storage = a.Storage
@ -47,7 +47,7 @@ func (a *account) UnmarshalJSON(input []byte) error {
a.Balance = (*big.Int)(dec.Balance)
}
if dec.Code != nil {
a.Code = *dec.Code
a.Code = (*[]byte)(dec.Code)
}
if dec.CodeHash != nil {
a.CodeHash = dec.CodeHash

View file

@ -44,21 +44,24 @@ func init() {
type stateMap = map[common.Address]*account
type account struct {
Balance *big.Int `json:"balance,omitempty"`
Code []byte `json:"code,omitempty"`
Balance *big.Int `json:"balance,omitempty"`
// Code is a pointer so omitempty can omit unchanged code (nil) while
// still emitting "0x" when code is cleared (e.g. EIP-7702 deauth).
Code *[]byte `json:"code,omitempty"`
CodeHash *common.Hash `json:"codeHash,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
empty bool
empty bool
}
func (a *account) exists() bool {
return a.Nonce > 0 || len(a.Code) > 0 || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
return a.Nonce > 0 || (a.Code != nil && len(*a.Code) > 0) || len(a.Storage) > 0 || (a.Balance != nil && a.Balance.Sign() != 0)
}
type accountMarshaling struct {
Balance *hexutil.Big
Code hexutil.Bytes
Code *hexutil.Bytes
}
type prestateTracer struct {
@ -266,24 +269,28 @@ func (t *prestateTracer) processDiffState() {
modified = true
postAccount.Nonce = newNonce
}
prevCodeHash := common.Hash{}
// Empty code hashes are excluded from the prestate, so default
// to EmptyCodeHash to match what GetCodeHash returns for codeless accounts.
prevCodeHash := types.EmptyCodeHash
if t.pre[addr].CodeHash != nil {
prevCodeHash = *t.pre[addr].CodeHash
}
// Empty code hashes are excluded from the prestate. Normalize
// the empty code hash to a zero hash to make it comparable.
if newCodeHash == types.EmptyCodeHash {
newCodeHash = common.Hash{}
}
if newCodeHash != prevCodeHash {
modified = true
postAccount.CodeHash = &newCodeHash
}
if !t.config.DisableCode {
newCode := t.env.StateDB.GetCode(addr)
if !bytes.Equal(newCode, t.pre[addr].Code) {
var prevCode []byte
if t.pre[addr].Code != nil {
prevCode = *t.pre[addr].Code
}
if !bytes.Equal(newCode, prevCode) {
modified = true
postAccount.Code = newCode
if newCode == nil {
newCode = []byte{}
}
postAccount.Code = &newCode
}
}
@ -323,10 +330,13 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
return
}
code := t.env.StateDB.GetCode(addr)
acc := &account{
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
Nonce: t.env.StateDB.GetNonce(addr),
Code: t.env.StateDB.GetCode(addr),
}
if len(code) > 0 {
acc.Code = &code
}
codeHash := t.env.StateDB.GetCodeHash(addr)
// If the code is empty, we don't need to store it in the prestate.

View file

@ -19,9 +19,7 @@ package log
import (
"context"
"errors"
"fmt"
"log/slog"
"maps"
"regexp"
"runtime"
"strconv"
@ -38,22 +36,22 @@ var errVmoduleSyntax = errors.New("expect comma-separated list of filename=N")
// matches; and requesting backtraces at certain positions.
type GlogHandler struct {
origin slog.Handler // The origin handler this wraps
lock sync.Mutex // synchronizes writes to config
config atomic.Pointer[glogConfig]
}
level atomic.Int32 // Current log level, atomically accessible
override atomic.Bool // Flag whether overrides are used, atomically accessible
patterns []pattern // Current list of patterns to override with
siteCache map[uintptr]slog.Level // Cache of callsite pattern evaluations
location string // file:line location where to do a stackdump at
lock sync.RWMutex // Lock protecting the override pattern list
type glogConfig struct {
patterns []pattern
cache sync.Map
level slog.Level
}
// NewGlogHandler creates a new log handler with filtering functionality similar
// to Google's glog logger. The returned handler implements Handler.
func NewGlogHandler(h slog.Handler) *GlogHandler {
return &GlogHandler{
origin: h,
}
func NewGlogHandler(origin slog.Handler) *GlogHandler {
h := &GlogHandler{origin: origin}
h.config.Store(new(glogConfig))
return h
}
// pattern contains a filter for the Vmodule option, holding a verbosity level
@ -66,7 +64,12 @@ type pattern struct {
// Verbosity sets the glog verbosity ceiling. The verbosity of individual packages
// and source files can be raised using Vmodule.
func (h *GlogHandler) Verbosity(level slog.Level) {
h.level.Store(int32(level))
h.lock.Lock()
defer h.lock.Unlock()
cfg := h.config.Load()
newcfg := &glogConfig{level: level, patterns: cfg.patterns}
h.config.Store(newcfg)
}
// Vmodule sets the glog verbosity pattern.
@ -128,13 +131,13 @@ func (h *GlogHandler) Vmodule(ruleset string) error {
re, _ := regexp.Compile(matcher)
filter = append(filter, pattern{re, level})
}
// Swap out the vmodule pattern for the new filter system
h.lock.Lock()
defer h.lock.Unlock()
h.patterns = filter
h.siteCache = make(map[uintptr]slog.Level)
h.override.Store(len(filter) != 0)
cfg := h.config.Load()
newcfg := &glogConfig{level: cfg.level, patterns: filter}
h.config.Store(newcfg)
h.lock.Unlock()
return nil
}
@ -142,30 +145,9 @@ func (h *GlogHandler) Vmodule(ruleset string) error {
// Enabled implements slog.Handler, reporting whether the handler handles records
// at the given level.
func (h *GlogHandler) Enabled(ctx context.Context, lvl slog.Level) bool {
// fast-track skipping logging if override not enabled and the provided verbosity is above configured
return h.override.Load() || slog.Level(h.level.Load()) <= lvl
}
// WithAttrs implements slog.Handler, returning a new Handler whose attributes
// consist of both the receiver's attributes and the arguments.
func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
h.lock.RLock()
siteCache := maps.Clone(h.siteCache)
h.lock.RUnlock()
patterns := []pattern{}
patterns = append(patterns, h.patterns...)
res := GlogHandler{
origin: h.origin.WithAttrs(attrs),
patterns: patterns,
siteCache: siteCache,
location: h.location,
}
res.level.Store(h.level.Load())
res.override.Store(h.override.Load())
return &res
// fast-track skipping logging if vmodule is not enabled or level too low
cfg := h.config.Load()
return len(cfg.patterns) > 0 || cfg.level <= lvl
}
// WithGroup implements slog.Handler, returning a new Handler with the given
@ -178,37 +160,70 @@ func (h *GlogHandler) WithGroup(name string) slog.Handler {
// Handle implements slog.Handler, filtering a log record through the global,
// local and backtrace filters, finally emitting it if either allow it through.
func (h *GlogHandler) Handle(_ context.Context, r slog.Record) error {
// If the global log level allows, fast track logging
if slog.Level(h.level.Load()) <= r.Level {
return h.origin.Handle(context.Background(), r)
}
func (h *GlogHandler) Handle(ctx context.Context, r slog.Record) error {
return h.handle(ctx, r, h.origin)
}
// Check callsite cache for previously calculated log levels
h.lock.RLock()
lvl, ok := h.siteCache[r.PC]
h.lock.RUnlock()
// If we didn't cache the callsite yet, calculate it
if !ok {
h.lock.Lock()
func (h *GlogHandler) handle(ctx context.Context, r slog.Record, origin slog.Handler) error {
cfg := h.config.Load()
var lvl slog.Level
cachedLvl, ok := cfg.cache.Load(r.PC)
if ok {
// Fast path: cache hit
lvl = cachedLvl.(slog.Level)
} else {
// Resolve the callsite file.
fs := runtime.CallersFrames([]uintptr{r.PC})
frame, _ := fs.Next()
for _, rule := range h.patterns {
if rule.pattern.MatchString(fmt.Sprintf("+%s", frame.File)) {
h.siteCache[r.PC], lvl, ok = rule.level, rule.level, true
file := frame.File
// Match against patterns and cache the level applied at this callsite.
lvl = cfg.level // default: use global level
for _, rule := range cfg.patterns {
if rule.pattern.MatchString("+" + file) {
lvl = rule.level
}
}
// If no rule matched, remember to drop log the next time
if !ok {
h.siteCache[r.PC] = 0
}
h.lock.Unlock()
cfg.cache.Store(r.PC, lvl)
}
// Handle the message.
if lvl <= r.Level {
return h.origin.Handle(context.Background(), r)
return origin.Handle(ctx, r)
}
return nil
}
// WithAttrs implements slog.Handler, returning a new Handler whose attributes
// consist of both the receiver's attributes and the arguments.
//
// Note the handler created here will still listen to Verbosity and Vmodule settings
// done on the original handler.
func (h *GlogHandler) WithAttrs(attrs []slog.Attr) slog.Handler {
return &glogWithAttrs{base: h, origin: h.origin.WithAttrs(attrs)}
}
type glogWithAttrs struct {
base *GlogHandler
origin slog.Handler
}
func (wh *glogWithAttrs) Enabled(ctx context.Context, lvl slog.Level) bool {
return wh.base.Enabled(ctx, lvl)
}
func (wh *glogWithAttrs) Handle(ctx context.Context, r slog.Record) error {
return wh.base.handle(ctx, r, wh.origin)
}
func (wh *glogWithAttrs) WithAttrs(attrs []slog.Attr) slog.Handler {
return &glogWithAttrs{base: wh.base, origin: wh.origin.WithAttrs(attrs)}
}
// WithGroup implements slog.Handler, returning a new Handler with the given
// group appended to the receiver's existing groups.
//
// Note, this function is not implemented.
func (wh *glogWithAttrs) WithGroup(name string) slog.Handler {
panic("not implemented")
}

View file

@ -33,6 +33,64 @@ func TestLoggingWithVmodule(t *testing.T) {
}
}
// TestLoggingWithVmoduleDowngrade checks that vmodule can be downgraded.
func TestLoggingWithVmoduleDowngrade(t *testing.T) {
out := new(bytes.Buffer)
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false))
glog.Verbosity(LevelTrace) // Allow all logs globally
logger := NewLogger(glog)
// This should appear (global level allows it)
logger.Info("before vmodule downgrade, this should be logged")
if !bytes.Contains(out.Bytes(), []byte("before vmodule downgrade")) {
t.Fatal("expected 'before vmodule downgrade' to be logged")
}
out.Reset()
// Downgrade this file to only allow Warn and above
glog.Vmodule("logger_test.go=2")
// Info should now be filtered out
logger.Info("after vmodule downgrade, this should be filtered")
if bytes.Contains(out.Bytes(), []byte("after vmodule downgrade, this should be filtered")) {
t.Fatal("expected 'after vmodule downgrade, this should be filtered' to NOT be logged after vmodule downgrade")
}
// Warn should still appear
logger.Warn("after vmodule downgrade, this should be logged")
if !bytes.Contains(out.Bytes(), []byte("after vmodule downgrade, this should be logged")) {
t.Fatal("expected 'should appear' to be logged")
}
}
// TestWithAttrsVerbosityChange checks that verbosity changes affect child loggers.
func TestWithAttrsVerbosityChange(t *testing.T) {
out := new(bytes.Buffer)
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false))
glog.Verbosity(LevelInfo)
// Create a child logger with an extra attribute.
child := slog.New(glog.WithAttrs([]slog.Attr{slog.String("peer", "foo")}))
// Debug should be filtered at Info level.
child.Debug("this should be filtered")
if bytes.Contains(out.Bytes(), []byte("this should be filtered")) {
t.Fatal("expected debug message to be filtered at Info level")
}
// Change verbosity on the parent to allow Debug.
glog.Verbosity(LevelDebug)
// Child should pick up the new level and include its attributes.
child.Debug("this should be logged")
if !bytes.Contains(out.Bytes(), []byte("this should be logged")) {
t.Fatal("expected child logger to pick up verbosity change")
}
if !bytes.Contains(out.Bytes(), []byte("peer=foo")) {
t.Fatal("expected child logger to include WithAttrs attributes")
}
}
func TestTerminalHandlerWithAttrs(t *testing.T) {
out := new(bytes.Buffer)
glog := NewGlogHandler(NewTerminalHandlerWithLevel(out, LevelTrace, false).WithAttrs([]slog.Attr{slog.String("baz", "bat")}))