Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d572c77e4c | ||
|
|
565085959b | ||
|
|
b7b1b0c001 | ||
|
|
08702d3380 | ||
|
|
91e3a3ea1f | ||
|
|
73477bd0fc | ||
|
|
8749c8e8ce | ||
|
|
79fe2899c7 |
33
CHANGELOG.md
33
CHANGELOG.md
@@ -1,37 +1,4 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
## v1.4.9
|
|
||||||
### FEATURE
|
|
||||||
* [\#2463](https://github.com/bnb-chain/bsc/pull/2463) utils: add check_blobtx.js
|
|
||||||
* [\#2470](https://github.com/bnb-chain/bsc/pull/2470) jsutils: faucet successful requests within blocks
|
|
||||||
* [\#2467](https://github.com/bnb-chain/bsc/pull/2467) internal/ethapi: add optional parameter for blobSidecars
|
|
||||||
|
|
||||||
### IMPROVEMENT
|
|
||||||
* [\#2462](https://github.com/bnb-chain/bsc/pull/2462) cmd/utils: add a flag to change breathe block interval for testing
|
|
||||||
* [\#2497](https://github.com/bnb-chain/bsc/pull/2497) params/config: add Bohr hardfork
|
|
||||||
* [\#2479](https://github.com/bnb-chain/bsc/pull/2479) dev: ensure consistency in BPS bundle result
|
|
||||||
|
|
||||||
### BUGFIX
|
|
||||||
* [\#2461](https://github.com/bnb-chain/bsc/pull/2461) eth/handler: check lists in body before broadcast blocks
|
|
||||||
* [\#2455](https://github.com/bnb-chain/bsc/pull/2455) cmd: fix memory leak when big dataset
|
|
||||||
* [\#2466](https://github.com/bnb-chain/bsc/pull/2466) sync: fix some sync issues caused by prune-block.
|
|
||||||
* [\#2475](https://github.com/bnb-chain/bsc/pull/2475) fix: move mev op to MinerAPI & add command to console
|
|
||||||
* [\#2473](https://github.com/bnb-chain/bsc/pull/2473) fix: limit the gas price of the mev bid
|
|
||||||
* [\#2484](https://github.com/bnb-chain/bsc/pull/2484) fix: fix inspect database error
|
|
||||||
* [\#2481](https://github.com/bnb-chain/bsc/pull/2481) fix: keep 9W blocks in ancient db when prune block
|
|
||||||
* [\#2495](https://github.com/bnb-chain/bsc/pull/2495) fix: add an empty freeze db
|
|
||||||
* [\#2507](https://github.com/bnb-chain/bsc/pull/2507) fix: waiting for the last simulation before pick best bid
|
|
||||||
|
|
||||||
## v1.4.8
|
|
||||||
### FEATURE
|
|
||||||
* [\#2483](https://github.com/bnb-chain/bsc/pull/2483) core/vm: add secp256r1 into PrecompiledContractsHaber
|
|
||||||
* [\#2400](https://github.com/bnb-chain/bsc/pull/2400) RIP-7212: Precompile for secp256r1 Curve Support
|
|
||||||
|
|
||||||
### IMPROVEMENT
|
|
||||||
NA
|
|
||||||
|
|
||||||
### BUGFIX
|
|
||||||
NA
|
|
||||||
|
|
||||||
## v1.4.7
|
## v1.4.7
|
||||||
### FEATURE
|
### FEATURE
|
||||||
* [\#2439](https://github.com/bnb-chain/bsc/pull/2439) config: setup Mainnet Tycho(Cancun) hardfork date
|
* [\#2439](https://github.com/bnb-chain/bsc/pull/2439) config: setup Mainnet Tycho(Cancun) hardfork date
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ To combine DPoS and PoA for consensus, BNB Smart Chain implement a novel consens
|
|||||||
2. Validators take turns to produce blocks in a PoA manner, similar to Ethereum's Clique consensus engine.
|
2. Validators take turns to produce blocks in a PoA manner, similar to Ethereum's Clique consensus engine.
|
||||||
3. Validator set are elected in and out based on a staking based governance on BNB Beacon Chain.
|
3. Validator set are elected in and out based on a staking based governance on BNB Beacon Chain.
|
||||||
4. The validator set change is relayed via a cross-chain communication mechanism.
|
4. The validator set change is relayed via a cross-chain communication mechanism.
|
||||||
5. Parlia consensus engine will interact with a set of [system contracts](https://docs.bnbchain.org/bnb-smart-chain/staking/overview/#system-contracts) to achieve liveness slash, revenue distributing and validator set renewing func.
|
5. Parlia consensus engine will interact with a set of [system contracts](https://docs.bnbchain.org/docs/learn/system-contract) to achieve liveness slash, revenue distributing and validator set renewing func.
|
||||||
|
|
||||||
|
|
||||||
### Light Client of BNB Beacon Chain
|
### Light Client of BNB Beacon Chain
|
||||||
@@ -183,7 +183,7 @@ This tool is optional and if you leave it out you can always attach to an alread
|
|||||||
|
|
||||||
#### 7. More
|
#### 7. More
|
||||||
|
|
||||||
More details about [running a node](https://docs.bnbchain.org/bnb-smart-chain/developers/node_operators/full_node/) and [becoming a validator](https://docs.bnbchain.org/bnb-smart-chain/validator/create-val/)
|
More details about [running a node](https://docs.bnbchain.org/docs/validator/fullnode) and [becoming a validator](https://docs.bnbchain.org/docs/validator/create-val)
|
||||||
|
|
||||||
*Note: Although some internal protective measures prevent transactions from
|
*Note: Although some internal protective measures prevent transactions from
|
||||||
crossing over between the main network and test network, you should always
|
crossing over between the main network and test network, you should always
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ var (
|
|||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.CachePreimagesFlag,
|
utils.CachePreimagesFlag,
|
||||||
utils.OverrideCancun,
|
utils.OverrideCancun,
|
||||||
utils.OverrideHaber,
|
|
||||||
utils.OverrideBohr,
|
|
||||||
utils.OverrideVerkle,
|
utils.OverrideVerkle,
|
||||||
}, utils.DatabaseFlags),
|
}, utils.DatabaseFlags),
|
||||||
Description: `
|
Description: `
|
||||||
@@ -258,14 +256,6 @@ func initGenesis(ctx *cli.Context) error {
|
|||||||
v := ctx.Uint64(utils.OverrideCancun.Name)
|
v := ctx.Uint64(utils.OverrideCancun.Name)
|
||||||
overrides.OverrideCancun = &v
|
overrides.OverrideCancun = &v
|
||||||
}
|
}
|
||||||
if ctx.IsSet(utils.OverrideHaber.Name) {
|
|
||||||
v := ctx.Uint64(utils.OverrideHaber.Name)
|
|
||||||
overrides.OverrideHaber = &v
|
|
||||||
}
|
|
||||||
if ctx.IsSet(utils.OverrideBohr.Name) {
|
|
||||||
v := ctx.Uint64(utils.OverrideBohr.Name)
|
|
||||||
overrides.OverrideBohr = &v
|
|
||||||
}
|
|
||||||
if ctx.IsSet(utils.OverrideVerkle.Name) {
|
if ctx.IsSet(utils.OverrideVerkle.Name) {
|
||||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||||
overrides.OverrideVerkle = &v
|
overrides.OverrideVerkle = &v
|
||||||
|
|||||||
@@ -189,14 +189,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
|||||||
v := ctx.Uint64(utils.OverrideCancun.Name)
|
v := ctx.Uint64(utils.OverrideCancun.Name)
|
||||||
cfg.Eth.OverrideCancun = &v
|
cfg.Eth.OverrideCancun = &v
|
||||||
}
|
}
|
||||||
if ctx.IsSet(utils.OverrideHaber.Name) {
|
|
||||||
v := ctx.Uint64(utils.OverrideHaber.Name)
|
|
||||||
cfg.Eth.OverrideHaber = &v
|
|
||||||
}
|
|
||||||
if ctx.IsSet(utils.OverrideBohr.Name) {
|
|
||||||
v := ctx.Uint64(utils.OverrideBohr.Name)
|
|
||||||
cfg.Eth.OverrideBohr = &v
|
|
||||||
}
|
|
||||||
if ctx.IsSet(utils.OverrideVerkle.Name) {
|
if ctx.IsSet(utils.OverrideVerkle.Name) {
|
||||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||||
cfg.Eth.OverrideVerkle = &v
|
cfg.Eth.OverrideVerkle = &v
|
||||||
@@ -288,6 +280,7 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
|
|||||||
if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
|
if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
|
||||||
cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name)
|
cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name)
|
||||||
}
|
}
|
||||||
|
cfg.Metrics.EnabledExpensive = true
|
||||||
if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
|
if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
|
||||||
cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
|
cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,12 +106,12 @@ Remove blockchain and state databases`,
|
|||||||
dbInspectTrieCmd = &cli.Command{
|
dbInspectTrieCmd = &cli.Command{
|
||||||
Action: inspectTrie,
|
Action: inspectTrie,
|
||||||
Name: "inspect-trie",
|
Name: "inspect-trie",
|
||||||
ArgsUsage: "<blocknum> <jobnum> <topn>",
|
ArgsUsage: "<blocknum> <jobnum>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
utils.DataDirFlag,
|
utils.DataDirFlag,
|
||||||
utils.SyncModeFlag,
|
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.`,
|
Description: `This commands iterates the entrie WorldState.`,
|
||||||
}
|
}
|
||||||
dbCheckStateContentCmd = &cli.Command{
|
dbCheckStateContentCmd = &cli.Command{
|
||||||
@@ -386,7 +386,6 @@ func inspectTrie(ctx *cli.Context) error {
|
|||||||
blockNumber uint64
|
blockNumber uint64
|
||||||
trieRootHash common.Hash
|
trieRootHash common.Hash
|
||||||
jobnum uint64
|
jobnum uint64
|
||||||
topN uint64
|
|
||||||
)
|
)
|
||||||
|
|
||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
@@ -406,37 +405,24 @@ func inspectTrie(ctx *cli.Context) error {
|
|||||||
var err error
|
var err error
|
||||||
blockNumber, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64)
|
blockNumber, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse blocknum, Args[0]: %v, err: %v", ctx.Args().Get(0), err)
|
return fmt.Errorf("failed to Parse blocknum, Args[0]: %v, err: %v", ctx.Args().Get(0), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.NArg() == 1 {
|
if ctx.NArg() == 1 {
|
||||||
jobnum = 1000
|
jobnum = 1000
|
||||||
topN = 10
|
|
||||||
} else if ctx.NArg() == 2 {
|
|
||||||
var err error
|
|
||||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
|
||||||
}
|
|
||||||
topN = 10
|
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||||
}
|
|
||||||
|
|
||||||
topN, err = strconv.ParseUint(ctx.Args().Get(2), 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse topn, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if blockNumber != math.MaxUint64 {
|
if blockNumber != math.MaxUint64 {
|
||||||
headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber)
|
headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber)
|
||||||
if headerBlockHash == (common.Hash{}) {
|
if headerBlockHash == (common.Hash{}) {
|
||||||
return errors.New("ReadHeadBlockHash empty hash")
|
return errors.New("ReadHeadBlockHash empry hash")
|
||||||
}
|
}
|
||||||
blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber)
|
blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber)
|
||||||
trieRootHash = blockHeader.Root
|
trieRootHash = blockHeader.Root
|
||||||
@@ -451,7 +437,6 @@ func inspectTrie(ctx *cli.Context) error {
|
|||||||
if dbScheme == rawdb.PathScheme {
|
if dbScheme == rawdb.PathScheme {
|
||||||
config = &triedb.Config{
|
config = &triedb.Config{
|
||||||
PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly),
|
PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly),
|
||||||
Cache: 0,
|
|
||||||
}
|
}
|
||||||
} else if dbScheme == rawdb.HashScheme {
|
} else if dbScheme == rawdb.HashScheme {
|
||||||
config = triedb.HashDefaults
|
config = triedb.HashDefaults
|
||||||
@@ -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())
|
fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum, int(topN))
|
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -508,7 +493,7 @@ func ancientInspect(ctx *cli.Context) error {
|
|||||||
stack, _ := makeConfigNode(ctx)
|
stack, _ := makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
db := utils.MakeChainDatabase(ctx, stack, true, true)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
return rawdb.AncientInspect(db)
|
return rawdb.AncientInspect(db)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,8 +73,6 @@ var (
|
|||||||
utils.SmartCardDaemonPathFlag,
|
utils.SmartCardDaemonPathFlag,
|
||||||
utils.RialtoHash,
|
utils.RialtoHash,
|
||||||
utils.OverrideCancun,
|
utils.OverrideCancun,
|
||||||
utils.OverrideHaber,
|
|
||||||
utils.OverrideBohr,
|
|
||||||
utils.OverrideVerkle,
|
utils.OverrideVerkle,
|
||||||
utils.OverrideFullImmutabilityThreshold,
|
utils.OverrideFullImmutabilityThreshold,
|
||||||
utils.OverrideMinBlocksForBlobRequests,
|
utils.OverrideMinBlocksForBlobRequests,
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, ancient
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
frdb, err := rawdb.NewDatabaseWithFreezer(kvdb, ancient, namespace, readonly, disableFreeze, isLastOffset, pruneAncientData, false)
|
frdb, err := rawdb.NewDatabaseWithFreezer(kvdb, ancient, namespace, readonly, disableFreeze, isLastOffset, pruneAncientData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
kvdb.Close()
|
kvdb.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -178,10 +178,11 @@ func BlockchainCreator(t *testing.T, chaindbPath, AncientPath string, blockRemai
|
|||||||
|
|
||||||
// Force run a freeze cycle
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
Freeze(threshold uint64) error
|
Freeze() error
|
||||||
Ancients() (uint64, error)
|
Ancients() (uint64, error)
|
||||||
}
|
}
|
||||||
db.(freezer).Freeze(10)
|
blockchain.SetFinalized(blocks[len(blocks)-1].Header())
|
||||||
|
db.(freezer).Freeze()
|
||||||
|
|
||||||
frozen, err := db.Ancients()
|
frozen, err := db.Ancients()
|
||||||
//make sure there're frozen items
|
//make sure there're frozen items
|
||||||
|
|||||||
@@ -43,11 +43,9 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
|
||||||
cli "github.com/urfave/cli/v2"
|
cli "github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -247,16 +245,7 @@ func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) {
|
|||||||
NoBuild: true,
|
NoBuild: true,
|
||||||
AsyncBuild: false,
|
AsyncBuild: false,
|
||||||
}
|
}
|
||||||
dbScheme := rawdb.ReadStateScheme(chaindb)
|
snaptree, err := snapshot.New(snapconfig, chaindb, triedb.NewDatabase(chaindb, nil), headBlock.Root(), TriesInMemory, false)
|
||||||
var config *triedb.Config
|
|
||||||
if dbScheme == rawdb.PathScheme {
|
|
||||||
config = &triedb.Config{
|
|
||||||
PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly),
|
|
||||||
}
|
|
||||||
} else if dbScheme == rawdb.HashScheme {
|
|
||||||
config = triedb.HashDefaults
|
|
||||||
}
|
|
||||||
snaptree, err := snapshot.New(snapconfig, chaindb, triedb.NewDatabase(chaindb, config), headBlock.Root(), TriesInMemory, false)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("snaptree error", "err", err)
|
log.Error("snaptree error", "err", err)
|
||||||
return nil, err // The relevant snapshot(s) might not exist
|
return nil, err // The relevant snapshot(s) might not exist
|
||||||
@@ -344,9 +333,6 @@ func pruneBlock(ctx *cli.Context) error {
|
|||||||
stack, config = makeConfigNode(ctx)
|
stack, config = makeConfigNode(ctx)
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
blockAmountReserved = ctx.Uint64(utils.BlockAmountReserved.Name)
|
blockAmountReserved = ctx.Uint64(utils.BlockAmountReserved.Name)
|
||||||
if blockAmountReserved < params.FullImmutabilityThreshold {
|
|
||||||
return fmt.Errorf("block-amount-reserved must be greater than or equal to %d", params.FullImmutabilityThreshold)
|
|
||||||
}
|
|
||||||
chaindb, err = accessDb(ctx, stack)
|
chaindb, err = accessDb(ctx, stack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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);
|
|
||||||
});
|
|
||||||
@@ -310,16 +310,6 @@ var (
|
|||||||
Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting",
|
Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting",
|
||||||
Category: flags.EthCategory,
|
Category: flags.EthCategory,
|
||||||
}
|
}
|
||||||
OverrideHaber = &cli.Uint64Flag{
|
|
||||||
Name: "override.haber",
|
|
||||||
Usage: "Manually specify the Haber fork timestamp, overriding the bundled setting",
|
|
||||||
Category: flags.EthCategory,
|
|
||||||
}
|
|
||||||
OverrideBohr = &cli.Uint64Flag{
|
|
||||||
Name: "override.bohr",
|
|
||||||
Usage: "Manually specify the Bohr fork timestamp, overriding the bundled setting",
|
|
||||||
Category: flags.EthCategory,
|
|
||||||
}
|
|
||||||
OverrideVerkle = &cli.Uint64Flag{
|
OverrideVerkle = &cli.Uint64Flag{
|
||||||
Name: "override.verkle",
|
Name: "override.verkle",
|
||||||
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
||||||
@@ -1087,7 +1077,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
|||||||
Name: "block-amount-reserved",
|
Name: "block-amount-reserved",
|
||||||
Usage: "Sets the expected remained amount of blocks for offline block prune",
|
Usage: "Sets the expected remained amount of blocks for offline block prune",
|
||||||
Category: flags.BlockHistoryCategory,
|
Category: flags.BlockHistoryCategory,
|
||||||
Value: params.FullImmutabilityThreshold,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckSnapshotWithMPT = &cli.BoolFlag{
|
CheckSnapshotWithMPT = &cli.BoolFlag{
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ func TestHistoryImportAndExport(t *testing.T) {
|
|||||||
|
|
||||||
// Now import Era.
|
// Now import Era.
|
||||||
freezer := t.TempDir()
|
freezer := t.TempDir()
|
||||||
db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false, false, false, false, false)
|
db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,31 +66,6 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
|
|||||||
return validator
|
return validator
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateListsInBody validates that UncleHash, WithdrawalsHash, and WithdrawalsHash correspond to the lists in the block body, respectively.
|
|
||||||
func ValidateListsInBody(block *types.Block) error {
|
|
||||||
header := block.Header()
|
|
||||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
|
||||||
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
|
||||||
}
|
|
||||||
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
|
|
||||||
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
|
|
||||||
}
|
|
||||||
// Withdrawals are present after the Shanghai fork.
|
|
||||||
if header.WithdrawalsHash != nil {
|
|
||||||
// Withdrawals list must be present in body after Shanghai.
|
|
||||||
if block.Withdrawals() == nil {
|
|
||||||
return errors.New("missing withdrawals in block body")
|
|
||||||
}
|
|
||||||
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
|
|
||||||
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
|
||||||
}
|
|
||||||
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
|
|
||||||
// Withdrawals are not allowed prior to shanghai fork
|
|
||||||
return errors.New("withdrawals present in block body")
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateBody validates the given block's uncles and verifies the block
|
// ValidateBody validates the given block's uncles and verifies the block
|
||||||
// header's transaction and uncle roots. The headers are assumed to be already
|
// header's transaction and uncle roots. The headers are assumed to be already
|
||||||
// validated at this point.
|
// validated at this point.
|
||||||
@@ -108,12 +83,31 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||||
|
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
||||||
|
}
|
||||||
|
|
||||||
validateFuns := []func() error{
|
validateFuns := []func() error{
|
||||||
func() error {
|
func() error {
|
||||||
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 {
|
func() error {
|
||||||
|
// Withdrawals are present after the Shanghai fork.
|
||||||
|
if header.WithdrawalsHash != nil {
|
||||||
|
// Withdrawals list must be present in body after Shanghai.
|
||||||
|
if block.Withdrawals() == nil {
|
||||||
|
return errors.New("missing withdrawals in block body")
|
||||||
|
}
|
||||||
|
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
|
||||||
|
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
||||||
|
}
|
||||||
|
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
|
||||||
|
// Withdrawals are not allowed prior to shanghai fork
|
||||||
|
return errors.New("withdrawals present in block body")
|
||||||
|
}
|
||||||
// Blob transactions may be present after the Cancun fork.
|
// Blob transactions may be present after the Cancun fork.
|
||||||
var blobs int
|
var blobs int
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
|
|||||||
@@ -441,6 +441,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
diskRoot = bc.triedb.Head()
|
diskRoot = bc.triedb.Head()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
diskRoot = common.HexToHash("0x59d2a69ad465dbadf78f99635af9ed8125636cbdedc50bda9668ab2ac677b17a")
|
||||||
if diskRoot != (common.Hash{}) {
|
if diskRoot != (common.Hash{}) {
|
||||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
|
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
|
||||||
|
|
||||||
@@ -576,7 +577,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
}
|
}
|
||||||
// Start tx indexer if it's enabled.
|
// Start tx indexer if it's enabled.
|
||||||
if txLookupLimit != nil {
|
if txLookupLimit != nil {
|
||||||
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
|
// bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
|
||||||
}
|
}
|
||||||
return bc, nil
|
return bc, nil
|
||||||
}
|
}
|
||||||
@@ -2275,12 +2276,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
||||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||||
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
|
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
|
||||||
triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
|
blockExecutionTimer.Update(ptime) // The time spent on EVM processing
|
||||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
blockValidationTimer.Update(vtime) // The time spent on block validation
|
||||||
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
|
|
||||||
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
|
|
||||||
blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
|
|
||||||
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
|
|
||||||
|
|
||||||
// Write the block to the chain and get the status.
|
// Write the block to the chain and get the status.
|
||||||
var (
|
var (
|
||||||
@@ -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
|
snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
|
||||||
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
|
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
|
||||||
|
|
||||||
blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
blockWriteTimer.UpdateSince(wstart)
|
||||||
blockInsertTimer.UpdateSince(start)
|
blockInsertTimer.UpdateSince(start)
|
||||||
|
|
||||||
// Report the import stats before returning the various results
|
// 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 {
|
func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription {
|
||||||
return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch))
|
return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AncientTail retrieves the tail the ancients blocks
|
|
||||||
func (bc *BlockChain) AncientTail() (uint64, error) {
|
|
||||||
tail, err := bc.db.Tail()
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return tail, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1832,10 +1832,14 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
|||||||
}
|
}
|
||||||
// Force run a freeze cycle
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
Freeze(threshold uint64) error
|
Freeze() error
|
||||||
Ancients() (uint64, error)
|
Ancients() (uint64, error)
|
||||||
}
|
}
|
||||||
db.(freezer).Freeze(tt.freezeThreshold)
|
if tt.freezeThreshold < uint64(tt.canonicalBlocks) {
|
||||||
|
final := uint64(tt.canonicalBlocks) - tt.freezeThreshold
|
||||||
|
chain.SetFinalized(canonblocks[int(final)-1].Header())
|
||||||
|
}
|
||||||
|
db.(freezer).Freeze()
|
||||||
|
|
||||||
// Set the simulated pivot block
|
// Set the simulated pivot block
|
||||||
if tt.pivotBlock != nil {
|
if tt.pivotBlock != nil {
|
||||||
|
|||||||
@@ -2045,10 +2045,14 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
|
|||||||
|
|
||||||
// Force run a freeze cycle
|
// Force run a freeze cycle
|
||||||
type freezer interface {
|
type freezer interface {
|
||||||
Freeze(threshold uint64) error
|
Freeze() error
|
||||||
Ancients() (uint64, error)
|
Ancients() (uint64, error)
|
||||||
}
|
}
|
||||||
db.(freezer).Freeze(tt.freezeThreshold)
|
if tt.freezeThreshold < uint64(tt.canonicalBlocks) {
|
||||||
|
final := uint64(tt.canonicalBlocks) - tt.freezeThreshold
|
||||||
|
chain.SetFinalized(canonblocks[int(final)-1].Header())
|
||||||
|
}
|
||||||
|
db.(freezer).Freeze()
|
||||||
|
|
||||||
// Set the simulated pivot block
|
// Set the simulated pivot block
|
||||||
if tt.pivotBlock != nil {
|
if tt.pivotBlock != nil {
|
||||||
|
|||||||
@@ -974,7 +974,7 @@ func testFastVsFullChains(t *testing.T, scheme string) {
|
|||||||
t.Fatalf("failed to insert receipt %d: %v", n, err)
|
t.Fatalf("failed to insert receipt %d: %v", n, err)
|
||||||
}
|
}
|
||||||
// Freezer style fast import the chain.
|
// Freezer style fast import the chain.
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1069,7 +1069,7 @@ func testLightVsFastVsFullChainHeads(t *testing.T, scheme string) {
|
|||||||
|
|
||||||
// makeDb creates a db instance for testing.
|
// makeDb creates a db instance for testing.
|
||||||
makeDb := func() ethdb.Database {
|
makeDb := func() ethdb.Database {
|
||||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@@ -1957,7 +1957,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
|
|||||||
competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
|
competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
|
||||||
|
|
||||||
// Import the shared chain and the original canonical one
|
// Import the shared chain and the original canonical one
|
||||||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||||
@@ -2026,7 +2026,7 @@ func testBlockchainRecovery(t *testing.T, scheme string) {
|
|||||||
_, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil)
|
_, blocks, receipts := GenerateChainWithGenesis(gspec, ethash.NewFaker(), int(height), nil)
|
||||||
|
|
||||||
// Import the chain as a ancient-first node and ensure all pointers are updated
|
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@@ -2097,7 +2097,7 @@ func testInsertReceiptChainRollback(t *testing.T, scheme string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set up a BlockChain that uses the ancient store.
|
// Set up a BlockChain that uses the ancient store.
|
||||||
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@@ -2167,7 +2167,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Import the canonical chain
|
// Import the canonical chain
|
||||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
defer diskdb.Close()
|
defer diskdb.Close()
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
|
||||||
@@ -2384,7 +2384,7 @@ func testInsertKnownChainData(t *testing.T, typ string, scheme string) {
|
|||||||
b.OffsetTime(-9) // A higher difficulty
|
b.OffsetTime(-9) // A higher difficulty
|
||||||
})
|
})
|
||||||
// Import the shared chain and the original canonical one
|
// Import the shared chain and the original canonical one
|
||||||
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@@ -2555,7 +2555,7 @@ func testInsertKnownChainDataWithMerging(t *testing.T, typ string, mergeHeight i
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Import the shared chain and the original canonical one
|
// Import the shared chain and the original canonical one
|
||||||
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
chaindb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
@@ -3858,7 +3858,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
|||||||
}
|
}
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
})
|
})
|
||||||
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
diskdb, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
defer diskdb.Close()
|
defer diskdb.Close()
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
chain, err := NewBlockChain(diskdb, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{}, nil, nil)
|
||||||
@@ -4483,7 +4483,7 @@ func (c *mockParlia) CalcDifficulty(chain consensus.ChainHeaderReader, time uint
|
|||||||
func TestParliaBlobFeeReward(t *testing.T) {
|
func TestParliaBlobFeeReward(t *testing.T) {
|
||||||
// Have N headers in the freezer
|
// Have N headers in the freezer
|
||||||
frdir := t.TempDir()
|
frdir := t.TempDir()
|
||||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false, false)
|
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create database with ancient backend")
|
t.Fatalf("failed to create database with ancient backend")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,8 +217,6 @@ func (e *GenesisMismatchError) Error() string {
|
|||||||
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
||||||
type ChainOverrides struct {
|
type ChainOverrides struct {
|
||||||
OverrideCancun *uint64
|
OverrideCancun *uint64
|
||||||
OverrideHaber *uint64
|
|
||||||
OverrideBohr *uint64
|
|
||||||
OverrideVerkle *uint64
|
OverrideVerkle *uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,12 +246,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
|||||||
if overrides != nil && overrides.OverrideCancun != nil {
|
if overrides != nil && overrides.OverrideCancun != nil {
|
||||||
config.CancunTime = overrides.OverrideCancun
|
config.CancunTime = overrides.OverrideCancun
|
||||||
}
|
}
|
||||||
if overrides != nil && overrides.OverrideHaber != nil {
|
|
||||||
config.HaberTime = overrides.OverrideHaber
|
|
||||||
}
|
|
||||||
if overrides != nil && overrides.OverrideBohr != nil {
|
|
||||||
config.BohrTime = overrides.OverrideBohr
|
|
||||||
}
|
|
||||||
if overrides != nil && overrides.OverrideVerkle != nil {
|
if overrides != nil && overrides.OverrideVerkle != nil {
|
||||||
config.VerkleTime = overrides.OverrideVerkle
|
config.VerkleTime = overrides.OverrideVerkle
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -518,7 +518,7 @@ func checkBlobSidecarsRLP(have, want types.BlobSidecars) error {
|
|||||||
func TestAncientStorage(t *testing.T) {
|
func TestAncientStorage(t *testing.T) {
|
||||||
// Freezer style fast import the chain.
|
// Freezer style fast import the chain.
|
||||||
frdir := t.TempDir()
|
frdir := t.TempDir()
|
||||||
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false, false)
|
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create database with ancient backend")
|
t.Fatalf("failed to create database with ancient backend")
|
||||||
}
|
}
|
||||||
@@ -657,7 +657,7 @@ func TestHashesInRange(t *testing.T) {
|
|||||||
func BenchmarkWriteAncientBlocks(b *testing.B) {
|
func BenchmarkWriteAncientBlocks(b *testing.B) {
|
||||||
// Open freezer database.
|
// Open freezer database.
|
||||||
frdir := b.TempDir()
|
frdir := b.TempDir()
|
||||||
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false, false)
|
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to create database with ancient backend")
|
b.Fatalf("failed to create database with ancient backend")
|
||||||
}
|
}
|
||||||
@@ -1001,7 +1001,7 @@ func TestHeadersRLPStorage(t *testing.T) {
|
|||||||
// Have N headers in the freezer
|
// Have N headers in the freezer
|
||||||
frdir := t.TempDir()
|
frdir := t.TempDir()
|
||||||
|
|
||||||
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false, false)
|
db, err := NewDatabaseWithFreezer(NewMemoryDatabase(), frdir, "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create database with ancient backend")
|
t.Fatalf("failed to create database with ancient backend")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,10 +18,12 @@ package rawdb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReadSnapshotDisabled retrieves if the snapshot maintenance is disabled.
|
// ReadSnapshotDisabled retrieves if the snapshot maintenance is disabled.
|
||||||
@@ -74,6 +76,10 @@ func DeleteSnapshotRoot(db ethdb.KeyValueWriter) {
|
|||||||
|
|
||||||
// ReadAccountSnapshot retrieves the snapshot entry of an account trie leaf.
|
// ReadAccountSnapshot retrieves the snapshot entry of an account trie leaf.
|
||||||
func ReadAccountSnapshot(db ethdb.KeyValueReader, hash common.Hash) []byte {
|
func ReadAccountSnapshot(db ethdb.KeyValueReader, hash common.Hash) []byte {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { rawdbGetAccountSnapNodeTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
data, _ := db.Get(accountSnapshotKey(hash))
|
data, _ := db.Get(accountSnapshotKey(hash))
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
@@ -94,6 +100,10 @@ func DeleteAccountSnapshot(db ethdb.KeyValueWriter, hash common.Hash) {
|
|||||||
|
|
||||||
// ReadStorageSnapshot retrieves the snapshot entry of an storage trie leaf.
|
// ReadStorageSnapshot retrieves the snapshot entry of an storage trie leaf.
|
||||||
func ReadStorageSnapshot(db ethdb.KeyValueReader, accountHash, storageHash common.Hash) []byte {
|
func ReadStorageSnapshot(db ethdb.KeyValueReader, accountHash, storageHash common.Hash) []byte {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { rawdbGetStorageSnapNodeTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
data, _ := db.Get(storageSnapshotKey(accountHash, storageHash))
|
data, _ := db.Get(storageSnapshotKey(accountHash, storageHash))
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,11 +19,13 @@ package rawdb
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -68,6 +70,10 @@ func (h *hasher) release() {
|
|||||||
// ReadAccountTrieNode retrieves the account trie node and the associated node
|
// ReadAccountTrieNode retrieves the account trie node and the associated node
|
||||||
// hash with the specified node path.
|
// hash with the specified node path.
|
||||||
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) {
|
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { rawdbGetAccountTrieNodeTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
data, err := db.Get(accountTrieNodeKey(path))
|
data, err := db.Get(accountTrieNodeKey(path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, common.Hash{}
|
return nil, common.Hash{}
|
||||||
@@ -116,6 +122,10 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) {
|
|||||||
// ReadStorageTrieNode retrieves the storage trie node and the associated node
|
// ReadStorageTrieNode retrieves the storage trie node and the associated node
|
||||||
// hash with the specified node path.
|
// hash with the specified node path.
|
||||||
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) {
|
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { rawdbGetStorageTrieNodeTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
data, err := db.Get(storageTrieNodeKey(accountHash, path))
|
data, err := db.Get(storageTrieNodeKey(accountHash, path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, common.Hash{}
|
return nil, common.Hash{}
|
||||||
@@ -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 {
|
func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte {
|
||||||
switch scheme {
|
switch scheme {
|
||||||
case HashScheme:
|
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:
|
case PathScheme:
|
||||||
var (
|
var (
|
||||||
blob []byte
|
blob []byte
|
||||||
|
|||||||
@@ -24,12 +24,12 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -51,31 +51,25 @@ var (
|
|||||||
// The background thread will keep moving ancient chain segments from key-value
|
// The background thread will keep moving ancient chain segments from key-value
|
||||||
// database to flat files for saving space on live database.
|
// database to flat files for saving space on live database.
|
||||||
type chainFreezer struct {
|
type chainFreezer struct {
|
||||||
threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
|
|
||||||
|
|
||||||
*Freezer
|
*Freezer
|
||||||
quit chan struct{}
|
quit chan struct{}
|
||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
trigger chan chan struct{} // Manual blocking freeze trigger, test determinism
|
trigger chan chan struct{} // Manual blocking freeze trigger, test determinism
|
||||||
|
|
||||||
freezeEnv atomic.Value
|
freezeEnv atomic.Value
|
||||||
|
|
||||||
multiDatabase bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// newChainFreezer initializes the freezer for ancient chain data.
|
// newChainFreezer initializes the freezer for ancient chain data.
|
||||||
func newChainFreezer(datadir string, namespace string, readonly bool, offset uint64, multiDatabase bool) (*chainFreezer, error) {
|
func newChainFreezer(datadir string, namespace string, readonly bool, offset uint64) (*chainFreezer, error) {
|
||||||
freezer, err := NewChainFreezer(datadir, namespace, readonly, offset)
|
freezer, err := NewChainFreezer(datadir, namespace, readonly, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cf := chainFreezer{
|
return &chainFreezer{
|
||||||
Freezer: freezer,
|
Freezer: freezer,
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
trigger: make(chan chan struct{}),
|
trigger: make(chan chan struct{}),
|
||||||
}
|
}, nil
|
||||||
cf.threshold.Store(params.FullImmutabilityThreshold)
|
|
||||||
return &cf, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the chain freezer instance and terminates the background thread.
|
// Close closes the chain freezer instance and terminates the background thread.
|
||||||
@@ -191,26 +185,13 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
threshold, err := f.freezeThreshold(nfdb)
|
||||||
frozen uint64
|
|
||||||
threshold uint64
|
|
||||||
first uint64 // the first block to freeze
|
|
||||||
last uint64 // the last block to freeze
|
|
||||||
|
|
||||||
hash common.Hash
|
|
||||||
number *uint64
|
|
||||||
head *types.Header
|
|
||||||
)
|
|
||||||
|
|
||||||
// use finalized block as the chain freeze indicator was used for multiDatabase feature, if multiDatabase is false, keep 9W blocks in db
|
|
||||||
if f.multiDatabase {
|
|
||||||
threshold, err = f.freezeThreshold(nfdb)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
backoff = true
|
backoff = true
|
||||||
log.Debug("Current full block not old enough to freeze", "err", err)
|
log.Debug("Current full block not old enough to freeze", "err", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
frozen = f.frozen.Load()
|
frozen := f.frozen.Load()
|
||||||
|
|
||||||
// Short circuit if the blocks below threshold are already frozen.
|
// Short circuit if the blocks below threshold are already frozen.
|
||||||
if frozen != 0 && frozen-1 >= threshold {
|
if frozen != 0 && frozen-1 >= threshold {
|
||||||
@@ -218,74 +199,15 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
|||||||
log.Debug("Ancient blocks frozen already", "threshold", threshold, "frozen", frozen)
|
log.Debug("Ancient blocks frozen already", "threshold", threshold, "frozen", frozen)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
hash = ReadHeadBlockHash(nfdb)
|
|
||||||
if hash == (common.Hash{}) {
|
|
||||||
log.Debug("Current full block hash unavailable") // new chain, empty database
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
number = ReadHeaderNumber(nfdb, hash)
|
|
||||||
if number == nil {
|
|
||||||
log.Error("Current full block number unavailable", "hash", hash)
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
head = ReadHeader(nfdb, hash, *number)
|
|
||||||
if head == nil {
|
|
||||||
log.Error("Current full block unavailable", "number", *number, "hash", hash)
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
first = frozen
|
|
||||||
last = threshold
|
|
||||||
if last-first+1 > freezerBatchLimit {
|
|
||||||
last = freezerBatchLimit + first - 1
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Retrieve the freezing threshold.
|
|
||||||
hash = ReadHeadBlockHash(nfdb)
|
|
||||||
if hash == (common.Hash{}) {
|
|
||||||
log.Debug("Current full block hash unavailable") // new chain, empty database
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
number = ReadHeaderNumber(nfdb, hash)
|
|
||||||
threshold = f.threshold.Load()
|
|
||||||
frozen = f.frozen.Load()
|
|
||||||
switch {
|
|
||||||
case number == nil:
|
|
||||||
log.Error("Current full block number unavailable", "hash", hash)
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
|
|
||||||
case *number < threshold:
|
|
||||||
log.Debug("Current full block not old enough to freeze", "number", *number, "hash", hash, "delay", threshold)
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
|
|
||||||
case *number-threshold <= frozen:
|
|
||||||
log.Debug("Ancient blocks frozen already", "number", *number, "hash", hash, "frozen", frozen)
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
head = ReadHeader(nfdb, hash, *number)
|
|
||||||
if head == nil {
|
|
||||||
log.Error("Current full block unavailable", "number", *number, "hash", hash)
|
|
||||||
backoff = true
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
first, _ = f.Ancients()
|
|
||||||
last = *number - threshold
|
|
||||||
if last-first > freezerBatchLimit {
|
|
||||||
last = first + freezerBatchLimit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Seems we have data ready to be frozen, process in usable batches
|
// Seems we have data ready to be frozen, process in usable batches
|
||||||
var (
|
var (
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
|
first = frozen // the first block to freeze
|
||||||
|
last = threshold // the last block to freeze
|
||||||
)
|
)
|
||||||
|
if last-first+1 > freezerBatchLimit {
|
||||||
|
last = freezerBatchLimit + first - 1
|
||||||
|
}
|
||||||
|
|
||||||
ancients, err := f.freezeRangeWithBlobs(nfdb, first, last)
|
ancients, err := f.freezeRangeWithBlobs(nfdb, first, last)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -373,6 +295,24 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
|||||||
log.Debug("Deep froze chain segment", context...)
|
log.Debug("Deep froze chain segment", context...)
|
||||||
|
|
||||||
env, _ := f.freezeEnv.Load().(*ethdb.FreezerEnv)
|
env, _ := f.freezeEnv.Load().(*ethdb.FreezerEnv)
|
||||||
|
hash := ReadHeadBlockHash(nfdb)
|
||||||
|
if hash == (common.Hash{}) {
|
||||||
|
log.Debug("Current full block hash unavailable") // new chain, empty database
|
||||||
|
backoff = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
number := ReadHeaderNumber(nfdb, hash)
|
||||||
|
if number == nil {
|
||||||
|
log.Error("Current full block number unavailable", "hash", hash)
|
||||||
|
backoff = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
head := ReadHeader(nfdb, hash, *number)
|
||||||
|
if head == nil {
|
||||||
|
log.Error("Current full block unavailable", "number", *number, "hash", hash)
|
||||||
|
backoff = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
// try prune blob data after cancun fork
|
// try prune blob data after cancun fork
|
||||||
if isCancun(env, head.Number, head.Time) {
|
if isCancun(env, head.Number, head.Time) {
|
||||||
f.tryPruneBlobAncientTable(env, *number)
|
f.tryPruneBlobAncientTable(env, *number)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func (frdb *freezerdb) BlockStoreReader() ethdb.Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (frdb *freezerdb) BlockStoreWriter() ethdb.Writer {
|
func (frdb *freezerdb) BlockStoreWriter() ethdb.Writer {
|
||||||
// TODO implement me
|
//TODO implement me
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,22 +138,13 @@ func (frdb *freezerdb) SetBlockStore(block ethdb.Database) {
|
|||||||
frdb.blockStore = block
|
frdb.blockStore = block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (frdb *freezerdb) HasSeparateBlockStore() bool {
|
|
||||||
return frdb.blockStore != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Freeze is a helper method used for external testing to trigger and block until
|
// Freeze is a helper method used for external testing to trigger and block until
|
||||||
// a freeze cycle completes, without having to sleep for a minute to trigger the
|
// a freeze cycle completes, without having to sleep for a minute to trigger the
|
||||||
// automatic background run.
|
// automatic background run.
|
||||||
func (frdb *freezerdb) Freeze(threshold uint64) error {
|
func (frdb *freezerdb) Freeze() error {
|
||||||
if frdb.AncientStore.(*chainFreezer).readonly {
|
if frdb.AncientStore.(*chainFreezer).readonly {
|
||||||
return errReadOnly
|
return errReadOnly
|
||||||
}
|
}
|
||||||
// Set the freezer threshold to a temporary value
|
|
||||||
defer func(old uint64) {
|
|
||||||
frdb.AncientStore.(*chainFreezer).threshold.Store(old)
|
|
||||||
}(frdb.AncientStore.(*chainFreezer).threshold.Load())
|
|
||||||
frdb.AncientStore.(*chainFreezer).threshold.Store(threshold)
|
|
||||||
// Trigger a freeze cycle and block until it's done
|
// Trigger a freeze cycle and block until it's done
|
||||||
trigger := make(chan struct{}, 1)
|
trigger := make(chan struct{}, 1)
|
||||||
frdb.AncientStore.(*chainFreezer).trigger <- trigger
|
frdb.AncientStore.(*chainFreezer).trigger <- trigger
|
||||||
@@ -193,7 +184,7 @@ func (db *nofreezedb) Ancients() (uint64, error) {
|
|||||||
return 0, errNotSupported
|
return 0, errNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// ItemAmountInAncient returns an error as we don't have a backing chain freezer.
|
// Ancients returns an error as we don't have a backing chain freezer.
|
||||||
func (db *nofreezedb) ItemAmountInAncient() (uint64, error) {
|
func (db *nofreezedb) ItemAmountInAncient() (uint64, error) {
|
||||||
return 0, errNotSupported
|
return 0, errNotSupported
|
||||||
}
|
}
|
||||||
@@ -272,10 +263,6 @@ func (db *nofreezedb) SetBlockStore(block ethdb.Database) {
|
|||||||
db.blockStore = block
|
db.blockStore = block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *nofreezedb) HasSeparateBlockStore() bool {
|
|
||||||
return db.blockStore != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *nofreezedb) BlockStoreReader() ethdb.Reader {
|
func (db *nofreezedb) BlockStoreReader() ethdb.Reader {
|
||||||
if db.blockStore != nil {
|
if db.blockStore != nil {
|
||||||
return db.blockStore
|
return db.blockStore
|
||||||
@@ -331,110 +318,6 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database {
|
|||||||
return &nofreezedb{KeyValueStore: db}
|
return &nofreezedb{KeyValueStore: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
type emptyfreezedb struct {
|
|
||||||
ethdb.KeyValueStore
|
|
||||||
}
|
|
||||||
|
|
||||||
// HasAncient returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) HasAncient(kind string, number uint64) (bool, error) {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ancient returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) Ancient(kind string, number uint64) ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AncientRange returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) AncientRange(kind string, start, max, maxByteSize uint64) ([][]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ancients returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) Ancients() (uint64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ItemAmountInAncient returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) ItemAmountInAncient() (uint64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tail returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) Tail() (uint64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AncientSize returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) AncientSize(kind string) (uint64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ModifyAncients returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) ModifyAncients(func(ethdb.AncientWriteOp) error) (int64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TruncateHead returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) TruncateHead(items uint64) (uint64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TruncateTail returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) TruncateTail(items uint64) (uint64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TruncateTableTail returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) TruncateTableTail(kind string, tail uint64) (uint64, error) {
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ResetTable returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) ResetTable(kind string, startAt uint64, onlyEmpty bool) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sync returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) Sync() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *emptyfreezedb) DiffStore() ethdb.KeyValueStore { return db }
|
|
||||||
func (db *emptyfreezedb) SetDiffStore(diff ethdb.KeyValueStore) {}
|
|
||||||
func (db *emptyfreezedb) StateStore() ethdb.Database { return db }
|
|
||||||
func (db *emptyfreezedb) SetStateStore(state ethdb.Database) {}
|
|
||||||
func (db *emptyfreezedb) StateStoreReader() ethdb.Reader { return db }
|
|
||||||
func (db *emptyfreezedb) BlockStore() ethdb.Database { return db }
|
|
||||||
func (db *emptyfreezedb) SetBlockStore(block ethdb.Database) {}
|
|
||||||
func (db *emptyfreezedb) HasSeparateBlockStore() bool { return false }
|
|
||||||
func (db *emptyfreezedb) BlockStoreReader() ethdb.Reader { return db }
|
|
||||||
func (db *emptyfreezedb) BlockStoreWriter() ethdb.Writer { return db }
|
|
||||||
func (db *emptyfreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error) (err error) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
func (db *emptyfreezedb) AncientOffSet() uint64 { return 0 }
|
|
||||||
|
|
||||||
// MigrateTable returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) MigrateTable(kind string, convert convertLegacyFn) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AncientDatadir returns nil for pruned db that we don't have a backing chain freezer.
|
|
||||||
func (db *emptyfreezedb) AncientDatadir() (string, error) {
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
func (db *emptyfreezedb) SetupFreezerEnv(env *ethdb.FreezerEnv) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewEmptyFreezeDB is used for CLI such as `geth db inspect` in pruned db that we don't
|
|
||||||
// have a backing chain freezer.
|
|
||||||
// WARNING: it must be only used in the above case.
|
|
||||||
func NewEmptyFreezeDB(db ethdb.KeyValueStore) ethdb.Database {
|
|
||||||
return &emptyfreezedb{KeyValueStore: db}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFreezerDb only create a freezer without statedb.
|
// NewFreezerDb only create a freezer without statedb.
|
||||||
func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool, newOffSet uint64) (*Freezer, error) {
|
func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool, newOffSet uint64) (*Freezer, error) {
|
||||||
// Create the idle freezer instance, this operation should be atomic to avoid mismatch between offset and acientDB.
|
// Create the idle freezer instance, this operation should be atomic to avoid mismatch between offset and acientDB.
|
||||||
@@ -475,7 +358,7 @@ func resolveChainFreezerDir(ancient string) string {
|
|||||||
// value data store with a freezer moving immutable chain segments into cold
|
// value data store with a freezer moving immutable chain segments into cold
|
||||||
// storage. The passed ancient indicates the path of root ancient directory
|
// storage. The passed ancient indicates the path of root ancient directory
|
||||||
// where the chain freezer can be opened.
|
// where the chain freezer can be opened.
|
||||||
func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace string, readonly, disableFreeze, isLastOffset, pruneAncientData, multiDatabase bool) (ethdb.Database, error) {
|
func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace string, readonly, disableFreeze, isLastOffset, pruneAncientData bool) (ethdb.Database, error) {
|
||||||
var offset uint64
|
var offset uint64
|
||||||
// The offset of ancientDB should be handled differently in different scenarios.
|
// The offset of ancientDB should be handled differently in different scenarios.
|
||||||
if isLastOffset {
|
if isLastOffset {
|
||||||
@@ -484,12 +367,6 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
|||||||
offset = ReadOffSetOfCurrentAncientFreezer(db)
|
offset = ReadOffSetOfCurrentAncientFreezer(db)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This case is used for someone who wants to execute geth db inspect CLI in a pruned db
|
|
||||||
if !disableFreeze && readonly && ReadAncientType(db) == PruneFreezerType {
|
|
||||||
log.Warn("Disk db is pruned, using an empty freezer db for CLI")
|
|
||||||
return NewEmptyFreezeDB(db), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if pruneAncientData && !disableFreeze && !readonly {
|
if pruneAncientData && !disableFreeze && !readonly {
|
||||||
frdb, err := newPrunedFreezer(resolveChainFreezerDir(ancient), db, offset)
|
frdb, err := newPrunedFreezer(resolveChainFreezerDir(ancient), db, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -517,7 +394,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the idle freezer instance
|
// Create the idle freezer instance
|
||||||
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly, offset, multiDatabase)
|
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly, offset)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printChainMetadata(db)
|
printChainMetadata(db)
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -698,8 +575,6 @@ type OpenOptions struct {
|
|||||||
// Ephemeral means that filesystem sync operations should be avoided: data integrity in the face of
|
// Ephemeral means that filesystem sync operations should be avoided: data integrity in the face of
|
||||||
// a crash is not important. This option should typically be used in tests.
|
// a crash is not important. This option should typically be used in tests.
|
||||||
Ephemeral bool
|
Ephemeral bool
|
||||||
|
|
||||||
MultiDataBase bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// openKeyValueDatabase opens a disk-based key-value database, e.g. leveldb or pebble.
|
// openKeyValueDatabase opens a disk-based key-value database, e.g. leveldb or pebble.
|
||||||
@@ -744,13 +619,13 @@ func Open(o OpenOptions) (ethdb.Database, error) {
|
|||||||
}
|
}
|
||||||
if ReadAncientType(kvdb) == PruneFreezerType {
|
if ReadAncientType(kvdb) == PruneFreezerType {
|
||||||
if !o.PruneAncientData {
|
if !o.PruneAncientData {
|
||||||
log.Warn("NOTICE: You're opening a pruned disk db!")
|
log.Warn("Disk db is pruned")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(o.AncientsDirectory) == 0 {
|
if len(o.AncientsDirectory) == 0 {
|
||||||
return kvdb, nil
|
return kvdb, nil
|
||||||
}
|
}
|
||||||
frdb, err := NewDatabaseWithFreezer(kvdb, o.AncientsDirectory, o.Namespace, o.ReadOnly, o.DisableFreeze, o.IsLastOffset, o.PruneAncientData, o.MultiDataBase)
|
frdb, err := NewDatabaseWithFreezer(kvdb, o.AncientsDirectory, o.Namespace, o.ReadOnly, o.DisableFreeze, o.IsLastOffset, o.PruneAncientData)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
kvdb.Close()
|
kvdb.Close()
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -894,7 +769,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
|||||||
trieIter = db.StateStore().NewIterator(keyPrefix, nil)
|
trieIter = db.StateStore().NewIterator(keyPrefix, nil)
|
||||||
defer trieIter.Release()
|
defer trieIter.Release()
|
||||||
}
|
}
|
||||||
if db.HasSeparateBlockStore() {
|
if db.BlockStore() != db {
|
||||||
blockIter = db.BlockStore().NewIterator(keyPrefix, nil)
|
blockIter = db.BlockStore().NewIterator(keyPrefix, nil)
|
||||||
defer blockIter.Release()
|
defer blockIter.Release()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ func (f *Freezer) Ancient(kind string, number uint64) ([]byte, error) {
|
|||||||
// - if maxBytes is not specified, 'count' items will be returned if they are present.
|
// - if maxBytes is not specified, 'count' items will be returned if they are present.
|
||||||
func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
||||||
if table := f.tables[kind]; table != nil {
|
if table := f.tables[kind]; table != nil {
|
||||||
return table.RetrieveItems(start-f.offset, count, maxBytes)
|
return table.RetrieveItems(start, count, maxBytes)
|
||||||
}
|
}
|
||||||
return nil, errUnknownTable
|
return nil, errUnknownTable
|
||||||
}
|
}
|
||||||
@@ -252,7 +252,7 @@ func (f *Freezer) Ancients() (uint64, error) {
|
|||||||
func (f *Freezer) TableAncients(kind string) (uint64, error) {
|
func (f *Freezer) TableAncients(kind string) (uint64, error) {
|
||||||
f.writeLock.RLock()
|
f.writeLock.RLock()
|
||||||
defer f.writeLock.RUnlock()
|
defer f.writeLock.RUnlock()
|
||||||
return f.tables[kind].items.Load() + f.offset, nil
|
return f.tables[kind].items.Load(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ItemAmountInAncient returns the actual length of current ancientDB.
|
// 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)
|
||||||
|
)
|
||||||
@@ -43,10 +43,6 @@ func (t *table) SetBlockStore(block ethdb.Database) {
|
|||||||
panic("not implement")
|
panic("not implement")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *table) HasSeparateBlockStore() bool {
|
|
||||||
panic("not implement")
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTable returns a database object that prefixes all keys with a given string.
|
// NewTable returns a database object that prefixes all keys with a given string.
|
||||||
func NewTable(db ethdb.Database, prefix string) ethdb.Database {
|
func NewTable(db ethdb.Database, prefix string) ethdb.Database {
|
||||||
return &table{
|
return &table{
|
||||||
|
|||||||
@@ -382,7 +382,7 @@ func (p *BlockPruner) backUpOldDb(name string, cache, handles int, namespace str
|
|||||||
log.Info("chainDB opened successfully")
|
log.Info("chainDB opened successfully")
|
||||||
|
|
||||||
// Get the number of items in old ancient db.
|
// Get the number of items in old ancient db.
|
||||||
itemsOfAncient, err := chainDb.BlockStore().ItemAmountInAncient()
|
itemsOfAncient, err := chainDb.ItemAmountInAncient()
|
||||||
log.Info("the number of items in ancientDB is ", "itemsOfAncient", itemsOfAncient)
|
log.Info("the number of items in ancientDB is ", "itemsOfAncient", itemsOfAncient)
|
||||||
|
|
||||||
// If we can't access the freezer or it's empty, abort.
|
// If we can't access the freezer or it's empty, abort.
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, roo
|
|||||||
snap.layers[head.Root()] = head
|
snap.layers[head.Root()] = head
|
||||||
head = head.Parent()
|
head = head.Parent()
|
||||||
}
|
}
|
||||||
log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root)
|
log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root, "snapshot_cache_size", common.StorageSize(config.CacheSize)*1024*1024)
|
||||||
return snap, nil
|
return snap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
@@ -29,9 +30,14 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
processTxTimer = metrics.NewRegisteredTimer("process/tx/time", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||||
// state from one point to another.
|
// state from one point to another.
|
||||||
//
|
//
|
||||||
@@ -104,6 +110,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||||||
systemTxs := make([]*types.Transaction, 0, 2)
|
systemTxs := make([]*types.Transaction, 0, 2)
|
||||||
|
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer processTxTimer.UpdateSince(start)
|
||||||
|
}
|
||||||
if isPoSA {
|
if isPoSA {
|
||||||
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
|
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
|
||||||
bloomProcessors.Close()
|
bloomProcessors.Close()
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ type txIndexer struct {
|
|||||||
|
|
||||||
// newTxIndexer initializes the transaction indexer.
|
// newTxIndexer initializes the transaction indexer.
|
||||||
func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer {
|
func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer {
|
||||||
|
limit = 0
|
||||||
indexer := &txIndexer{
|
indexer := &txIndexer{
|
||||||
limit: limit,
|
limit: limit,
|
||||||
db: chain.db,
|
db: chain.db,
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ func TestTxIndexer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
frdir := t.TempDir()
|
frdir := t.TempDir()
|
||||||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false, false)
|
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false)
|
||||||
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
|
rawdb.WriteAncientBlocks(db, append([]*types.Block{gspec.ToBlock()}, blocks...), append([]types.Receipts{{}}, receipts...), big.NewInt(0))
|
||||||
|
|
||||||
// Index the initial blocks from ancient store
|
// Index the initial blocks from ancient store
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import (
|
|||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
mapset "github.com/deckarep/golang-set/v2"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
@@ -42,12 +40,6 @@ func (b *BidArgs) ToBid(builder common.Address, signer Signer) (*Bid, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(b.RawBid.UnRevertible) > len(txs) {
|
|
||||||
return nil, fmt.Errorf("expect NonRevertible no more than %d", len(txs))
|
|
||||||
}
|
|
||||||
unRevertibleHashes := mapset.NewThreadUnsafeSetWithSize[common.Hash](len(b.RawBid.UnRevertible))
|
|
||||||
unRevertibleHashes.Append(b.RawBid.UnRevertible...)
|
|
||||||
|
|
||||||
if len(b.PayBidTx) != 0 {
|
if len(b.PayBidTx) != 0 {
|
||||||
var payBidTx = new(Transaction)
|
var payBidTx = new(Transaction)
|
||||||
err = payBidTx.UnmarshalBinary(b.PayBidTx)
|
err = payBidTx.UnmarshalBinary(b.PayBidTx)
|
||||||
@@ -63,7 +55,6 @@ func (b *BidArgs) ToBid(builder common.Address, signer Signer) (*Bid, error) {
|
|||||||
BlockNumber: b.RawBid.BlockNumber,
|
BlockNumber: b.RawBid.BlockNumber,
|
||||||
ParentHash: b.RawBid.ParentHash,
|
ParentHash: b.RawBid.ParentHash,
|
||||||
Txs: txs,
|
Txs: txs,
|
||||||
UnRevertible: unRevertibleHashes,
|
|
||||||
GasUsed: b.RawBid.GasUsed + b.PayBidTxGasUsed,
|
GasUsed: b.RawBid.GasUsed + b.PayBidTxGasUsed,
|
||||||
GasFee: b.RawBid.GasFee,
|
GasFee: b.RawBid.GasFee,
|
||||||
BuilderFee: b.RawBid.BuilderFee,
|
BuilderFee: b.RawBid.BuilderFee,
|
||||||
@@ -82,7 +73,6 @@ type RawBid struct {
|
|||||||
BlockNumber uint64 `json:"blockNumber"`
|
BlockNumber uint64 `json:"blockNumber"`
|
||||||
ParentHash common.Hash `json:"parentHash"`
|
ParentHash common.Hash `json:"parentHash"`
|
||||||
Txs []hexutil.Bytes `json:"txs"`
|
Txs []hexutil.Bytes `json:"txs"`
|
||||||
UnRevertible []common.Hash `json:"unRevertible"`
|
|
||||||
GasUsed uint64 `json:"gasUsed"`
|
GasUsed uint64 `json:"gasUsed"`
|
||||||
GasFee *big.Int `json:"gasFee"`
|
GasFee *big.Int `json:"gasFee"`
|
||||||
BuilderFee *big.Int `json:"builderFee"`
|
BuilderFee *big.Int `json:"builderFee"`
|
||||||
@@ -168,7 +158,6 @@ type Bid struct {
|
|||||||
BlockNumber uint64
|
BlockNumber uint64
|
||||||
ParentHash common.Hash
|
ParentHash common.Hash
|
||||||
Txs Transactions
|
Txs Transactions
|
||||||
UnRevertible mapset.Set[common.Hash]
|
|
||||||
GasUsed uint64
|
GasUsed uint64
|
||||||
GasFee *big.Int
|
GasFee *big.Int
|
||||||
BuilderFee *big.Int
|
BuilderFee *big.Int
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
"github.com/ethereum/go-ethereum/crypto/secp256k1"
|
||||||
"github.com/ethereum/go-ethereum/crypto/secp256r1"
|
|
||||||
"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/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@@ -248,36 +247,6 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
|
|||||||
common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
|
common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrecompiledContractsHaber contains the default set of pre-compiled Ethereum
|
|
||||||
// contracts used in the Haber release.
|
|
||||||
var PrecompiledContractsHaber = map[common.Address]PrecompiledContract{
|
|
||||||
common.BytesToAddress([]byte{1}): &ecrecover{},
|
|
||||||
common.BytesToAddress([]byte{2}): &sha256hash{},
|
|
||||||
common.BytesToAddress([]byte{3}): &ripemd160hash{},
|
|
||||||
common.BytesToAddress([]byte{4}): &dataCopy{},
|
|
||||||
common.BytesToAddress([]byte{5}): &bigModExp{eip2565: true},
|
|
||||||
common.BytesToAddress([]byte{6}): &bn256AddIstanbul{},
|
|
||||||
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
|
|
||||||
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
|
|
||||||
common.BytesToAddress([]byte{9}): &blake2F{},
|
|
||||||
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
|
|
||||||
|
|
||||||
common.BytesToAddress([]byte{100}): &tmHeaderValidate{},
|
|
||||||
common.BytesToAddress([]byte{101}): &iavlMerkleProofValidatePlato{},
|
|
||||||
common.BytesToAddress([]byte{102}): &blsSignatureVerify{},
|
|
||||||
common.BytesToAddress([]byte{103}): &cometBFTLightBlockValidateHertz{},
|
|
||||||
common.BytesToAddress([]byte{104}): &verifyDoubleSignEvidence{},
|
|
||||||
common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
|
|
||||||
|
|
||||||
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrecompiledContractsP256Verify contains the precompiled Ethereum
|
|
||||||
// contract specified in EIP-7212. This is exported for testing purposes.
|
|
||||||
var PrecompiledContractsP256Verify = map[common.Address]PrecompiledContract{
|
|
||||||
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
|
|
||||||
}
|
|
||||||
|
|
||||||
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
|
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
|
||||||
// contracts specified in EIP-2537. These are exported for testing purposes.
|
// contracts specified in EIP-2537. These are exported for testing purposes.
|
||||||
var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
|
var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
|
||||||
@@ -293,7 +262,6 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
PrecompiledAddressesHaber []common.Address
|
|
||||||
PrecompiledAddressesCancun []common.Address
|
PrecompiledAddressesCancun []common.Address
|
||||||
PrecompiledAddressesFeynman []common.Address
|
PrecompiledAddressesFeynman []common.Address
|
||||||
PrecompiledAddressesHertz []common.Address
|
PrecompiledAddressesHertz []common.Address
|
||||||
@@ -345,16 +313,11 @@ func init() {
|
|||||||
for k := range PrecompiledContractsCancun {
|
for k := range PrecompiledContractsCancun {
|
||||||
PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k)
|
PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k)
|
||||||
}
|
}
|
||||||
for k := range PrecompiledContractsHaber {
|
|
||||||
PrecompiledAddressesHaber = append(PrecompiledAddressesHaber, k)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ActivePrecompiles returns the precompiles enabled with the current configuration.
|
// ActivePrecompiles returns the precompiles enabled with the current configuration.
|
||||||
func ActivePrecompiles(rules params.Rules) []common.Address {
|
func ActivePrecompiles(rules params.Rules) []common.Address {
|
||||||
switch {
|
switch {
|
||||||
case rules.IsHaber:
|
|
||||||
return PrecompiledAddressesHaber
|
|
||||||
case rules.IsCancun:
|
case rules.IsCancun:
|
||||||
return PrecompiledAddressesCancun
|
return PrecompiledAddressesCancun
|
||||||
case rules.IsFeynman:
|
case rules.IsFeynman:
|
||||||
@@ -1426,40 +1389,6 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
|
|||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
// P256VERIFY (secp256r1 signature verification)
|
|
||||||
// implemented as a native contract
|
|
||||||
type p256Verify struct{}
|
|
||||||
|
|
||||||
// RequiredGas returns the gas required to execute the precompiled contract
|
|
||||||
func (c *p256Verify) RequiredGas(input []byte) uint64 {
|
|
||||||
return params.P256VerifyGas
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run executes the precompiled contract with given 160 bytes of param, returning the output and the used gas
|
|
||||||
func (c *p256Verify) Run(input []byte) ([]byte, error) {
|
|
||||||
// Required input length is 160 bytes
|
|
||||||
const p256VerifyInputLength = 160
|
|
||||||
// Check the input length
|
|
||||||
if len(input) != p256VerifyInputLength {
|
|
||||||
// Input length is invalid
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the hash, r, s, x, y from the input
|
|
||||||
hash := input[0:32]
|
|
||||||
r, s := new(big.Int).SetBytes(input[32:64]), new(big.Int).SetBytes(input[64:96])
|
|
||||||
x, y := new(big.Int).SetBytes(input[96:128]), new(big.Int).SetBytes(input[128:160])
|
|
||||||
|
|
||||||
// Verify the secp256r1 signature
|
|
||||||
if secp256r1.Verify(hash, r, s, x, y) {
|
|
||||||
// Signature is valid
|
|
||||||
return common.LeftPadBytes(common.Big1.Bytes(), 32), nil
|
|
||||||
} else {
|
|
||||||
// Signature is invalid
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// verifyDoubleSignEvidence implements bsc header verification precompile.
|
// verifyDoubleSignEvidence implements bsc header verification precompile.
|
||||||
type verifyDoubleSignEvidence struct{}
|
type verifyDoubleSignEvidence struct{}
|
||||||
|
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ var allPrecompiles = map[common.Address]PrecompiledContract{
|
|||||||
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
|
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
|
||||||
common.BytesToAddress([]byte{9}): &blake2F{},
|
common.BytesToAddress([]byte{9}): &blake2F{},
|
||||||
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
|
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
|
||||||
|
|
||||||
common.BytesToAddress([]byte{0x01, 0x00}): &p256Verify{},
|
|
||||||
common.BytesToAddress([]byte{0x0f, 0x0a}): &bls12381G1Add{},
|
common.BytesToAddress([]byte{0x0f, 0x0a}): &bls12381G1Add{},
|
||||||
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1Mul{},
|
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1Mul{},
|
||||||
common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G1MultiExp{},
|
common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G1MultiExp{},
|
||||||
@@ -409,18 +407,6 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.B) {
|
|||||||
benchmarkPrecompiled("0f", testcase, b)
|
benchmarkPrecompiled("0f", testcase, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Benchmarks the sample inputs from the P256VERIFY precompile.
|
|
||||||
func BenchmarkPrecompiledP256Verify(bench *testing.B) {
|
|
||||||
t := precompiledTest{
|
|
||||||
Input: "4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e",
|
|
||||||
Expected: "0000000000000000000000000000000000000000000000000000000000000001",
|
|
||||||
Name: "p256Verify",
|
|
||||||
}
|
|
||||||
benchmarkPrecompiled("100", t, bench)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPrecompiledP256Verify(t *testing.T) { testJson("p256Verify", "100", t) }
|
|
||||||
|
|
||||||
func TestDoubleSignSlash(t *testing.T) {
|
func TestDoubleSignSlash(t *testing.T) {
|
||||||
tc := precompiledTest{
|
tc := precompiledTest{
|
||||||
Input: "f906278202cab9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0fae1a05fcb14bfd9b8a9f2b65007a9b6c2000de0627a73be644dd993d32342c494976ea74026e726554db657fa54763abd0c3a0aa9a0f385cc58ed297ff0d66eb5580b02853d3478ba418b1819ac659ee05df49b9794a0bf88464af369ed6b8cf02db00f0b9556ffa8d49cd491b00952a7f83431446638a00a6d0870e586a76278fbfdcedf76ef6679af18fc1f9137cfad495f434974ea81b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a804ae755e0fe64b59753f4db6308a1f679747bce186aa2c62b95fa6eeff3fbd08f3b0667e45428a54ade15bad19f49641c499b431b36f65803ea71b379e6b61de501a0232c9ba2d41b40d36ed794c306747bcbc49bf61a0f37409c18bfe2b5bef26a2d880000000000000000b9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0b2789a5357827ed838335283e15c4dcc42b9bebcbf2919a18613246787e2f96094976ea74026e726554db657fa54763abd0c3a0aa9a071ce4c09ee275206013f0063761bc19c93c13990582f918cc57333634c94ce89a00e095703e5c9b149f253fe89697230029e32484a410b4b1f2c61442d73c3095aa0d317ae19ede7c8a2d3ac9ef98735b049bcb7278d12f48c42b924538b60a25e12b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a80c0b17bfe88534296ff064cb7156548f6deba2d6310d5044ed6485f087dc6ef232e051c28e1909c2b50a3b4f29345d66681c319bef653e52e5d746480d5a3983b00a0b56228685be711834d0f154292d07826dea42a0fad3e4f56c31470b7fbfbea26880000000000000000",
|
Input: "f906278202cab9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0fae1a05fcb14bfd9b8a9f2b65007a9b6c2000de0627a73be644dd993d32342c494976ea74026e726554db657fa54763abd0c3a0aa9a0f385cc58ed297ff0d66eb5580b02853d3478ba418b1819ac659ee05df49b9794a0bf88464af369ed6b8cf02db00f0b9556ffa8d49cd491b00952a7f83431446638a00a6d0870e586a76278fbfdcedf76ef6679af18fc1f9137cfad495f434974ea81b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a804ae755e0fe64b59753f4db6308a1f679747bce186aa2c62b95fa6eeff3fbd08f3b0667e45428a54ade15bad19f49641c499b431b36f65803ea71b379e6b61de501a0232c9ba2d41b40d36ed794c306747bcbc49bf61a0f37409c18bfe2b5bef26a2d880000000000000000b9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0b2789a5357827ed838335283e15c4dcc42b9bebcbf2919a18613246787e2f96094976ea74026e726554db657fa54763abd0c3a0aa9a071ce4c09ee275206013f0063761bc19c93c13990582f918cc57333634c94ce89a00e095703e5c9b149f253fe89697230029e32484a410b4b1f2c61442d73c3095aa0d317ae19ede7c8a2d3ac9ef98735b049bcb7278d12f48c42b924538b60a25e12b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a80c0b17bfe88534296ff064cb7156548f6deba2d6310d5044ed6485f087dc6ef232e051c28e1909c2b50a3b4f29345d66681c319bef653e52e5d746480d5a3983b00a0b56228685be711834d0f154292d07826dea42a0fad3e4f56c31470b7fbfbea26880000000000000000",
|
||||||
|
|||||||
@@ -48,8 +48,6 @@ type (
|
|||||||
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
|
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
|
||||||
var precompiles map[common.Address]PrecompiledContract
|
var precompiles map[common.Address]PrecompiledContract
|
||||||
switch {
|
switch {
|
||||||
case evm.chainRules.IsHaber:
|
|
||||||
precompiles = PrecompiledContractsHaber
|
|
||||||
case evm.chainRules.IsCancun:
|
case evm.chainRules.IsCancun:
|
||||||
precompiles = PrecompiledContractsCancun
|
precompiles = PrecompiledContractsCancun
|
||||||
case evm.chainRules.IsFeynman:
|
case evm.chainRules.IsFeynman:
|
||||||
|
|||||||
5469
core/vm/testdata/precompiles/p256Verify.json
vendored
5469
core/vm/testdata/precompiles/p256Verify.json
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,21 +0,0 @@
|
|||||||
package secp256r1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"crypto/elliptic"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Generates appropriate public key format from given coordinates
|
|
||||||
func newPublicKey(x, y *big.Int) *ecdsa.PublicKey {
|
|
||||||
// Check if the given coordinates are valid
|
|
||||||
if x == nil || y == nil || !elliptic.P256().IsOnCurve(x, y) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ecdsa.PublicKey{
|
|
||||||
Curve: elliptic.P256(),
|
|
||||||
X: x,
|
|
||||||
Y: y,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package secp256r1
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"math/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Verify verifies the given signature (r, s) for the given hash and public key (x, y).
|
|
||||||
// It returns true if the signature is valid, false otherwise.
|
|
||||||
func Verify(hash []byte, r, s, x, y *big.Int) bool {
|
|
||||||
// Create the public key format
|
|
||||||
publicKey := newPublicKey(x, y)
|
|
||||||
|
|
||||||
// Check if they are invalid public key coordinates
|
|
||||||
if publicKey == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the signature with the public key,
|
|
||||||
// then return true if it's valid, false otherwise
|
|
||||||
return ecdsa.Verify(publicKey, hash, r, s)
|
|
||||||
}
|
|
||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@@ -141,3 +142,31 @@ func (api *AdminAPI) ImportChain(file string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MevRunning returns true if the validator accept bids from builder
|
||||||
|
func (api *AdminAPI) MevRunning() bool {
|
||||||
|
return api.eth.APIBackend.MevRunning()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartMev starts mev. It notifies the miner to start to receive bids.
|
||||||
|
func (api *AdminAPI) StartMev() {
|
||||||
|
api.eth.APIBackend.StartMev()
|
||||||
|
}
|
||||||
|
|
||||||
|
// StopMev stops mev. It notifies the miner to stop receiving bids from this moment,
|
||||||
|
// but the bids before this moment would still been taken into consideration by mev.
|
||||||
|
func (api *AdminAPI) StopMev() {
|
||||||
|
api.eth.APIBackend.StopMev()
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddBuilder adds a builder to the bid simulator.
|
||||||
|
// url is the endpoint of the builder, for example, "https://mev-builder.amazonaws.com",
|
||||||
|
// if validator is equipped with sentry, ignore the url.
|
||||||
|
func (api *AdminAPI) AddBuilder(builder common.Address, url string) error {
|
||||||
|
return api.eth.APIBackend.AddBuilder(builder, url)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveBuilder removes a builder from the bid simulator.
|
||||||
|
func (api *AdminAPI) RemoveBuilder(builder common.Address) error {
|
||||||
|
return api.eth.APIBackend.RemoveBuilder(builder)
|
||||||
|
}
|
||||||
|
|||||||
@@ -89,31 +89,3 @@ func (api *MinerAPI) SetEtherbase(etherbase common.Address) bool {
|
|||||||
func (api *MinerAPI) SetRecommitInterval(interval int) {
|
func (api *MinerAPI) SetRecommitInterval(interval int) {
|
||||||
api.e.Miner().SetRecommitInterval(time.Duration(interval) * time.Millisecond)
|
api.e.Miner().SetRecommitInterval(time.Duration(interval) * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MevRunning returns true if the validator accept bids from builder
|
|
||||||
func (api *MinerAPI) MevRunning() bool {
|
|
||||||
return api.e.APIBackend.MevRunning()
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartMev starts mev. It notifies the miner to start to receive bids.
|
|
||||||
func (api *MinerAPI) StartMev() {
|
|
||||||
api.e.APIBackend.StartMev()
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopMev stops mev. It notifies the miner to stop receiving bids from this moment,
|
|
||||||
// but the bids before this moment would still been taken into consideration by mev.
|
|
||||||
func (api *MinerAPI) StopMev() {
|
|
||||||
api.e.APIBackend.StopMev()
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddBuilder adds a builder to the bid simulator.
|
|
||||||
// url is the endpoint of the builder, for example, "https://mev-builder.amazonaws.com",
|
|
||||||
// if validator is equipped with sentry, ignore the url.
|
|
||||||
func (api *MinerAPI) AddBuilder(builder common.Address, url string) error {
|
|
||||||
return api.e.APIBackend.AddBuilder(builder, url)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveBuilder removes a builder from the bid simulator.
|
|
||||||
func (api *MinerAPI) RemoveBuilder(builder common.Address) error {
|
|
||||||
return api.e.APIBackend.RemoveBuilder(builder)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -161,11 +161,12 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
// Optimize memory distribution by reallocating surplus allowance from the
|
// Optimize memory distribution by reallocating surplus allowance from the
|
||||||
// dirty cache to the clean cache.
|
// dirty cache to the clean cache.
|
||||||
if config.StateScheme == rawdb.PathScheme && config.TrieDirtyCache > pathdb.MaxDirtyBufferSize/1024/1024 {
|
if config.StateScheme == rawdb.PathScheme && config.TrieDirtyCache > pathdb.MaxDirtyBufferSize/1024/1024 {
|
||||||
|
config.TrieCleanCache += config.TrieDirtyCache - pathdb.MaxDirtyBufferSize/1024/1024
|
||||||
|
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
|
||||||
log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024, "adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize))
|
log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024, "adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize))
|
||||||
log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024)
|
log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024)
|
||||||
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
|
|
||||||
}
|
}
|
||||||
log.Info("Allocated trie memory caches", "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.
|
// Try to recover offline state pruning only in hash-based.
|
||||||
if config.StateScheme == rawdb.HashScheme {
|
if config.StateScheme == rawdb.HashScheme {
|
||||||
@@ -183,14 +184,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
chainConfig.CancunTime = config.OverrideCancun
|
chainConfig.CancunTime = config.OverrideCancun
|
||||||
overrides.OverrideCancun = config.OverrideCancun
|
overrides.OverrideCancun = config.OverrideCancun
|
||||||
}
|
}
|
||||||
if config.OverrideHaber != nil {
|
|
||||||
chainConfig.HaberTime = config.OverrideHaber
|
|
||||||
overrides.OverrideHaber = config.OverrideHaber
|
|
||||||
}
|
|
||||||
if config.OverrideBohr != nil {
|
|
||||||
chainConfig.BohrTime = config.OverrideBohr
|
|
||||||
overrides.OverrideBohr = config.OverrideBohr
|
|
||||||
}
|
|
||||||
if config.OverrideVerkle != nil {
|
if config.OverrideVerkle != nil {
|
||||||
chainConfig.VerkleTime = config.OverrideVerkle
|
chainConfig.VerkleTime = config.OverrideVerkle
|
||||||
overrides.OverrideVerkle = config.OverrideVerkle
|
overrides.OverrideVerkle = config.OverrideVerkle
|
||||||
|
|||||||
@@ -209,9 +209,6 @@ type BlockChain interface {
|
|||||||
|
|
||||||
// UpdateChasingHead update remote best chain head, used by DA check now.
|
// UpdateChasingHead update remote best chain head, used by DA check now.
|
||||||
UpdateChasingHead(head *types.Header)
|
UpdateChasingHead(head *types.Header)
|
||||||
|
|
||||||
// AncientTail retrieves the tail the ancients blocks
|
|
||||||
AncientTail() (uint64, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DownloadOption func(downloader *Downloader) *Downloader
|
type DownloadOption func(downloader *Downloader) *Downloader
|
||||||
@@ -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
|
// We're above the max reorg threshold, find the earliest fork point
|
||||||
floor = int64(localHeight - maxForkAncestry)
|
floor = int64(localHeight - maxForkAncestry)
|
||||||
}
|
}
|
||||||
// if we have pruned too much history, reset the floor
|
|
||||||
if tail, err := d.blockchain.AncientTail(); err == nil && tail > uint64(floor) {
|
|
||||||
floor = int64(tail)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're doing a light sync, ensure the floor doesn't go below the CHT, as
|
// If we're doing a light sync, ensure the floor doesn't go below the CHT, as
|
||||||
// all headers before that point will be missing.
|
// all headers before that point will be missing.
|
||||||
if mode == LightSync {
|
if mode == LightSync {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ func newTester(t *testing.T) *downloadTester {
|
|||||||
// newTester creates a new downloader test mocker.
|
// newTester creates a new downloader test mocker.
|
||||||
func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
|
func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
|
||||||
freezer := t.TempDir()
|
freezer := t.TempDir()
|
||||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false, false, false, false, false)
|
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), freezer, "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,12 +191,6 @@ type Config struct {
|
|||||||
// OverrideCancun (TODO: remove after the fork)
|
// OverrideCancun (TODO: remove after the fork)
|
||||||
OverrideCancun *uint64 `toml:",omitempty"`
|
OverrideCancun *uint64 `toml:",omitempty"`
|
||||||
|
|
||||||
// OverrideHaber (TODO: remove after the fork)
|
|
||||||
OverrideHaber *uint64 `toml:",omitempty"`
|
|
||||||
|
|
||||||
// OverrideBohr (TODO: remove after the fork)
|
|
||||||
OverrideBohr *uint64 `toml:",omitempty"`
|
|
||||||
|
|
||||||
// OverrideVerkle (TODO: remove after the fork)
|
// OverrideVerkle (TODO: remove after the fork)
|
||||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||||
|
|
||||||
|
|||||||
@@ -71,8 +71,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||||||
RPCEVMTimeout time.Duration
|
RPCEVMTimeout time.Duration
|
||||||
RPCTxFeeCap float64
|
RPCTxFeeCap float64
|
||||||
OverrideCancun *uint64 `toml:",omitempty"`
|
OverrideCancun *uint64 `toml:",omitempty"`
|
||||||
OverrideHaber *uint64 `toml:",omitempty"`
|
|
||||||
OverrideBohr *uint64 `toml:",omitempty"`
|
|
||||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||||
BlobExtraReserve uint64
|
BlobExtraReserve uint64
|
||||||
}
|
}
|
||||||
@@ -131,8 +129,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||||||
enc.RPCEVMTimeout = c.RPCEVMTimeout
|
enc.RPCEVMTimeout = c.RPCEVMTimeout
|
||||||
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
||||||
enc.OverrideCancun = c.OverrideCancun
|
enc.OverrideCancun = c.OverrideCancun
|
||||||
enc.OverrideHaber = c.OverrideHaber
|
|
||||||
enc.OverrideBohr = c.OverrideBohr
|
|
||||||
enc.OverrideVerkle = c.OverrideVerkle
|
enc.OverrideVerkle = c.OverrideVerkle
|
||||||
enc.BlobExtraReserve = c.BlobExtraReserve
|
enc.BlobExtraReserve = c.BlobExtraReserve
|
||||||
return &enc, nil
|
return &enc, nil
|
||||||
@@ -195,8 +191,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||||||
RPCEVMTimeout *time.Duration
|
RPCEVMTimeout *time.Duration
|
||||||
RPCTxFeeCap *float64
|
RPCTxFeeCap *float64
|
||||||
OverrideCancun *uint64 `toml:",omitempty"`
|
OverrideCancun *uint64 `toml:",omitempty"`
|
||||||
OverrideHaber *uint64 `toml:",omitempty"`
|
|
||||||
OverrideBohr *uint64 `toml:",omitempty"`
|
|
||||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||||
BlobExtraReserve *uint64
|
BlobExtraReserve *uint64
|
||||||
}
|
}
|
||||||
@@ -366,12 +360,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||||||
if dec.OverrideCancun != nil {
|
if dec.OverrideCancun != nil {
|
||||||
c.OverrideCancun = dec.OverrideCancun
|
c.OverrideCancun = dec.OverrideCancun
|
||||||
}
|
}
|
||||||
if dec.OverrideHaber != nil {
|
|
||||||
c.OverrideHaber = dec.OverrideHaber
|
|
||||||
}
|
|
||||||
if dec.OverrideBohr != nil {
|
|
||||||
c.OverrideBohr = dec.OverrideBohr
|
|
||||||
}
|
|
||||||
if dec.OverrideVerkle != nil {
|
if dec.OverrideVerkle != nil {
|
||||||
c.OverrideVerkle = dec.OverrideVerkle
|
c.OverrideVerkle = dec.OverrideVerkle
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ func (f *fetcherTester) chainFinalizedHeight() uint64 {
|
|||||||
return f.blocks[f.hashes[len(f.hashes)-3]].NumberU64()
|
return f.blocks[f.hashes[len(f.hashes)-3]].NumberU64()
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertHeaders injects a new headers into the simulated chain.
|
// insertChain injects a new headers into the simulated chain.
|
||||||
func (f *fetcherTester) insertHeaders(headers []*types.Header) (int, error) {
|
func (f *fetcherTester) insertHeaders(headers []*types.Header) (int, error) {
|
||||||
f.lock.Lock()
|
f.lock.Lock()
|
||||||
defer f.lock.Unlock()
|
defer f.lock.Unlock()
|
||||||
|
|||||||
@@ -320,22 +320,26 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
broadcastBlockWithCheck := func(block *types.Block, propagate bool) {
|
broadcastBlockWithCheck := func(block *types.Block, propagate bool) {
|
||||||
if propagate {
|
// All the block fetcher activities should be disabled
|
||||||
checkErrs := make(chan error, 2)
|
// after the transition. Print the warning log.
|
||||||
|
if h.merger.PoSFinalized() {
|
||||||
go func() {
|
log.Warn("Unexpected validation activity", "hash", block.Hash(), "number", block.Number())
|
||||||
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
|
return
|
||||||
}
|
}
|
||||||
|
// Reject all the PoS style headers in the first place. No matter
|
||||||
|
// the chain has finished the transition or not, the PoS headers
|
||||||
|
// should only come from the trusted consensus layer instead of
|
||||||
|
// p2p network.
|
||||||
|
if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok {
|
||||||
|
if beacon.IsPoSHeader(block.Header()) {
|
||||||
|
log.Warn("unexpected post-merge header")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if propagate {
|
||||||
|
if 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)
|
h.BroadcastBlock(block, propagate)
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ func (c *mockParlia) CalcDifficulty(chain consensus.ChainHeaderReader, time uint
|
|||||||
func newTestParliaHandlerAfterCancun(t *testing.T, config *params.ChainConfig, mode downloader.SyncMode, preCancunBlks, postCancunBlks uint64) *testHandler {
|
func newTestParliaHandlerAfterCancun(t *testing.T, config *params.ChainConfig, mode downloader.SyncMode, preCancunBlks, postCancunBlks uint64) *testHandler {
|
||||||
// Have N headers in the freezer
|
// Have N headers in the freezer
|
||||||
frdir := t.TempDir()
|
frdir := t.TempDir()
|
||||||
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false, false)
|
db, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "", false, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create database with ancient backend")
|
t.Fatalf("failed to create database with ancient backend")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,7 +183,6 @@ type StateStoreReader interface {
|
|||||||
type BlockStore interface {
|
type BlockStore interface {
|
||||||
BlockStore() Database
|
BlockStore() Database
|
||||||
SetBlockStore(block Database)
|
SetBlockStore(block Database)
|
||||||
HasSeparateBlockStore() bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BlockStoreReader interface {
|
type BlockStoreReader interface {
|
||||||
|
|||||||
@@ -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) {
|
func NewCustom(file string, namespace string, customize func(options *opt.Options)) (*Database, error) {
|
||||||
options := configureOptions(customize)
|
options := configureOptions(customize)
|
||||||
logger := log.New("database", file)
|
logger := log.New("database", file)
|
||||||
usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
|
// usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
|
||||||
logCtx := []interface{}{"cache", common.StorageSize(usedCache), "handles", options.GetOpenFilesCacheCapacity()}
|
logCtx := []interface{}{"handles", options.GetOpenFilesCacheCapacity()}
|
||||||
if options.ReadOnly {
|
if options.ReadOnly {
|
||||||
logCtx = append(logCtx, "readonly", "true")
|
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
|
// Open the db and recover any potential corruptions
|
||||||
db, err := leveldb.OpenFile(file, options)
|
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.
|
// Get retrieves the given key if it's present in the key-value store.
|
||||||
func (db *Database) Get(key []byte) ([]byte, error) {
|
func (db *Database) Get(key []byte) ([]byte, error) {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { ethdb.EthdbGetTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
dat, err := db.db.Get(key, nil)
|
dat, err := db.db.Get(key, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -199,11 +209,19 @@ func (db *Database) Get(key []byte) ([]byte, error) {
|
|||||||
|
|
||||||
// Put inserts the given value into the key-value store.
|
// Put inserts the given value into the key-value store.
|
||||||
func (db *Database) Put(key []byte, value []byte) error {
|
func (db *Database) Put(key []byte, value []byte) error {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { ethdb.EthdbPutTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
return db.db.Put(key, value, nil)
|
return db.db.Put(key, value, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete removes the key from the key-value store.
|
// Delete removes the key from the key-value store.
|
||||||
func (db *Database) Delete(key []byte) error {
|
func (db *Database) Delete(key []byte) error {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { ethdb.EthdbDeleteTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
return db.db.Delete(key, nil)
|
return db.db.Delete(key, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,6 +319,8 @@ func (db *Database) meter(refresh time.Duration, namespace string) {
|
|||||||
merr = err
|
merr = err
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
fmt.Printf("loop print level db stats db_metrics=\n%v\n", stats)
|
||||||
|
db.log.Info("loop print level db stats", "stats", stats)
|
||||||
// Iterate over all the leveldbTable rows, and accumulate the entries
|
// Iterate over all the leveldbTable rows, and accumulate the entries
|
||||||
for j := 0; j < len(compactions[i%2]); j++ {
|
for j := 0; j < len(compactions[i%2]); j++ {
|
||||||
compactions[i%2][j] = 0
|
compactions[i%2][j] = 0
|
||||||
@@ -414,6 +434,10 @@ func (b *batch) ValueSize() int {
|
|||||||
|
|
||||||
// Write flushes any accumulated data to disk.
|
// Write flushes any accumulated data to disk.
|
||||||
func (b *batch) Write() error {
|
func (b *batch) Write() error {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
return b.db.Write(b.b, nil)
|
return b.db.Write(b.b, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
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
|
memTableSize = maxMemTableSize - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024),
|
logger.Info("Pebble db Allocated cache and file handles", "handles", handles, "block_cache_size", common.StorageSize(cache*1024*1024),
|
||||||
"handles", handles, "memory table", common.StorageSize(memTableSize))
|
"memory_table_size", common.StorageSize(memTableSize))
|
||||||
|
|
||||||
db := &Database{
|
db := &Database{
|
||||||
fn: file,
|
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.
|
// Get retrieves the given key if it's present in the key-value store.
|
||||||
func (d *Database) Get(key []byte) ([]byte, error) {
|
func (d *Database) Get(key []byte) ([]byte, error) {
|
||||||
|
var (
|
||||||
|
step1Start time.Time
|
||||||
|
step1End time.Time
|
||||||
|
step2Start time.Time
|
||||||
|
step2End time.Time
|
||||||
|
step3Start time.Time
|
||||||
|
step3End time.Time
|
||||||
|
step4Start time.Time
|
||||||
|
step4End time.Time
|
||||||
|
keyLen int
|
||||||
|
valueLen int
|
||||||
|
)
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() {
|
||||||
|
ethdb.EthdbGetTimer.UpdateSince(start)
|
||||||
|
if time.Now().Sub(start) > 100*time.Millisecond {
|
||||||
|
d.log.Error("perf pebble read",
|
||||||
|
"key", key,
|
||||||
|
"key_len", keyLen,
|
||||||
|
"value_len", valueLen,
|
||||||
|
"step1", common.PrettyDuration(step1End.Sub(step1Start)),
|
||||||
|
"step2", common.PrettyDuration(step2End.Sub(step2Start)),
|
||||||
|
"step3", common.PrettyDuration(step3End.Sub(step3Start)),
|
||||||
|
"step4", common.PrettyDuration(step4End.Sub(step4Start)))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
keyLen = len(key)
|
||||||
|
step1Start = time.Now()
|
||||||
d.quitLock.RLock()
|
d.quitLock.RLock()
|
||||||
|
step1End = time.Now()
|
||||||
defer d.quitLock.RUnlock()
|
defer d.quitLock.RUnlock()
|
||||||
if d.closed {
|
if d.closed {
|
||||||
return nil, pebble.ErrClosed
|
return nil, pebble.ErrClosed
|
||||||
}
|
}
|
||||||
|
step2Start = time.Now()
|
||||||
|
innerStart := time.Now()
|
||||||
dat, closer, err := d.db.Get(key)
|
dat, closer, err := d.db.Get(key)
|
||||||
|
valueLen = len(dat)
|
||||||
|
ethdb.EthdbInnerGetTimer.UpdateSince(innerStart)
|
||||||
|
step2End = time.Now()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
step3Start = time.Now()
|
||||||
ret := make([]byte, len(dat))
|
ret := make([]byte, len(dat))
|
||||||
copy(ret, dat)
|
copy(ret, dat)
|
||||||
|
step3End = time.Now()
|
||||||
|
|
||||||
|
step4Start = time.Now()
|
||||||
closer.Close()
|
closer.Close()
|
||||||
|
step4End = time.Now()
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put inserts the given value into the key-value store.
|
// Put inserts the given value into the key-value store.
|
||||||
func (d *Database) Put(key []byte, value []byte) error {
|
func (d *Database) Put(key []byte, value []byte) error {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { ethdb.EthdbPutTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
d.quitLock.RLock()
|
d.quitLock.RLock()
|
||||||
defer d.quitLock.RUnlock()
|
defer d.quitLock.RUnlock()
|
||||||
if d.closed {
|
if d.closed {
|
||||||
@@ -336,6 +382,10 @@ func (d *Database) Put(key []byte, value []byte) error {
|
|||||||
|
|
||||||
// Delete removes the key from the key-value store.
|
// Delete removes the key from the key-value store.
|
||||||
func (d *Database) Delete(key []byte) error {
|
func (d *Database) Delete(key []byte) error {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { ethdb.EthdbDeleteTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
d.quitLock.RLock()
|
d.quitLock.RLock()
|
||||||
defer d.quitLock.RUnlock()
|
defer d.quitLock.RUnlock()
|
||||||
if d.closed {
|
if d.closed {
|
||||||
@@ -494,6 +544,9 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
|
|||||||
nonLevel0CompCount = int64(d.nonLevel0Comp.Load())
|
nonLevel0CompCount = int64(d.nonLevel0Comp.Load())
|
||||||
level0CompCount = int64(d.level0Comp.Load())
|
level0CompCount = int64(d.level0Comp.Load())
|
||||||
)
|
)
|
||||||
|
fmt.Printf("loop print pebble db stats db_metrics=\n%v\n", stats)
|
||||||
|
d.log.Info("loop print pebble db stats", "comp_time", compTime, "write_delay_count", writeDelayCount, "write_delay_time",
|
||||||
|
writeDelayTime, "non_level0_comp_count", nonLevel0CompCount, "level0_comp_count", level0CompCount)
|
||||||
writeDelayTimes[i%2] = writeDelayTime
|
writeDelayTimes[i%2] = writeDelayTime
|
||||||
writeDelayCounts[i%2] = writeDelayCount
|
writeDelayCounts[i%2] = writeDelayCount
|
||||||
compTimes[i%2] = compTime
|
compTimes[i%2] = compTime
|
||||||
@@ -599,6 +652,10 @@ func (b *batch) ValueSize() int {
|
|||||||
|
|
||||||
// Write flushes any accumulated data to disk.
|
// Write flushes any accumulated data to disk.
|
||||||
func (b *batch) Write() error {
|
func (b *batch) Write() error {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
b.db.quitLock.RLock()
|
b.db.quitLock.RLock()
|
||||||
defer b.db.quitLock.RUnlock()
|
defer b.db.quitLock.RUnlock()
|
||||||
if b.db.closed {
|
if b.db.closed {
|
||||||
|
|||||||
@@ -44,10 +44,6 @@ func (db *Database) BlockStore() ethdb.Database {
|
|||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *Database) HasSeparateBlockStore() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *Database) SetBlockStore(block ethdb.Database) {
|
func (db *Database) SetBlockStore(block ethdb.Database) {
|
||||||
panic("not supported")
|
panic("not supported")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -659,30 +659,6 @@ web3._extend({
|
|||||||
name: 'stop',
|
name: 'stop',
|
||||||
call: 'miner_stop'
|
call: 'miner_stop'
|
||||||
}),
|
}),
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'mevRunning',
|
|
||||||
call: 'miner_mevRunning'
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'startMev',
|
|
||||||
call: 'miner_startMev'
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'stopMev',
|
|
||||||
call: 'miner_stopMev'
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'addBuilder',
|
|
||||||
call: 'miner_addBuilder',
|
|
||||||
params: 2,
|
|
||||||
inputFormatter: [web3._extend.formatters.inputAddressFormatter, null]
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
|
||||||
name: 'removeBuilder',
|
|
||||||
call: 'miner_removeBuilder',
|
|
||||||
params: 1,
|
|
||||||
inputFormatter: [web3._extend.formatters.inputAddressFormatter]
|
|
||||||
}),
|
|
||||||
new web3._extend.Method({
|
new web3._extend.Method({
|
||||||
name: 'setEtherbase',
|
name: 'setEtherbase',
|
||||||
call: 'miner_setEtherbase',
|
call: 'miner_setEtherbase',
|
||||||
|
|||||||
@@ -37,8 +37,8 @@ type Config struct {
|
|||||||
|
|
||||||
// DefaultConfig is the default config for metrics used in go-ethereum.
|
// DefaultConfig is the default config for metrics used in go-ethereum.
|
||||||
var DefaultConfig = Config{
|
var DefaultConfig = Config{
|
||||||
Enabled: false,
|
Enabled: true,
|
||||||
EnabledExpensive: false,
|
EnabledExpensive: true,
|
||||||
HTTP: "127.0.0.1",
|
HTTP: "127.0.0.1",
|
||||||
Port: 6060,
|
Port: 6060,
|
||||||
EnableInfluxDB: false,
|
EnableInfluxDB: false,
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ import (
|
|||||||
//
|
//
|
||||||
// This global kill-switch helps quantify the observer effect and makes
|
// This global kill-switch helps quantify the observer effect and makes
|
||||||
// for less cluttered pprof profiles.
|
// for less cluttered pprof profiles.
|
||||||
var Enabled = false
|
var Enabled = true
|
||||||
|
|
||||||
// EnabledExpensive is a soft-flag meant for external packages to check if costly
|
// EnabledExpensive is a soft-flag meant for external packages to check if costly
|
||||||
// metrics gathering is allowed or not. The goal is to separate standard metrics
|
// metrics gathering is allowed or not. The goal is to separate standard metrics
|
||||||
// for health monitoring and debug metrics that might impact runtime performance.
|
// for health monitoring and debug metrics that might impact runtime performance.
|
||||||
var EnabledExpensive = false
|
var EnabledExpensive = true
|
||||||
|
|
||||||
// enablerFlags is the CLI flag names to use to enable metrics collections.
|
// enablerFlags is the CLI flag names to use to enable metrics collections.
|
||||||
var enablerFlags = []string{"metrics"}
|
var enablerFlags = []string{"metrics"}
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ import (
|
|||||||
const (
|
const (
|
||||||
// maxBidPerBuilderPerBlock is the max bid number per builder
|
// maxBidPerBuilderPerBlock is the max bid number per builder
|
||||||
maxBidPerBuilderPerBlock = 3
|
maxBidPerBuilderPerBlock = 3
|
||||||
|
|
||||||
|
// leftOverTimeRate is the rate of left over time to simulate a bid
|
||||||
|
leftOverTimeRate = 11
|
||||||
|
// leftOverTimeScale is the scale of left over time to simulate a bid
|
||||||
|
leftOverTimeScale = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -73,7 +78,6 @@ type simBidReq struct {
|
|||||||
type bidSimulator struct {
|
type bidSimulator struct {
|
||||||
config *MevConfig
|
config *MevConfig
|
||||||
delayLeftOver time.Duration
|
delayLeftOver time.Duration
|
||||||
minGasPrice *big.Int
|
|
||||||
chain *core.BlockChain
|
chain *core.BlockChain
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
@@ -110,7 +114,6 @@ type bidSimulator struct {
|
|||||||
func newBidSimulator(
|
func newBidSimulator(
|
||||||
config *MevConfig,
|
config *MevConfig,
|
||||||
delayLeftOver time.Duration,
|
delayLeftOver time.Duration,
|
||||||
minGasPrice *big.Int,
|
|
||||||
chain *core.BlockChain,
|
chain *core.BlockChain,
|
||||||
chainConfig *params.ChainConfig,
|
chainConfig *params.ChainConfig,
|
||||||
engine consensus.Engine,
|
engine consensus.Engine,
|
||||||
@@ -119,7 +122,6 @@ func newBidSimulator(
|
|||||||
b := &bidSimulator{
|
b := &bidSimulator{
|
||||||
config: config,
|
config: config,
|
||||||
delayLeftOver: delayLeftOver,
|
delayLeftOver: delayLeftOver,
|
||||||
minGasPrice: minGasPrice,
|
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
@@ -313,6 +315,18 @@ func (b *bidSimulator) newBidLoop() {
|
|||||||
|
|
||||||
// commit aborts in-flight bid execution with given signal and resubmits a new one.
|
// commit aborts in-flight bid execution with given signal and resubmits a new one.
|
||||||
commit := func(reason int32, bidRuntime *BidRuntime) {
|
commit := func(reason int32, bidRuntime *BidRuntime) {
|
||||||
|
// if the left time is not enough to do simulation, return
|
||||||
|
var simDuration time.Duration
|
||||||
|
if lastBid := b.GetBestBid(bidRuntime.bid.ParentHash); lastBid != nil && lastBid.duration != 0 {
|
||||||
|
simDuration = lastBid.duration
|
||||||
|
}
|
||||||
|
|
||||||
|
if time.Until(b.bidMustBefore(bidRuntime.bid.ParentHash)) <= simDuration*leftOverTimeRate/leftOverTimeScale {
|
||||||
|
log.Debug("BidSimulator: abort commit, not enough time to simulate",
|
||||||
|
"builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if interruptCh != nil {
|
if interruptCh != nil {
|
||||||
// each commit work will have its own interruptCh to stop work with a reason
|
// each commit work will have its own interruptCh to stop work with a reason
|
||||||
interruptCh <- reason
|
interruptCh <- reason
|
||||||
@@ -353,7 +367,6 @@ func (b *bidSimulator) newBidLoop() {
|
|||||||
expectedValidatorReward: expectedValidatorReward,
|
expectedValidatorReward: expectedValidatorReward,
|
||||||
packedBlockReward: big.NewInt(0),
|
packedBlockReward: big.NewInt(0),
|
||||||
packedValidatorReward: big.NewInt(0),
|
packedValidatorReward: big.NewInt(0),
|
||||||
finished: make(chan struct{}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
simulatingBid := b.GetSimulatingBid(newBid.ParentHash)
|
simulatingBid := b.GetSimulatingBid(newBid.ParentHash)
|
||||||
@@ -394,6 +407,11 @@ func (b *bidSimulator) newBidLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *bidSimulator) bidMustBefore(parentHash common.Hash) time.Time {
|
||||||
|
parentHeader := b.chain.GetHeaderByHash(parentHash)
|
||||||
|
return bidutil.BidMustBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *bidSimulator) bidBetterBefore(parentHash common.Hash) time.Time {
|
func (b *bidSimulator) bidBetterBefore(parentHash common.Hash) time.Time {
|
||||||
parentHeader := b.chain.GetHeaderByHash(parentHash)
|
parentHeader := b.chain.GetHeaderByHash(parentHash)
|
||||||
return bidutil.BidBetterBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver, b.config.BidSimulationLeftOver)
|
return bidutil.BidBetterBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver, b.config.BidSimulationLeftOver)
|
||||||
@@ -509,6 +527,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
|
|
||||||
// ensure simulation exited then start next simulation
|
// ensure simulation exited then start next simulation
|
||||||
b.SetSimulatingBid(parentHash, bidRuntime)
|
b.SetSimulatingBid(parentHash, bidRuntime)
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
defer func(simStart time.Time) {
|
defer func(simStart time.Time) {
|
||||||
logCtx := []any{
|
logCtx := []any{
|
||||||
@@ -534,11 +553,10 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.RemoveSimulatingBid(parentHash)
|
b.RemoveSimulatingBid(parentHash)
|
||||||
close(bidRuntime.finished)
|
bidSimTimer.UpdateSince(start)
|
||||||
|
|
||||||
if success {
|
if success {
|
||||||
bidRuntime.duration = time.Since(simStart)
|
bidRuntime.duration = time.Since(simStart)
|
||||||
bidSimTimer.UpdateSince(simStart)
|
|
||||||
|
|
||||||
// only recommit self bid when newBidCh is empty
|
// only recommit self bid when newBidCh is empty
|
||||||
if len(b.newBidCh) > 0 {
|
if len(b.newBidCh) > 0 {
|
||||||
@@ -562,14 +580,6 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the left time is not enough to do simulation, return
|
|
||||||
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
|
|
||||||
if delay == nil || *delay <= 0 {
|
|
||||||
log.Info("BidSimulator: abort commit, not enough time to simulate",
|
|
||||||
"builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
gasLimit := bidRuntime.env.header.GasLimit
|
gasLimit := bidRuntime.env.header.GasLimit
|
||||||
if bidRuntime.env.gasPool == nil {
|
if bidRuntime.env.gasPool == nil {
|
||||||
bidRuntime.env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
bidRuntime.env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||||
@@ -582,7 +592,6 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit transactions in bid
|
|
||||||
for _, tx := range bidRuntime.bid.Txs {
|
for _, tx := range bidRuntime.bid.Txs {
|
||||||
select {
|
select {
|
||||||
case <-interruptCh:
|
case <-interruptCh:
|
||||||
@@ -600,7 +609,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
err = bidRuntime.commitTransaction(b.chain, b.chainConfig, tx, bidRuntime.bid.UnRevertible.Contains(tx.Hash()))
|
err = bidRuntime.commitTransaction(b.chain, b.chainConfig, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("BidSimulator: failed to commit tx", "bidHash", bidRuntime.bid.Hash(), "tx", tx.Hash(), "err", err)
|
log.Error("BidSimulator: failed to commit tx", "bidHash", bidRuntime.bid.Hash(), "tx", tx.Hash(), "err", err)
|
||||||
err = fmt.Errorf("invalid tx in bid, %v", err)
|
err = fmt.Errorf("invalid tx in bid, %v", err)
|
||||||
@@ -608,41 +617,26 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if bid reward is valid
|
|
||||||
{
|
|
||||||
bidRuntime.packReward(b.config.ValidatorCommission)
|
bidRuntime.packReward(b.config.ValidatorCommission)
|
||||||
|
|
||||||
|
// return if bid is invalid, reportIssue issue to mev-sentry/builder if simulation is fully done
|
||||||
if !bidRuntime.validReward() {
|
if !bidRuntime.validReward() {
|
||||||
err = errors.New("reward does not achieve the expectation")
|
err = errors.New("reward does not achieve the expectation")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// check if bid gas price is lower than min gas price
|
// fill transactions from mempool
|
||||||
{
|
|
||||||
bidGasUsed := uint64(0)
|
|
||||||
bidGasFee := bidRuntime.env.state.GetBalance(consensus.SystemAddress)
|
|
||||||
|
|
||||||
for _, receipt := range bidRuntime.env.receipts {
|
|
||||||
bidGasUsed += receipt.GasUsed
|
|
||||||
}
|
|
||||||
|
|
||||||
bidGasPrice := new(big.Int).Div(bidGasFee.ToBig(), new(big.Int).SetUint64(bidGasUsed))
|
|
||||||
if bidGasPrice.Cmp(b.minGasPrice) < 0 {
|
|
||||||
err = errors.New("bid gas price is lower than min gas price")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if enable greedy merge, fill bid env with transactions from mempool
|
|
||||||
if b.config.GreedyMergeTx {
|
if b.config.GreedyMergeTx {
|
||||||
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
|
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
|
||||||
if delay != nil && *delay > 0 {
|
if delay != nil && *delay > 0 {
|
||||||
|
stopTimer := time.NewTimer(*delay)
|
||||||
|
|
||||||
bidTxsSet := mapset.NewSet[common.Hash]()
|
bidTxsSet := mapset.NewSet[common.Hash]()
|
||||||
for _, tx := range bidRuntime.bid.Txs {
|
for _, tx := range bidRuntime.bid.Txs {
|
||||||
bidTxsSet.Add(tx.Hash())
|
bidTxsSet.Add(tx.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
fillErr := b.bidWorker.fillTransactions(interruptCh, bidRuntime.env, nil, bidTxsSet)
|
fillErr := b.bidWorker.fillTransactions(interruptCh, bidRuntime.env, stopTimer, bidTxsSet)
|
||||||
log.Trace("BidSimulator: greedy merge stopped", "block", bidRuntime.env.header.Number,
|
log.Trace("BidSimulator: greedy merge stopped", "block", bidRuntime.env.header.Number,
|
||||||
"builder", bidRuntime.bid.Builder, "tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr)
|
"builder", bidRuntime.bid.Builder, "tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr)
|
||||||
|
|
||||||
@@ -651,9 +645,8 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit payBidTx at the end of the block
|
|
||||||
bidRuntime.env.gasPool.AddGas(params.PayBidTxGasLimit)
|
bidRuntime.env.gasPool.AddGas(params.PayBidTxGasLimit)
|
||||||
err = bidRuntime.commitTransaction(b.chain, b.chainConfig, payBidTx, true)
|
err = bidRuntime.commitTransaction(b.chain, b.chainConfig, payBidTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("BidSimulator: failed to commit tx", "builder", bidRuntime.bid.Builder,
|
log.Error("BidSimulator: failed to commit tx", "builder", bidRuntime.bid.Builder,
|
||||||
"bidHash", bidRuntime.bid.Hash(), "tx", payBidTx.Hash(), "err", err)
|
"bidHash", bidRuntime.bid.Hash(), "tx", payBidTx.Hash(), "err", err)
|
||||||
@@ -718,7 +711,6 @@ type BidRuntime struct {
|
|||||||
packedBlockReward *big.Int
|
packedBlockReward *big.Int
|
||||||
packedValidatorReward *big.Int
|
packedValidatorReward *big.Int
|
||||||
|
|
||||||
finished chan struct{}
|
|
||||||
duration time.Duration
|
duration time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,9 +727,11 @@ func (r *BidRuntime) packReward(validatorCommission uint64) {
|
|||||||
r.packedValidatorReward.Sub(r.packedValidatorReward, r.bid.BuilderFee)
|
r.packedValidatorReward.Sub(r.packedValidatorReward, r.bid.BuilderFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *BidRuntime) commitTransaction(chain *core.BlockChain, chainConfig *params.ChainConfig, tx *types.Transaction, unRevertible bool) error {
|
func (r *BidRuntime) commitTransaction(chain *core.BlockChain, chainConfig *params.ChainConfig, tx *types.Transaction) error {
|
||||||
var (
|
var (
|
||||||
env = r.env
|
env = r.env
|
||||||
|
snap = env.state.Snapshot()
|
||||||
|
gp = env.gasPool.Gas()
|
||||||
sc *types.BlobSidecar
|
sc *types.BlobSidecar
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -761,9 +755,9 @@ func (r *BidRuntime) commitTransaction(chain *core.BlockChain, chainConfig *para
|
|||||||
receipt, err := core.ApplyTransaction(chainConfig, chain, &env.coinbase, env.gasPool, env.state, env.header, tx,
|
receipt, err := core.ApplyTransaction(chainConfig, chain, &env.coinbase, env.gasPool, env.state, env.header, tx,
|
||||||
&env.header.GasUsed, *chain.GetVMConfig(), core.NewReceiptBloomGenerator())
|
&env.header.GasUsed, *chain.GetVMConfig(), core.NewReceiptBloomGenerator())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
env.state.RevertToSnapshot(snap)
|
||||||
|
env.gasPool.SetGas(gp)
|
||||||
return err
|
return err
|
||||||
} else if unRevertible && receipt.Status == types.ReceiptStatusFailed {
|
|
||||||
return errors.New("no revertible transaction failed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if tx.Type() == types.BlobTxType {
|
if tx.Type() == types.BlobTxType {
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
|
|||||||
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, false),
|
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, false),
|
||||||
}
|
}
|
||||||
|
|
||||||
miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, config.GasPrice, eth.BlockChain(), chainConfig, engine, miner.worker)
|
miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, eth.BlockChain(), chainConfig, engine, miner.worker)
|
||||||
miner.worker.setBestBidFetcher(miner.bidSimulator)
|
miner.worker.setBestBidFetcher(miner.bidSimulator)
|
||||||
|
|
||||||
miner.wg.Add(1)
|
miner.wg.Add(1)
|
||||||
|
|||||||
@@ -67,14 +67,13 @@ const (
|
|||||||
// the current 4 mining loops could have asynchronous risk of mining block with
|
// the current 4 mining loops could have asynchronous risk of mining block with
|
||||||
// save height, keep recently mined blocks to avoid double sign for safety,
|
// save height, keep recently mined blocks to avoid double sign for safety,
|
||||||
recentMinedCacheLimit = 20
|
recentMinedCacheLimit = 20
|
||||||
|
|
||||||
// the default to wait for the mev miner to finish
|
|
||||||
waitMEVMinerEndTimeLimit = 50 * time.Millisecond
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil)
|
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil)
|
||||||
finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil)
|
finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil)
|
||||||
|
fillTxFnTimer = metrics.NewRegisteredTimer("worker/filltransactions/all", nil)
|
||||||
|
fillTxFnPartialTimer = metrics.NewRegisteredTimer("worker/filltransactions/partial", nil)
|
||||||
|
|
||||||
errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
|
errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
|
||||||
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
||||||
@@ -174,7 +173,6 @@ type getWorkReq struct {
|
|||||||
|
|
||||||
type bidFetcher interface {
|
type bidFetcher interface {
|
||||||
GetBestBid(parentHash common.Hash) *BidRuntime
|
GetBestBid(parentHash common.Hash) *BidRuntime
|
||||||
GetSimulatingBid(prevBlockHash common.Hash) *BidRuntime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// worker is the main object which takes care of submitting new work to consensus engine
|
// worker is the main object which takes care of submitting new work to consensus engine
|
||||||
@@ -1060,6 +1058,8 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
|||||||
// into the given sealing block. The transaction selection and ordering strategy can
|
// into the given sealing block. The transaction selection and ordering strategy can
|
||||||
// be customized with the plugin in the future.
|
// be customized with the plugin in the future.
|
||||||
func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer, bidTxs mapset.Set[common.Hash]) (err error) {
|
func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer, bidTxs mapset.Set[common.Hash]) (err error) {
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
w.mu.RLock()
|
w.mu.RLock()
|
||||||
tip := w.tip
|
tip := w.tip
|
||||||
w.mu.RUnlock()
|
w.mu.RUnlock()
|
||||||
@@ -1114,6 +1114,7 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
|
|||||||
localBlobTxs[account] = txs
|
localBlobTxs[account] = txs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fillTxFnPartialTimer.UpdateSince(start)
|
||||||
|
|
||||||
// Fill the block with all available pending transactions.
|
// Fill the block with all available pending transactions.
|
||||||
// we will abort when:
|
// we will abort when:
|
||||||
@@ -1138,6 +1139,7 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fillTxFnTimer.UpdateSince(start)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1340,15 +1342,6 @@ LOOP:
|
|||||||
// when in-turn, compare with remote work.
|
// when in-turn, compare with remote work.
|
||||||
from := bestWork.coinbase
|
from := bestWork.coinbase
|
||||||
if w.bidFetcher != nil && bestWork.header.Difficulty.Cmp(diffInTurn) == 0 {
|
if w.bidFetcher != nil && bestWork.header.Difficulty.Cmp(diffInTurn) == 0 {
|
||||||
if pendingBid := w.bidFetcher.GetSimulatingBid(bestWork.header.ParentHash); pendingBid != nil {
|
|
||||||
waitBidTimer := time.NewTimer(waitMEVMinerEndTimeLimit)
|
|
||||||
defer waitBidTimer.Stop()
|
|
||||||
select {
|
|
||||||
case <-waitBidTimer.C:
|
|
||||||
case <-pendingBid.finished:
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bestBid := w.bidFetcher.GetBestBid(bestWork.header.ParentHash)
|
bestBid := w.bidFetcher.GetBestBid(bestWork.header.ParentHash)
|
||||||
|
|
||||||
if bestBid != nil {
|
if bestBid != nil {
|
||||||
|
|||||||
@@ -779,7 +779,6 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r
|
|||||||
Cache: cache,
|
Cache: cache,
|
||||||
Handles: handles,
|
Handles: handles,
|
||||||
ReadOnly: readonly,
|
ReadOnly: readonly,
|
||||||
MultiDataBase: n.CheckIfMultiDataBase(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,8 +152,6 @@ var (
|
|||||||
FeynmanTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
|
FeynmanTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
|
||||||
FeynmanFixTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
|
FeynmanFixTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
|
||||||
CancunTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
|
CancunTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
|
||||||
HaberTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
|
|
||||||
BohrTime: nil,
|
|
||||||
|
|
||||||
Parlia: &ParliaConfig{
|
Parlia: &ParliaConfig{
|
||||||
Period: 3,
|
Period: 3,
|
||||||
@@ -192,8 +190,6 @@ var (
|
|||||||
FeynmanTime: newUint64(1710136800), // 2024-03-11 6:00:00 AM UTC
|
FeynmanTime: newUint64(1710136800), // 2024-03-11 6:00:00 AM UTC
|
||||||
FeynmanFixTime: newUint64(1711342800), // 2024-03-25 5:00:00 AM UTC
|
FeynmanFixTime: newUint64(1711342800), // 2024-03-25 5:00:00 AM UTC
|
||||||
CancunTime: newUint64(1713330442), // 2024-04-17 05:07:22 AM UTC
|
CancunTime: newUint64(1713330442), // 2024-04-17 05:07:22 AM UTC
|
||||||
HaberTime: newUint64(1716962820), // 2024-05-29 06:07:00 AM UTC
|
|
||||||
BohrTime: nil,
|
|
||||||
|
|
||||||
Parlia: &ParliaConfig{
|
Parlia: &ParliaConfig{
|
||||||
Period: 3,
|
Period: 3,
|
||||||
@@ -233,8 +229,6 @@ var (
|
|||||||
FeynmanTime: newUint64(0),
|
FeynmanTime: newUint64(0),
|
||||||
FeynmanFixTime: newUint64(0),
|
FeynmanFixTime: newUint64(0),
|
||||||
CancunTime: newUint64(0),
|
CancunTime: newUint64(0),
|
||||||
HaberTime: newUint64(0),
|
|
||||||
BohrTime: newUint64(0),
|
|
||||||
|
|
||||||
Parlia: &ParliaConfig{
|
Parlia: &ParliaConfig{
|
||||||
Period: 3,
|
Period: 3,
|
||||||
@@ -273,7 +267,6 @@ var (
|
|||||||
FeynmanTime: newUint64(0),
|
FeynmanTime: newUint64(0),
|
||||||
FeynmanFixTime: newUint64(0),
|
FeynmanFixTime: newUint64(0),
|
||||||
CancunTime: newUint64(0),
|
CancunTime: newUint64(0),
|
||||||
|
|
||||||
Parlia: &ParliaConfig{
|
Parlia: &ParliaConfig{
|
||||||
Period: 3,
|
Period: 3,
|
||||||
Epoch: 200,
|
Epoch: 200,
|
||||||
@@ -511,8 +504,6 @@ type ChainConfig struct {
|
|||||||
FeynmanTime *uint64 `json:"feynmanTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already activated)
|
FeynmanTime *uint64 `json:"feynmanTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already activated)
|
||||||
FeynmanFixTime *uint64 `json:"feynmanFixTime,omitempty"` // FeynmanFix switch time (nil = no fork, 0 = already activated)
|
FeynmanFixTime *uint64 `json:"feynmanFixTime,omitempty"` // FeynmanFix switch time (nil = no fork, 0 = already activated)
|
||||||
CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun)
|
CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun)
|
||||||
HaberTime *uint64 `json:"haberTime,omitempty"` // Haber switch time (nil = no fork, 0 = already on haber)
|
|
||||||
BohrTime *uint64 `json:"bohrTime,omitempty"` // Bohr switch time (nil = no fork, 0 = already on bohr)
|
|
||||||
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
|
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
|
||||||
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
||||||
|
|
||||||
@@ -618,17 +609,7 @@ func (c *ChainConfig) String() string {
|
|||||||
CancunTime = big.NewInt(0).SetUint64(*c.CancunTime)
|
CancunTime = big.NewInt(0).SetUint64(*c.CancunTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
var HaberTime *big.Int
|
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, CatalystBlock: %v, London: %v, ArrowGlacier: %v, MergeFork:%v, Euler: %v, Gibbs: %v, Nano: %v, Moran: %v, Planck: %v,Luban: %v, Plato: %v, Hertz: %v, Hertzfix: %v, ShanghaiTime: %v, KeplerTime: %v, FeynmanTime: %v, FeynmanFixTime: %v, CancunTime: %v, Engine: %v}",
|
||||||
if c.HaberTime != nil {
|
|
||||||
HaberTime = big.NewInt(0).SetUint64(*c.HaberTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
var BohrTime *big.Int
|
|
||||||
if c.BohrTime != nil {
|
|
||||||
BohrTime = big.NewInt(0).SetUint64(*c.BohrTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Ramanujan: %v, Niels: %v, MirrorSync: %v, Bruno: %v, Berlin: %v, YOLO v3: %v, CatalystBlock: %v, London: %v, ArrowGlacier: %v, MergeFork:%v, Euler: %v, Gibbs: %v, Nano: %v, Moran: %v, Planck: %v,Luban: %v, Plato: %v, Hertz: %v, Hertzfix: %v, ShanghaiTime: %v, KeplerTime: %v, FeynmanTime: %v, FeynmanFixTime: %v, CancunTime: %v, HaberTime: %v, BohrTime: %v, Engine: %v}",
|
|
||||||
c.ChainID,
|
c.ChainID,
|
||||||
c.HomesteadBlock,
|
c.HomesteadBlock,
|
||||||
c.DAOForkBlock,
|
c.DAOForkBlock,
|
||||||
@@ -665,8 +646,6 @@ func (c *ChainConfig) String() string {
|
|||||||
FeynmanTime,
|
FeynmanTime,
|
||||||
FeynmanFixTime,
|
FeynmanFixTime,
|
||||||
CancunTime,
|
CancunTime,
|
||||||
HaberTime,
|
|
||||||
BohrTime,
|
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -934,25 +913,6 @@ func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool {
|
|||||||
return c.IsLondon(num) && isTimestampForked(c.CancunTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.CancunTime, time)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsHaber returns whether time is either equal to the Haber fork time or greater.
|
|
||||||
func (c *ChainConfig) IsHaber(num *big.Int, time uint64) bool {
|
|
||||||
return c.IsLondon(num) && isTimestampForked(c.HaberTime, time)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsBohr returns whether time is either equal to the Bohr fork time or greater.
|
|
||||||
func (c *ChainConfig) IsBohr(num *big.Int, time uint64) bool {
|
|
||||||
return c.IsLondon(num) && isTimestampForked(c.BohrTime, time)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsOnBohr returns whether currentBlockTime is either equal to the Bohr fork time or greater firstly.
|
|
||||||
func (c *ChainConfig) IsOnBohr(currentBlockNumber *big.Int, lastBlockTime uint64, currentBlockTime uint64) bool {
|
|
||||||
lastBlockNumber := new(big.Int)
|
|
||||||
if currentBlockNumber.Cmp(big.NewInt(1)) >= 0 {
|
|
||||||
lastBlockNumber.Sub(currentBlockNumber, big.NewInt(1))
|
|
||||||
}
|
|
||||||
return !c.IsBohr(lastBlockNumber, lastBlockTime) && c.IsBohr(currentBlockNumber, currentBlockTime)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsPrague returns whether num is either equal to the Prague fork time or greater.
|
// IsPrague returns whether num is either equal to the Prague fork time or greater.
|
||||||
func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool {
|
func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool {
|
||||||
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
|
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
|
||||||
@@ -1016,8 +976,6 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
|
|||||||
{name: "feynmanTime", timestamp: c.FeynmanTime},
|
{name: "feynmanTime", timestamp: c.FeynmanTime},
|
||||||
{name: "feynmanFixTime", timestamp: c.FeynmanFixTime},
|
{name: "feynmanFixTime", timestamp: c.FeynmanFixTime},
|
||||||
{name: "cancunTime", timestamp: c.CancunTime},
|
{name: "cancunTime", timestamp: c.CancunTime},
|
||||||
{name: "haberTime", timestamp: c.HaberTime},
|
|
||||||
{name: "bohrTime", timestamp: c.BohrTime},
|
|
||||||
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
|
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
|
||||||
{name: "verkleTime", timestamp: c.VerkleTime, optional: true},
|
{name: "verkleTime", timestamp: c.VerkleTime, optional: true},
|
||||||
} {
|
} {
|
||||||
@@ -1347,8 +1305,8 @@ type Rules struct {
|
|||||||
IsPlato bool
|
IsPlato bool
|
||||||
IsHertz bool
|
IsHertz bool
|
||||||
IsHertzfix bool
|
IsHertzfix bool
|
||||||
IsShanghai, IsKepler, IsFeynman, IsCancun, IsHaber bool
|
IsShanghai, IsKepler, IsFeynman, IsCancun, IsPrague bool
|
||||||
IsBohr, IsPrague, IsVerkle bool
|
IsVerkle bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rules ensures c's ChainID is not nil.
|
// Rules ensures c's ChainID is not nil.
|
||||||
@@ -1383,8 +1341,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
|
|||||||
IsKepler: c.IsKepler(num, timestamp),
|
IsKepler: c.IsKepler(num, timestamp),
|
||||||
IsFeynman: c.IsFeynman(num, timestamp),
|
IsFeynman: c.IsFeynman(num, timestamp),
|
||||||
IsCancun: c.IsCancun(num, timestamp),
|
IsCancun: c.IsCancun(num, timestamp),
|
||||||
IsHaber: c.IsHaber(num, timestamp),
|
|
||||||
IsBohr: c.IsBohr(num, timestamp),
|
|
||||||
IsPrague: c.IsPrague(num, timestamp),
|
IsPrague: c.IsPrague(num, timestamp),
|
||||||
IsVerkle: c.IsVerkle(num, timestamp),
|
IsVerkle: c.IsVerkle(num, timestamp),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,8 +170,6 @@ const (
|
|||||||
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
|
Bls12381MapG1Gas uint64 = 5500 // Gas price for BLS12-381 mapping field element to G1 operation
|
||||||
Bls12381MapG2Gas uint64 = 110000 // Gas price for BLS12-381 mapping field element to G2 operation
|
Bls12381MapG2Gas uint64 = 110000 // Gas price for BLS12-381 mapping field element to G2 operation
|
||||||
|
|
||||||
P256VerifyGas uint64 = 3450 // secp256r1 elliptic curve signature verifier gas price
|
|
||||||
|
|
||||||
// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,
|
// The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529,
|
||||||
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
|
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
|
||||||
RefundQuotient uint64 = 2
|
RefundQuotient uint64 = 2
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import (
|
|||||||
const (
|
const (
|
||||||
VersionMajor = 1 // Major version component of the current release
|
VersionMajor = 1 // Major version component of the current release
|
||||||
VersionMinor = 4 // Minor version component of the current release
|
VersionMinor = 4 // Minor version component of the current release
|
||||||
VersionPatch = 9 // Patch version component of the current release
|
VersionPatch = 7 // Patch version component of the current release
|
||||||
VersionMeta = "" // Version metadata to append to the version string
|
VersionMeta = "" // Version metadata to append to the version string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -4,15 +4,17 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/mclock"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@@ -24,113 +26,63 @@ import (
|
|||||||
"golang.org/x/sync/semaphore"
|
"golang.org/x/sync/semaphore"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
Nonce uint64
|
||||||
|
Balance *big.Int
|
||||||
|
Root common.Hash // merkle root of the storage trie
|
||||||
|
CodeHash []byte
|
||||||
|
}
|
||||||
|
|
||||||
type Database interface {
|
type Database interface {
|
||||||
database.Database
|
database.Database
|
||||||
Scheme() string
|
Scheme() string
|
||||||
Cap(limit common.StorageSize) error
|
Cap(limit common.StorageSize) error
|
||||||
DiskDB() ethdb.Database
|
DiskDB() ethdb.Database
|
||||||
}
|
}
|
||||||
|
|
||||||
const TopN = 3
|
|
||||||
|
|
||||||
type Inspector struct {
|
type Inspector struct {
|
||||||
trie *Trie // traverse trie
|
trie *Trie // traverse trie
|
||||||
db Database
|
db Database
|
||||||
stateRootHash common.Hash
|
stateRootHash common.Hash
|
||||||
blockNum uint64
|
blocknum uint64
|
||||||
root node // root of triedb
|
root node // root of triedb
|
||||||
|
totalNum uint64
|
||||||
|
wg sync.WaitGroup
|
||||||
|
statLock sync.RWMutex
|
||||||
|
result map[string]*TrieTreeStat
|
||||||
sem *semaphore.Weighted
|
sem *semaphore.Weighted
|
||||||
eoaAccountNums uint64
|
eoaAccountNums uint64
|
||||||
|
|
||||||
wg sync.WaitGroup
|
|
||||||
|
|
||||||
results stat
|
|
||||||
topN int
|
|
||||||
|
|
||||||
totalAccountNum atomic.Uint64
|
|
||||||
totalStorageNum atomic.Uint64
|
|
||||||
lastTime mclock.AbsTime
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type stat struct {
|
type TrieTreeStat struct {
|
||||||
lock sync.RWMutex
|
is_account_trie bool
|
||||||
account *trieStat
|
theNodeStatByLevel [15]NodeStat
|
||||||
storageTopN []*trieStat
|
totalNodeStat NodeStat
|
||||||
storageTopNTotal []uint64
|
|
||||||
storageTotal nodeStat
|
|
||||||
storageTrieNum uint64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type trieStat struct {
|
type NodeStat struct {
|
||||||
owner common.Hash
|
ShortNodeCnt uint64
|
||||||
totalNodeStat nodeStat
|
FullNodeCnt uint64
|
||||||
nodeStatByLevel [16]nodeStat
|
ValueNodeCnt uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
type nodeStat struct {
|
func (trieStat *TrieTreeStat) AtomicAdd(theNode node, height uint32) {
|
||||||
ShortNodeCnt atomic.Uint64
|
|
||||||
FullNodeCnt atomic.Uint64
|
|
||||||
ValueNodeCnt atomic.Uint64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ns *nodeStat) IsEmpty() bool {
|
|
||||||
if ns.FullNodeCnt.Load() == 0 && ns.ShortNodeCnt.Load() == 0 && ns.ValueNodeCnt.Load() == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stat) add(ts *trieStat, topN int) {
|
|
||||||
s.lock.Lock()
|
|
||||||
defer s.lock.Unlock()
|
|
||||||
if ts.owner == (common.Hash{}) {
|
|
||||||
s.account = ts
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
total := ts.totalNodeStat.ValueNodeCnt.Load() + ts.totalNodeStat.FullNodeCnt.Load() + ts.totalNodeStat.ShortNodeCnt.Load()
|
|
||||||
if len(s.storageTopNTotal) == 0 || total > s.storageTopNTotal[len(s.storageTopNTotal)-1] {
|
|
||||||
var (
|
|
||||||
i int
|
|
||||||
t uint64
|
|
||||||
)
|
|
||||||
for i, t = range s.storageTopNTotal {
|
|
||||||
if total < t {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
s.storageTopNTotal = append(s.storageTopNTotal[:i], append([]uint64{total}, s.storageTopNTotal[i:]...)...)
|
|
||||||
s.storageTopN = append(s.storageTopN[:i], append([]*trieStat{ts}, s.storageTopN[i:]...)...)
|
|
||||||
if len(s.storageTopN) > topN {
|
|
||||||
s.storageTopNTotal = s.storageTopNTotal[:topN]
|
|
||||||
s.storageTopN = s.storageTopN[:topN]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
s.storageTotal.ShortNodeCnt.Add(ts.totalNodeStat.ShortNodeCnt.Load())
|
|
||||||
s.storageTotal.ValueNodeCnt.Add(ts.totalNodeStat.ValueNodeCnt.Load())
|
|
||||||
s.storageTotal.FullNodeCnt.Add(ts.totalNodeStat.FullNodeCnt.Load())
|
|
||||||
s.storageTrieNum++
|
|
||||||
}
|
|
||||||
|
|
||||||
func (trieStat *trieStat) add(theNode node, height int) {
|
|
||||||
switch (theNode).(type) {
|
switch (theNode).(type) {
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
trieStat.totalNodeStat.ShortNodeCnt.Add(1)
|
atomic.AddUint64(&trieStat.totalNodeStat.ShortNodeCnt, 1)
|
||||||
trieStat.nodeStatByLevel[height].ShortNodeCnt.Add(1)
|
atomic.AddUint64(&(trieStat.theNodeStatByLevel[height].ShortNodeCnt), 1)
|
||||||
case *fullNode:
|
case *fullNode:
|
||||||
trieStat.totalNodeStat.FullNodeCnt.Add(1)
|
atomic.AddUint64(&trieStat.totalNodeStat.FullNodeCnt, 1)
|
||||||
trieStat.nodeStatByLevel[height].FullNodeCnt.Add(1)
|
atomic.AddUint64(&trieStat.theNodeStatByLevel[height].FullNodeCnt, 1)
|
||||||
case valueNode:
|
case valueNode:
|
||||||
trieStat.totalNodeStat.ValueNodeCnt.Add(1)
|
atomic.AddUint64(&trieStat.totalNodeStat.ValueNodeCnt, 1)
|
||||||
trieStat.nodeStatByLevel[height].ValueNodeCnt.Add(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 {
|
func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) {
|
||||||
sw := new(strings.Builder)
|
table := tablewriter.NewWriter(os.Stdout)
|
||||||
table := tablewriter.NewWriter(sw)
|
|
||||||
table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"})
|
table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"})
|
||||||
if ownerAddress == "" {
|
if ownerAddress == "" {
|
||||||
table.SetCaption(true, fmt.Sprintf("%v", treeType))
|
table.SetCaption(true, fmt.Sprintf("%v", treeType))
|
||||||
@@ -138,27 +90,38 @@ func (trieStat *trieStat) Display(ownerAddress string, treeType string) string {
|
|||||||
table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress))
|
table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress))
|
||||||
}
|
}
|
||||||
table.SetAlignment(1)
|
table.SetAlignment(1)
|
||||||
|
for i := 0; i < len(trieStat.theNodeStatByLevel); i++ {
|
||||||
for i := range trieStat.nodeStatByLevel {
|
nodeStat := trieStat.theNodeStatByLevel[i]
|
||||||
if trieStat.nodeStatByLevel[i].IsEmpty() {
|
if nodeStat.FullNodeCnt == 0 && nodeStat.ShortNodeCnt == 0 && nodeStat.ValueNodeCnt == 0 {
|
||||||
continue
|
break
|
||||||
}
|
}
|
||||||
table.AppendBulk([][]string{
|
table.AppendBulk([][]string{
|
||||||
{"-", fmt.Sprintf("%d", i),
|
{"-", strconv.Itoa(i), nodeStat.ShortNodeCount(), nodeStat.FullNodeCount(), nodeStat.ValueNodeCount()},
|
||||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ShortNodeCnt.Load()),
|
|
||||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].FullNodeCnt.Load()),
|
|
||||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ValueNodeCnt.Load())},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
table.AppendBulk([][]string{
|
table.AppendBulk([][]string{
|
||||||
{"Total", "-", 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()
|
table.Render()
|
||||||
return sw.String()
|
}
|
||||||
|
|
||||||
|
func Uint64ToString(cnt uint64) string {
|
||||||
|
return fmt.Sprintf("%v", cnt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nodeStat *NodeStat) ShortNodeCount() string {
|
||||||
|
return Uint64ToString(nodeStat.ShortNodeCnt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (nodeStat *NodeStat) FullNodeCount() string {
|
||||||
|
return Uint64ToString(nodeStat.FullNodeCnt)
|
||||||
|
}
|
||||||
|
func (nodeStat *NodeStat) ValueNodeCount() string {
|
||||||
|
return Uint64ToString(nodeStat.ValueNodeCnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInspector return a inspector obj
|
// NewInspector return a inspector obj
|
||||||
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uint64, jobNum uint64, topN int) (*Inspector, error) {
|
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uint64, jobnum uint64) (*Inspector, error) {
|
||||||
if tr == nil {
|
if tr == nil {
|
||||||
return nil, errors.New("trie is nil")
|
return nil, errors.New("trie is nil")
|
||||||
}
|
}
|
||||||
@@ -171,17 +134,12 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uin
|
|||||||
trie: tr,
|
trie: tr,
|
||||||
db: db,
|
db: db,
|
||||||
stateRootHash: stateRootHash,
|
stateRootHash: stateRootHash,
|
||||||
blockNum: blockNum,
|
blocknum: blocknum,
|
||||||
root: tr.root,
|
root: tr.root,
|
||||||
results: stat{},
|
result: make(map[string]*TrieTreeStat),
|
||||||
topN: topN,
|
totalNum: (uint64)(0),
|
||||||
totalAccountNum: atomic.Uint64{},
|
|
||||||
totalStorageNum: atomic.Uint64{},
|
|
||||||
lastTime: mclock.Now(),
|
|
||||||
sem: semaphore.NewWeighted(int64(jobNum)),
|
|
||||||
|
|
||||||
wg: sync.WaitGroup{},
|
wg: sync.WaitGroup{},
|
||||||
|
sem: semaphore.NewWeighted(int64(jobnum)),
|
||||||
eoaAccountNums: 0,
|
eoaAccountNums: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,123 +147,155 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Run statistics, external call
|
// Run statistics, external call
|
||||||
func (s *Inspector) Run() {
|
func (inspect *Inspector) Run() {
|
||||||
|
accountTrieStat := &TrieTreeStat{
|
||||||
|
is_account_trie: true,
|
||||||
|
}
|
||||||
|
if inspect.db.Scheme() == rawdb.HashScheme {
|
||||||
ticker := time.NewTicker(30 * time.Second)
|
ticker := time.NewTicker(30 * time.Second)
|
||||||
go func() {
|
go func() {
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
if s.db.Scheme() == rawdb.HashScheme {
|
inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
|
||||||
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{},
|
|
||||||
}
|
}
|
||||||
s.traversal(s.trie, ts, s.root, 0, []byte{})
|
|
||||||
s.results.add(ts, s.topN)
|
if _, ok := inspect.result[""]; !ok {
|
||||||
s.wg.Wait()
|
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
|
// nil node
|
||||||
if n == nil {
|
if theNode == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ts.add(n, height)
|
switch current := (theNode).(type) {
|
||||||
|
|
||||||
switch current := (n).(type) {
|
|
||||||
case *shortNode:
|
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:
|
case *fullNode:
|
||||||
for idx, child := range current.Children {
|
for idx, child := range current.Children {
|
||||||
if child == nil {
|
if child == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p := common.CopyBytes(append(path, byte(idx)))
|
childPath := append(path, byte(idx))
|
||||||
s.traversal(trie, ts, child, height+1, p)
|
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:
|
case hashNode:
|
||||||
tn, err := trie.resloveWithoutTrack(current, path)
|
n, err := theTrie.resloveWithoutTrack(current, path)
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
s.PrintProgress(trie)
|
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, n, height, path)
|
||||||
s.traversal(trie, ts, tn, height, path)
|
return
|
||||||
case valueNode:
|
case valueNode:
|
||||||
if !hasTerm(path) {
|
if !hasTerm(path) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
var account types.StateAccount
|
var account Account
|
||||||
if err := rlp.Decode(bytes.NewReader(current), &account); err != nil {
|
if err := rlp.Decode(bytes.NewReader(current), &account); err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash {
|
if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash {
|
||||||
s.eoaAccountNums++
|
inspect.eoaAccountNums++
|
||||||
}
|
}
|
||||||
if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash {
|
if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
ownerAddress := common.BytesToHash(hexToCompact(path))
|
ownerAddress := common.BytesToHash(hexToCompact(path))
|
||||||
contractTrie, err := New(StorageTrieID(s.stateRootHash, ownerAddress, account.Root), s.db)
|
contractTrie, err := New(StorageTrieID(inspect.stateRootHash, ownerAddress, account.Root), inspect.db)
|
||||||
if err != nil {
|
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()
|
contractTrie.tracer.reset()
|
||||||
|
trieStat := &TrieTreeStat{
|
||||||
|
is_account_trie: false,
|
||||||
|
}
|
||||||
|
|
||||||
if s.sem.TryAcquire(1) {
|
inspect.statLock.Lock()
|
||||||
s.wg.Add(1)
|
if _, ok := inspect.result[ownerAddress.String()]; !ok {
|
||||||
go func() {
|
inspect.result[ownerAddress.String()] = trieStat
|
||||||
t := &trieStat{
|
|
||||||
owner: ownerAddress,
|
|
||||||
}
|
|
||||||
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
|
|
||||||
s.results.add(t, s.topN)
|
|
||||||
s.sem.Release(1)
|
|
||||||
s.wg.Done()
|
|
||||||
}()
|
|
||||||
} else {
|
|
||||||
t := &trieStat{
|
|
||||||
owner: ownerAddress,
|
|
||||||
}
|
|
||||||
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
|
|
||||||
s.results.add(t, s.topN)
|
|
||||||
}
|
}
|
||||||
|
inspect.statLock.Unlock()
|
||||||
|
|
||||||
|
// log.Info("Find Contract Trie Tree, rootHash: ", contractTrie.Hash().String(), "")
|
||||||
|
inspect.wg.Add(1)
|
||||||
|
go inspect.SubConcurrentTraversal(contractTrie, trieStat, contractTrie.root, 0, []byte{})
|
||||||
default:
|
default:
|
||||||
panic(errors.New("invalid node type to traverse"))
|
panic(errors.New("Invalid node type to traverse."))
|
||||||
}
|
}
|
||||||
|
theTrieTreeStat.AtomicAdd(theNode, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Inspector) PrintProgress(t *Trie) {
|
func (inspect *Inspector) DisplayResult() {
|
||||||
var (
|
|
||||||
elapsed = mclock.Now().Sub(s.lastTime)
|
|
||||||
)
|
|
||||||
if t.owner == (common.Hash{}) {
|
|
||||||
s.totalAccountNum.Add(1)
|
|
||||||
} else {
|
|
||||||
s.totalStorageNum.Add(1)
|
|
||||||
}
|
|
||||||
if elapsed > 4*time.Second {
|
|
||||||
log.Info("traversal progress", "TotalAccountNum", s.totalAccountNum.Load(), "TotalStorageNum", s.totalStorageNum.Load(), "Goroutine", runtime.NumGoroutine())
|
|
||||||
s.lastTime = mclock.Now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Inspector) DisplayResult() {
|
|
||||||
// display root hash
|
// display root hash
|
||||||
fmt.Println(s.results.account.Display("", "AccountTrie"))
|
if _, ok := inspect.result[""]; !ok {
|
||||||
fmt.Println("EOA accounts num: ", s.eoaAccountNums)
|
log.Info("Display result error", "missing account trie")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
inspect.result[""].Display("", "AccountTrie")
|
||||||
|
|
||||||
|
type SortedTrie struct {
|
||||||
|
totalNum uint64
|
||||||
|
ownerAddress string
|
||||||
|
}
|
||||||
// display contract trie
|
// display contract trie
|
||||||
for _, st := range s.results.storageTopN {
|
var sortedTriesByNums []SortedTrie
|
||||||
fmt.Println(st.Display(st.owner.String(), "StorageTrie"))
|
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",
|
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"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
"github.com/ethereum/go-ethereum/triedb/database"
|
"github.com/ethereum/go-ethereum/triedb/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
trieGetTimer = metrics.NewRegisteredTimer("trie/get/time", nil)
|
||||||
|
trieReaderGetTimer = metrics.NewRegisteredTimer("trie/reader/get/time", nil)
|
||||||
|
trieReaderTotalTimer = metrics.NewRegisteredTimer("trie/reader/total/time", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on
|
// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on
|
||||||
// top of a database. Whenever trie performs a commit operation, the generated
|
// top of a database. Whenever trie performs a commit operation, the generated
|
||||||
// nodes will be gathered and returned in a set. Once the trie is committed,
|
// nodes will be gathered and returned in a set. Once the trie is committed,
|
||||||
@@ -146,6 +154,10 @@ func (t *Trie) Get(key []byte) ([]byte, error) {
|
|||||||
if t.committed {
|
if t.committed {
|
||||||
return nil, ErrCommitted
|
return nil, ErrCommitted
|
||||||
}
|
}
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { trieGetTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0)
|
value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0)
|
||||||
if err == nil && didResolve {
|
if err == nil && didResolve {
|
||||||
t.root = newroot
|
t.root = newroot
|
||||||
@@ -178,7 +190,11 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
|
|||||||
}
|
}
|
||||||
return value, n, didResolve, err
|
return value, n, didResolve, err
|
||||||
case hashNode:
|
case hashNode:
|
||||||
|
start := time.Now()
|
||||||
child, err := t.resolveAndTrack(n, key[:pos])
|
child, err := t.resolveAndTrack(n, key[:pos])
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
trieReaderGetTimer.UpdateSince(start)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, n, true, err
|
return nil, n, true, err
|
||||||
}
|
}
|
||||||
@@ -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
|
// node's original value. The rlp-encoded blob is preferred to be loaded from
|
||||||
// database because it's easy to decode node while complex to encode node to blob.
|
// database because it's easy to decode node while complex to encode node to blob.
|
||||||
func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
|
func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { trieReaderTotalTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
blob, err := t.reader.node(prefix, common.BytesToHash(n))
|
blob, err := t.reader.node(prefix, common.BytesToHash(n))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ type tester struct {
|
|||||||
|
|
||||||
func newTester(t *testing.T, historyLimit uint64) *tester {
|
func newTester(t *testing.T, historyLimit uint64) *tester {
|
||||||
var (
|
var (
|
||||||
disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false, false)
|
disk, _ = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false, false, false, false)
|
||||||
db = New(disk, &Config{
|
db = New(disk, &Config{
|
||||||
StateHistory: historyLimit,
|
StateHistory: historyLimit,
|
||||||
CleanCacheSize: 256 * 1024,
|
CleanCacheSize: 256 * 1024,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package pathdb
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
@@ -104,6 +105,8 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
|
|||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
start := time.Now()
|
||||||
|
|
||||||
// If the trie node is known locally, return it
|
// If the trie node is known locally, return it
|
||||||
subset, ok := dl.nodes[owner]
|
subset, ok := dl.nodes[owner]
|
||||||
if ok {
|
if ok {
|
||||||
@@ -114,14 +117,18 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
|
|||||||
if n.Hash != hash {
|
if n.Hash != hash {
|
||||||
dirtyFalseMeter.Mark(1)
|
dirtyFalseMeter.Mark(1)
|
||||||
log.Error("Unexpected trie node in diff layer", "owner", owner, "path", path, "expect", hash, "got", n.Hash)
|
log.Error("Unexpected trie node in diff layer", "owner", owner, "path", path, "expect", hash, "got", n.Hash)
|
||||||
|
pathGetDiffLayerTimer.UpdateSince(start)
|
||||||
return nil, newUnexpectedNodeError("diff", hash, n.Hash, owner, path, n.Blob)
|
return nil, newUnexpectedNodeError("diff", hash, n.Hash, owner, path, n.Blob)
|
||||||
}
|
}
|
||||||
dirtyHitMeter.Mark(1)
|
dirtyHitMeter.Mark(1)
|
||||||
dirtyNodeHitDepthHist.Update(int64(depth))
|
dirtyNodeHitDepthHist.Update(int64(depth))
|
||||||
dirtyReadMeter.Mark(int64(len(n.Blob)))
|
dirtyReadMeter.Mark(int64(len(n.Blob)))
|
||||||
|
pathGetDiffLayerTimer.UpdateSince(start)
|
||||||
return n.Blob, nil
|
return n.Blob, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pathGetDiffLayerTimer.UpdateSince(start)
|
||||||
|
|
||||||
// Trie node unknown to this layer, resolve from parent
|
// Trie node unknown to this layer, resolve from parent
|
||||||
if diff, ok := dl.parent.(*diffLayer); ok {
|
if diff, ok := dl.parent.(*diffLayer); ok {
|
||||||
return diff.node(owner, path, hash, depth+1)
|
return diff.node(owner, path, hash, depth+1)
|
||||||
|
|||||||
@@ -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"
|
||||||
@@ -27,6 +28,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
"github.com/ethereum/go-ethereum/trie/triestate"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
@@ -155,6 +157,10 @@ func (dl *diskLayer) markStale() {
|
|||||||
func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
|
func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
defer dl.lock.RUnlock()
|
defer dl.lock.RUnlock()
|
||||||
|
if metrics.EnabledExpensive {
|
||||||
|
start := time.Now()
|
||||||
|
defer func() { pathGetDiskLayerTimer.UpdateSince(start) }()
|
||||||
|
}
|
||||||
|
|
||||||
if dl.stale {
|
if dl.stale {
|
||||||
return nil, errSnapshotStale
|
return nil, errSnapshotStale
|
||||||
|
|||||||
@@ -152,13 +152,12 @@ func (kr *JournalKVReader) Close() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newJournalWriter(file string, db ethdb.Database, journalType JournalType) JournalWriter {
|
func newJournalWriter(file string, db ethdb.Database, journalType JournalType) JournalWriter {
|
||||||
|
log.Info("New journal writer", "path", file, "journalType", journalType)
|
||||||
if journalType == JournalKVType {
|
if journalType == JournalKVType {
|
||||||
log.Info("New journal writer for journal kv")
|
|
||||||
return &JournalKVWriter{
|
return &JournalKVWriter{
|
||||||
diskdb: db,
|
diskdb: db,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Info("New journal writer for journal file", "path", file)
|
|
||||||
fd, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
fd, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -170,8 +169,8 @@ func newJournalWriter(file string, db ethdb.Database, journalType JournalType) J
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newJournalReader(file string, db ethdb.Database, journalType JournalType) (JournalReader, error) {
|
func newJournalReader(file string, db ethdb.Database, journalType JournalType) (JournalReader, error) {
|
||||||
|
log.Info("New journal reader", "path", file, "journalType", journalType)
|
||||||
if journalType == JournalKVType {
|
if journalType == JournalKVType {
|
||||||
log.Info("New journal reader for journal kv")
|
|
||||||
journal := rawdb.ReadTrieJournal(db)
|
journal := rawdb.ReadTrieJournal(db)
|
||||||
if len(journal) == 0 {
|
if len(journal) == 0 {
|
||||||
return nil, errMissJournal
|
return nil, errMissJournal
|
||||||
@@ -180,7 +179,6 @@ func newJournalReader(file string, db ethdb.Database, journalType JournalType) (
|
|||||||
journalBuf: bytes.NewBuffer(journal),
|
journalBuf: bytes.NewBuffer(journal),
|
||||||
}, nil
|
}, nil
|
||||||
} else {
|
} else {
|
||||||
log.Info("New journal reader for journal file", "path", file)
|
|
||||||
fd, err := os.Open(file)
|
fd, err := os.Open(file)
|
||||||
if errors.Is(err, fs.ErrNotExist) {
|
if errors.Is(err, fs.ErrNotExist) {
|
||||||
return nil, errMissJournal
|
return nil, errMissJournal
|
||||||
|
|||||||
@@ -47,4 +47,7 @@ var (
|
|||||||
historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil)
|
historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil)
|
||||||
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil)
|
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil)
|
||||||
historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil)
|
historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil)
|
||||||
|
|
||||||
|
pathGetDiffLayerTimer = metrics.NewRegisteredTimer("pathdb/get/difflayer/time", nil)
|
||||||
|
pathGetDiskLayerTimer = metrics.NewRegisteredTimer("pathdb/get/disklayer/time", nil)
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user