Compare commits

..

19 Commits

Author SHA1 Message Date
will-2012
f5b5805359 Merge pull request #2705 from will-2012/perf-pbssbsc
perf: add db metrics
2024-09-19 11:16:10 +08:00
will@2012
34bc9e02aa Merge remote-tracking branch 'bsc/versa_base' into perf-pbssbsc 2024-09-14 10:09:16 +08:00
will@2012
8a3d62e756 perf: add db metrics 2024-09-14 10:06:38 +08:00
joeycli
d4879836c0 chore: add statedb get metrices 2024-09-06 14:06:12 +08:00
joeycli
4b00174821 chore: add snapshot metrices 2024-09-06 11:04:37 +08:00
joeycli
3082da4e86 chore: add validate metrics 2024-09-04 10:20:47 +08:00
joeycli
d334f520be chore: add state trie metrics 2024-09-04 09:39:08 +08:00
joeycli
cef6acec23 chore: add execute, verify and commit total metrics 2024-09-02 09:08:55 +08:00
joeycli
092fbafa3c chore: delete share mem pool 2024-09-01 12:20:05 +08:00
joeycli
c4e8ec7fea chore: add mgasps metrics 2024-08-29 16:43:04 +08:00
zzzckck
83a9b13771 Merge pull request #2607 from NathanBSC/for_release_v1.4.12
Revert "miner/worker: broadcast block immediately once sealed (bnb-chain#2576)"
2024-07-24 12:07:13 +08:00
NathanBSC
c6cb43b7ca Revert "miner/worker: broadcast block immediately once sealed (#2576)"
This reverts commit 6d5b4ad64d.
2024-07-22 18:23:10 +08:00
NathanBSC
222e10810e core: cache block after wroten into db 2024-07-22 18:22:56 +08:00
zzzckck
26b236fb5f Merge pull request #2586 from bnb-chain/master_2_develop
Draft release v1.4.12
2024-07-17 17:45:39 +08:00
zzzckck
900cf26c65 Merge branch 'master' into master_2_develop 2024-07-17 17:29:11 +08:00
dependabot[bot]
75d162983a build(deps): bump github.com/hashicorp/go-retryablehttp (#2537)
Bumps [github.com/hashicorp/go-retryablehttp](https://github.com/hashicorp/go-retryablehttp) from 0.7.4 to 0.7.7.
- [Changelog](https://github.com/hashicorp/go-retryablehttp/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/go-retryablehttp/compare/v0.7.4...v0.7.7)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-retryablehttp
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-28 13:51:53 +08:00
zoro
719412551a Merge pull request #2549 from bnb-chain/develop
release: prepare for v1.4.11
2024-06-27 17:37:26 +08:00
zzzckck
f0c7795542 Merge pull request #2527 from bnb-chain/develop
Draft release v1.4.10
2024-06-21 16:13:48 +08:00
zzzckck
4566ac7659 Merge pull request #2511 from bnb-chain/develop
Draft release v1.4.9
2024-06-11 11:51:22 +08:00
35 changed files with 378 additions and 393 deletions

View File

@@ -49,7 +49,6 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
"golang.org/x/time/rate"
) )
var ( var (
@@ -217,8 +216,6 @@ type faucet struct {
bep2eInfos map[string]bep2eInfo bep2eInfos map[string]bep2eInfo
bep2eAbi abi.ABI bep2eAbi abi.ABI
limiter *IPRateLimiter
} }
// wsConn wraps a websocket connection with a write mutex as the underlying // wsConn wraps a websocket connection with a write mutex as the underlying
@@ -238,12 +235,6 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [
return nil, err return nil, err
} }
// Allow 1 request per minute with burst of 5, and cache up to 1000 IPs
limiter, err := NewIPRateLimiter(rate.Limit(1.0), 5, 1000)
if err != nil {
return nil, err
}
return &faucet{ return &faucet{
config: genesis.Config, config: genesis.Config,
client: client, client: client,
@@ -254,7 +245,6 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [
update: make(chan struct{}, 1), update: make(chan struct{}, 1),
bep2eInfos: bep2eInfos, bep2eInfos: bep2eInfos,
bep2eAbi: bep2eAbi, bep2eAbi: bep2eAbi,
limiter: limiter,
}, nil }, nil
} }
@@ -282,20 +272,6 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) {
// apiHandler handles requests for Ether grants and transaction statuses. // apiHandler handles requests for Ether grants and transaction statuses.
func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) { func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
if len(r.Header.Get("X-Forwarded-For")) > 0 {
ips := strings.Split(r.Header.Get("X-Forwarded-For"), ",")
if len(ips) > 0 {
ip = strings.TrimSpace(ips[len(ips)-1])
}
}
if !f.limiter.GetLimiter(ip).Allow() {
log.Warn("Too many requests from client: ", "client", ip)
http.Error(w, "Too many requests", http.StatusTooManyRequests)
return
}
upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }} upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
conn, err := upgrader.Upgrade(w, r, nil) conn, err := upgrader.Upgrade(w, r, nil)
if err != nil { if err != nil {
@@ -649,7 +625,6 @@ func (f *faucet) loop() {
balance := new(big.Int).Div(f.balance, ether) balance := new(big.Int).Div(f.balance, ether)
for _, conn := range f.conns { for _, conn := range f.conns {
go func(conn *wsConn) {
if err := send(conn, map[string]interface{}{ if err := send(conn, map[string]interface{}{
"funds": balance, "funds": balance,
"funded": f.nonce, "funded": f.nonce,
@@ -657,14 +632,12 @@ func (f *faucet) loop() {
}, time.Second); err != nil { }, time.Second); err != nil {
log.Warn("Failed to send stats to client", "err", err) log.Warn("Failed to send stats to client", "err", err)
conn.conn.Close() conn.conn.Close()
return // Exit the goroutine if the first send fails continue
} }
if err := send(conn, head, time.Second); err != nil { if err := send(conn, head, time.Second); err != nil {
log.Warn("Failed to send header to client", "err", err) log.Warn("Failed to send header to client", "err", err)
conn.conn.Close() conn.conn.Close()
} }
}(conn)
} }
f.lock.RUnlock() f.lock.RUnlock()
} }
@@ -683,12 +656,10 @@ func (f *faucet) loop() {
// Pending requests updated, stream to clients // Pending requests updated, stream to clients
f.lock.RLock() f.lock.RLock()
for _, conn := range f.conns { for _, conn := range f.conns {
go func(conn *wsConn) {
if err := send(conn, map[string]interface{}{"requests": f.reqs}, time.Second); err != nil { if err := send(conn, map[string]interface{}{"requests": f.reqs}, time.Second); err != nil {
log.Warn("Failed to send requests to client", "err", err) log.Warn("Failed to send requests to client", "err", err)
conn.conn.Close() conn.conn.Close()
} }
}(conn)
} }
f.lock.RUnlock() f.lock.RUnlock()
} }

View File

@@ -1,44 +0,0 @@
package main
import (
lru "github.com/hashicorp/golang-lru"
"golang.org/x/time/rate"
)
type IPRateLimiter struct {
ips *lru.Cache // LRU cache to store IP addresses and their associated rate limiters
r rate.Limit // the rate limit, e.g., 5 requests per second
b int // the burst size, e.g., allowing a burst of 10 requests at once. The rate limiter gets into action
// only after this number exceeds
}
func NewIPRateLimiter(r rate.Limit, b int, size int) (*IPRateLimiter, error) {
cache, err := lru.New(size)
if err != nil {
return nil, err
}
i := &IPRateLimiter{
ips: cache,
r: r,
b: b,
}
return i, nil
}
func (i *IPRateLimiter) addIP(ip string) *rate.Limiter {
limiter := rate.NewLimiter(i.r, i.b)
i.ips.Add(ip, limiter)
return limiter
}
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
if limiter, exists := i.ips.Get(ip); exists {
return limiter.(*rate.Limiter)
}
return i.addIP(ip)
}

View File

@@ -33,7 +33,7 @@ node get_perf.js --rpc ${url} --startNum ${start} --endNum ${end}
output as following output as following
```bash ```bash
Get the performance between [ 19470 , 19670 ) Get the performance between [ 19470 , 19670 )
txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975 justifiedBlocksRatio = 0.98 txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975
txCountPerSecond = 1045.8602329450914 avgGasUsedPerBlock = 250.02062627 avgGasUsedPerSecond = 83.20153952412646 txCountPerSecond = 1045.8602329450914 avgGasUsedPerBlock = 250.02062627 avgGasUsedPerSecond = 83.20153952412646
``` ```

