Skip to content

Commit dcef8f7

Browse files
authored
execution: rationalise extremely verbose bal logging (erigontech#21649)
## engineapi, stagedsync: quiet per-block BAL logging, report mismatches via error log + file dumps ## Why On Amsterdam devnets every `engine_newPayload` logged the full decoded BAL (`bal from header: ...`) and every executed block logged an additional `bal` debug line, producing large blocks of debug output in steady state. Meanwhile the signal that actually matters — a BAL mismatch — was handled inconsistently: one mismatch site dumped the entire BAL body inline into the log stream, the other emitted multi-line debug strings plus ad-hoc file writes. ## What - Remove the per-newPayload `bal from header` debug dump (`engine_server.go`) and the per-block `bal` debug line (`ProcessBAL`). Steady-state BAL logging is now silent. - Extract mismatch reporting into `reportBALMismatch`, used by both mismatch checks in `ProcessBAL` (delivered-BAL-vs-header and computed-BAL-vs-header): - one structured error line: `blockNum`, `blockHash`, `blockBalHash` (committed in the header), `computedBlockBalHash` - dumps both BALs under `<datadir>/bal/` for offline diffing: `computed_bal_<N>.txt` (derived by us) and `block_bal_<N>.txt` (delivered with the block, when present) - Unify the two BAL file writers into a single `writeBALToFile`; the `dbg.TraceBlockAccessLists` trace path now writes the same `computed_bal_<N>.txt`. - Rename locals in `ProcessBAL` to make provenance explicit: `blockBal`/`blockBalHash`/`blockBalBytes` come from the block, `computedBlockBal`/`computedBlockBalHash` are what we arrived at; the delivered BAL is decoded once and its hash computed once. - Thread the caller's `log.Logger` through `ProcessBAL` and its helpers instead of the package-level logger (parallel executor passes `pe.logger`).
1 parent 348041b commit dcef8f7

3 files changed

Lines changed: 39 additions & 83 deletions

File tree

execution/engineapi/engine_server.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,6 @@ func (s *EngineServer) newPayload(ctx context.Context, req *engine_types.Executi
388388
}
389389
}
390390

391-
log.Debug(fmt.Sprintf("bal from header: %s", blockAccessList.DebugString()))
392-
393391
if (!s.config.IsCancun(header.Time) && version >= clparams.DenebVersion) ||
394392
(s.config.IsCancun(header.Time) && version < clparams.DenebVersion) ||
395393
(!s.config.IsPrague(header.Time) && version >= clparams.ElectraVersion) ||

execution/stagedsync/bal_create.go

Lines changed: 38 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os"
66
"path/filepath"
77

8+
"github.com/erigontech/erigon/common"
89
"github.com/erigontech/erigon/common/dbg"
910
"github.com/erigontech/erigon/common/log/v3"
1011
"github.com/erigontech/erigon/db/kv"
@@ -14,40 +15,31 @@ import (
1415
"github.com/erigontech/erigon/execution/types"
1516
)
1617

