Compare commits
21 Commits
faucet-bal
...
perf-pbss
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d572c77e4c | ||
|
|
565085959b | ||
|
|
b7b1b0c001 | ||
|
|
08702d3380 | ||
|
|
91e3a3ea1f | ||
|
|
73477bd0fc | ||
|
|
8749c8e8ce | ||
|
|
79fe2899c7 | ||
|
|
f45305b1ad | ||
|
|
d16532d678 | ||
|
|
c577ce3720 | ||
|
|
f2ec3cc6a5 | ||
|
|
0a2e1282d2 | ||
|
|
adb5e8fe86 | ||
|
|
4ab1c865b2 | ||
|
|
43b2ffa63b | ||
|
|
a05724588f | ||
|
|
060e5c6b34 | ||
|
|
46df9b4dcb | ||
|
|
7f3f72ed41 | ||
|
|
cbff31944b |
@@ -280,6 +280,7 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
|
||||
if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
|
||||
cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name)
|
||||
}
|
||||
cfg.Metrics.EnabledExpensive = true
|
||||
if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
|
||||
cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
|
||||
}
|
||||
|
||||
@@ -106,12 +106,12 @@ Remove blockchain and state databases`,
|
||||
dbInspectTrieCmd = &cli.Command{
|
||||
Action: inspectTrie,
|
||||
Name: "inspect-trie",
|
||||
ArgsUsage: "<blocknum> <jobnum> <topn>",
|
||||
ArgsUsage: "<blocknum> <jobnum>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.SyncModeFlag,
|
||||
},
|
||||
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",
|
||||
Usage: "Inspect the MPT tree of the account and contract.",
|
||||
Description: `This commands iterates the entrie WorldState.`,
|
||||
}
|
||||
dbCheckStateContentCmd = &cli.Command{
|
||||
@@ -386,7 +386,6 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
blockNumber uint64
|
||||
trieRootHash common.Hash
|
||||
jobnum uint64
|
||||
topN uint64
|
||||
)
|
||||
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
@@ -412,25 +411,12 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
|
||||
if ctx.NArg() == 1 {
|
||||
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 {
|
||||
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, 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 {
|
||||
@@ -451,7 +437,6 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
if dbScheme == rawdb.PathScheme {
|
||||
config = &triedb.Config{
|
||||
PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly),
|
||||
Cache: 0,
|
||||
}
|
||||
} else if dbScheme == rawdb.HashScheme {
|
||||
config = triedb.HashDefaults
|
||||
@@ -463,7 +448,7 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String())
|
||||
return err
|
||||
}
|
||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum, int(topN))
|
||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
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);
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
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);
|
||||
});
|
||||
@@ -66,31 +66,6 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
|
||||
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
|
||||
// header's transaction and uncle roots. The headers are assumed to be already
|
||||
// validated at this point.
|
||||
@@ -108,12 +83,31 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
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{
|
||||
func() error {
|
||||
return ValidateListsInBody(block)
|
||||
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)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
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.
|
||||
var blobs int
|
||||
for i, tx := range block.Transactions() {
|
||||
|
||||
@@ -441,6 +441,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
diskRoot = bc.triedb.Head()
|
||||
}
|
||||
}
|
||||
diskRoot = common.HexToHash("0x59d2a69ad465dbadf78f99635af9ed8125636cbdedc50bda9668ab2ac677b17a")
|
||||
if diskRoot != (common.Hash{}) {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
|
||||
|
||||
@@ -576,7 +577,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
}
|
||||
// Start tx indexer if it's enabled.
|
||||
if txLookupLimit != nil {
|
||||
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
|
||||
// bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
|
||||
}
|
||||
return bc, nil
|
||||
}
|
||||
@@ -2267,20 +2268,16 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
bc.cacheBlock(block.Hash(), block)
|
||||
|
||||
// Update the metrics touched during block processing and validation
|
||||
accountReadTimer.Update(statedb.AccountReads) // Account 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)
|
||||
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account 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)
|
||||
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
|
||||
triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
|
||||
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
|
||||
accountReadTimer.Update(statedb.AccountReads) // Account 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)
|
||||
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account 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)
|
||||
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
|
||||
blockExecutionTimer.Update(ptime) // The time spent on EVM processing
|
||||
blockValidationTimer.Update(vtime) // The time spent on block validation
|
||||
|
||||
// Write the block to the chain and get the status.
|
||||
var (
|
||||
@@ -2305,7 +2302,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
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
|
||||
|
||||
blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||
blockWriteTimer.UpdateSince(wstart)
|
||||
blockInsertTimer.UpdateSince(start)
|
||||
|
||||
// Report the import stats before returning the various results
|
||||
|
||||
@@ -511,12 +511,3 @@ func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscr
|
||||
func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription {
|
||||
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
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@ package rawdb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
)
|
||||
|
||||
// ReadSnapshotDisabled retrieves if the snapshot maintenance is disabled.
|
||||
@@ -74,6 +76,10 @@ func DeleteSnapshotRoot(db ethdb.KeyValueWriter) {
|
||||
|
||||
// ReadAccountSnapshot retrieves the snapshot entry of an account trie leaf.
|
||||
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))
|
||||
return data
|
||||
}
|
||||
@@ -94,6 +100,10 @@ func DeleteAccountSnapshot(db ethdb.KeyValueWriter, hash common.Hash) {
|
||||
|
||||
// ReadStorageSnapshot retrieves the snapshot entry of an storage trie leaf.
|
||||
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))
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ package rawdb
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
@@ -68,6 +70,10 @@ func (h *hasher) release() {
|
||||
// ReadAccountTrieNode retrieves the account trie node and the associated node
|
||||
// hash with the specified node path.
|
||||
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))
|
||||
if err != nil {
|
||||
return nil, common.Hash{}
|
||||
@@ -116,6 +122,10 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) {
|
||||
// ReadStorageTrieNode retrieves the storage trie node and the associated node
|
||||
// hash with the specified node path.
|
||||
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))
|
||||
if err != nil {
|
||||
return nil, common.Hash{}
|
||||
@@ -218,7 +228,22 @@ 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 {
|
||||
switch scheme {
|
||||
case HashScheme:
|
||||
return ReadLegacyTrieNode(db, hash)
|
||||
var (
|
||||
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:
|
||||
var (
|
||||
blob []byte
|
||||
|
||||
@@ -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.
|
||||
func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
||||
if table := f.tables[kind]; table != nil {
|
||||
return table.RetrieveItems(start-f.offset, count, maxBytes)
|
||||
return table.RetrieveItems(start, count, maxBytes)
|
||||
}
|
||||
return nil, errUnknownTable
|
||||
}
|
||||
@@ -252,7 +252,7 @@ func (f *Freezer) Ancients() (uint64, error) {
|
||||
func (f *Freezer) TableAncients(kind string) (uint64, error) {
|
||||
f.writeLock.RLock()
|
||||
defer f.writeLock.RUnlock()
|
||||
return f.tables[kind].items.Load() + f.offset, nil
|
||||
return f.tables[kind].items.Load(), nil
|
||||
}
|
||||
|
||||
// ItemAmountInAncient returns the actual length of current ancientDB.
|
||||
|
||||
10
core/rawdb/metrics.go
Normal file
10
core/rawdb/metrics.go
Normal file
@@ -0,0 +1,10 @@
|
||||
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)
|
||||
)
|
||||
@@ -236,7 +236,7 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, roo
|
||||
snap.layers[head.Root()] = head
|
||||
head = head.Parent()
|
||||
}
|
||||
log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root)
|
||||
log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root, "snapshot_cache_size", common.StorageSize(config.CacheSize)*1024*1024)
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
@@ -29,9 +30,14 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var (
|
||||
processTxTimer = metrics.NewRegisteredTimer("process/tx/time", nil)
|
||||
)
|
||||
|
||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||
// state from one point to another.
|
||||
//
|
||||
@@ -104,6 +110,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
systemTxs := make([]*types.Transaction, 0, 2)
|
||||
|
||||
for i, tx := range block.Transactions() {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer processTxTimer.UpdateSince(start)
|
||||
}
|
||||
if isPoSA {
|
||||
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
|
||||
bloomProcessors.Close()
|
||||
|
||||
@@ -53,6 +53,7 @@ type txIndexer struct {
|
||||
|
||||
// newTxIndexer initializes the transaction indexer.
|
||||
func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer {
|
||||
limit = 0
|
||||
indexer := &txIndexer{
|
||||
limit: limit,
|
||||
db: chain.db,
|
||||
|
||||
@@ -161,11 +161,12 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
// Optimize memory distribution by reallocating surplus allowance from the
|
||||
// dirty cache to the clean cache.
|
||||
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("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024)
|
||||
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
|
||||
}
|
||||
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*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)
|
||||
|
||||
// Try to recover offline state pruning only in hash-based.
|
||||
if config.StateScheme == rawdb.HashScheme {
|
||||
|
||||
@@ -209,9 +209,6 @@ type BlockChain interface {
|
||||
|
||||
// UpdateChasingHead update remote best chain head, used by DA check now.
|
||||
UpdateChasingHead(head *types.Header)
|
||||
|
||||
// AncientTail retrieves the tail the ancients blocks
|
||||
AncientTail() (uint64, error)
|
||||
}
|
||||
|
||||
type DownloadOption func(downloader *Downloader) *Downloader
|
||||
@@ -800,11 +797,6 @@ func (d *Downloader) findAncestor(p *peerConnection, localHeight uint64, remoteH
|
||||
// We're above the max reorg threshold, find the earliest fork point
|
||||
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
|
||||
// all headers before that point will be missing.
|
||||
if mode == LightSync {
|
||||
|
||||
@@ -320,22 +320,26 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
}
|
||||
|
||||
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 {
|
||||
checkErrs := make(chan error, 2)
|
||||
|
||||
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
|
||||
}
|
||||
if err := core.IsDataAvailable(h.chain, block); err != nil {
|
||||
log.Error("Propagating block with invalid sidecars", "number", block.Number(), "hash", block.Hash(), "err", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
h.BroadcastBlock(block, propagate)
|
||||
|
||||
@@ -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.
|
||||
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, fullBlob bool) ([]*types.BlobTxSidecar, error) {
|
||||
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) {
|
||||
var r []*types.BlobTxSidecar
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String(), fullBlob)
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String(), true)
|
||||
if err == nil && r == nil {
|
||||
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
|
||||
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash, fullBlob bool) (*types.BlobTxSidecar, error) {
|
||||
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) {
|
||||
var r *types.BlobTxSidecar
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlockSidecarByTxHash", hash, fullBlob)
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlockSidecarByTxHash", hash, true)
|
||||
if err == nil && r == nil {
|
||||
return nil, ethereum.NotFound
|
||||
}
|
||||
|
||||
@@ -111,12 +111,18 @@ 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) {
|
||||
options := configureOptions(customize)
|
||||
logger := log.New("database", file)
|
||||
usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
|
||||
logCtx := []interface{}{"cache", common.StorageSize(usedCache), "handles", options.GetOpenFilesCacheCapacity()}
|
||||
// usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
|
||||
logCtx := []interface{}{"handles", options.GetOpenFilesCacheCapacity()}
|
||||
if options.ReadOnly {
|
||||
logCtx = append(logCtx, "readonly", "true")
|
||||
}
|
||||
logger.Info("Allocated cache and file handles", logCtx...)
|
||||
if options.BlockCacheCapacity != 0 {
|
||||
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
|
||||
db, err := leveldb.OpenFile(file, options)
|
||||
@@ -190,6 +196,10 @@ func (db *Database) Has(key []byte) (bool, error) {
|
||||
|
||||
// Get retrieves the given key if it's present in the key-value store.
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -199,11 +209,19 @@ func (db *Database) Get(key []byte) ([]byte, error) {
|
||||
|
||||
// Put inserts the given value into the key-value store.
|
||||
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)
|
||||
}
|
||||
|
||||
// Delete removes the key from the key-value store.
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -301,6 +319,8 @@ func (db *Database) meter(refresh time.Duration, namespace string) {
|
||||
merr = err
|
||||
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
|
||||
for j := 0; j < len(compactions[i%2]); j++ {
|
||||
compactions[i%2][j] = 0
|
||||
@@ -414,6 +434,10 @@ func (b *batch) ValueSize() int {
|
||||
|
||||
// Write flushes any accumulated data to disk.
|
||||
func (b *batch) Write() error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
|
||||
}
|
||||
return b.db.Write(b.b, nil)
|
||||
}
|
||||
|
||||
|
||||
11
ethdb/metrics.go
Normal file
11
ethdb/metrics.go
Normal file
@@ -0,0 +1,11 @@
|
||||
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)
|
||||
)
|
||||
@@ -183,8 +183,8 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
|
||||
memTableSize = maxMemTableSize - 1
|
||||
}
|
||||
|
||||
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024),
|
||||
"handles", handles, "memory table", common.StorageSize(memTableSize))
|
||||
logger.Info("Pebble db Allocated cache and file handles", "handles", handles, "block_cache_size", common.StorageSize(cache*1024*1024),
|
||||
"memory_table_size", common.StorageSize(memTableSize))
|
||||
|
||||
db := &Database{
|
||||
fn: file,
|
||||
@@ -309,23 +309,69 @@ func (d *Database) Has(key []byte) (bool, error) {
|
||||
|
||||
// Get retrieves the given key if it's present in the key-value store.
|
||||
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()
|
||||
step1End = time.Now()
|
||||
defer d.quitLock.RUnlock()
|
||||
if d.closed {
|
||||
return nil, pebble.ErrClosed
|
||||
}
|
||||
step2Start = time.Now()
|
||||
innerStart := time.Now()
|
||||
dat, closer, err := d.db.Get(key)
|
||||
valueLen = len(dat)
|
||||
ethdb.EthdbInnerGetTimer.UpdateSince(innerStart)
|
||||
step2End = time.Now()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step3Start = time.Now()
|
||||
ret := make([]byte, len(dat))
|
||||
copy(ret, dat)
|
||||
step3End = time.Now()
|
||||
|
||||
step4Start = time.Now()
|
||||
closer.Close()
|
||||
step4End = time.Now()
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Put inserts the given value into the key-value store.
|
||||
func (d *Database) Put(key []byte, value []byte) error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbPutTimer.UpdateSince(start) }()
|
||||
}
|
||||
d.quitLock.RLock()
|
||||
defer d.quitLock.RUnlock()
|
||||
if d.closed {
|
||||
@@ -336,6 +382,10 @@ func (d *Database) Put(key []byte, value []byte) error {
|
||||
|
||||
// Delete removes the key from the key-value store.
|
||||
func (d *Database) Delete(key []byte) error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbDeleteTimer.UpdateSince(start) }()
|
||||
}
|
||||
d.quitLock.RLock()
|
||||
defer d.quitLock.RUnlock()
|
||||
if d.closed {
|
||||
@@ -494,6 +544,9 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
|
||||
nonLevel0CompCount = int64(d.nonLevel0Comp.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
|
||||
writeDelayCounts[i%2] = writeDelayCount
|
||||
compTimes[i%2] = compTime
|
||||
@@ -599,6 +652,10 @@ func (b *batch) ValueSize() int {
|
||||
|
||||
// Write flushes any accumulated data to disk.
|
||||
func (b *batch) Write() error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
|
||||
}
|
||||
b.db.quitLock.RLock()
|
||||
defer b.db.quitLock.RUnlock()
|
||||
if b.db.closed {
|
||||
|
||||
@@ -1010,7 +1010,11 @@ func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.
|
||||
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)
|
||||
if header == nil || err != nil {
|
||||
// When the block doesn't exist, the RPC method should return JSON null
|
||||
@@ -1023,12 +1027,16 @@ func (s *BlockChainAPI) GetBlobSidecars(ctx context.Context, blockNrOrHash rpc.B
|
||||
}
|
||||
result := make([]map[string]interface{}, len(blobSidecars))
|
||||
for i, sidecar := range blobSidecars {
|
||||
result[i] = marshalBlobSidecar(sidecar, fullBlob)
|
||||
result[i] = marshalBlobSidecar(sidecar, showBlob)
|
||||
}
|
||||
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)
|
||||
if txTarget == nil {
|
||||
return nil, nil
|
||||
@@ -1045,7 +1053,7 @@ func (s *BlockChainAPI) GetBlobSidecarByTxHash(ctx context.Context, hash common.
|
||||
}
|
||||
for _, sidecar := range blobSidecars {
|
||||
if sidecar.TxIndex == Index {
|
||||
return marshalBlobSidecar(sidecar, fullBlob), nil
|
||||
return marshalBlobSidecar(sidecar, showBlob), nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2204,7 +2204,7 @@ func TestRPCGetBlobSidecars(t *testing.T) {
|
||||
result interface{}
|
||||
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 {
|
||||
t.Errorf("test %d: want no error, have %v", i, err)
|
||||
continue
|
||||
@@ -2254,7 +2254,7 @@ func TestGetBlobSidecarByTxHash(t *testing.T) {
|
||||
fullBlob: true,
|
||||
file: "block-with-blobSidecars",
|
||||
},
|
||||
// 4. block show part blobs
|
||||
// 5. block show part blobs
|
||||
{
|
||||
test: txHashs[6],
|
||||
fullBlob: false,
|
||||
@@ -2267,7 +2267,7 @@ func TestGetBlobSidecarByTxHash(t *testing.T) {
|
||||
result interface{}
|
||||
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 {
|
||||
t.Errorf("test %d: want no error, have %v", i, err)
|
||||
continue
|
||||
|
||||
@@ -37,8 +37,8 @@ type Config struct {
|
||||
|
||||
// DefaultConfig is the default config for metrics used in go-ethereum.
|
||||
var DefaultConfig = Config{
|
||||
Enabled: false,
|
||||
EnabledExpensive: false,
|
||||
Enabled: true,
|
||||
EnabledExpensive: true,
|
||||
HTTP: "127.0.0.1",
|
||||
Port: 6060,
|
||||
EnableInfluxDB: false,
|
||||
|
||||
@@ -22,12 +22,12 @@ import (
|
||||
//
|
||||
// This global kill-switch helps quantify the observer effect and makes
|
||||
// for less cluttered pprof profiles.
|
||||
var Enabled = false
|
||||
var Enabled = true
|
||||
|
||||
// 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
|
||||
// for health monitoring and debug metrics that might impact runtime performance.
|
||||
var EnabledExpensive = false
|
||||
var EnabledExpensive = true
|
||||
|
||||
// enablerFlags is the CLI flag names to use to enable metrics collections.
|
||||
var enablerFlags = []string{"metrics"}
|
||||
|
||||
@@ -70,8 +70,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil)
|
||||
finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil)
|
||||
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", 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")
|
||||
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
||||
@@ -1056,6 +1058,8 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
||||
// into the given sealing block. The transaction selection and ordering strategy can
|
||||
// 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) {
|
||||
start := time.Now()
|
||||
|
||||
w.mu.RLock()
|
||||
tip := w.tip
|
||||
w.mu.RUnlock()
|
||||
@@ -1110,6 +1114,7 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
|
||||
localBlobTxs[account] = txs
|
||||
}
|
||||
}
|
||||
fillTxFnPartialTimer.UpdateSince(start)
|
||||
|
||||
// Fill the block with all available pending transactions.
|
||||
// we will abort when:
|
||||
@@ -1134,6 +1139,7 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
|
||||
return err
|
||||
}
|
||||
}
|
||||
fillTxFnTimer.UpdateSince(start)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,15 +4,17 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -24,113 +26,63 @@ import (
|
||||
"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 {
|
||||
database.Database
|
||||
Scheme() string
|
||||
Cap(limit common.StorageSize) error
|
||||
DiskDB() ethdb.Database
|
||||
}
|
||||
|
||||
const TopN = 3
|
||||
|
||||
type Inspector struct {
|
||||
trie *Trie // traverse trie
|
||||
db Database
|
||||
stateRootHash common.Hash
|
||||
blockNum uint64
|
||||
blocknum uint64
|
||||
root node // root of triedb
|
||||
totalNum uint64
|
||||
wg sync.WaitGroup
|
||||
statLock sync.RWMutex
|
||||
result map[string]*TrieTreeStat
|
||||
sem *semaphore.Weighted
|
||||
eoaAccountNums uint64
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
results stat
|
||||
topN int
|
||||
|
||||
totalAccountNum atomic.Uint64
|
||||
totalStorageNum atomic.Uint64
|
||||
lastTime mclock.AbsTime
|
||||
}
|
||||
|
||||
type stat struct {
|
||||
lock sync.RWMutex
|
||||
account *trieStat
|
||||
storageTopN []*trieStat
|
||||
storageTopNTotal []uint64
|
||||
storageTotal nodeStat
|
||||
storageTrieNum uint64
|
||||
type TrieTreeStat struct {
|
||||
is_account_trie bool
|
||||
theNodeStatByLevel [15]NodeStat
|
||||
totalNodeStat NodeStat
|
||||
}
|
||||
|
||||
type trieStat struct {
|
||||
owner common.Hash
|
||||
totalNodeStat nodeStat
|
||||
nodeStatByLevel [16]nodeStat
|
||||
type NodeStat struct {
|
||||
ShortNodeCnt uint64
|
||||
FullNodeCnt uint64
|
||||
ValueNodeCnt uint64
|
||||
}
|
||||
|
||||
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) {
|
||||
func (trieStat *TrieTreeStat) AtomicAdd(theNode node, height uint32) {
|
||||
switch (theNode).(type) {
|
||||
case *shortNode:
|
||||
trieStat.totalNodeStat.ShortNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].ShortNodeCnt.Add(1)
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.ShortNodeCnt, 1)
|
||||
atomic.AddUint64(&(trieStat.theNodeStatByLevel[height].ShortNodeCnt), 1)
|
||||
case *fullNode:
|
||||
trieStat.totalNodeStat.FullNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].FullNodeCnt.Add(1)
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.FullNodeCnt, 1)
|
||||
atomic.AddUint64(&trieStat.theNodeStatByLevel[height].FullNodeCnt, 1)
|
||||
case valueNode:
|
||||
trieStat.totalNodeStat.ValueNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].ValueNodeCnt.Add(1)
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.ValueNodeCnt, 1)
|
||||
atomic.AddUint64(&((trieStat.theNodeStatByLevel[height]).ValueNodeCnt), 1)
|
||||
default:
|
||||
panic(errors.New("Invalid node type to statistics"))
|
||||
}
|
||||
}
|
||||
|
||||
func (trieStat *trieStat) Display(ownerAddress string, treeType string) string {
|
||||
sw := new(strings.Builder)
|
||||
table := tablewriter.NewWriter(sw)
|
||||
func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) {
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"})
|
||||
if ownerAddress == "" {
|
||||
table.SetCaption(true, fmt.Sprintf("%v", treeType))
|
||||
@@ -138,27 +90,38 @@ func (trieStat *trieStat) Display(ownerAddress string, treeType string) string {
|
||||
table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress))
|
||||
}
|
||||
table.SetAlignment(1)
|
||||
|
||||
for i := range trieStat.nodeStatByLevel {
|
||||
if trieStat.nodeStatByLevel[i].IsEmpty() {
|
||||
continue
|
||||
for i := 0; i < len(trieStat.theNodeStatByLevel); i++ {
|
||||
nodeStat := trieStat.theNodeStatByLevel[i]
|
||||
if nodeStat.FullNodeCnt == 0 && nodeStat.ShortNodeCnt == 0 && nodeStat.ValueNodeCnt == 0 {
|
||||
break
|
||||
}
|
||||
table.AppendBulk([][]string{
|
||||
{"-", 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())},
|
||||
{"-", strconv.Itoa(i), nodeStat.ShortNodeCount(), nodeStat.FullNodeCount(), nodeStat.ValueNodeCount()},
|
||||
})
|
||||
}
|
||||
table.AppendBulk([][]string{
|
||||
{"Total", "-", fmt.Sprintf("%d", trieStat.totalNodeStat.ShortNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.FullNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.ValueNodeCnt.Load())},
|
||||
{"Total", "-", trieStat.totalNodeStat.ShortNodeCount(), trieStat.totalNodeStat.FullNodeCount(), trieStat.totalNodeStat.ValueNodeCount()},
|
||||
})
|
||||
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
|
||||
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uint64, jobNum uint64, topN int) (*Inspector, error) {
|
||||
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uint64, jobnum uint64) (*Inspector, error) {
|
||||
if tr == nil {
|
||||
return nil, errors.New("trie is nil")
|
||||
}
|
||||
@@ -168,20 +131,15 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uin
|
||||
}
|
||||
|
||||
ins := &Inspector{
|
||||
trie: tr,
|
||||
db: db,
|
||||
stateRootHash: stateRootHash,
|
||||
blockNum: blockNum,
|
||||
root: tr.root,
|
||||
results: stat{},
|
||||
topN: topN,
|
||||
totalAccountNum: atomic.Uint64{},
|
||||
totalStorageNum: atomic.Uint64{},
|
||||
lastTime: mclock.Now(),
|
||||
sem: semaphore.NewWeighted(int64(jobNum)),
|
||||
|
||||
wg: sync.WaitGroup{},
|
||||
|
||||
trie: tr,
|
||||
db: db,
|
||||
stateRootHash: stateRootHash,
|
||||
blocknum: blocknum,
|
||||
root: tr.root,
|
||||
result: make(map[string]*TrieTreeStat),
|
||||
totalNum: (uint64)(0),
|
||||
wg: sync.WaitGroup{},
|
||||
sem: semaphore.NewWeighted(int64(jobnum)),
|
||||
eoaAccountNums: 0,
|
||||
}
|
||||
|
||||
@@ -189,123 +147,155 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uin
|
||||
}
|
||||
|
||||
// Run statistics, external call
|
||||
func (s *Inspector) Run() {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
if s.db.Scheme() == rawdb.HashScheme {
|
||||
s.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
}()
|
||||
|
||||
log.Info("Find Account Trie Tree", "rootHash: ", s.trie.Hash().String(), "BlockNum: ", s.blockNum)
|
||||
|
||||
ts := &trieStat{
|
||||
owner: common.Hash{},
|
||||
func (inspect *Inspector) Run() {
|
||||
accountTrieStat := &TrieTreeStat{
|
||||
is_account_trie: true,
|
||||
}
|
||||
s.traversal(s.trie, ts, s.root, 0, []byte{})
|
||||
s.results.add(ts, s.topN)
|
||||
s.wg.Wait()
|
||||
if inspect.db.Scheme() == rawdb.HashScheme {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if _, ok := inspect.result[""]; !ok {
|
||||
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{})
|
||||
inspect.wg.Wait()
|
||||
}
|
||||
|
||||
func (s *Inspector) traversal(trie *Trie, ts *trieStat, n node, height int, path []byte) {
|
||||
func (inspect *Inspector) SubConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, 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
|
||||
if n == nil {
|
||||
if theNode == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ts.add(n, height)
|
||||
|
||||
switch current := (n).(type) {
|
||||
switch current := (theNode).(type) {
|
||||
case *shortNode:
|
||||
s.traversal(trie, ts, current.Val, height, append(path, current.Key...))
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, current.Val, height, append(path, current.Key...))
|
||||
case *fullNode:
|
||||
for idx, child := range current.Children {
|
||||
if child == nil {
|
||||
continue
|
||||
}
|
||||
p := common.CopyBytes(append(path, byte(idx)))
|
||||
s.traversal(trie, ts, child, height+1, p)
|
||||
childPath := append(path, byte(idx))
|
||||
if inspect.sem.TryAcquire(1) {
|
||||
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:
|
||||
tn, err := trie.resloveWithoutTrack(current, path)
|
||||
n, err := theTrie.resloveWithoutTrack(current, path)
|
||||
if err != nil {
|
||||
fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, trie.Hash().String(), height+1, path)
|
||||
fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, theTrie.Hash().String(), height+1, path)
|
||||
return
|
||||
}
|
||||
s.PrintProgress(trie)
|
||||
s.traversal(trie, ts, tn, height, path)
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, n, height, path)
|
||||
return
|
||||
case valueNode:
|
||||
if !hasTerm(path) {
|
||||
break
|
||||
}
|
||||
var account types.StateAccount
|
||||
var account Account
|
||||
if err := rlp.Decode(bytes.NewReader(current), &account); err != nil {
|
||||
break
|
||||
}
|
||||
if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash {
|
||||
s.eoaAccountNums++
|
||||
inspect.eoaAccountNums++
|
||||
}
|
||||
if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash {
|
||||
break
|
||||
}
|
||||
ownerAddress := common.BytesToHash(hexToCompact(path))
|
||||
contractTrie, err := New(StorageTrieID(s.stateRootHash, ownerAddress, account.Root), s.db)
|
||||
contractTrie, err := New(StorageTrieID(inspect.stateRootHash, ownerAddress, account.Root), inspect.db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
fmt.Printf("New contract trie node: %v, error: %v, Height: %v, Path: %v\n", theNode, err, height, path)
|
||||
break
|
||||
}
|
||||
contractTrie.tracer.reset()
|
||||
|
||||
if s.sem.TryAcquire(1) {
|
||||
s.wg.Add(1)
|
||||
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)
|
||||
trieStat := &TrieTreeStat{
|
||||
is_account_trie: false,
|
||||
}
|
||||
|
||||
inspect.statLock.Lock()
|
||||
if _, ok := inspect.result[ownerAddress.String()]; !ok {
|
||||
inspect.result[ownerAddress.String()] = trieStat
|
||||
}
|
||||
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:
|
||||
panic(errors.New("invalid node type to traverse"))
|
||||
panic(errors.New("Invalid node type to traverse."))
|
||||
}
|
||||
theTrieTreeStat.AtomicAdd(theNode, height)
|
||||
}
|
||||
|
||||
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() {
|
||||
func (inspect *Inspector) DisplayResult() {
|
||||
// display root hash
|
||||
fmt.Println(s.results.account.Display("", "AccountTrie"))
|
||||
fmt.Println("EOA accounts num: ", s.eoaAccountNums)
|
||||
if _, ok := inspect.result[""]; !ok {
|
||||
log.Info("Display result error", "missing account trie")
|
||||
return
|
||||
}
|
||||
inspect.result[""].Display("", "AccountTrie")
|
||||
|
||||
type SortedTrie struct {
|
||||
totalNum uint64
|
||||
ownerAddress string
|
||||
}
|
||||
// display contract trie
|
||||
for _, st := range s.results.storageTopN {
|
||||
fmt.Println(st.Display(st.owner.String(), "StorageTrie"))
|
||||
var sortedTriesByNums []SortedTrie
|
||||
var totalContactsNodeStat NodeStat
|
||||
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",
|
||||
s.results.storageTrieNum, s.results.storageTotal.ShortNodeCnt.Load(), s.results.storageTotal.FullNodeCnt.Load(), s.results.storageTotal.ValueNodeCnt.Load())
|
||||
contractTrieCnt, totalContactsNodeStat.ShortNodeCnt, totalContactsNodeStat.FullNodeCnt, totalContactsNodeStat.ValueNodeCnt)
|
||||
}
|
||||
|
||||
20
trie/trie.go
20
trie/trie.go
@@ -21,14 +21,22 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"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
|
||||
// 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,
|
||||
@@ -146,6 +154,10 @@ func (t *Trie) Get(key []byte) ([]byte, error) {
|
||||
if t.committed {
|
||||
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)
|
||||
if err == nil && didResolve {
|
||||
t.root = newroot
|
||||
@@ -178,7 +190,11 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
|
||||
}
|
||||
return value, n, didResolve, err
|
||||
case hashNode:
|
||||
start := time.Now()
|
||||
child, err := t.resolveAndTrack(n, key[:pos])
|
||||
if metrics.EnabledExpensive {
|
||||
trieReaderGetTimer.UpdateSince(start)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, n, true, err
|
||||
}
|
||||
@@ -586,6 +602,10 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) {
|
||||
// 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.
|
||||
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))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -19,6 +19,7 @@ package pathdb
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -104,6 +105,8 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
|
||||
dl.lock.RLock()
|
||||
defer dl.lock.RUnlock()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// If the trie node is known locally, return it
|
||||
subset, ok := dl.nodes[owner]
|
||||
if ok {
|
||||
@@ -114,14 +117,18 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
|
||||
if n.Hash != hash {
|
||||
dirtyFalseMeter.Mark(1)
|
||||
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)
|
||||
}
|
||||
dirtyHitMeter.Mark(1)
|
||||
dirtyNodeHitDepthHist.Update(int64(depth))
|
||||
dirtyReadMeter.Mark(int64(len(n.Blob)))
|
||||
pathGetDiffLayerTimer.UpdateSince(start)
|
||||
return n.Blob, nil
|
||||
}
|
||||
}
|
||||
pathGetDiffLayerTimer.UpdateSince(start)
|
||||
|
||||
// Trie node unknown to this layer, resolve from parent
|
||||
if diff, ok := dl.parent.(*diffLayer); ok {
|
||||
return diff.node(owner, path, hash, depth+1)
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/fastcache"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"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/triestate"
|
||||
"golang.org/x/crypto/sha3"
|
||||
@@ -155,6 +157,10 @@ func (dl *diskLayer) markStale() {
|
||||
func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
|
||||
dl.lock.RLock()
|
||||
defer dl.lock.RUnlock()
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { pathGetDiskLayerTimer.UpdateSince(start) }()
|
||||
}
|
||||
|
||||
if dl.stale {
|
||||
return nil, errSnapshotStale
|
||||
|
||||
@@ -47,4 +47,7 @@ var (
|
||||
historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil)
|
||||
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", 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)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user