View File

@@ -12,7 +12,6 @@ const main = async () => {
let txCountTotal = 0; let txCountTotal = 0;
let gasUsedTotal = 0; let gasUsedTotal = 0;
let inturnBlocks = 0; let inturnBlocks = 0;
let justifiedBlocks = 0;
for (let i = program.startNum; i < program.endNum; i++) { for (let i = program.startNum; i < program.endNum; i++) {
let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [ let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]); ethers.toQuantity(i)]);
@@ -27,14 +26,6 @@ const main = async () => {
inturnBlocks += 1 inturnBlocks += 1
} }
let timestamp = eval(eval(header.timestamp).toString(10)) let timestamp = eval(eval(header.timestamp).toString(10))
let justifiedNumber = await provider.send("parlia_getJustifiedNumber", [
ethers.toQuantity(i)]);
if (justifiedNumber + 1 == i) {
justifiedBlocks += 1
} else {
console.log("justified unexpected", "BlockNumber =", i,"justifiedNumber",justifiedNumber)
}
console.log("BlockNumber =", i, "mod =", i%4, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp) console.log("BlockNumber =", i, "mod =", i%4, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp)
} }
@@ -50,14 +41,13 @@ const main = async () => {
let timeCost = endTime - startTime let timeCost = endTime - startTime
let avgBlockTime = timeCost/blockCount let avgBlockTime = timeCost/blockCount
let inturnBlocksRatio = inturnBlocks/blockCount let inturnBlocksRatio = inturnBlocks/blockCount
let justifiedBlocksRatio = justifiedBlocks/blockCount
let tps = txCountTotal/timeCost let tps = txCountTotal/timeCost
let M = 1000000 let M = 1000000
let avgGasUsedPerBlock = gasUsedTotal/blockCount/M let avgGasUsedPerBlock = gasUsedTotal/blockCount/M
let avgGasUsedPerSecond = gasUsedTotal/timeCost/M let avgGasUsedPerSecond = gasUsedTotal/timeCost/M
console.log("Get the performance between [", program.startNum, ",", program.endNum, ")"); console.log("Get the performance between [", program.startNum, ",", program.endNum, ")");
console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio, "justifiedBlocksRatio =", justifiedBlocksRatio); console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio);
console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond); console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond);
}; };

View File

@@ -59,9 +59,6 @@ type ChainHeaderReader interface {
// GetHighestVerifiedHeader retrieves the highest header verified. // GetHighestVerifiedHeader retrieves the highest header verified.
GetHighestVerifiedHeader() *types.Header GetHighestVerifiedHeader() *types.Header
// GetVerifiedBlockByHash retrieves the highest verified block.
GetVerifiedBlockByHash(hash common.Hash) *types.Header
// ChasingHead return the best chain head of peers. // ChasingHead return the best chain head of peers.
ChasingHead() *types.Header ChasingHead() *types.Header
} }

View File

@@ -31,7 +31,13 @@ type API struct {
// GetSnapshot retrieves the state snapshot at a given block. // GetSnapshot retrieves the state snapshot at a given block.
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) { func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
header := api.getHeader(number) // Retrieve the requested block number (or current if none requested)
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
// Ensure we have an actually valid block and return its snapshot // Ensure we have an actually valid block and return its snapshot
if header == nil { if header == nil {
return nil, errUnknownBlock return nil, errUnknownBlock
@@ -50,7 +56,13 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
// GetValidators retrieves the list of validators at the specified block. // GetValidators retrieves the list of validators at the specified block.
func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) { func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
header := api.getHeader(number) // Retrieve the requested block number (or current if none requested)
var header *types.Header
if number == nil || *number == rpc.LatestBlockNumber {
header = api.chain.CurrentHeader()
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
// Ensure we have an actually valid block and return the validators from its snapshot // Ensure we have an actually valid block and return the validators from its snapshot
if header == nil { if header == nil {
return nil, errUnknownBlock return nil, errUnknownBlock
@@ -74,52 +86,3 @@ func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error)
} }
return snap.validators(), nil return snap.validators(), nil
} }
func (api *API) GetJustifiedNumber(number *rpc.BlockNumber) (uint64, error) {
header := api.getHeader(number)
// Ensure we have an actually valid block and return the validators from its snapshot
if header == nil {
return 0, errUnknownBlock
}
snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil || snap.Attestation == nil {
return 0, err
}
return snap.Attestation.TargetNumber, nil
}
func (api *API) GetFinalizedNumber(number *rpc.BlockNumber) (uint64, error) {
header := api.getHeader(number)
// Ensure we have an actually valid block and return the validators from its snapshot
if header == nil {
return 0, errUnknownBlock
}
snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil || snap.Attestation == nil {
return 0, err
}
return snap.Attestation.SourceNumber, nil
}
func (api *API) getHeader(number *rpc.BlockNumber) (header *types.Header) {
currentHeader := api.chain.CurrentHeader()
if number == nil || *number == rpc.LatestBlockNumber {
header = currentHeader // current if none requested
} else if *number == rpc.SafeBlockNumber {
justifiedNumber, _, err := api.parlia.GetJustifiedNumberAndHash(api.chain, []*types.Header{currentHeader})
if err != nil {
return nil
}
header = api.chain.GetHeaderByNumber(justifiedNumber)
} else if *number == rpc.FinalizedBlockNumber {
header = api.parlia.GetFinalizedHeader(api.chain, currentHeader)
} else if *number == rpc.PendingBlockNumber {
return nil // no pending blocks on bsc
} else if *number == rpc.EarliestBlockNumber {
header = api.chain.GetHeaderByNumber(0)
} else {
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
}
return
}

View File

@@ -6,7 +6,6 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io"
"math" "math"
"math/big" "math/big"
"math/rand" "math/rand"
@@ -605,11 +604,15 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas) return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
case header.BlobGasUsed != nil: case header.BlobGasUsed != nil:
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed) return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
case header.ParentBeaconRoot != nil:
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
case header.WithdrawalsHash != nil: case header.WithdrawalsHash != nil:
return fmt.Errorf("invalid WithdrawalsHash, have %#x, expected nil", header.WithdrawalsHash) return fmt.Errorf("invalid WithdrawalsHash, have %#x, expected nil", header.WithdrawalsHash)
} }
} else { } else {
switch { switch {
case header.ParentBeaconRoot != nil:
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
case !header.EmptyWithdrawalsHash(): case !header.EmptyWithdrawalsHash():
return errors.New("header has wrong WithdrawalsHash") return errors.New("header has wrong WithdrawalsHash")
} }
@@ -618,17 +621,6 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
} }
} }
bohr := chain.Config().IsBohr(header.Number, header.Time)
if !bohr {
if header.ParentBeaconRoot != nil {
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
}
} else {
if header.ParentBeaconRoot == nil || *header.ParentBeaconRoot != (common.Hash{}) {
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected zero hash", header.ParentBeaconRoot)
}
}
// All basic checks passed, verify cascading fields // All basic checks passed, verify cascading fields
return p.verifyCascadingFields(chain, header, parents) return p.verifyCascadingFields(chain, header, parents)
} }
@@ -1370,7 +1362,7 @@ func (p *Parlia) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *
func (p *Parlia) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error { func (p *Parlia) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error {
targetNumber := vote.Data.TargetNumber targetNumber := vote.Data.TargetNumber
targetHash := vote.Data.TargetHash targetHash := vote.Data.TargetHash
header := chain.GetVerifiedBlockByHash(targetHash) header := chain.GetHeaderByHash(targetHash)
if header == nil { if header == nil {
log.Warn("BlockHeader at current voteBlockNumber is nil", "targetNumber", targetNumber, "targetHash", targetHash) log.Warn("BlockHeader at current voteBlockNumber is nil", "targetNumber", targetNumber, "targetHash", targetHash)
return errors.New("BlockHeader at current voteBlockNumber is nil") return errors.New("BlockHeader at current voteBlockNumber is nil")
@@ -1602,35 +1594,11 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
return new(big.Int).Set(diffNoTurn) return new(big.Int).Set(diffNoTurn)
} }
func encodeSigHeaderWithoutVoteAttestation(w io.Writer, header *types.Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
header.MixDigest,
header.Nonce,
})
if err != nil {
panic("can't encode: " + err.Error())
}
}
// SealHash returns the hash of a block without vote attestation prior to it being sealed. // SealHash returns the hash of a block without vote attestation prior to it being sealed.
// So it's not the real hash of a block, just used as unique id to distinguish task // So it's not the real hash of a block, just used as unique id to distinguish task
func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) { func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) {
hasher := sha3.NewLegacyKeccak256() hasher := sha3.NewLegacyKeccak256()
encodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID) types.EncodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
hasher.Sum(hash[:0]) hasher.Sum(hash[:0])
return hash return hash
} }

