Compare commits

..

8 Commits

Author SHA1 Message Date
emailtovamos
e149161d54 jsutil: correct the division 2024-05-21 15:42:58 +01:00
emailtovamos
cb0b34b7c2 jsutils: update logs 2024-05-16 14:34:11 +01:00
emailtovamos
5b7a71e38e jsutils: faucet balance 2024-05-16 12:25:25 +01:00
galaio
6b8cbbe172 sync: fix some sync issues caused by prune-block. (#2466) 2024-05-16 12:07:13 +08:00
setunapo
5ea2ada0ee utils: add check_blobtx.js (#2463) 2024-05-15 18:17:57 +08:00
Fynn
b230a02006 cmd: fix memory leak when big dataset (#2455) 2024-05-15 15:28:57 +08:00
Nathan
86e3a02490 cmd/utils: add a flag to change breathe block interval for testing (#2462) 2024-05-15 15:27:05 +08:00
Nathan
0c0958ff87 eth/handler: check lists in body before broadcast blocks (#2461) 2024-05-15 14:54:25 +08:00
31 changed files with 400 additions and 453 deletions

View File

@@ -280,7 +280,6 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) { if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name) cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name)
} }
cfg.Metrics.EnabledExpensive = true
if ctx.IsSet(utils.MetricsHTTPFlag.Name) { if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name) cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
} }

View File