17-
func CreateBAL(blockNum uint64, txIO *state.VersionedIO, dataDir string) types.BlockAccessList {
18+
func CreateBAL(blockNum uint64, txIO *state.VersionedIO, dataDir string, logger log.Logger) types.BlockAccessList {
1819
bal := txIO.AsBlockAccessList()
1920
if dbg.TraceBlockAccessLists {
20-
writeBALToFile(bal, blockNum, dataDir)
21+
writeBALToFile(bal, dataDir, fmt.Sprintf("computed_bal_%d.txt", blockNum), logger)
2122
}
2223
return bal
2324
}
2425

25-
// writeBALToFile writes the Block Access List to a text file for debugging/analysis
26-
func writeBALToFile(bal types.BlockAccessList, blockNum uint64, dataDir string) {
26+
// writeBALToFile dumps the Block Access List to <dataDir>/bal/<name> for debugging/analysis.
27+
func writeBALToFile(bal types.BlockAccessList, dataDir string, name string, logger log.Logger) {
2728
if dataDir == "" {
2829
return
2930
}
30-
3131
balDir := filepath.Join(dataDir, "bal")
32-
if err := os.MkdirAll(balDir, 0755); err != nil {
33-
log.Warn("Failed to create BAL directory", "dir", balDir, "error", err)
32+
if err := os.MkdirAll(balDir, 0o755); err != nil {
33+
logger.Warn("failed to create BAL debug directory", "dir", balDir, "err", err)
3434
return
3535
}
36-
37-
filename := filepath.Join(balDir, fmt.Sprintf("bal_block_%d.txt", blockNum))
38-
39-
file, err := os.Create(filename)
40-
if err != nil {
41-
log.Warn("Failed to create BAL file", "blockNum", blockNum, "error", err)
42-
return
36+
path := filepath.Join(balDir, name)
37+
if err := os.WriteFile(path, []byte(bal.DebugString()), 0o644); err != nil {
38+
logger.Warn("failed to write BAL debug file", "path", path, "err", err)
4339
}
44-
defer file.Close()
45-
46-
fmt.Fprintf(file, "Block Access List for Block %d\n", blockNum)
47-
bal.DebugPrint(file)
4840
}
4941

50-
func ProcessBAL(tx kv.TemporalRwTx, h *types.Header, vio *state.VersionedIO, isEIP7928 bool, experimental bool, dataDir string) error {
42+
func ProcessBAL(tx kv.TemporalRwTx, h *types.Header, vio *state.VersionedIO, isEIP7928 bool, experimental bool, dataDir string, logger log.Logger) error {
5143
if !isEIP7928 && !experimental {
5244
return nil
5345
}
@@ -56,97 +48,63 @@ func ProcessBAL(tx kv.TemporalRwTx, h *types.Header, vio *state.VersionedIO, isE
5648
}
5749
blockNum := h.Number.Uint64()
5850
blockHash := h.Hash()
59-
bal := CreateBAL(blockNum, vio, dataDir)
60-
err := bal.Validate()
51+
computedBlockBal := CreateBAL(blockNum, vio, dataDir, logger)
52+
err := computedBlockBal.Validate()
6153
if err != nil {
6254
return fmt.Errorf("block %d: invalid computed block access list: %w", blockNum, err)
6355
}
64-
log.Debug("bal", "blockNum", blockNum, "hash", bal.Hash())
6556
if !isEIP7928 {
6657
return nil
6758
}
6859
// EIP-7928 size bound is only consensus-binding once Amsterdam activates.
69-
if err := bal.ValidateMaxItems(h.GasLimit); err != nil {
60+
if err := computedBlockBal.ValidateMaxItems(h.GasLimit); err != nil {
7061
return fmt.Errorf("%w, block %d: %w", rules.ErrInvalidBlock, blockNum, err)
7162
}
7263
if h.BlockAccessListHash == nil {
7364
return fmt.Errorf("block %d: EIP-7928 active but BlockAccessListHash is nil in header", blockNum)
7465
}
75-
headerBALHash := *h.BlockAccessListHash
76-
dbBALBytes, err := rawdb.ReadBlockAccessListBytes(tx, blockHash, blockNum)
66+
blockBalHash := *h.BlockAccessListHash
67+
blockBalBytes, err := rawdb.ReadBlockAccessListBytes(tx, blockHash, blockNum)
7768
if err != nil {
7869
return fmt.Errorf("block %d: read stored block access list: %w", blockNum, err)
7970
}
8071
// A stored BAL sidecar may be absent — eth/71 backfill is best-effort and
8172
// never blocks stage progress — so cross-check it only when present.
82-
if dbBALBytes != nil {
83-
dbBAL, err := types.DecodeBlockAccessListBytes(dbBALBytes)
73+
var blockBal types.BlockAccessList
74+
if blockBalBytes != nil {
75+
blockBal, err = types.DecodeBlockAccessListBytes(blockBalBytes)
8476
if err != nil {
8577
return fmt.Errorf("block %d: read stored block access list: %w", blockNum, err)
8678
}
87-
if err = dbBAL.Validate(); err != nil {
79+
if err = blockBal.Validate(); err != nil {
8880
return fmt.Errorf("block %d: db block access list is invalid: %w", blockNum, err)
8981
}
90-
if err = dbBAL.ValidateMaxItems(h.GasLimit); err != nil {
82+
if err = blockBal.ValidateMaxItems(h.GasLimit); err != nil {
9183
return fmt.Errorf("block %d: stored block access list exceeds max items: %w", blockNum, err)
9284
}
93-
94-
if headerBALHash != dbBAL.Hash() {
95-
log.Info(fmt.Sprintf("bal from block: %s", dbBAL.DebugString()))
96-
return fmt.Errorf("block %d: invalid block access list, hash mismatch: got %s expected %s", blockNum, dbBAL.Hash(), headerBALHash)
85+
if blockBalHash != blockBal.Hash() {
86+
reportBALMismatch(blockNum, blockHash, blockBal, blockBalHash, computedBlockBal, dataDir, logger)
87+
return fmt.Errorf("block %d: invalid block access list, hash mismatch: got %s expected %s", blockNum, blockBal.Hash(), blockBalHash)
9788
}
9889
}
9990
// Always validate computed BAL against header. The BalancePath cross-check
10091
// in VersionMap.validateRead ensures deterministic parallel execution even
10192
// without a stored BAL body (HasBAL=false), so the computed BAL is accurate.
102-
if headerBALHash != bal.Hash() {
103-
// Dump full BAL DebugStrings to stderr via the logger so container
104-
// stdout captures (kurtosis/docker log collection) preserve the diff
105-
// even when the on-disk dumpDir below is unreachable (e.g. ephemeral
106-
// container, CI runner without artifact capture of /data).
107-
// Each DebugString is one multi-line value tagged with block metadata
108-
// so operators can diff computed vs stored without hunting for files.
109-
computedDebug := bal.DebugString()
110-
var storedDebug string
111-
if dbBALBytes != nil {
112-
dbBAL2, decErr := types.DecodeBlockAccessListBytes(dbBALBytes)
113-
if decErr != nil {
114-
log.Warn("failed to decode stored BAL for debug dump", "err", decErr)
115-
} else if dbBAL2 != nil {
116-
storedDebug = dbBAL2.DebugString()
117-
}
118-
}
119-
log.Error("BAL mismatch: computed", "block", blockNum, "hash", bal.Hash(), "headerHash", headerBALHash, "bal", computedDebug)
120-
if storedDebug != "" {
121-
log.Error("BAL mismatch: stored (from sidecar)", "block", blockNum, "hash", headerBALHash, "bal", storedDebug)
122-
}
123-
124-
dumpDir := ""
125-
if dataDir != "" {
126-
balDir := filepath.Join(dataDir, "bal")
127-
if err := os.MkdirAll(balDir, 0o755); err != nil {
128-
log.Warn("failed to create BAL debug directory", "dir", balDir, "err", err)
129-
} else {
130-
computedPath := filepath.Join(balDir, fmt.Sprintf("computed_bal_%d.txt", blockNum))
131-
if err := os.WriteFile(computedPath, []byte(computedDebug), 0o644); err != nil {
132-
log.Warn("failed to write computed BAL debug file", "path", computedPath, "err", err)
133-
} else {
134-
dumpDir = balDir
135-
}
136-
if storedDebug != "" {
137-
storedPath := filepath.Join(balDir, fmt.Sprintf("stored_bal_%d.txt", blockNum))
138-
if err := os.WriteFile(storedPath, []byte(storedDebug), 0o644); err != nil {
139-
log.Warn("failed to write stored BAL debug file", "path", storedPath, "err", err)
140-
}
141-
}
142-
}
143-
}
144-
if dumpDir != "" {
145-
return fmt.Errorf("%w, block=%d (hash=%s): block access list mismatch: got %s expected %s; debug dumps in %s",
146-
rules.ErrInvalidBlock, blockNum, blockHash, bal.Hash(), headerBALHash, dumpDir)
147-
}
93+
computedBlockBalHash := computedBlockBal.Hash()
94+
if blockBalHash != computedBlockBalHash {
95+
reportBALMismatch(blockNum, blockHash, blockBal, blockBalHash, computedBlockBal, dataDir, logger)
14896
return fmt.Errorf("%w, block=%d (hash=%s): block access list mismatch: got %s expected %s",
149-
rules.ErrInvalidBlock, blockNum, blockHash, bal.Hash(), headerBALHash)
97+
rules.ErrInvalidBlock, blockNum, blockHash, computedBlockBalHash, blockBalHash)
15098
}
15199
return nil
152100
}
101+
102+
// reportBALMismatch logs a BAL hash mismatch and dumps the block's BAL and the
103+
// computed one under <dataDir>/bal for offline diffing.
104+
func reportBALMismatch(blockNum uint64, blockHash common.Hash, blockBal types.BlockAccessList, blockBalHash common.Hash, computedBlockBal types.BlockAccessList, dataDir string, logger log.Logger) {
105+
logger.Error("BAL mismatch", "blockNum", blockNum, "blockHash", blockHash, "blockBalHash", blockBalHash, "computedBlockBalHash", computedBlockBal.Hash())
106+
writeBALToFile(computedBlockBal, dataDir, fmt.Sprintf("computed_bal_%d.txt", blockNum), logger)
107+
if blockBal != nil {
108+
writeBALToFile(blockBal, dataDir, fmt.Sprintf("block_bal_%d.txt", blockNum), logger)
109+
}
110+
}

execution/stagedsync/exec3_parallel.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ func (pe *parallelExecutor) execImpl(ctx context.Context, execStage *StageState,
606606
}
607607

608608
if pe.cfg.chainConfig.IsAmsterdam(applyResult.BlockTime) || pe.cfg.experimentalBAL {
609-
err = ProcessBAL(rwTx, lastHeader, applyResult.TxIO, pe.cfg.chainConfig.IsAmsterdam(applyResult.BlockTime), pe.cfg.experimentalBAL, pe.cfg.dirs.DataDir)
609+
err = ProcessBAL(rwTx, lastHeader, applyResult.TxIO, pe.cfg.chainConfig.IsAmsterdam(applyResult.BlockTime), pe.cfg.experimentalBAL, pe.cfg.dirs.DataDir, pe.logger)
610610
if err != nil {
611611
return err
612612
}

0 commit comments

Comments
 (0)