View File

@@ -22,7 +22,6 @@ import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"math"
"sort" "sort"
lru "github.com/hashicorp/golang-lru" lru "github.com/hashicorp/golang-lru"
@@ -268,19 +267,8 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
} }
} }
snap.Recents[number] = validator snap.Recents[number] = validator
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
snap.updateAttestation(header, chainConfig, s.config)
// change validator set // change validator set
if number > 0 && number%s.config.Epoch == uint64(len(snap.Validators)/2) { if number > 0 && number%s.config.Epoch == uint64(len(snap.Validators)/2) {
epochKey := math.MaxUint64 - header.Number.Uint64()/s.config.Epoch // impossible used as a block number
if chainConfig.IsBohr(header.Number, header.Time) {
// after switching the validator set, snap.Validators may become larger,
// then the unexpected second switch will happen, just skip it.
if _, ok := snap.Recents[epochKey]; ok {
continue
}
}
checkpointHeader := FindAncientHeader(header, uint64(len(snap.Validators)/2), chain, parents) checkpointHeader := FindAncientHeader(header, uint64(len(snap.Validators)/2), chain, parents)
if checkpointHeader == nil { if checkpointHeader == nil {
return nil, consensus.ErrUnknownAncestor return nil, consensus.ErrUnknownAncestor
@@ -301,12 +289,6 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
} }
} }
} }
if chainConfig.IsBohr(header.Number, header.Time) {
// BEP-404: Clear Miner History when Switching Validators Set
snap.Recents = make(map[uint64]common.Address)
snap.Recents[epochKey] = common.Address{}
log.Debug("Recents are cleared up", "blockNumber", number)
} else {
oldLimit := len(snap.Validators)/2 + 1 oldLimit := len(snap.Validators)/2 + 1
newLimit := len(newVals)/2 + 1 newLimit := len(newVals)/2 + 1
if newLimit < oldLimit { if newLimit < oldLimit {
@@ -314,9 +296,8 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
delete(snap.Recents, number-uint64(newLimit)-uint64(i)) delete(snap.Recents, number-uint64(newLimit)-uint64(i))
} }
} }
} oldLimit = len(snap.Validators)
oldLimit := len(snap.Validators) newLimit = len(newVals)
newLimit := len(newVals)
if newLimit < oldLimit { if newLimit < oldLimit {
for i := 0; i < oldLimit-newLimit; i++ { for i := 0; i < oldLimit-newLimit; i++ {
delete(snap.RecentForkHashes, number-uint64(newLimit)-uint64(i)) delete(snap.RecentForkHashes, number-uint64(newLimit)-uint64(i))
@@ -330,6 +311,10 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
} }
} }
} }
snap.updateAttestation(header, chainConfig, s.config)
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
} }
snap.Number += uint64(len(headers)) snap.Number += uint64(len(headers))
snap.Hash = headers[len(headers)-1].Hash() snap.Hash = headers[len(headers)-1].Hash()

View File

@@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
@@ -40,6 +41,12 @@ func EnableRemoteVerifyManager(remoteValidator *remoteVerifyManager) BlockValida
} }
} }
var (
validateBloomTimer = metrics.NewRegisteredTimer("validate/bloom/time", nil)
validateReceiptTimer = metrics.NewRegisteredTimer("validate/receipt/time", nil)
validateRootTimer = metrics.NewRegisteredTimer("validate/root/time", nil)
)
// BlockValidator is responsible for validating block headers, uncles and // BlockValidator is responsible for validating block headers, uncles and
// processed state. // processed state.
// //
@@ -184,6 +191,10 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
// For valid blocks this should always validate to true. // For valid blocks this should always validate to true.
validateFuns := []func() error{ validateFuns := []func() error{
func() error { func() error {
defer func(start time.Time) {
validateBloomTimer.UpdateSince(start)
}(time.Now())
rbloom := types.CreateBloom(receipts) rbloom := types.CreateBloom(receipts)
if rbloom != header.Bloom { if rbloom != header.Bloom {
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom) return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
@@ -191,6 +202,9 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
return nil return nil
}, },
func() error { func() error {
defer func(start time.Time) {
validateReceiptTimer.UpdateSince(start)
}(time.Now())
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil)) receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
if receiptSha != header.ReceiptHash { if receiptSha != header.ReceiptHash {
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
@@ -209,6 +223,9 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
}) })
} else { } else {
validateFuns = append(validateFuns, func() error { validateFuns = append(validateFuns, func() error {
defer func(start time.Time) {
validateRootTimer.UpdateSince(start)
}(time.Now())
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error()) return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
} }

View File

@@ -74,6 +74,7 @@ var (
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil) blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil) chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
mGasPsGauge = metrics.NewRegisteredGauge("chain/process/gas", nil)
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil) accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil) accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
@@ -95,6 +96,9 @@ var (
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil) blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil) blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil) blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
blockValidationTotalTimer = metrics.NewRegisteredTimer("chain/total/validation", nil)
blockExecutionTotalTimer = metrics.NewRegisteredTimer("chain/total/execution", nil)
blockWriteTotalTimer = metrics.NewRegisteredTimer("chain/total/write", nil)
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
@@ -268,7 +272,6 @@ type BlockChain struct {
logsFeed event.Feed logsFeed event.Feed
blockProcFeed event.Feed blockProcFeed event.Feed
finalizedHeaderFeed event.Feed finalizedHeaderFeed event.Feed
highestVerifiedBlockFeed event.Feed
scope event.SubscriptionScope scope event.SubscriptionScope
genesisBlock *types.Block genesisBlock *types.Block
@@ -277,7 +280,6 @@ type BlockChain struct {
chainmu *syncx.ClosableMutex chainmu *syncx.ClosableMutex
highestVerifiedHeader atomic.Pointer[types.Header] highestVerifiedHeader atomic.Pointer[types.Header]
highestVerifiedBlock atomic.Pointer[types.Header]
currentBlock atomic.Pointer[types.Header] // Current head of the chain currentBlock atomic.Pointer[types.Header] // Current head of the chain
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
@@ -402,7 +404,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
} }
bc.highestVerifiedHeader.Store(nil) bc.highestVerifiedHeader.Store(nil)
bc.highestVerifiedBlock.Store(nil)
bc.currentBlock.Store(nil) bc.currentBlock.Store(nil)
bc.currentSnapBlock.Store(nil) bc.currentSnapBlock.Store(nil)
bc.chasingHead.Store(nil) bc.chasingHead.Store(nil)
@@ -1801,6 +1802,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
if err := blockBatch.Write(); err != nil { if err := blockBatch.Write(); err != nil {
log.Crit("Failed to write block into disk", "err", err) log.Crit("Failed to write block into disk", "err", err)
} }
bc.hc.tdCache.Add(block.Hash(), externTd)
bc.blockCache.Add(block.Hash(), block)
bc.receiptsCache.Add(block.Hash(), receipts)
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
bc.sidecarsCache.Add(block.Hash(), block.Sidecars())
}
wg.Done() wg.Done()
}() }()
@@ -1911,34 +1918,26 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// WriteBlockAndSetHead writes the given block and all associated state to the database, // WriteBlockAndSetHead writes the given block and all associated state to the database,
// and applies the block as the new chain head. // and applies the block as the new chain head.
func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool, mux *event.TypeMux) (status WriteStatus, err error) { func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if !bc.chainmu.TryLock() { if !bc.chainmu.TryLock() {
return NonStatTy, errChainStopped return NonStatTy, errChainStopped
} }
defer bc.chainmu.Unlock() defer bc.chainmu.Unlock()
return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent, mux) return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent)
} }
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead. // writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
// This function expects the chain mutex to be held. // This function expects the chain mutex to be held.
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool, mux *event.TypeMux) (status WriteStatus, err error) { func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if err := bc.writeBlockWithState(block, receipts, state); err != nil {
return NonStatTy, err
}
currentBlock := bc.CurrentBlock() currentBlock := bc.CurrentBlock()
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header()) reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header())
if err != nil { if err != nil {
return NonStatTy, err return NonStatTy, err
} }
if reorg {
bc.highestVerifiedBlock.Store(types.CopyHeader(block.Header()))
bc.highestVerifiedBlockFeed.Send(HighestVerifiedBlockEvent{Header: block.Header()})
if mux != nil {
mux.Post(NewSealedBlockEvent{Block: block})
}
}
if err := bc.writeBlockWithState(block, receipts, state); err != nil {
return NonStatTy, err
}
if reorg { if reorg {
// Reorganise the chain if the parent is not the head block // Reorganise the chain if the parent is not the head block
if block.ParentHash() != currentBlock.Hash() { if block.ParentHash() != currentBlock.Hash() {
@@ -2273,6 +2272,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
statedb.StopPrefetcher() statedb.StopPrefetcher()
return it.index, err return it.index, err
} }
blockExecutionTotalTimer.UpdateSince(pstart)
ptime := time.Since(pstart) ptime := time.Since(pstart)
// Validate the state using the default validator // Validate the state using the default validator
@@ -2283,6 +2284,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
statedb.StopPrefetcher() statedb.StopPrefetcher()
return it.index, err return it.index, err
} }
blockValidationTotalTimer.UpdateSince(vstart)
vtime := time.Since(vstart) vtime := time.Since(vstart)
proctime := time.Since(start) // processing + validation proctime := time.Since(start) // processing + validation
@@ -2311,11 +2314,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// Don't set the head, only insert the block // Don't set the head, only insert the block
err = bc.writeBlockWithState(block, receipts, statedb) err = bc.writeBlockWithState(block, receipts, statedb)
} else { } else {
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false, nil) status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
} }
if err != nil { if err != nil {
return it.index, err return it.index, err
} }
blockWriteTotalTimer.UpdateSince(wstart)
bc.cacheReceipts(block.Hash(), receipts, block) bc.cacheReceipts(block.Hash(), receipts, block)

