From c225f714737b593b396024b135c5b1379276df2d Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Wed, 7 Sep 2022 11:53:08 -0600 Subject: [PATCH 1/3] params,core: add more compact summary of chain config for bad blocks Co-authored-by: lightclient Co-authored-by: Felix Lange --- core/badblock.go | 119 +++++++++++++++++++++++++++++++++++++++++++++ core/blockchain.go | 21 +------- les/client.go | 2 +- params/config.go | 4 +- 4 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 core/badblock.go diff --git a/core/badblock.go b/core/badblock.go new file mode 100644 index 000000000000..003b1c8df266 --- /dev/null +++ b/core/badblock.go @@ -0,0 +1,119 @@ +// Copyright 2022 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 . + +package core + +import ( + "fmt" + "runtime" + "runtime/debug" + "strings" + + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/params" +) + +const ourPath = "github.com/ethereum/go-ethereum" // Path to our module + +// summarizeBadBlock returns a string summarizing the bad block and other +// relevant information. +func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string { + var receiptString string + for i, receipt := range receipts { + receiptString += fmt.Sprintf(" %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x\n", + i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), + receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) + } + return fmt.Sprintf(` +########## BAD BLOCK ######### +Block: %v (%#x) +Error: %v +Version: %v +Chain config: %#v +Receipts: +%v############################## +`, block.Number(), block.Hash(), err, runtimeInfo(), config, receiptString) +} + +// RuntimeInfo returns build and platform information about the current binary. +// +// If the package that is currently executing is a prefixed by our go-ethereum +// module path, it will print out commit and date VCS information. Otherwise, +// it will assume it's imported by a third-party and will return the imported +// version and whether it was replaced by another module. +func runtimeInfo() string { + var ( + version string + buildInfo, ok = debug.ReadBuildInfo() + ) + + switch { + case !ok: + // BuildInfo should generally be set. Fallback to the coded + // version if not. + version = params.VersionWithMeta + case strings.HasPrefix(buildInfo.Path, ourPath): + // If the main package is from our repo, we can actually + // retrieve the VCS information directly from the buildInfo. + revision, date, dirty := vcsInfo(buildInfo) + version = fmt.Sprintf("geth %s", params.VersionWithCommit(revision, date)) + if dirty { + version += " (dirty)" + } + default: + // Not our main package, probably imported by a different + // project. VCS data less relevant here. + mod := findModule(buildInfo, ourPath) + version = fmt.Sprintf("%s%s %s@%s", buildInfo.Path, buildInfo.Main.Version, mod.Path, mod.Version) + if mod.Replace != nil { + version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) + } + } + return fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) +} + +// findModule returns the module at path. +func findModule(info *debug.BuildInfo, path string) *debug.Module { + if info.Path == ourPath { + return &info.Main + } + for _, mod := range info.Deps { + if mod.Path == path { + return mod + } + } + return nil +} + +// vcsInfo returns VCS information of the build. +func vcsInfo(info *debug.BuildInfo) (revision, date string, dirty bool) { + revision = "unknown" + date = "unknown" + + for _, v := range info.Settings { + switch v.Key { + case "vcs.revision": + revision = v.Value + case "vcs.modified": + if v.Value == "true" { + dirty = true + } + case "vcs.time": + date = v.Value + } + } + return revision, date, dirty +} diff --git a/core/blockchain.go b/core/blockchain.go index f588cc50bd6f..0688d10f06a1 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -239,7 +239,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis } log.Info("") log.Info(strings.Repeat("-", 153)) - for _, line := range strings.Split(chainConfig.String(), "\n") { + for _, line := range strings.Split(chainConfig.Description(), "\n") { log.Info(line) } log.Info(strings.Repeat("-", 153)) @@ -2391,24 +2391,7 @@ func (bc *BlockChain) maintainTxIndex(ancients uint64) { // reportBlock logs a bad block error. func (bc *BlockChain) reportBlock(block *types.Block, receipts types.Receipts, err error) { rawdb.WriteBadBlock(bc.db, block) - - var receiptString string - for i, receipt := range receipts { - receiptString += fmt.Sprintf("\t %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x\n", - i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), - receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) - } - log.Error(fmt.Sprintf(` -########## BAD BLOCK ######### -Chain config: %v - -Number: %v -Hash: %#x -%v - -Error: %v -############################## -`, bc.chainConfig, block.Number(), block.Hash(), receiptString, err)) + log.Error(summarizeBadBlock(block, receipts, bc.Config(), err)) } // InsertHeaderChain attempts to insert the given header chain in to the local diff --git a/les/client.go b/les/client.go index 6e6beeb0001a..c304bf86f8a8 100644 --- a/les/client.go +++ b/les/client.go @@ -105,7 +105,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) { } log.Info("") log.Info(strings.Repeat("-", 153)) - for _, line := range strings.Split(chainConfig.String(), "\n") { + for _, line := range strings.Split(chainConfig.Description(), "\n") { log.Info(line) } log.Info(strings.Repeat("-", 153)) diff --git a/params/config.go b/params/config.go index d535d230493c..d0318c244cf1 100644 --- a/params/config.go +++ b/params/config.go @@ -406,8 +406,8 @@ func (c *CliqueConfig) String() string { return "clique" } -// String implements the fmt.Stringer interface. -func (c *ChainConfig) String() string { +// Description returns a human-readable description of ChainConfig. +func (c *ChainConfig) Description() string { var banner string // Create some basinc network config output From c9311a4e5b9f4486cf88b743fe27c6e78df5c554 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 15 Sep 2022 13:50:14 +0200 Subject: [PATCH 2/3] core: handle case where ourPath module is not found --- core/badblock.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/core/badblock.go b/core/badblock.go index 003b1c8df266..4afede8bb274 100644 --- a/core/badblock.go +++ b/core/badblock.go @@ -73,13 +73,18 @@ func runtimeInfo() string { if dirty { version += " (dirty)" } + default: // Not our main package, probably imported by a different // project. VCS data less relevant here. mod := findModule(buildInfo, ourPath) - version = fmt.Sprintf("%s%s %s@%s", buildInfo.Path, buildInfo.Main.Version, mod.Path, mod.Version) - if mod.Replace != nil { - version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) + if mod == nil { + version = params.VersionWithMeta + } else { + version = fmt.Sprintf("%s %s %s@%s", buildInfo.Path, buildInfo.Main.Version, mod.Path, mod.Version) + if mod.Replace != nil { + version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) + } } } return fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) From d695268c91b18db7b5491fe20327a54f2eee237c Mon Sep 17 00:00:00 2001 From: "lightclient@protonmail.com" Date: Fri, 16 Sep 2022 15:58:27 +0200 Subject: [PATCH 3/3] core: split out version and vcs getters in badblock --- core/badblock.go | 135 +++++++++++++++++++++++++++++------------------ 1 file changed, 84 insertions(+), 51 deletions(-) diff --git a/core/badblock.go b/core/badblock.go index 4afede8bb274..a2fdfac714da 100644 --- a/core/badblock.go +++ b/core/badblock.go @@ -33,92 +33,125 @@ const ourPath = "github.com/ethereum/go-ethereum" // Path to our module func summarizeBadBlock(block *types.Block, receipts []*types.Receipt, config *params.ChainConfig, err error) string { var receiptString string for i, receipt := range receipts { - receiptString += fmt.Sprintf(" %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x\n", + receiptString += fmt.Sprintf("\n %d: cumulative: %v gas: %v contract: %v status: %v tx: %v logs: %v bloom: %x state: %x", i, receipt.CumulativeGasUsed, receipt.GasUsed, receipt.ContractAddress.Hex(), receipt.Status, receipt.TxHash.Hex(), receipt.Logs, receipt.Bloom, receipt.PostState) } + version, vcs := runtimeInfo() + platform := fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) + if vcs != "" { + vcs = fmt.Sprintf("\nVCS: %s", vcs) + } return fmt.Sprintf(` ########## BAD BLOCK ######### Block: %v (%#x) Error: %v -Version: %v +Platform: %v%v Chain config: %#v -Receipts: -%v############################## -`, block.Number(), block.Hash(), err, runtimeInfo(), config, receiptString) +Receipts: %v +############################## +`, block.Number(), block.Hash(), err, platform, vcs, config, receiptString) } -// RuntimeInfo returns build and platform information about the current binary. +// runtimeInfo returns build and platform information about the current binary. // // If the package that is currently executing is a prefixed by our go-ethereum // module path, it will print out commit and date VCS information. Otherwise, // it will assume it's imported by a third-party and will return the imported // version and whether it was replaced by another module. -func runtimeInfo() string { +func runtimeInfo() (string, string) { var ( - version string + version = params.VersionWithMeta + vcs = "" buildInfo, ok = debug.ReadBuildInfo() ) - - switch { - case !ok: - // BuildInfo should generally be set. Fallback to the coded - // version if not. - version = params.VersionWithMeta - case strings.HasPrefix(buildInfo.Path, ourPath): - // If the main package is from our repo, we can actually - // retrieve the VCS information directly from the buildInfo. - revision, date, dirty := vcsInfo(buildInfo) - version = fmt.Sprintf("geth %s", params.VersionWithCommit(revision, date)) - if dirty { - version += " (dirty)" - } - - default: - // Not our main package, probably imported by a different - // project. VCS data less relevant here. - mod := findModule(buildInfo, ourPath) - if mod == nil { - version = params.VersionWithMeta - } else { - version = fmt.Sprintf("%s %s %s@%s", buildInfo.Path, buildInfo.Main.Version, mod.Path, mod.Version) - if mod.Replace != nil { - version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) + if ok { + version = versionInfo(buildInfo) + if status, ok := vcsInfo(buildInfo); ok { + modified := "" + if status.modified { + modified = " (dirty)" } + vcs = status.revision + "-" + status.time + modified } } - return fmt.Sprintf("%s %s %s %s", version, runtime.Version(), runtime.GOARCH, runtime.GOOS) + return version, vcs } -// findModule returns the module at path. -func findModule(info *debug.BuildInfo, path string) *debug.Module { - if info.Path == ourPath { - return &info.Main +// versionInfo returns version information for the currently executing +// implementation. +// +// Depending on how the code is instansiated, it returns different amounts of +// information. If it is unable to determine which module is related to our +// package it falls back to the hardcoded values in the params package. +func versionInfo(info *debug.BuildInfo) string { + // If the main package is from our repo, prefix version with "geth". + if strings.HasPrefix(info.Path, ourPath) { + return fmt.Sprintf("geth %s", info.Main.Version) } - for _, mod := range info.Deps { - if mod.Path == path { - return mod - } + // Not our main package, so explicitly print out the module path and + // version. + var version string + if info.Main.Path != "" && info.Main.Version != "" { + // These can be empty when invoked with "go run". + version = fmt.Sprintf("%s@%s ", info.Main.Path, info.Main.Version) } - return nil + mod := findModule(info, ourPath) + if mod == nil { + // If our module path wasn't imported, it's unclear which + // version of our code they are running. Fallback to hardcoded + // version. + return version + fmt.Sprintf("geth %s", params.VersionWithMeta) + } + // Our package is a dependency for the main module. Return path and + // version data for both. + version += fmt.Sprintf("%s@%s", mod.Path, mod.Version) + if mod.Replace != nil { + // If our package was replaced by something else, also note that. + version += fmt.Sprintf(" (replaced by %s@%s)", mod.Replace.Path, mod.Replace.Version) + } + return version } -// vcsInfo returns VCS information of the build. -func vcsInfo(info *debug.BuildInfo) (revision, date string, dirty bool) { - revision = "unknown" - date = "unknown" +type status struct { + revision string + time string + modified bool +} +// vcsInfo returns VCS information of the build. +func vcsInfo(info *debug.BuildInfo) (s status, ok bool) { for _, v := range info.Settings { switch v.Key { case "vcs.revision": - revision = v.Value + if len(v.Value) < 8 { + s.revision = v.Value + } else { + s.revision = v.Value[:8] + } case "vcs.modified": if v.Value == "true" { - dirty = true + s.modified = true } case "vcs.time": - date = v.Value + s.time = v.Value } } - return revision, date, dirty + if s.revision != "" && s.time != "" { + ok = true + } + return +} + +// findModule returns the module at path. +func findModule(info *debug.BuildInfo, path string) *debug.Module { + if info.Path == ourPath { + return &info.Main + } + for _, mod := range info.Deps { + if mod.Path == path { + return mod + } + } + return nil }