@@ -106,12 +106,12 @@ Remove blockchain and state databases`,
dbInspectTrieCmd = &cli.Command{ dbInspectTrieCmd = &cli.Command{
Action: inspectTrie, Action: inspectTrie,
Name: "inspect-trie", Name: "inspect-trie",
ArgsUsage: "<blocknum> <jobnum>", ArgsUsage: "<blocknum> <jobnum> <topn>",
Flags: []cli.Flag{ Flags: []cli.Flag{
utils.DataDirFlag, utils.DataDirFlag,
utils.SyncModeFlag, utils.SyncModeFlag,
}, },
Usage: "Inspect the MPT tree of the account and contract.", Usage: "Inspect the MPT tree of the account and contract. 'blocknum' can be latest/snapshot/number. 'topn' means output the top N storage tries info ranked by the total number of TrieNodes",
Description: `This commands iterates the entrie WorldState.`, Description: `This commands iterates the entrie WorldState.`,
} }
dbCheckStateContentCmd = &cli.Command{ dbCheckStateContentCmd = &cli.Command{
@@ -386,6 +386,7 @@ func inspectTrie(ctx *cli.Context) error {
blockNumber uint64 blockNumber uint64
trieRootHash common.Hash trieRootHash common.Hash
jobnum uint64 jobnum uint64
topN uint64
) )
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
@@ -411,12 +412,25 @@ func inspectTrie(ctx *cli.Context) error {
if ctx.NArg() == 1 { if ctx.NArg() == 1 {
jobnum = 1000 jobnum = 1000
topN = 10
} else if ctx.NArg() == 2 {
var err error
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
if err != nil {
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
}
topN = 10
} else { } else {
var err error var err error
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64) jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
if err != nil { if err != nil {
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err) return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
} }
topN, err = strconv.ParseUint(ctx.Args().Get(2), 10, 64)
if err != nil {
return fmt.Errorf("failed to Parse topn, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
}
} }
if blockNumber != math.MaxUint64 { if blockNumber != math.MaxUint64 {
@@ -437,6 +451,7 @@ func inspectTrie(ctx *cli.Context) error {
if dbScheme == rawdb.PathScheme { if dbScheme == rawdb.PathScheme {
config = &triedb.Config{ config = &triedb.Config{
PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly), PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly),
Cache: 0,
} }
} else if dbScheme == rawdb.HashScheme { } else if dbScheme == rawdb.HashScheme {
config = triedb.HashDefaults config = triedb.HashDefaults
@@ -448,7 +463,7 @@ func inspectTrie(ctx *cli.Context) error {
fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String()) fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String())
return err return err
} }
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum) theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum, int(topN))
if err != nil { if err != nil {
return err return err
} }

View File

@@ -0,0 +1,51 @@
import { ethers } from "ethers";
import program from "commander";
// depends on ethjs v6.11.0+ for 4844, https://github.com/ethers-io/ethers.js/releases/tag/v6.11.0
// BSC testnet enabled 4844 on block: 39539137
// Usage:
// nvm use 20
// node check_blobtx.js --rpc https://data-seed-prebsc-1-s1.binance.org:8545 --startNum 39539137
// node check_blobtx.js --rpc https://data-seed-prebsc-1-s1.binance.org:8545 --startNum 39539137 --endNum 40345994
program.option("--rpc <Rpc>", "Rpc Server URL");
program.option("--startNum <Num>", "start block", 0);
program.option("--endNum <Num>", "end block", 0);
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.rpc);
const main = async () => {
var startBlock = parseInt(program.startNum)
var endBlock = parseInt(program.endNum)
if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) {
console.error("invalid input, --startNum", program.startNum, "--end", program.endNum)
return
}
// if --endNum is not specified, set it to the latest block number.
if (endBlock == 0) {
endBlock = await provider.getBlockNumber();
}
if (startBlock > endBlock) {
console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock);
return
}
for (let i = startBlock; i <= endBlock; i++) {
let blockData = await provider.getBlock(i);
console.log("startBlock:",startBlock, "endBlock:", endBlock, "curBlock", i, "blobGasUsed", blockData.blobGasUsed);
if (blockData.blobGasUsed == 0) {
continue
}
for (let txIndex = 0; txIndex<= blockData.transactions.length - 1; txIndex++) {
let txHash = blockData.transactions[txIndex]
let txData = await provider.getTransaction(txHash);
if (txData.type == 3) {
console.log("BlobTx in block:",i, " txIndex:", txIndex, " txHash:", txHash);
}
}
}
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -0,0 +1,49 @@
import { ethers } from "ethers";
import program from "commander";
// Usage:
// node faucet_request.js --rpc localhost:8545 --startNum 39539137
// node faucet_request.js --rpc localhost:8545 --startNum 39539137 --endNum 40345994
// node faucet_request.js --rpc https://data-seed-prebsc-1-s1.bnbchain.org:8545 --startNum 39539137 --endNum 40345994
program.option("--rpc <Rpc>", "Rpc Server URL");
program.option("--startNum <Num>", "start block", 0);
program.option("--endNum <Num>", "end block", 0);
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.rpc);
const main = async () => {
var startBlock = parseInt(program.startNum)
var endBlock = parseInt(program.endNum)
if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) {
console.error("invalid input, --startNum", program.startNum, "--end", program.endNum)
return
}
// if --endNum is not specified, set it to the latest block number.
if (endBlock == 0) {
endBlock = await provider.getBlockNumber();
}
if (startBlock > endBlock) {
console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock);
return
}
let startBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", startBlock)
let endBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", endBlock)
const faucetAmount = BigInt(0.3 * 10**18); // Convert 0.3 ether to wei as a BigInt
const numFaucetRequest = (startBalance - endBalance) / faucetAmount;
// Convert BigInt to ether
const startBalanceEth = Number(startBalance) / 10**18;
const endBalanceEth = Number(endBalance) / 10**18;
console.log(`Start Balance: ${startBalanceEth} ETH`);
console.log(`End Balance: ${endBalanceEth} ETH`);
console.log("successful faucet request: ",numFaucetRequest);
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -66,6 +66,31 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
return validator return validator
} }
// ValidateListsInBody validates that UncleHash, WithdrawalsHash, and WithdrawalsHash correspond to the lists in the block body, respectively.
func ValidateListsInBody(block *types.Block) error {
header := block.Header()
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
}
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
}
// Withdrawals are present after the Shanghai fork.
if header.WithdrawalsHash != nil {
// Withdrawals list must be present in body after Shanghai.
if block.Withdrawals() == nil {
return errors.New("missing withdrawals in block body")
}
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
}
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
// Withdrawals are not allowed prior to shanghai fork
return errors.New("withdrawals present in block body")
}
return nil
}
// ValidateBody validates the given block's uncles and verifies the block // ValidateBody validates the given block's uncles and verifies the block
// header's transaction and uncle roots. The headers are assumed to be already // header's transaction and uncle roots. The headers are assumed to be already
// validated at this point. // validated at this point.
@@ -83,31 +108,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
if err := v.engine.VerifyUncles(v.bc, block); err != nil { if err := v.engine.VerifyUncles(v.bc, block); err != nil {
return err return err
} }
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
}
validateFuns := []func() error{ validateFuns := []func() error{
func() error { func() error {
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash { return ValidateListsInBody(block)
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
}
return nil
}, },
func() error { func() error {
// Withdrawals are present after the Shanghai fork.
if header.WithdrawalsHash != nil {
// Withdrawals list must be present in body after Shanghai.
if block.Withdrawals() == nil {
return errors.New("missing withdrawals in block body")
}
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
}
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
// Withdrawals are not allowed prior to shanghai fork
return errors.New("withdrawals present in block body")
}
// Blob transactions may be present after the Cancun fork. // Blob transactions may be present after the Cancun fork.
var blobs int var blobs int
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {

View File

@@ -441,7 +441,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
diskRoot = bc.triedb.Head() diskRoot = bc.triedb.Head()
} }
} }
diskRoot = common.HexToHash("0x59d2a69ad465dbadf78f99635af9ed8125636cbdedc50bda9668ab2ac677b17a")
if diskRoot != (common.Hash{}) { if diskRoot != (common.Hash{}) {
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot) log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
@@ -577,7 +576,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
} }
// Start tx indexer if it's enabled. // Start tx indexer if it's enabled.
if txLookupLimit != nil { if txLookupLimit != nil {
// bc.txIndexer = newTxIndexer(*txLookupLimit, bc) bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
} }
return bc, nil return bc, nil
} }
@@ -2268,16 +2267,20 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
bc.cacheBlock(block.Hash(), block) bc.cacheBlock(block.Hash(), block)
// Update the metrics touched during block processing and validation // Update the metrics touched during block processing and validation
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing) snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing) snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation) accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation) storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation) accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation) storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
blockExecutionTimer.Update(ptime) // The time spent on EVM processing triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
blockValidationTimer.Update(vtime) // The time spent on block validation trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
// Write the block to the chain and get the status. // Write the block to the chain and get the status.
var ( var (
@@ -2302,7 +2305,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
blockWriteTimer.UpdateSince(wstart) blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
blockInsertTimer.UpdateSince(start) blockInsertTimer.UpdateSince(start)
// Report the import stats before returning the various results // Report the import stats before returning the various results

View File

@@ -511,3 +511,12 @@ func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscr
func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription { func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription {
return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch)) return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch))
} }
// AncientTail retrieves the tail the ancients blocks
func (bc *BlockChain) AncientTail() (uint64, error) {
tail, err := bc.db.Tail()
if err != nil {
return 0, err
}
return tail, nil
}

View File

@@ -18,12 +18,10 @@ package rawdb
import ( import (
"encoding/binary" "encoding/binary"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
) )
// ReadSnapshotDisabled retrieves if the snapshot maintenance is disabled. // ReadSnapshotDisabled retrieves if the snapshot maintenance is disabled.
@@ -76,10 +74,6 @@ func DeleteSnapshotRoot(db ethdb.KeyValueWriter) {
// ReadAccountSnapshot retrieves the snapshot entry of an account trie leaf. // ReadAccountSnapshot retrieves the snapshot entry of an account trie leaf.
func ReadAccountSnapshot(db ethdb.KeyValueReader, hash common.Hash) []byte { func ReadAccountSnapshot(db ethdb.KeyValueReader, hash common.Hash) []byte {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { rawdbGetAccountSnapNodeTimer.UpdateSince(start) }()
}
data, _ := db.Get(accountSnapshotKey(hash)) data, _ := db.Get(accountSnapshotKey(hash))
return data return data
} }
@@ -100,10 +94,6 @@ func DeleteAccountSnapshot(db ethdb.KeyValueWriter, hash common.Hash) {
// ReadStorageSnapshot retrieves the snapshot entry of an storage trie leaf. // ReadStorageSnapshot retrieves the snapshot entry of an storage trie leaf.
func ReadStorageSnapshot(db ethdb.KeyValueReader, accountHash, storageHash common.Hash) []byte { func ReadStorageSnapshot(db ethdb.KeyValueReader, accountHash, storageHash common.Hash) []byte {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { rawdbGetStorageSnapNodeTimer.UpdateSince(start) }()
}
data, _ := db.Get(storageSnapshotKey(accountHash, storageHash)) data, _ := db.Get(storageSnapshotKey(accountHash, storageHash))
return data return data
} }

View File

@@ -19,13 +19,11 @@ package rawdb
import ( import (
"fmt" "fmt"
"sync" "sync"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
) )
@@ -70,10 +68,6 @@ func (h *hasher) release() {
// ReadAccountTrieNode retrieves the account trie node and the associated node // ReadAccountTrieNode retrieves the account trie node and the associated node
// hash with the specified node path. // hash with the specified node path.
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) { func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { rawdbGetAccountTrieNodeTimer.UpdateSince(start) }()
}
data, err := db.Get(accountTrieNodeKey(path)) data, err := db.Get(accountTrieNodeKey(path))
if err != nil { if err != nil {
return nil, common.Hash{} return nil, common.Hash{}
@@ -122,10 +116,6 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) {
// ReadStorageTrieNode retrieves the storage trie node and the associated node // ReadStorageTrieNode retrieves the storage trie node and the associated node
// hash with the specified node path. // hash with the specified node path.
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) { func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { rawdbGetStorageTrieNodeTimer.UpdateSince(start) }()
}
data, err := db.Get(storageTrieNodeKey(accountHash, path)) data, err := db.Get(storageTrieNodeKey(accountHash, path))
if err != nil { if err != nil {
return nil, common.Hash{} return nil, common.Hash{}
@@ -228,22 +218,7 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c
func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte { func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte {
switch scheme { switch scheme {
case HashScheme: case HashScheme:
var ( return ReadLegacyTrieNode(db, hash)
blob []byte
start time.Time
)
start = time.Now()
blob = ReadLegacyTrieNode(db, hash)
if owner == (common.Hash{}) {
if metrics.EnabledExpensive {
rawdbGetAccountTrieNodeTimer.UpdateSince(start)
}
} else {
if metrics.EnabledExpensive {
rawdbGetStorageTrieNodeTimer.UpdateSince(start)
}
}
return blob
case PathScheme: case PathScheme:
var ( var (
blob []byte blob []byte

View File

@@ -239,7 +239,7 @@ func (f *Freezer) Ancient(kind string, number uint64) ([]byte, error) {
// - if maxBytes is not specified, 'count' items will be returned if they are present. // - if maxBytes is not specified, 'count' items will be returned if they are present.
func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) { func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
if table := f.tables[kind]; table != nil { if table := f.tables[kind]; table != nil {
return table.RetrieveItems(start, count, maxBytes) return table.RetrieveItems(start-f.offset, count, maxBytes)
} }
return nil, errUnknownTable return nil, errUnknownTable
} }
@@ -252,7 +252,7 @@ func (f *Freezer) Ancients() (uint64, error) {
func (f *Freezer) TableAncients(kind string) (uint64, error) { func (f *Freezer) TableAncients(kind string) (uint64, error) {
f.writeLock.RLock() f.writeLock.RLock()
defer f.writeLock.RUnlock() defer f.writeLock.RUnlock()
return f.tables[kind].items.Load(), nil return f.tables[kind].items.Load() + f.offset, nil
} }
// ItemAmountInAncient returns the actual length of current ancientDB. // ItemAmountInAncient returns the actual length of current ancientDB.

View File

@@ -1,10 +0,0 @@
package rawdb
import "github.com/ethereum/go-ethereum/metrics"
var (
rawdbGetAccountTrieNodeTimer = metrics.NewRegisteredTimer("rawdb/get/account/trienode/time", nil)
rawdbGetStorageTrieNodeTimer = metrics.NewRegisteredTimer("rawdb/get/storage/trienode/time", nil)
rawdbGetAccountSnapNodeTimer = metrics.NewRegisteredTimer("rawdb/get/account/snapnode/time", nil)
rawdbGetStorageSnapNodeTimer = metrics.NewRegisteredTimer("rawdb/get/storage/snapnode/time", nil)
)

View File

@@ -236,7 +236,7 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, roo
snap.layers[head.Root()] = head snap.layers[head.Root()] = head
head = head.Parent() head = head.Parent()
} }
log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root, "snapshot_cache_size", common.StorageSize(config.CacheSize)*1024*1024) log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root)
return snap, nil return snap, nil
} }

View File

@@ -20,7 +20,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
@@ -30,14 +29,9 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
) )
var (
processTxTimer = metrics.NewRegisteredTimer("process/tx/time", nil)
)
// StateProcessor is a basic Processor, which takes care of transitioning // StateProcessor is a basic Processor, which takes care of transitioning
// state from one point to another. // state from one point to another.
// //
@@ -110,10 +104,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
systemTxs := make([]*types.Transaction, 0, 2) systemTxs := make([]*types.Transaction, 0, 2)
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
if metrics.EnabledExpensive {
start := time.Now()
defer processTxTimer.UpdateSince(start)
}
if isPoSA { if isPoSA {
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
bloomProcessors.Close() bloomProcessors.Close()

View File

@@ -53,7 +53,6 @@ type txIndexer struct {
// newTxIndexer initializes the transaction indexer. // newTxIndexer initializes the transaction indexer.
func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer { func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer {
limit = 0
indexer := &txIndexer{ indexer := &txIndexer{
limit: limit, limit: limit,
db: chain.db, db: chain.db,

View File

@@ -161,12 +161,11 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
// Optimize memory distribution by reallocating surplus allowance from the // Optimize memory distribution by reallocating surplus allowance from the
// dirty cache to the clean cache. // dirty cache to the clean cache.
if config.StateScheme == rawdb.PathScheme && config.TrieDirtyCache > pathdb.MaxDirtyBufferSize/1024/1024 { if config.StateScheme == rawdb.PathScheme && config.TrieDirtyCache > pathdb.MaxDirtyBufferSize/1024/1024 {
config.TrieCleanCache += config.TrieDirtyCache - pathdb.MaxDirtyBufferSize/1024/1024
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024, "adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize)) log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024, "adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize))
log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024) log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024)
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
} }
log.Info("Allocated trie memory caches", "schema", config.StateScheme, "trie_clean_cache", common.StorageSize(config.TrieCleanCache)*1024*1024, "trie_dirty_cache", common.StorageSize(config.TrieDirtyCache)*1024*1024, "snapshot_cache", common.StorageSize(config.SnapshotCache)*1024*1024) log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
// Try to recover offline state pruning only in hash-based. // Try to recover offline state pruning only in hash-based.
if config.StateScheme == rawdb.HashScheme { if config.StateScheme == rawdb.HashScheme {

View File

@@ -209,6 +209,9 @@ type BlockChain interface {
// UpdateChasingHead update remote best chain head, used by DA check now. // UpdateChasingHead update remote best chain head, used by DA check now.
UpdateChasingHead(head *types.Header) UpdateChasingHead(head *types.Header)
// AncientTail retrieves the tail the ancients blocks
AncientTail() (uint64, error)
} }
type DownloadOption func(downloader *Downloader) *Downloader type DownloadOption func(downloader *Downloader) *Downloader
@@ -797,6 +800,11 @@ func (d *Downloader) findAncestor(p *peerConnection, localHeight uint64, remoteH
// We're above the max reorg threshold, find the earliest fork point // We're above the max reorg threshold, find the earliest fork point
floor = int64(localHeight - maxForkAncestry) floor = int64(localHeight - maxForkAncestry)
} }
// if we have pruned too much history, reset the floor
if tail, err := d.blockchain.AncientTail(); err == nil && tail > uint64(floor) {
floor = int64(tail)
}
// If we're doing a light sync, ensure the floor doesn't go below the CHT, as // If we're doing a light sync, ensure the floor doesn't go below the CHT, as
// all headers before that point will be missing. // all headers before that point will be missing.
if mode == LightSync { if mode == LightSync {

View File

@@ -320,26 +320,22 @@ func newHandler(config *handlerConfig) (*handler, error) {
} }
broadcastBlockWithCheck := func(block *types.Block, propagate bool) { broadcastBlockWithCheck := func(block *types.Block, propagate bool) {
// All the block fetcher activities should be disabled
// after the transition. Print the warning log.
if h.merger.PoSFinalized() {
log.Warn("Unexpected validation activity", "hash", block.Hash(), "number", block.Number())
return
}
// Reject all the PoS style headers in the first place. No matter
// the chain has finished the transition or not, the PoS headers
// should only come from the trusted consensus layer instead of
// p2p network.
if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok {
if beacon.IsPoSHeader(block.Header()) {
log.Warn("unexpected post-merge header")
return
}
}
if propagate { if propagate {
if err := core.IsDataAvailable(h.chain, block); err != nil { checkErrs := make(chan error, 2)
log.Error("Propagating block with invalid sidecars", "number", block.Number(), "hash", block.Hash(), "err", err)
return go func() {
checkErrs <- core.ValidateListsInBody(block)
}()
go func() {
checkErrs <- core.IsDataAvailable(h.chain, block)
}()
for i := 0; i < cap(checkErrs); i++ {
err := <-checkErrs
if err != nil {
log.Error("Propagating invalid block", "number", block.Number(), "hash", block.Hash(), "err", err)
return
}
} }
} }
h.BroadcastBlock(block, propagate) h.BroadcastBlock(block, propagate)

View File

@@ -131,9 +131,9 @@ func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumb
} }
// BlobSidecars return the Sidecars of a given block number or hash. // BlobSidecars return the Sidecars of a given block number or hash.
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) { func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, fullBlob bool) ([]*types.BlobTxSidecar, error) {
var r []*types.BlobTxSidecar var r []*types.BlobTxSidecar
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String(), true) err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String(), fullBlob)
if err == nil && r == nil { if err == nil && r == nil {
return nil, ethereum.NotFound return nil, ethereum.NotFound
} }
@@ -141,9 +141,9 @@ func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumbe
} }
// BlobSidecarByTxHash return a sidecar of a given blob transaction // BlobSidecarByTxHash return a sidecar of a given blob transaction
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) { func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash, fullBlob bool) (*types.BlobTxSidecar, error) {
var r *types.BlobTxSidecar var r *types.BlobTxSidecar
err := ec.c.CallContext(ctx, &r, "eth_getBlockSidecarByTxHash", hash, true) err := ec.c.CallContext(ctx, &r, "eth_getBlockSidecarByTxHash", hash, fullBlob)
if err == nil && r == nil { if err == nil && r == nil {
return nil, ethereum.NotFound return nil, ethereum.NotFound
} }

View File

@@ -111,18 +111,12 @@ func New(file string, cache int, handles int, namespace string, readonly bool) (
func NewCustom(file string, namespace string, customize func(options *opt.Options)) (*Database, error) { func NewCustom(file string, namespace string, customize func(options *opt.Options)) (*Database, error) {
options := configureOptions(customize) options := configureOptions(customize)
logger := log.New("database", file) logger := log.New("database", file)
// usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2 usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
logCtx := []interface{}{"handles", options.GetOpenFilesCacheCapacity()} logCtx := []interface{}{"cache", common.StorageSize(usedCache), "handles", options.GetOpenFilesCacheCapacity()}
if options.ReadOnly { if options.ReadOnly {
logCtx = append(logCtx, "readonly", "true") logCtx = append(logCtx, "readonly", "true")
} }
if options.BlockCacheCapacity != 0 { logger.Info("Allocated cache and file handles", logCtx...)
logCtx = append(logCtx, "block_cache_size", common.StorageSize(options.BlockCacheCapacity))
}
if options.WriteBuffer != 0 {
logCtx = append(logCtx, "memory_table_size", common.StorageSize(options.WriteBuffer))
}
logger.Info("Level db Allocated cache and file handles", logCtx...)
// Open the db and recover any potential corruptions // Open the db and recover any potential corruptions
db, err := leveldb.OpenFile(file, options) db, err := leveldb.OpenFile(file, options)
@@ -196,10 +190,6 @@ func (db *Database) Has(key []byte) (bool, error) {
// Get retrieves the given key if it's present in the key-value store. // Get retrieves the given key if it's present in the key-value store.
func (db *Database) Get(key []byte) ([]byte, error) { func (db *Database) Get(key []byte) ([]byte, error) {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { ethdb.EthdbGetTimer.UpdateSince(start) }()
}
dat, err := db.db.Get(key, nil) dat, err := db.db.Get(key, nil)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -209,19 +199,11 @@ func (db *Database) Get(key []byte) ([]byte, error) {
// Put inserts the given value into the key-value store. // Put inserts the given value into the key-value store.
func (db *Database) Put(key []byte, value []byte) error { func (db *Database) Put(key []byte, value []byte) error {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { ethdb.EthdbPutTimer.UpdateSince(start) }()
}
return db.db.Put(key, value, nil) return db.db.Put(key, value, nil)
} }
// Delete removes the key from the key-value store. // Delete removes the key from the key-value store.
func (db *Database) Delete(key []byte) error { func (db *Database) Delete(key []byte) error {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { ethdb.EthdbDeleteTimer.UpdateSince(start) }()
}
return db.db.Delete(key, nil) return db.db.Delete(key, nil)
} }
@@ -319,8 +301,6 @@ func (db *Database) meter(refresh time.Duration, namespace string) {
merr = err merr = err
continue continue
} }
fmt.Printf("loop print level db stats db_metrics=\n%v\n", stats)
db.log.Info("loop print level db stats", "stats", stats)
// Iterate over all the leveldbTable rows, and accumulate the entries // Iterate over all the leveldbTable rows, and accumulate the entries
for j := 0; j < len(compactions[i%2]); j++ { for j := 0; j < len(compactions[i%2]); j++ {
compactions[i%2][j] = 0 compactions[i%2][j] = 0
@@ -434,10 +414,6 @@ func (b *batch) ValueSize() int {
// Write flushes any accumulated data to disk. // Write flushes any accumulated data to disk.
func (b *batch) Write() error { func (b *batch) Write() error {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
}
return b.db.Write(b.b, nil) return b.db.Write(b.b, nil)
} }

View File

@@ -1,11 +0,0 @@
package ethdb
import "github.com/ethereum/go-ethereum/metrics"
var (
EthdbGetTimer = metrics.NewRegisteredTimer("ethdb/get/time", nil)
EthdbInnerGetTimer = metrics.NewRegisteredTimer("ethdb/inner/get/time", nil)
EthdbPutTimer = metrics.NewRegisteredTimer("ethdb/put/time", nil)
EthdbDeleteTimer = metrics.NewRegisteredTimer("ethdb/delete/time", nil)
EthdbBatchWriteTimer = metrics.NewRegisteredTimer("ethdb/batch/write/time", nil)
)

View File

@@ -183,8 +183,8 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
memTableSize = maxMemTableSize - 1 memTableSize = maxMemTableSize - 1
} }
logger.Info("Pebble db Allocated cache and file handles", "handles", handles, "block_cache_size", common.StorageSize(cache*1024*1024), logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024),
"memory_table_size", common.StorageSize(memTableSize)) "handles", handles, "memory table", common.StorageSize(memTableSize))
db := &Database{ db := &Database{
fn: file, fn: file,
@@ -309,69 +309,23 @@ func (d *Database) Has(key []byte) (bool, error) {
// Get retrieves the given key if it's present in the key-value store. // Get retrieves the given key if it's present in the key-value store.
func (d *Database) Get(key []byte) ([]byte, error) { func (d *Database) Get(key []byte) ([]byte, error) {
var (
step1Start time.Time
step1End time.Time
step2Start time.Time
step2End time.Time
step3Start time.Time
step3End time.Time
step4Start time.Time
step4End time.Time
keyLen int
valueLen int
)
if metrics.EnabledExpensive {
start := time.Now()
defer func() {
ethdb.EthdbGetTimer.UpdateSince(start)
if time.Now().Sub(start) > 100*time.Millisecond {
d.log.Error("perf pebble read",
"key", key,
"key_len", keyLen,
"value_len", valueLen,
"step1", common.PrettyDuration(step1End.Sub(step1Start)),
"step2", common.PrettyDuration(step2End.Sub(step2Start)),
"step3", common.PrettyDuration(step3End.Sub(step3Start)),
"step4", common.PrettyDuration(step4End.Sub(step4Start)))
}
}()
}
keyLen = len(key)
step1Start = time.Now()
d.quitLock.RLock() d.quitLock.RLock()
step1End = time.Now()
defer d.quitLock.RUnlock() defer d.quitLock.RUnlock()
if d.closed { if d.closed {
return nil, pebble.ErrClosed return nil, pebble.ErrClosed
} }
step2Start = time.Now()
innerStart := time.Now()
dat, closer, err := d.db.Get(key) dat, closer, err := d.db.Get(key)
valueLen = len(dat)
ethdb.EthdbInnerGetTimer.UpdateSince(innerStart)
step2End = time.Now()
if err != nil { if err != nil {
return nil, err return nil, err
} }
step3Start = time.Now()
ret := make([]byte, len(dat)) ret := make([]byte, len(dat))
copy(ret, dat) copy(ret, dat)
step3End = time.Now()
step4Start = time.Now()
closer.Close() closer.Close()
step4End = time.Now()
return ret, nil return ret, nil
} }
// Put inserts the given value into the key-value store. // Put inserts the given value into the key-value store.
func (d *Database) Put(key []byte, value []byte) error { func (d *Database) Put(key []byte, value []byte) error {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { ethdb.EthdbPutTimer.UpdateSince(start) }()
}
d.quitLock.RLock() d.quitLock.RLock()
defer d.quitLock.RUnlock() defer d.quitLock.RUnlock()
if d.closed { if d.closed {
@@ -382,10 +336,6 @@ func (d *Database) Put(key []byte, value []byte) error {
// Delete removes the key from the key-value store. // Delete removes the key from the key-value store.
func (d *Database) Delete(key []byte) error { func (d *Database) Delete(key []byte) error {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { ethdb.EthdbDeleteTimer.UpdateSince(start) }()
}
d.quitLock.RLock() d.quitLock.RLock()
defer d.quitLock.RUnlock() defer d.quitLock.RUnlock()
if d.closed { if d.closed {
@@ -544,9 +494,6 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
nonLevel0CompCount = int64(d.nonLevel0Comp.Load()) nonLevel0CompCount = int64(d.nonLevel0Comp.Load())
level0CompCount = int64(d.level0Comp.Load()) level0CompCount = int64(d.level0Comp.Load())
) )
fmt.Printf("loop print pebble db stats db_metrics=\n%v\n", stats)
d.log.Info("loop print pebble db stats", "comp_time", compTime, "write_delay_count", writeDelayCount, "write_delay_time",
writeDelayTime, "non_level0_comp_count", nonLevel0CompCount, "level0_comp_count", level0CompCount)
writeDelayTimes[i%2] = writeDelayTime writeDelayTimes[i%2] = writeDelayTime
writeDelayCounts[i%2] = writeDelayCount writeDelayCounts[i%2] = writeDelayCount
compTimes[i%2] = compTime compTimes[i%2] = compTime
@@ -652,10 +599,6 @@ func (b *batch) ValueSize() int {
// Write flushes any accumulated data to disk. // Write flushes any accumulated data to disk.
func (b *batch) Write() error { func (b *batch) Write() error {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
}
b.db.quitLock.RLock() b.db.quitLock.RLock()
defer b.db.quitLock.RUnlock() defer b.db.quitLock.RUnlock()
if b.db.closed { if b.db.closed {

View File

@@ -1010,11 +1010,7 @@ func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.
return result, nil return result, nil
} }
func (s *BlockChainAPI) GetBlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, fullBlob *bool) ([]map[string]interface{}, error) { func (s *BlockChainAPI) GetBlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, fullBlob bool) ([]map[string]interface{}, error) {
showBlob := true
if fullBlob != nil {
showBlob = *fullBlob
}
header, err := s.b.HeaderByNumberOrHash(ctx, blockNrOrHash) header, err := s.b.HeaderByNumberOrHash(ctx, blockNrOrHash)
if header == nil || err != nil { if header == nil || err != nil {
// When the block doesn't exist, the RPC method should return JSON null // When the block doesn't exist, the RPC method should return JSON null
@@ -1027,16 +1023,12 @@ func (s *BlockChainAPI) GetBlobSidecars(ctx context.Context, blockNrOrHash rpc.B
} }
result := make([]map[string]interface{}, len(blobSidecars)) result := make([]map[string]interface{}, len(blobSidecars))
for i, sidecar := range blobSidecars { for i, sidecar := range blobSidecars {
result[i] = marshalBlobSidecar(sidecar, showBlob) result[i] = marshalBlobSidecar(sidecar, fullBlob)
} }
return result, nil return result, nil
} }
func (s *BlockChainAPI) GetBlobSidecarByTxHash(ctx context.Context, hash common.Hash, fullBlob *bool) (map[string]interface{}, error) { func (s *BlockChainAPI) GetBlobSidecarByTxHash(ctx context.Context, hash common.Hash, fullBlob bool) (map[string]interface{}, error) {
showBlob := true
if fullBlob != nil {
showBlob = *fullBlob
}
txTarget, blockHash, _, Index := rawdb.ReadTransaction(s.b.ChainDb(), hash) txTarget, blockHash, _, Index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
if txTarget == nil { if txTarget == nil {
return nil, nil return nil, nil
@@ -1053,7 +1045,7 @@ func (s *BlockChainAPI) GetBlobSidecarByTxHash(ctx context.Context, hash common.
} }
for _, sidecar := range blobSidecars { for _, sidecar := range blobSidecars {
if sidecar.TxIndex == Index { if sidecar.TxIndex == Index {
return marshalBlobSidecar(sidecar, showBlob), nil return marshalBlobSidecar(sidecar, fullBlob), nil
} }
} }

View File

@@ -2204,7 +2204,7 @@ func TestRPCGetBlobSidecars(t *testing.T) {
result interface{} result interface{}
err error err error
) )
result, err = api.GetBlobSidecars(context.Background(), tt.test, &tt.fullBlob) result, err = api.GetBlobSidecars(context.Background(), tt.test, tt.fullBlob)
if err != nil { if err != nil {
t.Errorf("test %d: want no error, have %v", i, err) t.Errorf("test %d: want no error, have %v", i, err)
continue continue
@@ -2254,7 +2254,7 @@ func TestGetBlobSidecarByTxHash(t *testing.T) {
fullBlob: true, fullBlob: true,
file: "block-with-blobSidecars", file: "block-with-blobSidecars",
}, },
// 5. block show part blobs // 4. block show part blobs
{ {
test: txHashs[6], test: txHashs[6],
fullBlob: false, fullBlob: false,
@@ -2267,7 +2267,7 @@ func TestGetBlobSidecarByTxHash(t *testing.T) {
result interface{} result interface{}
err error err error
) )
result, err = api.GetBlobSidecarByTxHash(context.Background(), tt.test, &tt.fullBlob) result, err = api.GetBlobSidecarByTxHash(context.Background(), tt.test, tt.fullBlob)
if err != nil { if err != nil {
t.Errorf("test %d: want no error, have %v", i, err) t.Errorf("test %d: want no error, have %v", i, err)
continue continue

View File

@@ -37,8 +37,8 @@ type Config struct {
// DefaultConfig is the default config for metrics used in go-ethereum. // DefaultConfig is the default config for metrics used in go-ethereum.
var DefaultConfig = Config{ var DefaultConfig = Config{
Enabled: true, Enabled: false,
EnabledExpensive: true, EnabledExpensive: false,
HTTP: "127.0.0.1", HTTP: "127.0.0.1",
Port: 6060, Port: 6060,
EnableInfluxDB: false, EnableInfluxDB: false,

View File

@@ -22,12 +22,12 @@ import (
// //
// This global kill-switch helps quantify the observer effect and makes // This global kill-switch helps quantify the observer effect and makes
// for less cluttered pprof profiles. // for less cluttered pprof profiles.
var Enabled = true var Enabled = false
// EnabledExpensive is a soft-flag meant for external packages to check if costly // EnabledExpensive is a soft-flag meant for external packages to check if costly
// metrics gathering is allowed or not. The goal is to separate standard metrics // metrics gathering is allowed or not. The goal is to separate standard metrics
// for health monitoring and debug metrics that might impact runtime performance. // for health monitoring and debug metrics that might impact runtime performance.
var EnabledExpensive = true var EnabledExpensive = false
// enablerFlags is the CLI flag names to use to enable metrics collections. // enablerFlags is the CLI flag names to use to enable metrics collections.
var enablerFlags = []string{"metrics"} var enablerFlags = []string{"metrics"}

View File

@@ -70,10 +70,8 @@ const (
) )
var ( var (
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil) writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil)
finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil) finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil)
fillTxFnTimer = metrics.NewRegisteredTimer("worker/filltransactions/all", nil)
fillTxFnPartialTimer = metrics.NewRegisteredTimer("worker/filltransactions/partial", nil)
errBlockInterruptedByNewHead = errors.New("new head arrived while building block") errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block") errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
@@ -1058,8 +1056,6 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
// into the given sealing block. The transaction selection and ordering strategy can // into the given sealing block. The transaction selection and ordering strategy can
// be customized with the plugin in the future. // be customized with the plugin in the future.
func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer, bidTxs mapset.Set[common.Hash]) (err error) { func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer, bidTxs mapset.Set[common.Hash]) (err error) {
start := time.Now()
w.mu.RLock() w.mu.RLock()
tip := w.tip tip := w.tip
w.mu.RUnlock() w.mu.RUnlock()
@@ -1114,7 +1110,6 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
localBlobTxs[account] = txs localBlobTxs[account] = txs
} }
} }
fillTxFnPartialTimer.UpdateSince(start)
// Fill the block with all available pending transactions. // Fill the block with all available pending transactions.
// we will abort when: // we will abort when:
@@ -1139,7 +1134,6 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
return err return err
} }
} }
fillTxFnTimer.UpdateSince(start)
return nil return nil
} }

View File

@@ -4,17 +4,15 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"math/big"
"os"
"runtime" "runtime"
"sort" "strings"
"strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/mclock"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
@@ -26,63 +24,113 @@ import (
"golang.org/x/sync/semaphore" "golang.org/x/sync/semaphore"
) )
type Account struct {
Nonce uint64
Balance *big.Int
Root common.Hash // merkle root of the storage trie
CodeHash []byte
}
type Database interface { type Database interface {
database.Database database.Database
Scheme() string Scheme() string
Cap(limit common.StorageSize) error Cap(limit common.StorageSize) error
DiskDB() ethdb.Database DiskDB() ethdb.Database
} }
const TopN = 3
type Inspector struct { type Inspector struct {
trie *Trie // traverse trie trie *Trie // traverse trie
db Database db Database
stateRootHash common.Hash stateRootHash common.Hash
blocknum uint64 blockNum uint64
root node // root of triedb root node // root of triedb
totalNum uint64
wg sync.WaitGroup
statLock sync.RWMutex
result map[string]*TrieTreeStat
sem *semaphore.Weighted sem *semaphore.Weighted
eoaAccountNums uint64 eoaAccountNums uint64
wg sync.WaitGroup
results stat
topN int
totalAccountNum atomic.Uint64
totalStorageNum atomic.Uint64
lastTime mclock.AbsTime
} }
type TrieTreeStat struct { type stat struct {
is_account_trie bool lock sync.RWMutex
theNodeStatByLevel [15]NodeStat account *trieStat
totalNodeStat NodeStat storageTopN []*trieStat
storageTopNTotal []uint64
storageTotal nodeStat
storageTrieNum uint64
} }
type NodeStat struct { type trieStat struct {
ShortNodeCnt uint64 owner common.Hash
FullNodeCnt uint64 totalNodeStat nodeStat
ValueNodeCnt uint64 nodeStatByLevel [16]nodeStat
} }
func (trieStat *TrieTreeStat) AtomicAdd(theNode node, height uint32) { type nodeStat struct {
ShortNodeCnt atomic.Uint64
FullNodeCnt atomic.Uint64
ValueNodeCnt atomic.Uint64
}
func (ns *nodeStat) IsEmpty() bool {
if ns.FullNodeCnt.Load() == 0 && ns.ShortNodeCnt.Load() == 0 && ns.ValueNodeCnt.Load() == 0 {
return true
}
return false
}
func (s *stat) add(ts *trieStat, topN int) {
s.lock.Lock()
defer s.lock.Unlock()
if ts.owner == (common.Hash{}) {
s.account = ts
return
}
total := ts.totalNodeStat.ValueNodeCnt.Load() + ts.totalNodeStat.FullNodeCnt.Load() + ts.totalNodeStat.ShortNodeCnt.Load()
if len(s.storageTopNTotal) == 0 || total > s.storageTopNTotal[len(s.storageTopNTotal)-1] {
var (
i int
t uint64
)
for i, t = range s.storageTopNTotal {
if total < t {
continue
}
break
}
s.storageTopNTotal = append(s.storageTopNTotal[:i], append([]uint64{total}, s.storageTopNTotal[i:]...)...)
s.storageTopN = append(s.storageTopN[:i], append([]*trieStat{ts}, s.storageTopN[i:]...)...)
if len(s.storageTopN) > topN {
s.storageTopNTotal = s.storageTopNTotal[:topN]
s.storageTopN = s.storageTopN[:topN]
}
}
s.storageTotal.ShortNodeCnt.Add(ts.totalNodeStat.ShortNodeCnt.Load())
s.storageTotal.ValueNodeCnt.Add(ts.totalNodeStat.ValueNodeCnt.Load())
s.storageTotal.FullNodeCnt.Add(ts.totalNodeStat.FullNodeCnt.Load())
s.storageTrieNum++
}
func (trieStat *trieStat) add(theNode node, height int) {
switch (theNode).(type) { switch (theNode).(type) {
case *shortNode: case *shortNode:
atomic.AddUint64(&trieStat.totalNodeStat.ShortNodeCnt, 1) trieStat.totalNodeStat.ShortNodeCnt.Add(1)
atomic.AddUint64(&(trieStat.theNodeStatByLevel[height].ShortNodeCnt), 1) trieStat.nodeStatByLevel[height].ShortNodeCnt.Add(1)
case *fullNode: case *fullNode:
atomic.AddUint64(&trieStat.totalNodeStat.FullNodeCnt, 1) trieStat.totalNodeStat.FullNodeCnt.Add(1)
atomic.AddUint64(&trieStat.theNodeStatByLevel[height].FullNodeCnt, 1) trieStat.nodeStatByLevel[height].FullNodeCnt.Add(1)
case valueNode: case valueNode:
atomic.AddUint64(&trieStat.totalNodeStat.ValueNodeCnt, 1) trieStat.totalNodeStat.ValueNodeCnt.Add(1)
atomic.AddUint64(&((trieStat.theNodeStatByLevel[height]).ValueNodeCnt), 1) trieStat.nodeStatByLevel[height].ValueNodeCnt.Add(1)
default:
panic(errors.New("Invalid node type to statistics"))
} }
} }
func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) { func (trieStat *trieStat) Display(ownerAddress string, treeType string) string {
table := tablewriter.NewWriter(os.Stdout) sw := new(strings.Builder)
table := tablewriter.NewWriter(sw)
table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"}) table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"})
if ownerAddress == "" { if ownerAddress == "" {
table.SetCaption(true, fmt.Sprintf("%v", treeType)) table.SetCaption(true, fmt.Sprintf("%v", treeType))
@@ -90,38 +138,27 @@ func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) {
table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress)) table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress))
} }
table.SetAlignment(1) table.SetAlignment(1)
for i := 0; i < len(trieStat.theNodeStatByLevel); i++ {
nodeStat := trieStat.theNodeStatByLevel[i] for i := range trieStat.nodeStatByLevel {
if nodeStat.FullNodeCnt == 0 && nodeStat.ShortNodeCnt == 0 && nodeStat.ValueNodeCnt == 0 { if trieStat.nodeStatByLevel[i].IsEmpty() {
break continue
} }
table.AppendBulk([][]string{ table.AppendBulk([][]string{
{"-", strconv.Itoa(i), nodeStat.ShortNodeCount(), nodeStat.FullNodeCount(), nodeStat.ValueNodeCount()}, {"-", fmt.Sprintf("%d", i),
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ShortNodeCnt.Load()),
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].FullNodeCnt.Load()),
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ValueNodeCnt.Load())},
}) })
} }
table.AppendBulk([][]string{ table.AppendBulk([][]string{
{"Total", "-", trieStat.totalNodeStat.ShortNodeCount(), trieStat.totalNodeStat.FullNodeCount(), trieStat.totalNodeStat.ValueNodeCount()}, {"Total", "-", fmt.Sprintf("%d", trieStat.totalNodeStat.ShortNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.FullNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.ValueNodeCnt.Load())},
}) })
table.Render() table.Render()
} return sw.String()
func Uint64ToString(cnt uint64) string {
return fmt.Sprintf("%v", cnt)
}
func (nodeStat *NodeStat) ShortNodeCount() string {
return Uint64ToString(nodeStat.ShortNodeCnt)
}
func (nodeStat *NodeStat) FullNodeCount() string {
return Uint64ToString(nodeStat.FullNodeCnt)
}
func (nodeStat *NodeStat) ValueNodeCount() string {
return Uint64ToString(nodeStat.ValueNodeCnt)
} }
// NewInspector return a inspector obj // NewInspector return a inspector obj
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uint64, jobnum uint64) (*Inspector, error) { func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uint64, jobNum uint64, topN int) (*Inspector, error) {
if tr == nil { if tr == nil {
return nil, errors.New("trie is nil") return nil, errors.New("trie is nil")
} }
@@ -131,15 +168,20 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uin
} }
ins := &Inspector{ ins := &Inspector{
trie: tr, trie: tr,
db: db, db: db,
stateRootHash: stateRootHash, stateRootHash: stateRootHash,
blocknum: blocknum, blockNum: blockNum,
root: tr.root, root: tr.root,
result: make(map[string]*TrieTreeStat), results: stat{},
totalNum: (uint64)(0), topN: topN,
wg: sync.WaitGroup{}, totalAccountNum: atomic.Uint64{},
sem: semaphore.NewWeighted(int64(jobnum)), totalStorageNum: atomic.Uint64{},
lastTime: mclock.Now(),
sem: semaphore.NewWeighted(int64(jobNum)),
wg: sync.WaitGroup{},
eoaAccountNums: 0, eoaAccountNums: 0,
} }
@@ -147,155 +189,123 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uin
} }
// Run statistics, external call // Run statistics, external call
func (inspect *Inspector) Run() { func (s *Inspector) Run() {
accountTrieStat := &TrieTreeStat{ ticker := time.NewTicker(30 * time.Second)
is_account_trie: true, go func() {
} defer ticker.Stop()
if inspect.db.Scheme() == rawdb.HashScheme { for range ticker.C {
ticker := time.NewTicker(30 * time.Second) if s.db.Scheme() == rawdb.HashScheme {
go func() { s.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
defer ticker.Stop()
for range ticker.C {
inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
} }
}() runtime.GC()
} }
}()
if _, ok := inspect.result[""]; !ok { log.Info("Find Account Trie Tree", "rootHash: ", s.trie.Hash().String(), "BlockNum: ", s.blockNum)
inspect.result[""] = accountTrieStat
}
log.Info("Find Account Trie Tree", "rootHash: ", inspect.trie.Hash().String(), "BlockNum: ", inspect.blocknum)
inspect.ConcurrentTraversal(inspect.trie, accountTrieStat, inspect.root, 0, []byte{}) ts := &trieStat{
inspect.wg.Wait() owner: common.Hash{},
}
s.traversal(s.trie, ts, s.root, 0, []byte{})
s.results.add(ts, s.topN)
s.wg.Wait()
} }
func (inspect *Inspector) SubConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) { func (s *Inspector) traversal(trie *Trie, ts *trieStat, n node, height int, path []byte) {
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, theNode, height, path)
inspect.wg.Done()
}
func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) {
// print process progress
total_num := atomic.AddUint64(&inspect.totalNum, 1)
if total_num%100000 == 0 {
fmt.Printf("Complete progress: %v, go routines Num: %v\n", total_num, runtime.NumGoroutine())
}
// nil node // nil node
if theNode == nil { if n == nil {
return return
} }
switch current := (theNode).(type) { ts.add(n, height)
switch current := (n).(type) {
case *shortNode: case *shortNode:
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, current.Val, height, append(path, current.Key...)) s.traversal(trie, ts, current.Val, height, append(path, current.Key...))
case *fullNode: case *fullNode:
for idx, child := range current.Children { for idx, child := range current.Children {
if child == nil { if child == nil {
continue continue
} }
childPath := append(path, byte(idx)) p := common.CopyBytes(append(path, byte(idx)))
if inspect.sem.TryAcquire(1) { s.traversal(trie, ts, child, height+1, p)
inspect.wg.Add(1)
dst := make([]byte, len(childPath))
copy(dst, childPath)
go inspect.SubConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, dst)
} else {
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, childPath)
}
} }
case hashNode: case hashNode:
n, err := theTrie.resloveWithoutTrack(current, path) tn, err := trie.resloveWithoutTrack(current, path)
if err != nil { if err != nil {
fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, theTrie.Hash().String(), height+1, path) fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, trie.Hash().String(), height+1, path)
return return
} }
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, n, height, path) s.PrintProgress(trie)
return s.traversal(trie, ts, tn, height, path)
case valueNode: case valueNode:
if !hasTerm(path) { if !hasTerm(path) {
break break
} }
var account Account var account types.StateAccount
if err := rlp.Decode(bytes.NewReader(current), &account); err != nil { if err := rlp.Decode(bytes.NewReader(current), &account); err != nil {
break break
} }
if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash { if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash {
inspect.eoaAccountNums++ s.eoaAccountNums++
} }
if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash { if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash {
break break
} }
ownerAddress := common.BytesToHash(hexToCompact(path)) ownerAddress := common.BytesToHash(hexToCompact(path))
contractTrie, err := New(StorageTrieID(inspect.stateRootHash, ownerAddress, account.Root), inspect.db) contractTrie, err := New(StorageTrieID(s.stateRootHash, ownerAddress, account.Root), s.db)
if err != nil { if err != nil {
fmt.Printf("New contract trie node: %v, error: %v, Height: %v, Path: %v\n", theNode, err, height, path) panic(err)
break
} }
contractTrie.tracer.reset() contractTrie.tracer.reset()
trieStat := &TrieTreeStat{
is_account_trie: false,
}
inspect.statLock.Lock() if s.sem.TryAcquire(1) {
if _, ok := inspect.result[ownerAddress.String()]; !ok { s.wg.Add(1)
inspect.result[ownerAddress.String()] = trieStat go func() {
t := &trieStat{
owner: ownerAddress,
}
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
s.results.add(t, s.topN)
s.sem.Release(1)
s.wg.Done()
}()
} else {
t := &trieStat{
owner: ownerAddress,
}
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
s.results.add(t, s.topN)
} }
inspect.statLock.Unlock()
// log.Info("Find Contract Trie Tree, rootHash: ", contractTrie.Hash().String(), "")
inspect.wg.Add(1)
go inspect.SubConcurrentTraversal(contractTrie, trieStat, contractTrie.root, 0, []byte{})
default: default:
panic(errors.New("Invalid node type to traverse.")) panic(errors.New("invalid node type to traverse"))
} }
theTrieTreeStat.AtomicAdd(theNode, height)
} }
func (inspect *Inspector) DisplayResult() { func (s *Inspector) PrintProgress(t *Trie) {
var (
elapsed = mclock.Now().Sub(s.lastTime)
)
if t.owner == (common.Hash{}) {
s.totalAccountNum.Add(1)
} else {
s.totalStorageNum.Add(1)
}
if elapsed > 4*time.Second {
log.Info("traversal progress", "TotalAccountNum", s.totalAccountNum.Load(), "TotalStorageNum", s.totalStorageNum.Load(), "Goroutine", runtime.NumGoroutine())
s.lastTime = mclock.Now()
}
}
func (s *Inspector) DisplayResult() {
// display root hash // display root hash
if _, ok := inspect.result[""]; !ok { fmt.Println(s.results.account.Display("", "AccountTrie"))
log.Info("Display result error", "missing account trie") fmt.Println("EOA accounts num: ", s.eoaAccountNums)
return
}
inspect.result[""].Display("", "AccountTrie")
type SortedTrie struct {
totalNum uint64
ownerAddress string
}
// display contract trie // display contract trie
var sortedTriesByNums []SortedTrie for _, st := range s.results.storageTopN {
var totalContactsNodeStat NodeStat fmt.Println(st.Display(st.owner.String(), "StorageTrie"))
var contractTrieCnt uint64 = 0
for ownerAddress, stat := range inspect.result {
if ownerAddress == "" {
continue
}
contractTrieCnt++
totalContactsNodeStat.ShortNodeCnt += stat.totalNodeStat.ShortNodeCnt
totalContactsNodeStat.FullNodeCnt += stat.totalNodeStat.FullNodeCnt
totalContactsNodeStat.ValueNodeCnt += stat.totalNodeStat.ValueNodeCnt
totalNodeCnt := stat.totalNodeStat.ShortNodeCnt + stat.totalNodeStat.ValueNodeCnt + stat.totalNodeStat.FullNodeCnt
sortedTriesByNums = append(sortedTriesByNums, SortedTrie{totalNum: totalNodeCnt, ownerAddress: ownerAddress})
}
sort.Slice(sortedTriesByNums, func(i, j int) bool {
return sortedTriesByNums[i].totalNum > sortedTriesByNums[j].totalNum
})
fmt.Println("EOA accounts num: ", inspect.eoaAccountNums)
// only display top 5
for i, t := range sortedTriesByNums {
if i > 5 {
break
}
if stat, ok := inspect.result[t.ownerAddress]; !ok {
log.Error("Storage trie stat not found", "ownerAddress", t.ownerAddress)
} else {
stat.Display(t.ownerAddress, "ContractTrie")
}
} }
fmt.Printf("Contract Trie, total trie num: %v, ShortNodeCnt: %v, FullNodeCnt: %v, ValueNodeCnt: %v\n", fmt.Printf("Contract Trie, total trie num: %v, ShortNodeCnt: %v, FullNodeCnt: %v, ValueNodeCnt: %v\n",
contractTrieCnt, totalContactsNodeStat.ShortNodeCnt, totalContactsNodeStat.FullNodeCnt, totalContactsNodeStat.ValueNodeCnt) s.results.storageTrieNum, s.results.storageTotal.ShortNodeCnt.Load(), s.results.storageTotal.FullNodeCnt.Load(), s.results.storageTotal.ValueNodeCnt.Load())
} }

View File

@@ -21,22 +21,14 @@ import (
"bytes" "bytes"
"errors" "errors"
"fmt" "fmt"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/triedb/database" "github.com/ethereum/go-ethereum/triedb/database"
) )
var (
trieGetTimer = metrics.NewRegisteredTimer("trie/get/time", nil)
trieReaderGetTimer = metrics.NewRegisteredTimer("trie/reader/get/time", nil)
trieReaderTotalTimer = metrics.NewRegisteredTimer("trie/reader/total/time", nil)
)
// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on // Trie is a Merkle Patricia Trie. Use New to create a trie that sits on
// top of a database. Whenever trie performs a commit operation, the generated // top of a database. Whenever trie performs a commit operation, the generated
// nodes will be gathered and returned in a set. Once the trie is committed, // nodes will be gathered and returned in a set. Once the trie is committed,
@@ -154,10 +146,6 @@ func (t *Trie) Get(key []byte) ([]byte, error) {
if t.committed { if t.committed {
return nil, ErrCommitted return nil, ErrCommitted
} }
if metrics.EnabledExpensive {
start := time.Now()
defer func() { trieGetTimer.UpdateSince(start) }()
}
value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0) value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0)
if err == nil && didResolve { if err == nil && didResolve {
t.root = newroot t.root = newroot
@@ -190,11 +178,7 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
} }
return value, n, didResolve, err return value, n, didResolve, err
case hashNode: case hashNode:
start := time.Now()
child, err := t.resolveAndTrack(n, key[:pos]) child, err := t.resolveAndTrack(n, key[:pos])
if metrics.EnabledExpensive {
trieReaderGetTimer.UpdateSince(start)
}
if err != nil { if err != nil {
return nil, n, true, err return nil, n, true, err
} }
@@ -602,10 +586,6 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) {
// node's original value. The rlp-encoded blob is preferred to be loaded from // node's original value. The rlp-encoded blob is preferred to be loaded from
// database because it's easy to decode node while complex to encode node to blob. // database because it's easy to decode node while complex to encode node to blob.
func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) { func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
if metrics.EnabledExpensive {
start := time.Now()
defer func() { trieReaderTotalTimer.UpdateSince(start) }()
}
blob, err := t.reader.node(prefix, common.BytesToHash(n)) blob, err := t.reader.node(prefix, common.BytesToHash(n))
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -19,7 +19,6 @@ package pathdb
import ( import (
"fmt" "fmt"
"sync" "sync"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@@ -105,8 +104,6 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
dl.lock.RLock() dl.lock.RLock()
defer dl.lock.RUnlock() defer dl.lock.RUnlock()
start := time.Now()
// If the trie node is known locally, return it // If the trie node is known locally, return it
subset, ok := dl.nodes[owner] subset, ok := dl.nodes[owner]
if ok { if ok {
@@ -117,18 +114,14 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
if n.Hash != hash { if n.Hash != hash {
dirtyFalseMeter.Mark(1) dirtyFalseMeter.Mark(1)
log.Error("Unexpected trie node in diff layer", "owner", owner, "path", path, "expect", hash, "got", n.Hash) log.Error("Unexpected trie node in diff layer", "owner", owner, "path", path, "expect", hash, "got", n.Hash)
pathGetDiffLayerTimer.UpdateSince(start)
return nil, newUnexpectedNodeError("diff", hash, n.Hash, owner, path, n.Blob) return nil, newUnexpectedNodeError("diff", hash, n.Hash, owner, path, n.Blob)
} }
dirtyHitMeter.Mark(1) dirtyHitMeter.Mark(1)
dirtyNodeHitDepthHist.Update(int64(depth)) dirtyNodeHitDepthHist.Update(int64(depth))
dirtyReadMeter.Mark(int64(len(n.Blob))) dirtyReadMeter.Mark(int64(len(n.Blob)))
pathGetDiffLayerTimer.UpdateSince(start)
return n.Blob, nil return n.Blob, nil
} }
} }
pathGetDiffLayerTimer.UpdateSince(start)
// Trie node unknown to this layer, resolve from parent // Trie node unknown to this layer, resolve from parent
if diff, ok := dl.parent.(*diffLayer); ok { if diff, ok := dl.parent.(*diffLayer); ok {
return diff.node(owner, path, hash, depth+1) return diff.node(owner, path, hash, depth+1)

View File

@@ -20,7 +20,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"time"
"github.com/VictoriaMetrics/fastcache" "github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@@ -28,7 +27,6 @@ import (
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/trie/triestate" "github.com/ethereum/go-ethereum/trie/triestate"
"golang.org/x/crypto/sha3" "golang.org/x/crypto/sha3"
@@ -157,10 +155,6 @@ func (dl *diskLayer) markStale() {
func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) { func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
dl.lock.RLock() dl.lock.RLock()
defer dl.lock.RUnlock() defer dl.lock.RUnlock()
if metrics.EnabledExpensive {
start := time.Now()
defer func() { pathGetDiskLayerTimer.UpdateSince(start) }()
}
if dl.stale { if dl.stale {
return nil, errSnapshotStale return nil, errSnapshotStale

View File

@@ -47,7 +47,4 @@ var (
historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil) historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil)
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil) historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil)
historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil) historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil)
pathGetDiffLayerTimer = metrics.NewRegisteredTimer("pathdb/get/difflayer/time", nil)
pathGetDiskLayerTimer = metrics.NewRegisteredTimer("pathdb/get/disklayer/time", nil)
) )