View File

@@ -64,6 +64,7 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000, "blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps, "elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
} }
mGasPsGauge.Update(int64(mgasps))
blockInsertMgaspsGauge.Update(int64(mgasps)) blockInsertMgaspsGauge.Update(int64(mgasps))
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute { if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...) context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)

View File

@@ -98,15 +98,6 @@ func (bc *BlockChain) GetHeaderByHash(hash common.Hash) *types.Header {
return bc.hc.GetHeaderByHash(hash) return bc.hc.GetHeaderByHash(hash)
} }
// GetVerifiedBlockByHash retrieves the header of a verified block, it may be only in memory.
func (bc *BlockChain) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
highestVerifiedBlock := bc.highestVerifiedBlock.Load()
if highestVerifiedBlock != nil && highestVerifiedBlock.Hash() == hash {
return highestVerifiedBlock
}
return bc.hc.GetHeaderByHash(hash)
}
// GetHeaderByNumber retrieves a block header from the database by number, // GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found. // caching it (associated with its hash) if found.
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
@@ -495,11 +486,6 @@ func (bc *BlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Su
return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch)) return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch))
} }
// SubscribeHighestVerifiedBlockEvent registers a subscription of HighestVerifiedBlockEvent.
func (bc *BlockChain) SubscribeHighestVerifiedHeaderEvent(ch chan<- HighestVerifiedBlockEvent) event.Subscription {
return bc.scope.Track(bc.highestVerifiedBlockFeed.Subscribe(ch))
}
// SubscribeChainBlockEvent registers a subscription of ChainBlockEvent. // SubscribeChainBlockEvent registers a subscription of ChainBlockEvent.
func (bc *BlockChain) SubscribeChainBlockEvent(ch chan<- ChainHeadEvent) event.Subscription { func (bc *BlockChain) SubscribeChainBlockEvent(ch chan<- ChainHeadEvent) event.Subscription {
return bc.scope.Track(bc.chainBlockFeed.Subscribe(ch)) return bc.scope.Track(bc.chainBlockFeed.Subscribe(ch))

View File

@@ -486,7 +486,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi
if cm.config.Parlia != nil { if cm.config.Parlia != nil {
header.WithdrawalsHash = &types.EmptyWithdrawalsHash header.WithdrawalsHash = &types.EmptyWithdrawalsHash
} }
if cm.config.Parlia == nil || cm.config.IsBohr(header.Number, header.Time) { if cm.config.Parlia == nil {
header.ParentBeaconRoot = new(common.Hash) header.ParentBeaconRoot = new(common.Hash)
} }
} }
@@ -621,10 +621,6 @@ func (cm *chainMaker) GetHighestVerifiedHeader() *types.Header {
panic("not supported") panic("not supported")
} }
func (cm *chainMaker) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
return cm.GetHeaderByHash(hash)
}
func (cm *chainMaker) ChasingHead() *types.Header { func (cm *chainMaker) ChasingHead() *types.Header {
panic("not supported") panic("not supported")
} }

View File

@@ -365,10 +365,6 @@ func (r *mockDAHeaderReader) GetHighestVerifiedHeader() *types.Header {
panic("not supported") panic("not supported")
} }
func (r *mockDAHeaderReader) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
panic("not supported")
}
func createMockDATx(config *params.ChainConfig, sidecar *types.BlobTxSidecar) *types.Transaction { func createMockDATx(config *params.ChainConfig, sidecar *types.BlobTxSidecar) *types.Transaction {
if sidecar == nil { if sidecar == nil {
tx := &types.DynamicFeeTx{ tx := &types.DynamicFeeTx{

View File

@@ -27,10 +27,7 @@ type NewTxsEvent struct{ Txs []*types.Transaction }
// ReannoTxsEvent is posted when a batch of local pending transactions exceed a specified duration. // ReannoTxsEvent is posted when a batch of local pending transactions exceed a specified duration.
type ReannoTxsEvent struct{ Txs []*types.Transaction } type ReannoTxsEvent struct{ Txs []*types.Transaction }
// NewSealedBlockEvent is posted when a block has been sealed. // NewMinedBlockEvent is posted when a block has been imported.
type NewSealedBlockEvent struct{ Block *types.Block }
// NewMinedBlockEvent is posted when a block has been mined.
type NewMinedBlockEvent struct{ Block *types.Block } type NewMinedBlockEvent struct{ Block *types.Block }
// RemovedLogsEvent is posted when a reorg happens // RemovedLogsEvent is posted when a reorg happens
@@ -53,5 +50,3 @@ type ChainSideEvent struct {
} }
type ChainHeadEvent struct{ Block *types.Block } type ChainHeadEvent struct{ Block *types.Block }
type HighestVerifiedBlockEvent struct{ Header *types.Header }

View File

@@ -121,12 +121,9 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
if f.preserve != nil { if f.preserve != nil {
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern) currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
} }
doubleSign := (extern.Coinbase == current.Coinbase)
reorg = !currentPreserve && (externPreserve || reorg = !currentPreserve && (externPreserve ||
extern.Time < current.Time || extern.Time < current.Time ||
extern.Time == current.Time && extern.Time == current.Time && f.rand.Float64() < 0.5)
((doubleSign && extern.Hash().Cmp(current.Hash()) < 0) ||
(!doubleSign && f.rand.Float64() < 0.5)))
} }
return reorg, nil return reorg, nil
} }

View File

@@ -444,7 +444,7 @@ func (g *Genesis) ToBlock() *types.Block {
// EIP-4788: The parentBeaconBlockRoot of the genesis block is always // EIP-4788: The parentBeaconBlockRoot of the genesis block is always
// the zero hash. This is because the genesis block does not have a parent // the zero hash. This is because the genesis block does not have a parent
// by definition. // by definition.
if conf.Parlia == nil || conf.IsBohr(num, g.Timestamp) { if conf.Parlia == nil {
head.ParentBeaconRoot = new(common.Hash) head.ParentBeaconRoot = new(common.Hash)
} }

View File

@@ -436,10 +436,6 @@ func (hc *HeaderChain) GetHighestVerifiedHeader() *types.Header {
return nil return nil
} }
func (hc *HeaderChain) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
return hc.GetHeaderByHash(hash)
}
func (hc *HeaderChain) ChasingHead() *types.Header { func (hc *HeaderChain) ChasingHead() *types.Header {
return nil return nil
} }

View File

@@ -34,4 +34,7 @@ var (
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil) slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil) slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil) slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil)
accountIntermediateRootTimer = metrics.NewRegisteredTimer("state/account/intermediate/root/time", nil)
storageIntermediateRootTimer = metrics.NewRegisteredTimer("state/storage/intermediate/root/time", nil)
) )

View File

@@ -286,6 +286,13 @@ func (dl *diffLayer) Stale() bool {
// Account directly retrieves the account associated with a particular hash in // Account directly retrieves the account associated with a particular hash in
// the snapshot slim data format. // the snapshot slim data format.
func (dl *diffLayer) Account(hash common.Hash) (*types.SlimAccount, error) { func (dl *diffLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
defer func(start time.Time) {
snapGetTimer.UpdateSince(start)
snapGetQPS.Mark(1)
snapGetAccountTimer.UpdateSince(start)
snapGetAccountQPS.Mark(1)
}(time.Now())
data, err := dl.AccountRLP(hash) data, err := dl.AccountRLP(hash)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -394,6 +401,13 @@ func (dl *diffLayer) accountRLP(hash common.Hash, depth int) ([]byte, error) {
// //
// Note the returned slot is not a copy, please don't modify it. // Note the returned slot is not a copy, please don't modify it.
func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, error) { func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, error) {
defer func(start time.Time) {
snapGetTimer.UpdateSince(start)
snapGetQPS.Mark(1)
snapGetStorageTimer.UpdateSince(start)
snapGetStorageQPS.Mark(1)
}(time.Now())
// Check the bloom filter first whether there's even a point in reaching into // Check the bloom filter first whether there's even a point in reaching into
// all the maps in all the layers below // all the maps in all the layers below
dl.lock.RLock() dl.lock.RLock()

View File

@@ -19,6 +19,7 @@ package snapshot
import ( import (
"bytes" "bytes"
"sync" "sync"
"time"
"github.com/VictoriaMetrics/fastcache" "github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@@ -136,7 +137,12 @@ func (dl *diskLayer) AccountRLP(hash common.Hash) ([]byte, error) {
return blob, nil return blob, nil
} }
// Cache doesn't contain account, pull from disk and cache for later // Cache doesn't contain account, pull from disk and cache for later
// TODO:
snapNodeQPS.Mark(1)
startLoadSnapNode := time.Now()
blob := rawdb.ReadAccountSnapshot(dl.diskdb, hash) blob := rawdb.ReadAccountSnapshot(dl.diskdb, hash)
snapNodeTime.Mark(time.Since(startLoadSnapNode).Nanoseconds())
dl.cache.Set(hash[:], blob) dl.cache.Set(hash[:], blob)
snapshotCleanAccountMissMeter.Mark(1) snapshotCleanAccountMissMeter.Mark(1)
@@ -176,7 +182,11 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
return blob, nil return blob, nil
} }
// Cache doesn't contain storage slot, pull from disk and cache for later // Cache doesn't contain storage slot, pull from disk and cache for later
// TODO:
snapNodeQPS.Mark(1)
startLoadSnapNode := time.Now()
blob := rawdb.ReadStorageSnapshot(dl.diskdb, accountHash, storageHash) blob := rawdb.ReadStorageSnapshot(dl.diskdb, accountHash, storageHash)
snapNodeTime.Mark(time.Since(startLoadSnapNode).Nanoseconds())
dl.cache.Set(key, blob) dl.cache.Set(key, blob)
snapshotCleanStorageMissMeter.Mark(1) snapshotCleanStorageMissMeter.Mark(1)

View File

@@ -50,4 +50,15 @@ var (
snapStorageWriteCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/write", nil) snapStorageWriteCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/write", nil)
// snapStorageCleanCounter measures time spent on deleting storages // snapStorageCleanCounter measures time spent on deleting storages
snapStorageCleanCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/clean", nil) snapStorageCleanCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/clean", nil)
snapNodeQPS = metrics.NewRegisteredMeter("pbss/snap/node/qps", nil)
snapNodeTime = metrics.NewRegisteredMeter("pbss/snap/node/time", nil)
snapGetTimer = metrics.NewRegisteredTimer("snap/get/time", nil)
snapGetQPS = metrics.NewRegisteredMeter("snap/get/qps", nil)
snapGetAccountTimer = metrics.NewRegisteredTimer("snap/account/get/time", nil)
snapGetAccountQPS = metrics.NewRegisteredMeter("snap/account/get/qps", nil)
snapGetStorageTimer = metrics.NewRegisteredTimer("snap/storage/get/time", nil)
snapGetStorageQPS = metrics.NewRegisteredMeter("snap/storage/get/qps", nil)
) )

View File

@@ -223,6 +223,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
return common.Hash{} return common.Hash{}
} }
// If no live objects are available, attempt to use snapshots // If no live objects are available, attempt to use snapshots
defer func(start time.Time) {
stateDBGetTimer.UpdateSince(start)
stateDBGetQPS.Mark(1)
stateDBGetStorageTimer.UpdateSince(start)
stateDBGetStorageQPS.Mark(1)
}(time.Now())
var ( var (
enc []byte enc []byte
err error err error

View File

@@ -54,6 +54,16 @@ type revision struct {
journalIndex int journalIndex int
} }
var (
stateDBGetTimer = metrics.NewRegisteredTimer("statedb/get/time", nil)
stateDBGetQPS = metrics.NewRegisteredMeter("statedb/get/qps", nil)
stateDBGetAccountTimer = metrics.NewRegisteredTimer("statedb/account/get/time", nil)
stateDBGetAccountQPS = metrics.NewRegisteredMeter("statedb/account/get/qps", nil)
stateDBGetStorageTimer = metrics.NewRegisteredTimer("statedb/storage/get/time", nil)
stateDBGetStorageQPS = metrics.NewRegisteredMeter("statedb/storage/get/qps", nil)
)
// StateDB structs within the ethereum protocol are used to store anything // StateDB structs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing // within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve: // nested states. It's the general query interface to retrieve:
@@ -166,7 +176,7 @@ func NewWithSharedPool(root common.Hash, db Database, snaps *snapshot.Tree) (*St
if err != nil { if err != nil {
return nil, err return nil, err
} }
statedb.storagePool = NewStoragePool() //statedb.storagePool = NewStoragePool()
return statedb, nil return statedb, nil
} }
@@ -716,6 +726,14 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
if obj := s.stateObjects[addr]; obj != nil { if obj := s.stateObjects[addr]; obj != nil {
return obj return obj
} }
defer func(start time.Time) {
stateDBGetTimer.UpdateSince(start)
stateDBGetQPS.Mark(1)
stateDBGetAccountTimer.UpdateSince(start)
stateDBGetAccountQPS.Mark(1)
}(time.Now())
// If no live objects are available, attempt to use snapshots // If no live objects are available, attempt to use snapshots
var data *types.StateAccount var data *types.StateAccount
if s.snap != nil { if s.snap != nil {
@@ -1147,6 +1165,10 @@ func (s *StateDB) populateSnapStorage(obj *stateObject) bool {
} }
func (s *StateDB) AccountsIntermediateRoot() { func (s *StateDB) AccountsIntermediateRoot() {
defer func(start time.Time) {
storageIntermediateRootTimer.UpdateSince(start)
}(time.Now())
tasks := make(chan func()) tasks := make(chan func())
finishCh := make(chan struct{}) finishCh := make(chan struct{})
defer close(finishCh) defer close(finishCh)
@@ -1191,6 +1213,9 @@ func (s *StateDB) AccountsIntermediateRoot() {
} }
func (s *StateDB) StateIntermediateRoot() common.Hash { func (s *StateDB) StateIntermediateRoot() common.Hash {
defer func(start time.Time) {
accountIntermediateRootTimer.UpdateSince(start)
}(time.Now())
// If there was a trie prefetcher operating, it gets aborted and irrevocably // If there was a trie prefetcher operating, it gets aborted and irrevocably
// modified after we start retrieving tries. Remove it from the statedb after // modified after we start retrieving tries. Remove it from the statedb after
// this round of use. // this round of use.

View File

@@ -673,7 +673,10 @@ type DiffAccountsInBlock struct {
Transactions []DiffAccountsInTx Transactions []DiffAccountsInTx
} }
var extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal var (
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
)
// SealHash returns the hash of a block prior to it being sealed. // SealHash returns the hash of a block prior to it being sealed.
func SealHash(header *Header, chainId *big.Int) (hash common.Hash) { func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
@@ -684,33 +687,7 @@ func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
} }
func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) { func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) {
var err error err := rlp.Encode(w, []interface{}{
if header.ParentBeaconRoot != nil && *header.ParentBeaconRoot == (common.Hash{}) {
err = rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
header.MixDigest,
header.Nonce,
header.BaseFee,
header.WithdrawalsHash,
header.BlobGasUsed,
header.ExcessBlobGas,
header.ParentBeaconRoot,
})
} else {
err = rlp.Encode(w, []interface{}{
chainId, chainId,
header.ParentHash, header.ParentHash,
header.UncleHash, header.UncleHash,
@@ -728,7 +705,30 @@ func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) {
header.MixDigest, header.MixDigest,
header.Nonce, header.Nonce,
}) })
} if err != nil {
panic("can't encode: " + err.Error())
}
}
func EncodeSigHeaderWithoutVoteAttestation(w io.Writer, header *Header, chainId *big.Int) {
err := rlp.Encode(w, []interface{}{
chainId,
header.ParentHash,
header.UncleHash,
header.Coinbase,
header.Root,
header.TxHash,
header.ReceiptHash,
header.Bloom,
header.Difficulty,
header.Number,
header.GasLimit,
header.GasUsed,
header.Time,
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
header.MixDigest,
header.Nonce,
})
if err != nil { if err != nil {
panic("can't encode: " + err.Error()) panic("can't encode: " + err.Error())
} }

View File

@@ -33,8 +33,8 @@ type VoteManager struct {
chain *core.BlockChain chain *core.BlockChain
highestVerifiedBlockCh chan core.HighestVerifiedBlockEvent chainHeadCh chan core.ChainHeadEvent
highestVerifiedBlockSub event.Subscription chainHeadSub event.Subscription
// used for backup validators to sync votes from corresponding mining validator // used for backup validators to sync votes from corresponding mining validator
syncVoteCh chan core.NewVoteEvent syncVoteCh chan core.NewVoteEvent
@@ -51,7 +51,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
voteManager := &VoteManager{ voteManager := &VoteManager{
eth: eth, eth: eth,
chain: chain, chain: chain,
highestVerifiedBlockCh: make(chan core.HighestVerifiedBlockEvent, highestVerifiedBlockChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
syncVoteCh: make(chan core.NewVoteEvent, voteBufferForPut), syncVoteCh: make(chan core.NewVoteEvent, voteBufferForPut),
pool: pool, pool: pool,
engine: engine, engine: engine,
@@ -74,7 +74,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
voteManager.journal = voteJournal voteManager.journal = voteJournal
// Subscribe to chain head event. // Subscribe to chain head event.
voteManager.highestVerifiedBlockSub = voteManager.chain.SubscribeHighestVerifiedHeaderEvent(voteManager.highestVerifiedBlockCh) voteManager.chainHeadSub = voteManager.chain.SubscribeChainHeadEvent(voteManager.chainHeadCh)
voteManager.syncVoteSub = voteManager.pool.SubscribeNewVoteEvent(voteManager.syncVoteCh) voteManager.syncVoteSub = voteManager.pool.SubscribeNewVoteEvent(voteManager.syncVoteCh)
go voteManager.loop() go voteManager.loop()
@@ -84,7 +84,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
func (voteManager *VoteManager) loop() { func (voteManager *VoteManager) loop() {
log.Debug("vote manager routine loop started") log.Debug("vote manager routine loop started")
defer voteManager.highestVerifiedBlockSub.Unsubscribe() defer voteManager.chainHeadSub.Unsubscribe()
defer voteManager.syncVoteSub.Unsubscribe() defer voteManager.syncVoteSub.Unsubscribe()
events := voteManager.eth.EventMux().Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) events := voteManager.eth.EventMux().Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
@@ -119,7 +119,7 @@ func (voteManager *VoteManager) loop() {
log.Debug("downloader is in DoneEvent mode, set the startVote flag to true") log.Debug("downloader is in DoneEvent mode, set the startVote flag to true")
startVote = true startVote = true
} }
case cHead := <-voteManager.highestVerifiedBlockCh: case cHead := <-voteManager.chainHeadCh:
if !startVote { if !startVote {
log.Debug("startVote flag is false, continue") log.Debug("startVote flag is false, continue")
continue continue
@@ -135,12 +135,12 @@ func (voteManager *VoteManager) loop() {
continue continue
} }
if cHead.Header == nil { if cHead.Block == nil {
log.Debug("cHead.Header is nil, continue") log.Debug("cHead.Block is nil, continue")
continue continue
} }
curHead := cHead.Header curHead := cHead.Block.Header()
if p, ok := voteManager.engine.(*parlia.Parlia); ok { if p, ok := voteManager.engine.(*parlia.Parlia); ok {
nextBlockMinedTime := time.Unix(int64((curHead.Time + p.Period())), 0) nextBlockMinedTime := time.Unix(int64((curHead.Time + p.Period())), 0)
timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote
@@ -217,7 +217,7 @@ func (voteManager *VoteManager) loop() {
case <-voteManager.syncVoteSub.Err(): case <-voteManager.syncVoteSub.Err():
log.Debug("voteManager subscribed votes failed") log.Debug("voteManager subscribed votes failed")
return return
case <-voteManager.highestVerifiedBlockSub.Err(): case <-voteManager.chainHeadSub.Err():
log.Debug("voteManager subscribed chainHead failed") log.Debug("voteManager subscribed chainHead failed")
return return
} }

View File

@@ -24,7 +24,7 @@ const (
lowerLimitOfVoteBlockNumber = 256 lowerLimitOfVoteBlockNumber = 256
upperLimitOfVoteBlockNumber = 11 // refer to fetcher.maxUncleDist upperLimitOfVoteBlockNumber = 11 // refer to fetcher.maxUncleDist
highestVerifiedBlockChanSize = 10 // highestVerifiedBlockChanSize is the size of channel listening to HighestVerifiedBlockEvent. chainHeadChanSize = 10 // chainHeadChanSize is the size of channel listening to ChainHeadEvent.
) )
var ( var (
@@ -57,8 +57,8 @@ type VotePool struct {
curVotesPq *votesPriorityQueue curVotesPq *votesPriorityQueue
futureVotesPq *votesPriorityQueue futureVotesPq *votesPriorityQueue
highestVerifiedBlockCh chan core.HighestVerifiedBlockEvent chainHeadCh chan core.ChainHeadEvent
highestVerifiedBlockSub event.Subscription chainHeadSub event.Subscription
votesCh chan *types.VoteEnvelope votesCh chan *types.VoteEnvelope
@@ -75,13 +75,13 @@ func NewVotePool(chain *core.BlockChain, engine consensus.PoSA) *VotePool {
futureVotes: make(map[common.Hash]*VoteBox), futureVotes: make(map[common.Hash]*VoteBox),
curVotesPq: &votesPriorityQueue{}, curVotesPq: &votesPriorityQueue{},
futureVotesPq: &votesPriorityQueue{}, futureVotesPq: &votesPriorityQueue{},
highestVerifiedBlockCh: make(chan core.HighestVerifiedBlockEvent, highestVerifiedBlockChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
votesCh: make(chan *types.VoteEnvelope, voteBufferForPut), votesCh: make(chan *types.VoteEnvelope, voteBufferForPut),
engine: engine, engine: engine,
} }
// Subscribe events from blockchain and start the main event loop. // Subscribe events from blockchain and start the main event loop.
votePool.highestVerifiedBlockSub = votePool.chain.SubscribeHighestVerifiedHeaderEvent(votePool.highestVerifiedBlockCh) votePool.chainHeadSub = votePool.chain.SubscribeChainHeadEvent(votePool.chainHeadCh)
go votePool.loop() go votePool.loop()
return votePool return votePool
@@ -89,18 +89,18 @@ func NewVotePool(chain *core.BlockChain, engine consensus.PoSA) *VotePool {
// loop is the vote pool's main even loop, waiting for and reacting to outside blockchain events and votes channel event. // loop is the vote pool's main even loop, waiting for and reacting to outside blockchain events and votes channel event.
func (pool *VotePool) loop() { func (pool *VotePool) loop() {
defer pool.highestVerifiedBlockSub.Unsubscribe() defer pool.chainHeadSub.Unsubscribe()
for { for {
select { select {
// Handle ChainHeadEvent. // Handle ChainHeadEvent.
case ev := <-pool.highestVerifiedBlockCh: case ev := <-pool.chainHeadCh:
if ev.Header != nil { if ev.Block != nil {
latestBlockNumber := ev.Header.Number.Uint64() latestBlockNumber := ev.Block.NumberU64()
pool.prune(latestBlockNumber) pool.prune(latestBlockNumber)
pool.transferVotesFromFutureToCur(ev.Header) pool.transferVotesFromFutureToCur(ev.Block.Header())
} }
case <-pool.highestVerifiedBlockSub.Err(): case <-pool.chainHeadSub.Err():
return return
// Handle votes channel and put the vote into vote pool. // Handle votes channel and put the vote into vote pool.
@@ -135,7 +135,7 @@ func (pool *VotePool) putIntoVotePool(vote *types.VoteEnvelope) bool {
var votesPq *votesPriorityQueue var votesPq *votesPriorityQueue
isFutureVote := false isFutureVote := false
voteBlock := pool.chain.GetVerifiedBlockByHash(targetHash) voteBlock := pool.chain.GetHeaderByHash(targetHash)
if voteBlock == nil { if voteBlock == nil {
votes = pool.futureVotes votes = pool.futureVotes
votesPq = pool.futureVotesPq votesPq = pool.futureVotesPq
@@ -226,7 +226,7 @@ func (pool *VotePool) transferVotesFromFutureToCur(latestBlockHeader *types.Head
futurePqBuffer := make([]*types.VoteData, 0) futurePqBuffer := make([]*types.VoteData, 0)
for futurePq.Len() > 0 && futurePq.Peek().TargetNumber <= latestBlockNumber { for futurePq.Len() > 0 && futurePq.Peek().TargetNumber <= latestBlockNumber {
blockHash := futurePq.Peek().TargetHash blockHash := futurePq.Peek().TargetHash
header := pool.chain.GetVerifiedBlockByHash(blockHash) header := pool.chain.GetHeaderByHash(blockHash)
if header == nil { if header == nil {
// Put into pq buffer used for later put again into futurePq // Put into pq buffer used for later put again into futurePq
futurePqBuffer = append(futurePqBuffer, heap.Pop(futurePq).(*types.VoteData)) futurePqBuffer = append(futurePqBuffer, heap.Pop(futurePq).(*types.VoteData))

View File

@@ -729,7 +729,7 @@ func (h *handler) Start(maxPeers int, maxPeersPerIP int) {
// broadcast mined blocks // broadcast mined blocks
h.wg.Add(1) h.wg.Add(1)
h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}, core.NewSealedBlockEvent{}) h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{})
go h.minedBroadcastLoop() go h.minedBroadcastLoop()
// start sync handlers // start sync handlers
@@ -946,9 +946,8 @@ func (h *handler) minedBroadcastLoop() {
if obj == nil { if obj == nil {
continue continue
} }
if ev, ok := obj.Data.(core.NewSealedBlockEvent); ok { if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok {
h.BroadcastBlock(ev.Block, true) // Propagate block to peers h.BroadcastBlock(ev.Block, true) // First propagate block to peers
} else if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok {
h.BroadcastBlock(ev.Block, false) // Only then announce to the rest h.BroadcastBlock(ev.Block, false) // Only then announce to the rest
} }
case <-h.stopCh: case <-h.stopCh:

6
go.mod
View File

@@ -24,7 +24,7 @@ require (
github.com/deckarep/golang-set/v2 v2.5.0 github.com/deckarep/golang-set/v2 v2.5.0
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
github.com/ethereum/c-kzg-4844 v0.4.0 github.com/ethereum/c-kzg-4844 v0.4.0
github.com/fatih/color v1.14.1 github.com/fatih/color v1.16.0
github.com/fatih/structs v1.1.0 github.com/fatih/structs v1.1.0
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.2 github.com/fjl/memsize v0.0.2
@@ -82,7 +82,7 @@ require (
golang.org/x/crypto v0.21.0 golang.org/x/crypto v0.21.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/sync v0.6.0 golang.org/x/sync v0.6.0
golang.org/x/sys v0.18.0 golang.org/x/sys v0.20.0
golang.org/x/text v0.14.0 golang.org/x/text v0.14.0
golang.org/x/time v0.5.0 golang.org/x/time v0.5.0
golang.org/x/tools v0.18.0 golang.org/x/tools v0.18.0
@@ -159,7 +159,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/merlin v0.1.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect

18
go.sum
View File

@@ -326,8 +326,9 @@ github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0= github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM= github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
@@ -580,14 +581,13 @@ github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA= github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -1503,8 +1503,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View File

@@ -665,7 +665,7 @@ func (w *worker) resultLoop() {
// Commit block and state to database. // Commit block and state to database.
task.state.SetExpectedStateRoot(block.Root()) task.state.SetExpectedStateRoot(block.Root())
start := time.Now() start := time.Now()
status, err := w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true, w.mux) status, err := w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true)
if status != core.CanonStatTy { if status != core.CanonStatTy {
if err != nil { if err != nil {
log.Error("Failed writing block to chain", "err", err, "status", status) log.Error("Failed writing block to chain", "err", err, "status", status)
@@ -1032,8 +1032,6 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
} }
if w.chainConfig.Parlia == nil { if w.chainConfig.Parlia == nil {
header.ParentBeaconRoot = genParams.beaconRoot header.ParentBeaconRoot = genParams.beaconRoot
} else if w.chainConfig.IsBohr(header.Number, header.Time) {
header.ParentBeaconRoot = new(common.Hash)
} }
} }
// Could potentially happen if starting to mine in an odd state. // Could potentially happen if starting to mine in an odd state.

View File

@@ -17,13 +17,48 @@
package trie package trie
import ( import (
"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/metrics"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"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 (
StateTreeOpenQPS = metrics.NewRegisteredMeter("state/tree/open/qps", nil)
StateTreeOpenTime = metrics.NewRegisteredTimer("state/tree/open/time", nil)
StateTreeGetQPS = metrics.NewRegisteredMeter("state/tree/get/qps", nil)
StateTreeGetTime = metrics.NewRegisteredTimer("state/tree/get/time", nil)
StateAccountTreeGetQPS = metrics.NewRegisteredMeter("state/tree/account/get/qps", nil)
StateAccountTreeGetTime = metrics.NewRegisteredTimer("state/tree/account/get/time", nil)
StateStorageTreeGetQPS = metrics.NewRegisteredMeter("state/tree/storage/get/qps", nil)
StateStorageTreeGetTime = metrics.NewRegisteredTimer("state/tree/storage/get/time", nil)
StateTreePutQPS = metrics.NewRegisteredMeter("state/tree/put/qps", nil)
StateTreePutTime = metrics.NewRegisteredTimer("state/tree/put/time", nil)
StateAccountTreePutQPS = metrics.NewRegisteredMeter("state/tree/account/put/qps", nil)
StateAccountTreePutTime = metrics.NewRegisteredTimer("state/tree/account/put/time", nil)
StateStorageTreePutQPS = metrics.NewRegisteredMeter("state/tree/storage/put/qps", nil)
StateStorageTreePutTime = metrics.NewRegisteredTimer("state/tree/storage/put/time", nil)
StateTreeDelQPS = metrics.NewRegisteredMeter("state/tree/del/qps", nil)
StateTreeDelTime = metrics.NewRegisteredTimer("state/tree/del/time", nil)
StateAccountTreeDelQPS = metrics.NewRegisteredMeter("state/tree/account/del/qps", nil)
StateAccountTreeDelTime = metrics.NewRegisteredTimer("state/tree/account/del/time", nil)
StateStorageTreeDelQPS = metrics.NewRegisteredMeter("state/tree/storage/del/qps", nil)
StateStorageTreeDelTime = metrics.NewRegisteredTimer("state/tree/storage/del/time", nil)
StateTreeCommitQPS = metrics.NewRegisteredMeter("state/tree/commit/qps", nil)
StateTreeCommitTime = metrics.NewRegisteredTimer("state/tree/commit/time", nil)
StateTreeCalcQPS = metrics.NewRegisteredMeter("state/tree/calc/qps", nil)
StateTreeCalcTime = metrics.NewRegisteredTimer("state/tree/calc/time", nil)
)
// SecureTrie is the old name of StateTrie. // SecureTrie is the old name of StateTrie.
// Deprecated: use StateTrie. // Deprecated: use StateTrie.
type SecureTrie = StateTrie type SecureTrie = StateTrie
@@ -63,6 +98,11 @@ type StateTrie struct {
// trie is initially empty. Otherwise, New will panic if db is nil // trie is initially empty. Otherwise, New will panic if db is nil
// and returns MissingNodeError if the root node cannot be found. // and returns MissingNodeError if the root node cannot be found.
func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) { func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) {
defer func(start time.Time) {
StateTreeOpenQPS.Mark(1)
StateTreeOpenTime.UpdateSince(start)
}(time.Now())
if db == nil { if db == nil {
panic("trie.NewStateTrie called without a database") panic("trie.NewStateTrie called without a database")
} }
@@ -87,6 +127,12 @@ func (t *StateTrie) MustGet(key []byte) []byte {
// If the specified storage slot is not in the trie, nil will be returned. // If the specified storage slot is not in the trie, nil will be returned.
// If a trie node is not found in the database, a MissingNodeError is returned. // If a trie node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) { func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
defer func(start time.Time) {
StateTreeGetQPS.Mark(1)
StateTreeGetTime.UpdateSince(start)
StateStorageTreeGetQPS.Mark(1)
StateStorageTreeGetTime.UpdateSince(start)
}(time.Now())
enc, err := t.trie.Get(t.hashKey(key)) enc, err := t.trie.Get(t.hashKey(key))
if err != nil || len(enc) == 0 { if err != nil || len(enc) == 0 {
return nil, err return nil, err
@@ -99,6 +145,12 @@ func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
// If the specified account is not in the trie, nil will be returned. // If the specified account is not in the trie, nil will be returned.
// If a trie node is not found in the database, a MissingNodeError is returned. // If a trie node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) { func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
defer func(start time.Time) {
StateTreeGetQPS.Mark(1)
StateTreeGetTime.UpdateSince(start)
StateAccountTreeGetQPS.Mark(1)
StateAccountTreeGetTime.UpdateSince(start)
}(time.Now())
res, err := t.trie.Get(t.hashKey(address.Bytes())) res, err := t.trie.Get(t.hashKey(address.Bytes()))
if res == nil || err != nil { if res == nil || err != nil {
return nil, err return nil, err
@@ -153,6 +205,12 @@ func (t *StateTrie) MustUpdate(key, value []byte) {
// //
// If a node is not found in the database, a MissingNodeError is returned. // If a node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error { func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
defer func(start time.Time) {
StateTreePutQPS.Mark(1)
StateTreePutTime.UpdateSince(start)
StateStorageTreePutQPS.Mark(1)
StateStorageTreePutTime.UpdateSince(start)
}(time.Now())
hk := t.hashKey(key) hk := t.hashKey(key)
v, _ := rlp.EncodeToBytes(value) v, _ := rlp.EncodeToBytes(value)
err := t.trie.Update(hk, v) err := t.trie.Update(hk, v)
@@ -165,6 +223,12 @@ func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
// UpdateAccount will abstract the write of an account to the secure trie. // UpdateAccount will abstract the write of an account to the secure trie.
func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error { func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error {
defer func(start time.Time) {
StateTreePutQPS.Mark(1)
StateTreePutTime.UpdateSince(start)
StateAccountTreePutQPS.Mark(1)
StateAccountTreePutTime.UpdateSince(start)
}(time.Now())
hk := t.hashKey(address.Bytes()) hk := t.hashKey(address.Bytes())
data, err := rlp.EncodeToBytes(acc) data, err := rlp.EncodeToBytes(acc)
if err != nil { if err != nil {
@@ -193,6 +257,12 @@ func (t *StateTrie) MustDelete(key []byte) {
// If the specified trie node is not in the trie, nothing will be changed. // If the specified trie node is not in the trie, nothing will be changed.
// If a node is not found in the database, a MissingNodeError is returned. // If a node is not found in the database, a MissingNodeError is returned.
func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error { func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
defer func(start time.Time) {
StateTreeDelQPS.Mark(1)
StateTreeDelTime.UpdateSince(start)
StateStorageTreeDelQPS.Mark(1)
StateStorageTreeDelTime.UpdateSince(start)
}(time.Now())
hk := t.hashKey(key) hk := t.hashKey(key)
delete(t.getSecKeyCache(), string(hk)) delete(t.getSecKeyCache(), string(hk))
return t.trie.Delete(hk) return t.trie.Delete(hk)
@@ -200,6 +270,12 @@ func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
// DeleteAccount abstracts an account deletion from the trie. // DeleteAccount abstracts an account deletion from the trie.
func (t *StateTrie) DeleteAccount(address common.Address) error { func (t *StateTrie) DeleteAccount(address common.Address) error {
defer func(start time.Time) {
StateTreeDelQPS.Mark(1)
StateTreeDelTime.UpdateSince(start)
StateAccountTreeDelQPS.Mark(1)
StateAccountTreeDelTime.UpdateSince(start)
}(time.Now())
hk := t.hashKey(address.Bytes()) hk := t.hashKey(address.Bytes())
delete(t.getSecKeyCache(), string(hk)) delete(t.getSecKeyCache(), string(hk))
return t.trie.Delete(hk) return t.trie.Delete(hk)
@@ -222,6 +298,10 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
// Once the trie is committed, it's not usable anymore. A new trie must // Once the trie is committed, it's not usable anymore. A new trie must
// be created with new root and updated trie database for following usage // be created with new root and updated trie database for following usage
func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
defer func(start time.Time) {
StateTreeCommitQPS.Mark(1)
StateTreeCommitTime.UpdateSince(start)
}(time.Now())
// Write all the pre-images to the actual disk database // Write all the pre-images to the actual disk database
if len(t.getSecKeyCache()) > 0 { if len(t.getSecKeyCache()) > 0 {
preimages := make(map[common.Hash][]byte) preimages := make(map[common.Hash][]byte)
@@ -238,6 +318,10 @@ func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, er
// Hash returns the root hash of StateTrie. It does not write to the // Hash returns the root hash of StateTrie. It does not write to the
// database and can be used even if the trie doesn't have one. // database and can be used even if the trie doesn't have one.
func (t *StateTrie) Hash() common.Hash { func (t *StateTrie) Hash() common.Hash {
defer func(start time.Time) {
StateTreeCalcQPS.Mark(1)
StateTreeCalcTime.UpdateSince(start)
}(time.Now())
return t.trie.Hash() return t.trie.Hash()
} }

View File

@@ -246,6 +246,10 @@ func (db *Database) Reader(root common.Hash) (layer, error) {
// The passed in maps(nodes, states) will be retained to avoid copying everything. // The passed in maps(nodes, states) will be retained to avoid copying everything.
// Therefore, these maps must not be changed afterwards. // Therefore, these maps must not be changed afterwards.
func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error { func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
defer func(start time.Time) {
PbssUpdateDiffQPS.Mark(1)
PbssUpdateDiffTime.UpdateSince(start)
}(time.Now())
// Hold the lock to prevent concurrent mutations. // Hold the lock to prevent concurrent mutations.
db.lock.Lock() db.lock.Lock()
defer db.lock.Unlock() defer db.lock.Unlock()

View File

@@ -20,6 +20,7 @@ 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"
@@ -197,11 +198,15 @@ func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]b
nBlob []byte nBlob []byte
nHash common.Hash nHash common.Hash
) )
// TODO:
trieNodeQPS.Mark(1)
startLoadTrieNode := time.Now()
if owner == (common.Hash{}) { if owner == (common.Hash{}) {
nBlob, nHash = rawdb.ReadAccountTrieNode(dl.db.diskdb, path) nBlob, nHash = rawdb.ReadAccountTrieNode(dl.db.diskdb, path)
} else { } else {
nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path) nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path)
} }
trieNodeTime.Mark(time.Since(startLoadTrieNode).Nanoseconds())
if nHash != hash { if nHash != hash {
diskFalseMeter.Mark(1) diskFalseMeter.Mark(1)
log.Error("Unexpected trie node in disk", "owner", owner, "path", path, "expect", hash, "got", nHash) log.Error("Unexpected trie node in disk", "owner", owner, "path", path, "expect", hash, "got", nHash)

View File

@@ -53,4 +53,10 @@ var (
diffHashCacheMissMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/miss", nil) diffHashCacheMissMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/miss", nil)
diffHashCacheSlowPathMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/slowpath", nil) diffHashCacheSlowPathMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/slowpath", nil)
diffHashCacheLengthGauge = metrics.NewRegisteredGauge("pathdb/difflayer/hashcache/size", nil) diffHashCacheLengthGauge = metrics.NewRegisteredGauge("pathdb/difflayer/hashcache/size", nil)
PbssUpdateDiffQPS = metrics.NewRegisteredMeter("pbss/difflayer/update/qps", nil)
PbssUpdateDiffTime = metrics.NewRegisteredTimer("pbss/difflayer/update/time", nil)
trieNodeQPS = metrics.NewRegisteredMeter("pbss/trie/node/qps", nil)
trieNodeTime = metrics.NewRegisteredMeter("pbss/trie/node/time", nil)
) )