Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d572c77e4c | ||
|
|
565085959b | ||
|
|
b7b1b0c001 | ||
|
|
08702d3380 | ||
|
|
91e3a3ea1f | ||
|
|
73477bd0fc | ||
|
|
8749c8e8ce | ||
|
|
79fe2899c7 |
57
CHANGELOG.md
57
CHANGELOG.md
@@ -1,61 +1,4 @@
|
||||
# Changelog
|
||||
|
||||
## v1.4.11
|
||||
|
||||
### BUGFIX
|
||||
* [\#2534](https://github.com/bnb-chain/bsc/pull/2534) fix: nil pointer when clear simulating bid
|
||||
* [\#2535](https://github.com/bnb-chain/bsc/pull/2535) upgrade: add HaberFix hardfork
|
||||
|
||||
|
||||
## v1.4.10
|
||||
### FEATURE
|
||||
NA
|
||||
|
||||
### IMPROVEMENT
|
||||
* [\#2512](https://github.com/bnb-chain/bsc/pull/2512) feat: add mev helper params and func
|
||||
* [\#2508](https://github.com/bnb-chain/bsc/pull/2508) perf: speedup pbss trienode read
|
||||
* [\#2509](https://github.com/bnb-chain/bsc/pull/2509) perf: optimize chain commit performance for multi-database
|
||||
* [\#2451](https://github.com/bnb-chain/bsc/pull/2451) core/forkchoice: improve stability when inturn block not generate
|
||||
|
||||
### BUGFIX
|
||||
* [\#2518](https://github.com/bnb-chain/bsc/pull/2518) fix: remove zero gasprice check for BSC
|
||||
* [\#2519](https://github.com/bnb-chain/bsc/pull/2519) UT: random failure of TestSnapSyncWithBlobs
|
||||
* [\#2515](https://github.com/bnb-chain/bsc/pull/2515) fix getBlobSidecars by ethclient
|
||||
* [\#2525](https://github.com/bnb-chain/bsc/pull/2525) fix: ensure empty withdrawals after cancun before broadcast
|
||||
|
||||
## 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
|
||||
### FEATURE
|
||||
* [\#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.
|
||||
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.
|
||||
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
|
||||
@@ -183,7 +183,7 @@ This tool is optional and if you leave it out you can always attach to an alread
|
||||
|
||||
#### 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
|
||||
crossing over between the main network and test network, you should always
|
||||
|
||||
@@ -63,8 +63,6 @@ var (
|
||||
Flags: flags.Merge([]cli.Flag{
|
||||
utils.CachePreimagesFlag,
|
||||
utils.OverrideCancun,
|
||||
utils.OverrideHaber,
|
||||
utils.OverrideBohr,
|
||||
utils.OverrideVerkle,
|
||||
}, utils.DatabaseFlags),
|
||||
Description: `
|
||||
@@ -258,14 +256,6 @@ func initGenesis(ctx *cli.Context) error {
|
||||
v := ctx.Uint64(utils.OverrideCancun.Name)
|
||||
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) {
|
||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||
overrides.OverrideVerkle = &v
|
||||
|
||||
@@ -189,14 +189,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||
v := ctx.Uint64(utils.OverrideCancun.Name)
|
||||
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) {
|
||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||
cfg.Eth.OverrideVerkle = &v
|
||||
@@ -288,6 +280,7 @@ func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) {
|
||||
if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) {
|
||||
cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name)
|
||||
}
|
||||
cfg.Metrics.EnabledExpensive = true
|
||||
if ctx.IsSet(utils.MetricsHTTPFlag.Name) {
|
||||
cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name)
|
||||
}
|
||||
|
||||
@@ -106,12 +106,12 @@ Remove blockchain and state databases`,
|
||||
dbInspectTrieCmd = &cli.Command{
|
||||
Action: inspectTrie,
|
||||
Name: "inspect-trie",
|
||||
ArgsUsage: "<blocknum> <jobnum> <topn>",
|
||||
ArgsUsage: "<blocknum> <jobnum>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.SyncModeFlag,
|
||||
},
|
||||
Usage: "Inspect the MPT tree of the account and contract. 'blocknum' can be latest/snapshot/number. 'topn' means output the top N storage tries info ranked by the total number of TrieNodes",
|
||||
Usage: "Inspect the MPT tree of the account and contract.",
|
||||
Description: `This commands iterates the entrie WorldState.`,
|
||||
}
|
||||
dbCheckStateContentCmd = &cli.Command{
|
||||
@@ -386,7 +386,6 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
blockNumber uint64
|
||||
trieRootHash common.Hash
|
||||
jobnum uint64
|
||||
topN uint64
|
||||
)
|
||||
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
@@ -406,37 +405,24 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
var err error
|
||||
blockNumber, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64)
|
||||
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 {
|
||||
jobnum = 1000
|
||||
topN = 10
|
||||
} else if ctx.NArg() == 2 {
|
||||
var err error
|
||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
topN = 10
|
||||
} else {
|
||||
var err error
|
||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
|
||||
topN, err = strconv.ParseUint(ctx.Args().Get(2), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse topn, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
}
|
||||
|
||||
if blockNumber != math.MaxUint64 {
|
||||
headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber)
|
||||
if headerBlockHash == (common.Hash{}) {
|
||||
return errors.New("ReadHeadBlockHash empty hash")
|
||||
return errors.New("ReadHeadBlockHash empry hash")
|
||||
}
|
||||
blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber)
|
||||
trieRootHash = blockHeader.Root
|
||||
@@ -451,7 +437,6 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
if dbScheme == rawdb.PathScheme {
|
||||
config = &triedb.Config{
|
||||
PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly),
|
||||
Cache: 0,
|
||||
}
|
||||
} else if dbScheme == rawdb.HashScheme {
|
||||
config = triedb.HashDefaults
|
||||
@@ -463,7 +448,7 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String())
|
||||
return err
|
||||
}
|
||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum, int(topN))
|
||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -508,7 +493,7 @@ func ancientInspect(ctx *cli.Context) error {
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
|
||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||
db := utils.MakeChainDatabase(ctx, stack, true, true)
|
||||
defer db.Close()
|
||||
return rawdb.AncientInspect(db)
|
||||
}
|
||||
|
||||
@@ -73,8 +73,6 @@ var (
|
||||
utils.SmartCardDaemonPathFlag,
|
||||
utils.RialtoHash,
|
||||
utils.OverrideCancun,
|
||||
utils.OverrideHaber,
|
||||
utils.OverrideBohr,
|
||||
utils.OverrideVerkle,
|
||||
utils.OverrideFullImmutabilityThreshold,
|
||||
utils.OverrideMinBlocksForBlobRequests,
|
||||
|
||||
@@ -75,7 +75,7 @@ func NewLevelDBDatabaseWithFreezer(file string, cache int, handles int, ancient
|
||||
if err != nil {
|
||||
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 {
|
||||
kvdb.Close()
|
||||
return nil, err
|
||||
@@ -178,10 +178,11 @@ func BlockchainCreator(t *testing.T, chaindbPath, AncientPath string, blockRemai
|
||||
|
||||
// Force run a freeze cycle
|
||||
type freezer interface {
|
||||
Freeze(threshold uint64) error
|
||||
Freeze() error
|
||||
Ancients() (uint64, error)
|
||||
}
|
||||
db.(freezer).Freeze(10)
|
||||
blockchain.SetFinalized(blocks[len(blocks)-1].Header())
|
||||
db.(freezer).Freeze()
|
||||
|
||||
frozen, err := db.Ancients()
|
||||
//make sure there're frozen items
|
||||
|
||||
@@ -43,11 +43,9 @@ import (
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/node"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
"github.com/ethereum/go-ethereum/trie"
|
||||
"github.com/ethereum/go-ethereum/triedb"
|
||||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
||||
cli "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@@ -247,16 +245,7 @@ func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) {
|
||||
NoBuild: true,
|
||||
AsyncBuild: false,
|
||||
}
|
||||
dbScheme := rawdb.ReadStateScheme(chaindb)
|
||||
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)
|
||||
snaptree, err := snapshot.New(snapconfig, chaindb, triedb.NewDatabase(chaindb, nil), headBlock.Root(), TriesInMemory, false)
|
||||
if err != nil {
|
||||
log.Error("snaptree error", "err", err)
|
||||
return nil, err // The relevant snapshot(s) might not exist
|
||||
@@ -344,9 +333,6 @@ func pruneBlock(ctx *cli.Context) error {
|
||||
stack, config = makeConfigNode(ctx)
|
||||
defer stack.Close()
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import { ethers } from "ethers";
|
||||
import program from "commander";
|
||||
|
||||
// depends on ethjs v6.11.0+ for 4844, https://github.com/ethers-io/ethers.js/releases/tag/v6.11.0
|
||||
// BSC testnet enabled 4844 on block: 39539137
|
||||
// Usage:
|
||||
// nvm use 20
|
||||
// node check_blobtx.js --rpc https://data-seed-prebsc-1-s1.binance.org:8545 --startNum 39539137
|
||||
// node check_blobtx.js --rpc https://data-seed-prebsc-1-s1.binance.org:8545 --startNum 39539137 --endNum 40345994
|
||||
program.option("--rpc <Rpc>", "Rpc Server URL");
|
||||
program.option("--startNum <Num>", "start block", 0);
|
||||
program.option("--endNum <Num>", "end block", 0);
|
||||
program.parse(process.argv);
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(program.rpc);
|
||||
const main = async () => {
|
||||
var startBlock = parseInt(program.startNum)
|
||||
var endBlock = parseInt(program.endNum)
|
||||
if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) {
|
||||
console.error("invalid input, --startNum", program.startNum, "--end", program.endNum)
|
||||
return
|
||||
}
|
||||
// if --endNum is not specified, set it to the latest block number.
|
||||
if (endBlock == 0) {
|
||||
endBlock = await provider.getBlockNumber();
|
||||
}
|
||||
if (startBlock > endBlock) {
|
||||
console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock);
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = startBlock; i <= endBlock; i++) {
|
||||
let blockData = await provider.getBlock(i);
|
||||
console.log("startBlock:",startBlock, "endBlock:", endBlock, "curBlock", i, "blobGasUsed", blockData.blobGasUsed);
|
||||
if (blockData.blobGasUsed == 0) {
|
||||
continue
|
||||
}
|
||||
for (let txIndex = 0; txIndex<= blockData.transactions.length - 1; txIndex++) {
|
||||
let txHash = blockData.transactions[txIndex]
|
||||
let txData = await provider.getTransaction(txHash);
|
||||
if (txData.type == 3) {
|
||||
console.log("BlobTx in block:",i, " txIndex:", txIndex, " txHash:", txHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
main().then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
import { ethers } from "ethers";
|
||||
import program from "commander";
|
||||
|
||||
// Usage:
|
||||
// node faucet_request.js --rpc localhost:8545 --startNum 39539137
|
||||
// node faucet_request.js --rpc localhost:8545 --startNum 39539137 --endNum 40345994
|
||||
|
||||
// node faucet_request.js --rpc https://data-seed-prebsc-1-s1.bnbchain.org:8545 --startNum 39539137 --endNum 40345994
|
||||
program.option("--rpc <Rpc>", "Rpc Server URL");
|
||||
program.option("--startNum <Num>", "start block", 0);
|
||||
program.option("--endNum <Num>", "end block", 0);
|
||||
program.parse(process.argv);
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(program.rpc);
|
||||
const main = async () => {
|
||||
var startBlock = parseInt(program.startNum)
|
||||
var endBlock = parseInt(program.endNum)
|
||||
if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) {
|
||||
console.error("invalid input, --startNum", program.startNum, "--end", program.endNum)
|
||||
return
|
||||
}
|
||||
// if --endNum is not specified, set it to the latest block number.
|
||||
if (endBlock == 0) {
|
||||
endBlock = await provider.getBlockNumber();
|
||||
}
|
||||
if (startBlock > endBlock) {
|
||||
console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock);
|
||||
return
|
||||
}
|
||||
|
||||
let startBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", startBlock)
|
||||
let endBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", endBlock)
|
||||
const faucetAmount = BigInt(0.3 * 10**18); // Convert 0.3 ether to wei as a BigInt
|
||||
const numFaucetRequest = (startBalance - endBalance) / faucetAmount;
|
||||
|
||||
// Convert BigInt to ether
|
||||
const startBalanceEth = Number(startBalance) / 10**18;
|
||||
const endBalanceEth = Number(endBalance) / 10**18;
|
||||
|
||||
console.log(`Start Balance: ${startBalanceEth} ETH`);
|
||||
console.log(`End Balance: ${endBalanceEth} ETH`);
|
||||
|
||||
console.log("successful faucet request: ",numFaucetRequest);
|
||||
};
|
||||
main().then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -310,16 +310,6 @@ var (
|
||||
Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting",
|
||||
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{
|
||||
Name: "override.verkle",
|
||||
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",
|
||||
Usage: "Sets the expected remained amount of blocks for offline block prune",
|
||||
Category: flags.BlockHistoryCategory,
|
||||
Value: params.FullImmutabilityThreshold,
|
||||
}
|
||||
|
||||
CheckSnapshotWithMPT = &cli.BoolFlag{
|
||||
|
||||
@@ -163,7 +163,7 @@ func TestHistoryImportAndExport(t *testing.T) {
|
||||
|
||||
// Now import Era.
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -66,31 +66,6 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
|
||||
return validator
|
||||
}
|
||||
|
||||
// ValidateListsInBody validates that UncleHash, WithdrawalsHash, and WithdrawalsHash correspond to the lists in the block body, respectively.
|
||||
func ValidateListsInBody(block *types.Block) error {
|
||||
header := block.Header()
|
||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
||||
}
|
||||
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
|
||||
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
|
||||
}
|
||||
// Withdrawals are present after the Shanghai fork.
|
||||
if header.WithdrawalsHash != nil {
|
||||
// Withdrawals list must be present in body after Shanghai.
|
||||
if block.Withdrawals() == nil {
|
||||
return errors.New("missing withdrawals in block body")
|
||||
}
|
||||
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
|
||||
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
||||
}
|
||||
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
|
||||
// Withdrawals are not allowed prior to shanghai fork
|
||||
return errors.New("withdrawals present in block body")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateBody validates the given block's uncles and verifies the block
|
||||
// header's transaction and uncle roots. The headers are assumed to be already
|
||||
// validated at this point.
|
||||
@@ -108,12 +83,31 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
return err
|
||||
}
|
||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
||||
}
|
||||
|
||||
validateFuns := []func() error{
|
||||
func() error {
|
||||
return ValidateListsInBody(block)
|
||||
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
|
||||
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
func() error {
|
||||
// Withdrawals are present after the Shanghai fork.
|
||||
if header.WithdrawalsHash != nil {
|
||||
// Withdrawals list must be present in body after Shanghai.
|
||||
if block.Withdrawals() == nil {
|
||||
return errors.New("missing withdrawals in block body")
|
||||
}
|
||||
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
|
||||
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
||||
}
|
||||
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
|
||||
// Withdrawals are not allowed prior to shanghai fork
|
||||
return errors.New("withdrawals present in block body")
|
||||
}
|
||||
// Blob transactions may be present after the Cancun fork.
|
||||
var blobs int
|
||||
for i, tx := range block.Transactions() {
|
||||
|
||||
@@ -301,7 +301,6 @@ type BlockChain struct {
|
||||
diffLayerFreezerBlockLimit uint64
|
||||
|
||||
wg sync.WaitGroup
|
||||
dbWg sync.WaitGroup
|
||||
quit chan struct{} // shutdown signal, closed in Stop.
|
||||
stopping atomic.Bool // false if chain is running, true when stopped
|
||||
procInterrupt atomic.Bool // interrupt signaler for block processing
|
||||
@@ -442,6 +441,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
diskRoot = bc.triedb.Head()
|
||||
}
|
||||
}
|
||||
diskRoot = common.HexToHash("0x59d2a69ad465dbadf78f99635af9ed8125636cbdedc50bda9668ab2ac677b17a")
|
||||
if diskRoot != (common.Hash{}) {
|
||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
|
||||
|
||||
@@ -577,7 +577,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
||||
}
|
||||
// Start tx indexer if it's enabled.
|
||||
if txLookupLimit != nil {
|
||||
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
|
||||
// bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
|
||||
}
|
||||
return bc, nil
|
||||
}
|
||||
@@ -670,7 +670,7 @@ func (bc *BlockChain) cacheBlock(hash common.Hash, block *types.Block) {
|
||||
// into node seamlessly.
|
||||
func (bc *BlockChain) empty() bool {
|
||||
genesis := bc.genesisBlock.Hash()
|
||||
for _, hash := range []common.Hash{rawdb.ReadHeadBlockHash(bc.db.BlockStore()), rawdb.ReadHeadHeaderHash(bc.db.BlockStore()), rawdb.ReadHeadFastBlockHash(bc.db.BlockStore())} {
|
||||
for _, hash := range []common.Hash{rawdb.ReadHeadBlockHash(bc.db.BlockStore()), rawdb.ReadHeadHeaderHash(bc.db.BlockStore()), rawdb.ReadHeadFastBlockHash(bc.db)} {
|
||||
if hash != genesis {
|
||||
return false
|
||||
}
|
||||
@@ -739,7 +739,7 @@ func (bc *BlockChain) loadLastState() error {
|
||||
bc.currentSnapBlock.Store(headBlock.Header())
|
||||
headFastBlockGauge.Update(int64(headBlock.NumberU64()))
|
||||
|
||||
if head := rawdb.ReadHeadFastBlockHash(bc.db.BlockStore()); head != (common.Hash{}) {
|
||||
if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) {
|
||||
if block := bc.GetBlockByHash(head); block != nil {
|
||||
bc.currentSnapBlock.Store(block.Header())
|
||||
headFastBlockGauge.Update(int64(block.NumberU64()))
|
||||
@@ -1138,7 +1138,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
||||
// If SetHead was only called as a chain reparation method, try to skip
|
||||
// touching the header chain altogether, unless the freezer is broken
|
||||
if repair {
|
||||
if target, force := updateFn(bc.db.BlockStore(), bc.CurrentBlock()); force {
|
||||
if target, force := updateFn(bc.db, bc.CurrentBlock()); force {
|
||||
bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn)
|
||||
}
|
||||
} else {
|
||||
@@ -1299,33 +1299,19 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {
|
||||
//
|
||||
// Note, this function assumes that the `mu` mutex is held!
|
||||
func (bc *BlockChain) writeHeadBlock(block *types.Block) {
|
||||
bc.dbWg.Add(2)
|
||||
defer bc.dbWg.Wait()
|
||||
go func() {
|
||||
defer bc.dbWg.Done()
|
||||
// Add the block to the canonical chain number scheme and mark as the head
|
||||
blockBatch := bc.db.BlockStore().NewBatch()
|
||||
rawdb.WriteCanonicalHash(blockBatch, block.Hash(), block.NumberU64())
|
||||
rawdb.WriteHeadHeaderHash(blockBatch, block.Hash())
|
||||
rawdb.WriteHeadBlockHash(blockBatch, block.Hash())
|
||||
rawdb.WriteHeadFastBlockHash(blockBatch, block.Hash())
|
||||
// Flush the whole batch into the disk, exit the node if failed
|
||||
if err := blockBatch.Write(); err != nil {
|
||||
log.Crit("Failed to update chain indexes and markers in block db", "err", err)
|
||||
}
|
||||
}()
|
||||
go func() {
|
||||
defer bc.dbWg.Done()
|
||||
// Add the block to the canonical chain number scheme and mark as the head
|
||||
rawdb.WriteCanonicalHash(bc.db.BlockStore(), block.Hash(), block.NumberU64())
|
||||
rawdb.WriteHeadHeaderHash(bc.db.BlockStore(), block.Hash())
|
||||
rawdb.WriteHeadBlockHash(bc.db.BlockStore(), block.Hash())
|
||||
|
||||
batch := bc.db.NewBatch()
|
||||
rawdb.WriteTxLookupEntriesByBlock(batch, block)
|
||||
|
||||
// Flush the whole batch into the disk, exit the node if failed
|
||||
if err := batch.Write(); err != nil {
|
||||
log.Crit("Failed to update chain indexes in chain db", "err", err)
|
||||
}
|
||||
}()
|
||||
batch := bc.db.NewBatch()
|
||||
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
|
||||
rawdb.WriteTxLookupEntriesByBlock(batch, block)
|
||||
|
||||
// Flush the whole batch into the disk, exit the node if failed
|
||||
if err := batch.Write(); err != nil {
|
||||
log.Crit("Failed to update chain indexes and markers", "err", err)
|
||||
}
|
||||
// Update all in-memory chain markers in the last step
|
||||
bc.hc.SetCurrentHeader(block.Header())
|
||||
|
||||
@@ -1546,7 +1532,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
||||
} else if !reorg {
|
||||
return false
|
||||
}
|
||||
rawdb.WriteHeadFastBlockHash(bc.db.BlockStore(), head.Hash())
|
||||
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
|
||||
bc.currentSnapBlock.Store(head.Header())
|
||||
headFastBlockGauge.Update(int64(head.NumberU64()))
|
||||
return true
|
||||
@@ -1789,6 +1775,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
wg := sync.WaitGroup{}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
rawdb.WritePreimages(bc.db, state.Preimages())
|
||||
blockBatch := bc.db.BlockStore().NewBatch()
|
||||
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
|
||||
rawdb.WriteBlock(blockBatch, block)
|
||||
@@ -1797,11 +1784,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
||||
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
|
||||
rawdb.WriteBlobSidecars(blockBatch, block.Hash(), block.NumberU64(), block.Sidecars())
|
||||
}
|
||||
if bc.db.StateStore() != nil {
|
||||
rawdb.WritePreimages(bc.db.StateStore(), state.Preimages())
|
||||
} else {
|
||||
rawdb.WritePreimages(blockBatch, state.Preimages())
|
||||
}
|
||||
rawdb.WritePreimages(blockBatch, state.Preimages())
|
||||
if err := blockBatch.Write(); err != nil {
|
||||
log.Crit("Failed to write block into disk", "err", err)
|
||||
}
|
||||
@@ -2285,20 +2268,16 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
bc.cacheBlock(block.Hash(), block)
|
||||
|
||||
// Update the metrics touched during block processing and validation
|
||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
||||
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
|
||||
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
|
||||
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
|
||||
triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
|
||||
trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
|
||||
trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
|
||||
trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
|
||||
blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
|
||||
blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
|
||||
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
|
||||
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
|
||||
snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
|
||||
snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
|
||||
accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
|
||||
storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
|
||||
accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
|
||||
storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
|
||||
blockExecutionTimer.Update(ptime) // The time spent on EVM processing
|
||||
blockValidationTimer.Update(vtime) // The time spent on block validation
|
||||
|
||||
// Write the block to the chain and get the status.
|
||||
var (
|
||||
@@ -2323,7 +2302,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
||||
snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
|
||||
triedbCommitTimer.Update(statedb.TrieDBCommits) // Trie database commits are complete, we can mark them
|
||||
|
||||
blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
|
||||
blockWriteTimer.UpdateSince(wstart)
|
||||
blockInsertTimer.UpdateSince(start)
|
||||
|
||||
// Report the import stats before returning the various results
|
||||
|
||||
@@ -511,12 +511,3 @@ func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscr
|
||||
func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription {
|
||||
return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch))
|
||||
}
|
||||
|
||||
// AncientTail retrieves the tail the ancients blocks
|
||||
func (bc *BlockChain) AncientTail() (uint64, error) {
|
||||
tail, err := bc.db.Tail()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return tail, nil
|
||||
}
|
||||
|
||||
@@ -1832,10 +1832,14 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
|
||||
}
|
||||
// Force run a freeze cycle
|
||||
type freezer interface {
|
||||
Freeze(threshold uint64) error
|
||||
Freeze() 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
|
||||
if tt.pivotBlock != nil {
|
||||
|
||||
@@ -2045,10 +2045,14 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
|
||||
|
||||
// Force run a freeze cycle
|
||||
type freezer interface {
|
||||
Freeze(threshold uint64) error
|
||||
Freeze() 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
|
||||
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)
|
||||
}
|
||||
// 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 {
|
||||
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 := 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 {
|
||||
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}) })
|
||||
|
||||
// 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()
|
||||
|
||||
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)
|
||||
|
||||
// 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 {
|
||||
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.
|
||||
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 {
|
||||
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
|
||||
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()
|
||||
|
||||
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
|
||||
})
|
||||
// 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 {
|
||||
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
|
||||
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 {
|
||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||
}
|
||||
@@ -3858,7 +3858,7 @@ func testSetCanonical(t *testing.T, scheme string) {
|
||||
}
|
||||
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()
|
||||
|
||||
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) {
|
||||
// Have N headers in the freezer
|
||||
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 {
|
||||
t.Fatalf("failed to create database with ancient backend")
|
||||
}
|
||||
|
||||
@@ -114,9 +114,7 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
|
||||
if f.preserve != nil {
|
||||
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
||||
}
|
||||
reorg = !currentPreserve && (externPreserve ||
|
||||
extern.Time < current.Time ||
|
||||
extern.Time == current.Time && f.rand.Float64() < 0.5)
|
||||
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
|
||||
}
|
||||
return reorg, nil
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
type ChainOverrides struct {
|
||||
OverrideCancun *uint64
|
||||
OverrideHaber *uint64
|
||||
OverrideBohr *uint64
|
||||
OverrideVerkle *uint64
|
||||
}
|
||||
|
||||
@@ -248,12 +246,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
||||
if overrides != nil && overrides.OverrideCancun != nil {
|
||||
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 {
|
||||
config.VerkleTime = overrides.OverrideVerkle
|
||||
}
|
||||
@@ -498,7 +490,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
|
||||
rawdb.WriteReceipts(db.BlockStore(), block.Hash(), block.NumberU64(), nil)
|
||||
rawdb.WriteCanonicalHash(db.BlockStore(), block.Hash(), block.NumberU64())
|
||||
rawdb.WriteHeadBlockHash(db.BlockStore(), block.Hash())
|
||||
rawdb.WriteHeadFastBlockHash(db.BlockStore(), block.Hash())
|
||||
rawdb.WriteHeadFastBlockHash(db, block.Hash())
|
||||
rawdb.WriteHeadHeaderHash(db.BlockStore(), block.Hash())
|
||||
rawdb.WriteChainConfig(db, block.Hash(), config)
|
||||
return block, nil
|
||||
|
||||
@@ -668,7 +668,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
|
||||
// first then remove the relative data from the database.
|
||||
//
|
||||
// Update head first(head fast block, head full block) before deleting the data.
|
||||
markerBatch := hc.chainDb.BlockStore().NewBatch()
|
||||
markerBatch := hc.chainDb.NewBatch()
|
||||
if updateFn != nil {
|
||||
newHead, force := updateFn(markerBatch, parent)
|
||||
if force && ((headTime > 0 && newHead.Time < headTime) || (headTime == 0 && newHead.Number.Uint64() < headBlock)) {
|
||||
@@ -677,7 +677,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
|
||||
}
|
||||
}
|
||||
// Update head header then.
|
||||
rawdb.WriteHeadHeaderHash(markerBatch, parentHash)
|
||||
rawdb.WriteHeadHeaderHash(hc.chainDb.BlockStore(), parentHash)
|
||||
if err := markerBatch.Write(); err != nil {
|
||||
log.Crit("Failed to update chain markers", "error", err)
|
||||
}
|
||||
|
||||
@@ -518,7 +518,7 @@ func checkBlobSidecarsRLP(have, want types.BlobSidecars) error {
|
||||
func TestAncientStorage(t *testing.T) {
|
||||
// Freezer style fast import the chain.
|
||||
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 {
|
||||
t.Fatalf("failed to create database with ancient backend")
|
||||
}
|
||||
@@ -657,7 +657,7 @@ func TestHashesInRange(t *testing.T) {
|
||||
func BenchmarkWriteAncientBlocks(b *testing.B) {
|
||||
// Open freezer database.
|
||||
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 {
|
||||
b.Fatalf("failed to create database with ancient backend")
|
||||
}
|
||||
@@ -1001,7 +1001,7 @@ func TestHeadersRLPStorage(t *testing.T) {
|
||||
// Have N headers in the freezer
|
||||
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 {
|
||||
t.Fatalf("failed to create database with ancient backend")
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@ package rawdb
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
)
|
||||
|
||||
// ReadSnapshotDisabled retrieves if the snapshot maintenance is disabled.
|
||||
@@ -74,6 +76,10 @@ func DeleteSnapshotRoot(db ethdb.KeyValueWriter) {
|
||||
|
||||
// ReadAccountSnapshot retrieves the snapshot entry of an account trie leaf.
|
||||
func ReadAccountSnapshot(db ethdb.KeyValueReader, hash common.Hash) []byte {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { rawdbGetAccountSnapNodeTimer.UpdateSince(start) }()
|
||||
}
|
||||
data, _ := db.Get(accountSnapshotKey(hash))
|
||||
return data
|
||||
}
|
||||
@@ -94,6 +100,10 @@ func DeleteAccountSnapshot(db ethdb.KeyValueWriter, hash common.Hash) {
|
||||
|
||||
// ReadStorageSnapshot retrieves the snapshot entry of an storage trie leaf.
|
||||
func ReadStorageSnapshot(db ethdb.KeyValueReader, accountHash, storageHash common.Hash) []byte {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { rawdbGetStorageSnapNodeTimer.UpdateSince(start) }()
|
||||
}
|
||||
data, _ := db.Get(storageSnapshotKey(accountHash, storageHash))
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -19,11 +19,13 @@ package rawdb
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
@@ -68,6 +70,10 @@ func (h *hasher) release() {
|
||||
// ReadAccountTrieNode retrieves the account trie node and the associated node
|
||||
// hash with the specified node path.
|
||||
func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) ([]byte, common.Hash) {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { rawdbGetAccountTrieNodeTimer.UpdateSince(start) }()
|
||||
}
|
||||
data, err := db.Get(accountTrieNodeKey(path))
|
||||
if err != nil {
|
||||
return nil, common.Hash{}
|
||||
@@ -116,6 +122,10 @@ func DeleteAccountTrieNode(db ethdb.KeyValueWriter, path []byte) {
|
||||
// ReadStorageTrieNode retrieves the storage trie node and the associated node
|
||||
// hash with the specified node path.
|
||||
func ReadStorageTrieNode(db ethdb.KeyValueReader, accountHash common.Hash, path []byte) ([]byte, common.Hash) {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { rawdbGetStorageTrieNodeTimer.UpdateSince(start) }()
|
||||
}
|
||||
data, err := db.Get(storageTrieNodeKey(accountHash, path))
|
||||
if err != nil {
|
||||
return nil, common.Hash{}
|
||||
@@ -218,7 +228,22 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c
|
||||
func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash common.Hash, scheme string) []byte {
|
||||
switch scheme {
|
||||
case HashScheme:
|
||||
return ReadLegacyTrieNode(db, hash)
|
||||
var (
|
||||
blob []byte
|
||||
start time.Time
|
||||
)
|
||||
start = time.Now()
|
||||
blob = ReadLegacyTrieNode(db, hash)
|
||||
if owner == (common.Hash{}) {
|
||||
if metrics.EnabledExpensive {
|
||||
rawdbGetAccountTrieNodeTimer.UpdateSince(start)
|
||||
}
|
||||
} else {
|
||||
if metrics.EnabledExpensive {
|
||||
rawdbGetStorageTrieNodeTimer.UpdateSince(start)
|
||||
}
|
||||
}
|
||||
return blob
|
||||
case PathScheme:
|
||||
var (
|
||||
blob []byte
|
||||
|
||||
@@ -24,12 +24,12 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -51,31 +51,25 @@ var (
|
||||
// The background thread will keep moving ancient chain segments from key-value
|
||||
// database to flat files for saving space on live database.
|
||||
type chainFreezer struct {
|
||||
threshold atomic.Uint64 // Number of recent blocks not to freeze (params.FullImmutabilityThreshold apart from tests)
|
||||
|
||||
*Freezer
|
||||
quit chan struct{}
|
||||
wg sync.WaitGroup
|
||||
trigger chan chan struct{} // Manual blocking freeze trigger, test determinism
|
||||
|
||||
freezeEnv atomic.Value
|
||||
|
||||
multiDatabase bool
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cf := chainFreezer{
|
||||
return &chainFreezer{
|
||||
Freezer: freezer,
|
||||
quit: make(chan struct{}),
|
||||
trigger: make(chan chan struct{}),
|
||||
}
|
||||
cf.threshold.Store(params.FullImmutabilityThreshold)
|
||||
return &cf, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Close closes the chain freezer instance and terminates the background thread.
|
||||
@@ -191,101 +185,29 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
||||
continue
|
||||
}
|
||||
|
||||
var (
|
||||
frozen uint64
|
||||
threshold uint64
|
||||
first uint64 // the first block to freeze
|
||||
last uint64 // the last block to freeze
|
||||
threshold, err := f.freezeThreshold(nfdb)
|
||||
if err != nil {
|
||||
backoff = true
|
||||
log.Debug("Current full block not old enough to freeze", "err", err)
|
||||
continue
|
||||
}
|
||||
frozen := f.frozen.Load()
|
||||
|
||||
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 {
|
||||
backoff = true
|
||||
log.Debug("Current full block not old enough to freeze", "err", err)
|
||||
continue
|
||||
}
|
||||
frozen = f.frozen.Load()
|
||||
|
||||
// Short circuit if the blocks below threshold are already frozen.
|
||||
if frozen != 0 && frozen-1 >= threshold {
|
||||
backoff = true
|
||||
log.Debug("Ancient blocks frozen already", "threshold", threshold, "frozen", frozen)
|
||||
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
|
||||
}
|
||||
// Short circuit if the blocks below threshold are already frozen.
|
||||
if frozen != 0 && frozen-1 >= threshold {
|
||||
backoff = true
|
||||
log.Debug("Ancient blocks frozen already", "threshold", threshold, "frozen", frozen)
|
||||
continue
|
||||
}
|
||||
// Seems we have data ready to be frozen, process in usable batches
|
||||
var (
|
||||
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)
|
||||
if err != nil {
|
||||
@@ -373,6 +295,24 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
||||
log.Debug("Deep froze chain segment", context...)
|
||||
|
||||
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
|
||||
if isCancun(env, head.Number, head.Time) {
|
||||
f.tryPruneBlobAncientTable(env, *number)
|
||||
|
||||
@@ -81,7 +81,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
|
||||
batch.Reset()
|
||||
|
||||
WriteHeadHeaderHash(db.BlockStore(), hash)
|
||||
WriteHeadFastBlockHash(db.BlockStore(), hash)
|
||||
WriteHeadFastBlockHash(db, hash)
|
||||
log.Info("Initialized database from freezer", "blocks", frozen, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ func (frdb *freezerdb) BlockStoreReader() ethdb.Reader {
|
||||
}
|
||||
|
||||
func (frdb *freezerdb) BlockStoreWriter() ethdb.Writer {
|
||||
// TODO implement me
|
||||
//TODO implement me
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -138,22 +138,13 @@ func (frdb *freezerdb) SetBlockStore(block ethdb.Database) {
|
||||
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
|
||||
// a freeze cycle completes, without having to sleep for a minute to trigger the
|
||||
// automatic background run.
|
||||
func (frdb *freezerdb) Freeze(threshold uint64) error {
|
||||
func (frdb *freezerdb) Freeze() error {
|
||||
if frdb.AncientStore.(*chainFreezer).readonly {
|
||||
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 := make(chan struct{}, 1)
|
||||
frdb.AncientStore.(*chainFreezer).trigger <- trigger
|
||||
@@ -193,7 +184,7 @@ func (db *nofreezedb) Ancients() (uint64, error) {
|
||||
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) {
|
||||
return 0, errNotSupported
|
||||
}
|
||||
@@ -272,10 +263,6 @@ func (db *nofreezedb) SetBlockStore(block ethdb.Database) {
|
||||
db.blockStore = block
|
||||
}
|
||||
|
||||
func (db *nofreezedb) HasSeparateBlockStore() bool {
|
||||
return db.blockStore != nil
|
||||
}
|
||||
|
||||
func (db *nofreezedb) BlockStoreReader() ethdb.Reader {
|
||||
if db.blockStore != nil {
|
||||
return db.blockStore
|
||||
@@ -331,110 +318,6 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database {
|
||||
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.
|
||||
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.
|
||||
@@ -475,7 +358,7 @@ func resolveChainFreezerDir(ancient string) string {
|
||||
// value data store with a freezer moving immutable chain segments into cold
|
||||
// storage. The passed ancient indicates the path of root ancient directory
|
||||
// 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
|
||||
// The offset of ancientDB should be handled differently in different scenarios.
|
||||
if isLastOffset {
|
||||
@@ -484,12 +367,6 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
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 {
|
||||
frdb, err := newPrunedFreezer(resolveChainFreezerDir(ancient), db, offset)
|
||||
if err != nil {
|
||||
@@ -517,7 +394,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
||||
}
|
||||
|
||||
// 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 {
|
||||
printChainMetadata(db)
|
||||
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
|
||||
// a crash is not important. This option should typically be used in tests.
|
||||
Ephemeral bool
|
||||
|
||||
MultiDataBase bool
|
||||
}
|
||||
|
||||
// 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 !o.PruneAncientData {
|
||||
log.Warn("NOTICE: You're opening a pruned disk db!")
|
||||
log.Warn("Disk db is pruned")
|
||||
}
|
||||
}
|
||||
if len(o.AncientsDirectory) == 0 {
|
||||
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 {
|
||||
kvdb.Close()
|
||||
return nil, err
|
||||
@@ -873,7 +748,7 @@ func DataTypeByKey(key []byte) DataType {
|
||||
return StateDataType
|
||||
}
|
||||
}
|
||||
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey, headBlockKey, headFastBlockKey} {
|
||||
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey} {
|
||||
if bytes.Equal(key, meta) {
|
||||
return BlockDataType
|
||||
}
|
||||
@@ -894,7 +769,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
trieIter = db.StateStore().NewIterator(keyPrefix, nil)
|
||||
defer trieIter.Release()
|
||||
}
|
||||
if db.HasSeparateBlockStore() {
|
||||
if db.BlockStore() != db {
|
||||
blockIter = db.BlockStore().NewIterator(keyPrefix, nil)
|
||||
defer blockIter.Release()
|
||||
}
|
||||
@@ -1088,7 +963,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
|
||||
hashNumPairings.Add(size)
|
||||
default:
|
||||
var accounted bool
|
||||
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey, headBlockKey, headFastBlockKey} {
|
||||
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey} {
|
||||
if bytes.Equal(key, meta) {
|
||||
metadata.Add(size)
|
||||
accounted = true
|
||||
@@ -1282,7 +1157,7 @@ func ReadChainMetadataFromMultiDatabase(db ethdb.Database) [][]string {
|
||||
data := [][]string{
|
||||
{"databaseVersion", pp(ReadDatabaseVersion(db))},
|
||||
{"headBlockHash", fmt.Sprintf("%v", ReadHeadBlockHash(db.BlockStore()))},
|
||||
{"headFastBlockHash", fmt.Sprintf("%v", ReadHeadFastBlockHash(db.BlockStore()))},
|
||||
{"headFastBlockHash", fmt.Sprintf("%v", ReadHeadFastBlockHash(db))},
|
||||
{"headHeaderHash", fmt.Sprintf("%v", ReadHeadHeaderHash(db.BlockStore()))},
|
||||
{"lastPivotNumber", pp(ReadLastPivotNumber(db))},
|
||||
{"len(snapshotSyncStatus)", fmt.Sprintf("%d bytes", len(ReadSnapshotSyncStatus(db)))},
|
||||
|
||||
@@ -239,7 +239,7 @@ func (f *Freezer) Ancient(kind string, number uint64) ([]byte, error) {
|
||||
// - if maxBytes is not specified, 'count' items will be returned if they are present.
|
||||
func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
||||
if table := f.tables[kind]; table != nil {
|
||||
return table.RetrieveItems(start-f.offset, count, maxBytes)
|
||||
return table.RetrieveItems(start, count, maxBytes)
|
||||
}
|
||||
return nil, errUnknownTable
|
||||
}
|
||||
@@ -252,7 +252,7 @@ func (f *Freezer) Ancients() (uint64, error) {
|
||||
func (f *Freezer) TableAncients(kind string) (uint64, error) {
|
||||
f.writeLock.RLock()
|
||||
defer f.writeLock.RUnlock()
|
||||
return f.tables[kind].items.Load() + f.offset, nil
|
||||
return f.tables[kind].items.Load(), nil
|
||||
}
|
||||
|
||||
// ItemAmountInAncient returns the actual length of current ancientDB.
|
||||
|
||||
10
core/rawdb/metrics.go
Normal file
10
core/rawdb/metrics.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package rawdb
|
||||
|
||||
import "github.com/ethereum/go-ethereum/metrics"
|
||||
|
||||
var (
|
||||
rawdbGetAccountTrieNodeTimer = metrics.NewRegisteredTimer("rawdb/get/account/trienode/time", nil)
|
||||
rawdbGetStorageTrieNodeTimer = metrics.NewRegisteredTimer("rawdb/get/storage/trienode/time", nil)
|
||||
rawdbGetAccountSnapNodeTimer = metrics.NewRegisteredTimer("rawdb/get/account/snapnode/time", nil)
|
||||
rawdbGetStorageSnapNodeTimer = metrics.NewRegisteredTimer("rawdb/get/storage/snapnode/time", nil)
|
||||
)
|
||||
@@ -43,10 +43,6 @@ func (t *table) SetBlockStore(block ethdb.Database) {
|
||||
panic("not implement")
|
||||
}
|
||||
|
||||
func (t *table) HasSeparateBlockStore() bool {
|
||||
panic("not implement")
|
||||
}
|
||||
|
||||
// NewTable returns a database object that prefixes all keys with a given string.
|
||||
func NewTable(db ethdb.Database, prefix string) ethdb.Database {
|
||||
return &table{
|
||||
|
||||
@@ -382,7 +382,7 @@ func (p *BlockPruner) backUpOldDb(name string, cache, handles int, namespace str
|
||||
log.Info("chainDB opened successfully")
|
||||
|
||||
// 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)
|
||||
|
||||
// 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
|
||||
head = head.Parent()
|
||||
}
|
||||
log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root)
|
||||
log.Info("Snapshot loaded", "diskRoot", snap.diskRoot(), "root", root, "snapshot_cache_size", common.StorageSize(config.CacheSize)*1024*1024)
|
||||
return snap, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
@@ -29,9 +30,14 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
var (
|
||||
processTxTimer = metrics.NewRegisteredTimer("process/tx/time", nil)
|
||||
)
|
||||
|
||||
// StateProcessor is a basic Processor, which takes care of transitioning
|
||||
// state from one point to another.
|
||||
//
|
||||
@@ -104,6 +110,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||
systemTxs := make([]*types.Transaction, 0, 2)
|
||||
|
||||
for i, tx := range block.Transactions() {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer processTxTimer.UpdateSince(start)
|
||||
}
|
||||
if isPoSA {
|
||||
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
|
||||
bloomProcessors.Close()
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,19 +0,0 @@
|
||||
package haber_fix
|
||||
|
||||
import _ "embed"
|
||||
|
||||
// contract codes for Chapel upgrade
|
||||
var (
|
||||
//go:embed chapel/ValidatorContract
|
||||
ChapelValidatorContract string
|
||||
//go:embed chapel/SlashContract
|
||||
ChapelSlashContract string
|
||||
)
|
||||
|
||||
// contract codes for Mainnet upgrade
|
||||
var (
|
||||
//go:embed mainnet/ValidatorContract
|
||||
MainnetValidatorContract string
|
||||
//go:embed mainnet/SlashContract
|
||||
MainnetSlashContract string
|
||||
)
|
||||
@@ -4,16 +4,17 @@ import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/bruno"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/euler"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/feynman"
|
||||
feynmanFix "github.com/ethereum/go-ethereum/core/systemcontracts/feynman_fix"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/gibbs"
|
||||
haberFix "github.com/ethereum/go-ethereum/core/systemcontracts/haber_fix"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/kepler"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/luban"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/mirror"
|
||||
@@ -22,8 +23,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/planck"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/plato"
|
||||
"github.com/ethereum/go-ethereum/core/systemcontracts/ramanujan"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
type UpgradeConfig struct {
|
||||
@@ -76,8 +75,6 @@ var (
|
||||
feynmanUpgrade = make(map[string]*Upgrade)
|
||||
|
||||
feynmanFixUpgrade = make(map[string]*Upgrade)
|
||||
|
||||
haberFixUpgrade = make(map[string]*Upgrade)
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -704,38 +701,6 @@ func init() {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
haberFixUpgrade[mainNet] = &Upgrade{
|
||||
UpgradeName: "haberFix",
|
||||
Configs: []*UpgradeConfig{
|
||||
{
|
||||
ContractAddr: common.HexToAddress(ValidatorContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/b743ce3f1f1e94c349b175cd6593bc263463b33b",
|
||||
Code: haberFix.MainnetValidatorContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(SlashContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/b743ce3f1f1e94c349b175cd6593bc263463b33b",
|
||||
Code: haberFix.MainnetSlashContract,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
haberFixUpgrade[chapelNet] = &Upgrade{
|
||||
UpgradeName: "haberFix",
|
||||
Configs: []*UpgradeConfig{
|
||||
{
|
||||
ContractAddr: common.HexToAddress(ValidatorContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/b743ce3f1f1e94c349b175cd6593bc263463b33b",
|
||||
Code: haberFix.ChapelValidatorContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(SlashContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/b743ce3f1f1e94c349b175cd6593bc263463b33b",
|
||||
Code: haberFix.ChapelSlashContract,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb *state.StateDB) {
|
||||
@@ -812,10 +777,6 @@ func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I
|
||||
applySystemContractUpgrade(feynmanFixUpgrade[network], blockNumber, statedb, logger)
|
||||
}
|
||||
|
||||
if config.IsOnHaberFix(blockNumber, lastBlockTime, blockTime) {
|
||||
applySystemContractUpgrade(haberFixUpgrade[network], blockNumber, statedb, logger)
|
||||
}
|
||||
|
||||
/*
|
||||
apply other upgrades
|
||||
*/
|
||||
@@ -838,7 +799,7 @@ func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb
|
||||
}
|
||||
}
|
||||
|
||||
newContractCode, err := hex.DecodeString(strings.TrimSpace(cfg.Code))
|
||||
newContractCode, err := hex.DecodeString(cfg.Code)
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("failed to decode new contract code: %s", err.Error()))
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ type txIndexer struct {
|
||||
|
||||
// newTxIndexer initializes the transaction indexer.
|
||||
func newTxIndexer(limit uint64, chain *BlockChain) *txIndexer {
|
||||
limit = 0
|
||||
indexer := &txIndexer{
|
||||
limit: limit,
|
||||
db: chain.db,
|
||||
|
||||
@@ -212,7 +212,7 @@ func TestTxIndexer(t *testing.T) {
|
||||
}
|
||||
for _, c := range cases {
|
||||
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))
|
||||
|
||||
// Index the initial blocks from ancient store
|
||||
|
||||
@@ -6,8 +6,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
@@ -42,12 +40,6 @@ func (b *BidArgs) ToBid(builder common.Address, signer Signer) (*Bid, error) {
|
||||
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 {
|
||||
var payBidTx = new(Transaction)
|
||||
err = payBidTx.UnmarshalBinary(b.PayBidTx)
|
||||
@@ -59,15 +51,14 @@ func (b *BidArgs) ToBid(builder common.Address, signer Signer) (*Bid, error) {
|
||||
}
|
||||
|
||||
bid := &Bid{
|
||||
Builder: builder,
|
||||
BlockNumber: b.RawBid.BlockNumber,
|
||||
ParentHash: b.RawBid.ParentHash,
|
||||
Txs: txs,
|
||||
UnRevertible: unRevertibleHashes,
|
||||
GasUsed: b.RawBid.GasUsed + b.PayBidTxGasUsed,
|
||||
GasFee: b.RawBid.GasFee,
|
||||
BuilderFee: b.RawBid.BuilderFee,
|
||||
rawBid: *b.RawBid,
|
||||
Builder: builder,
|
||||
BlockNumber: b.RawBid.BlockNumber,
|
||||
ParentHash: b.RawBid.ParentHash,
|
||||
Txs: txs,
|
||||
GasUsed: b.RawBid.GasUsed + b.PayBidTxGasUsed,
|
||||
GasFee: b.RawBid.GasFee,
|
||||
BuilderFee: b.RawBid.BuilderFee,
|
||||
rawBid: *b.RawBid,
|
||||
}
|
||||
|
||||
if bid.BuilderFee == nil {
|
||||
@@ -79,13 +70,12 @@ func (b *BidArgs) ToBid(builder common.Address, signer Signer) (*Bid, error) {
|
||||
|
||||
// RawBid represents a raw bid from builder directly.
|
||||
type RawBid struct {
|
||||
BlockNumber uint64 `json:"blockNumber"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
Txs []hexutil.Bytes `json:"txs"`
|
||||
UnRevertible []common.Hash `json:"unRevertible"`
|
||||
GasUsed uint64 `json:"gasUsed"`
|
||||
GasFee *big.Int `json:"gasFee"`
|
||||
BuilderFee *big.Int `json:"builderFee"`
|
||||
BlockNumber uint64 `json:"blockNumber"`
|
||||
ParentHash common.Hash `json:"parentHash"`
|
||||
Txs []hexutil.Bytes `json:"txs"`
|
||||
GasUsed uint64 `json:"gasUsed"`
|
||||
GasFee *big.Int `json:"gasFee"`
|
||||
BuilderFee *big.Int `json:"builderFee"`
|
||||
|
||||
hash atomic.Value
|
||||
}
|
||||
@@ -164,14 +154,13 @@ func (b *RawBid) Hash() common.Hash {
|
||||
|
||||
// Bid represents a bid.
|
||||
type Bid struct {
|
||||
Builder common.Address
|
||||
BlockNumber uint64
|
||||
ParentHash common.Hash
|
||||
Txs Transactions
|
||||
UnRevertible mapset.Set[common.Hash]
|
||||
GasUsed uint64
|
||||
GasFee *big.Int
|
||||
BuilderFee *big.Int
|
||||
Builder common.Address
|
||||
BlockNumber uint64
|
||||
ParentHash common.Hash
|
||||
Txs Transactions
|
||||
GasUsed uint64
|
||||
GasFee *big.Int
|
||||
BuilderFee *big.Int
|
||||
|
||||
rawBid RawBid
|
||||
}
|
||||
@@ -193,7 +182,5 @@ type MevParams struct {
|
||||
ValidatorCommission uint64 // 100 means 1%
|
||||
BidSimulationLeftOver time.Duration
|
||||
GasCeil uint64
|
||||
GasPrice *big.Int // Minimum avg gas price for bid block
|
||||
BuilderFeeCeil *big.Int
|
||||
Version string
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto/bn256"
|
||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||
"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/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -248,36 +247,6 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
|
||||
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
|
||||
// contracts specified in EIP-2537. These are exported for testing purposes.
|
||||
var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
|
||||
@@ -293,7 +262,6 @@ var PrecompiledContractsBLS = map[common.Address]PrecompiledContract{
|
||||
}
|
||||
|
||||
var (
|
||||
PrecompiledAddressesHaber []common.Address
|
||||
PrecompiledAddressesCancun []common.Address
|
||||
PrecompiledAddressesFeynman []common.Address
|
||||
PrecompiledAddressesHertz []common.Address
|
||||
@@ -345,16 +313,11 @@ func init() {
|
||||
for k := range PrecompiledContractsCancun {
|
||||
PrecompiledAddressesCancun = append(PrecompiledAddressesCancun, k)
|
||||
}
|
||||
for k := range PrecompiledContractsHaber {
|
||||
PrecompiledAddressesHaber = append(PrecompiledAddressesHaber, k)
|
||||
}
|
||||
}
|
||||
|
||||
// ActivePrecompiles returns the precompiles enabled with the current configuration.
|
||||
func ActivePrecompiles(rules params.Rules) []common.Address {
|
||||
switch {
|
||||
case rules.IsHaber:
|
||||
return PrecompiledAddressesHaber
|
||||
case rules.IsCancun:
|
||||
return PrecompiledAddressesCancun
|
||||
case rules.IsFeynman:
|
||||
@@ -1426,40 +1389,6 @@ func kZGToVersionedHash(kzg kzg4844.Commitment) common.Hash {
|
||||
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.
|
||||
type verifyDoubleSignEvidence struct{}
|
||||
|
||||
|
||||
@@ -46,19 +46,17 @@ type precompiledFailureTest struct {
|
||||
// allPrecompiles does not map to the actual set of precompiles, as it also contains
|
||||
// repriced versions of precompiles at certain slots
|
||||
var allPrecompiles = 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: false},
|
||||
common.BytesToAddress([]byte{0xf5}): &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{0x01, 0x00}): &p256Verify{},
|
||||
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: false},
|
||||
common.BytesToAddress([]byte{0xf5}): &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{0x0f, 0x0a}): &bls12381G1Add{},
|
||||
common.BytesToAddress([]byte{0x0f, 0x0b}): &bls12381G1Mul{},
|
||||
common.BytesToAddress([]byte{0x0f, 0x0c}): &bls12381G1MultiExp{},
|
||||
@@ -409,18 +407,6 @@ func BenchmarkPrecompiledBLS12381G2MultiExpWorstCase(b *testing.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) {
|
||||
tc := precompiledTest{
|
||||
Input: "f906278202cab9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0fae1a05fcb14bfd9b8a9f2b65007a9b6c2000de0627a73be644dd993d32342c494976ea74026e726554db657fa54763abd0c3a0aa9a0f385cc58ed297ff0d66eb5580b02853d3478ba418b1819ac659ee05df49b9794a0bf88464af369ed6b8cf02db00f0b9556ffa8d49cd491b00952a7f83431446638a00a6d0870e586a76278fbfdcedf76ef6679af18fc1f9137cfad495f434974ea81b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a804ae755e0fe64b59753f4db6308a1f679747bce186aa2c62b95fa6eeff3fbd08f3b0667e45428a54ade15bad19f49641c499b431b36f65803ea71b379e6b61de501a0232c9ba2d41b40d36ed794c306747bcbc49bf61a0f37409c18bfe2b5bef26a2d880000000000000000b9030ff9030ca01062d3d5015b9242bc193a9b0769f3d3780ecb55f97f40a752ae26d0b68cd0d8a0b2789a5357827ed838335283e15c4dcc42b9bebcbf2919a18613246787e2f96094976ea74026e726554db657fa54763abd0c3a0aa9a071ce4c09ee275206013f0063761bc19c93c13990582f918cc57333634c94ce89a00e095703e5c9b149f253fe89697230029e32484a410b4b1f2c61442d73c3095aa0d317ae19ede7c8a2d3ac9ef98735b049bcb7278d12f48c42b924538b60a25e12b901000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001820cdf830f4240830f4240846555fa64b90111d983010301846765746888676f312e32302e378664617277696e00007abd731ef8ae07b86091cb8836d58f5444b883422a18825d899035d3e6ea39ad1a50069bf0b86da8b5573dde1cb4a0a34f19ce94e0ef78ff7518c80265b8a3ca56e3c60167523590d4e8dcc324900559465fc0fa403774096614e135de280949b58a45cc96f2ba9e17f848820d41a08429d0d8b33ee72a84f750fefea846cbca54e487129c7961c680bb72309ca888820d42a08c9db14d938b19f9e2261bbeca2679945462be2b58103dfff73665d0d150fb8a80c0b17bfe88534296ff064cb7156548f6deba2d6310d5044ed6485f087dc6ef232e051c28e1909c2b50a3b4f29345d66681c319bef653e52e5d746480d5a3983b00a0b56228685be711834d0f154292d07826dea42a0fad3e4f56c31470b7fbfbea26880000000000000000",
|
||||
|
||||
@@ -48,8 +48,6 @@ type (
|
||||
func (evm *EVM) precompile(addr common.Address) (PrecompiledContract, bool) {
|
||||
var precompiles map[common.Address]PrecompiledContract
|
||||
switch {
|
||||
case evm.chainRules.IsHaber:
|
||||
precompiles = PrecompiledContractsHaber
|
||||
case evm.chainRules.IsCancun:
|
||||
precompiles = PrecompiledContractsCancun
|
||||
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"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -141,3 +142,31 @@ func (api *AdminAPI) ImportChain(file string) (bool, error) {
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -484,10 +484,6 @@ func (b *EthAPIBackend) RemoveBuilder(builder common.Address) error {
|
||||
return b.Miner().RemoveBuilder(builder)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) HasBuilder(builder common.Address) bool {
|
||||
return b.Miner().HasBuilder(builder)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error) {
|
||||
return b.Miner().SendBid(ctx, bid)
|
||||
}
|
||||
|
||||
@@ -89,31 +89,3 @@ func (api *MinerAPI) SetEtherbase(etherbase common.Address) bool {
|
||||
func (api *MinerAPI) SetRecommitInterval(interval int) {
|
||||
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,18 +161,13 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
// Optimize memory distribution by reallocating surplus allowance from the
|
||||
// dirty cache to the clean cache.
|
||||
if config.StateScheme == rawdb.PathScheme && config.TrieDirtyCache > pathdb.MaxDirtyBufferSize/1024/1024 {
|
||||
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,
|
||||
"adjusted", common.StorageSize(config.TrieCleanCache+config.TrieDirtyCache-pathdb.MaxDirtyBufferSize/1024/1024)*1024*1024)
|
||||
config.TrieCleanCache += config.TrieDirtyCache - pathdb.MaxDirtyBufferSize/1024/1024
|
||||
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
|
||||
log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024, "adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize))
|
||||
log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024)
|
||||
}
|
||||
log.Info("Allocated memory caches",
|
||||
"state_scheme", config.StateScheme,
|
||||
"trie_clean_cache", common.StorageSize(config.TrieCleanCache)*1024*1024,
|
||||
"trie_dirty_cache", common.StorageSize(config.TrieDirtyCache)*1024*1024,
|
||||
"snapshot_cache", common.StorageSize(config.SnapshotCache)*1024*1024)
|
||||
log.Info("Allocated trie memory caches", "schema", config.StateScheme, "trie_clean_cache", common.StorageSize(config.TrieCleanCache)*1024*1024, "trie_dirty_cache", common.StorageSize(config.TrieDirtyCache)*1024*1024, "snapshot_cache", common.StorageSize(config.SnapshotCache)*1024*1024)
|
||||
|
||||
// Try to recover offline state pruning only in hash-based.
|
||||
if config.StateScheme == rawdb.HashScheme {
|
||||
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, config.TriesInMemory); err != nil {
|
||||
@@ -189,14 +184,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
chainConfig.CancunTime = 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 {
|
||||
chainConfig.VerkleTime = 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(head *types.Header)
|
||||
|
||||
// AncientTail retrieves the tail the ancients blocks
|
||||
AncientTail() (uint64, error)
|
||||
}
|
||||
|
||||
type DownloadOption func(downloader *Downloader) *Downloader
|
||||
@@ -800,11 +797,6 @@ func (d *Downloader) findAncestor(p *peerConnection, localHeight uint64, remoteH
|
||||
// We're above the max reorg threshold, find the earliest fork point
|
||||
floor = int64(localHeight - maxForkAncestry)
|
||||
}
|
||||
// if we have pruned too much history, reset the floor
|
||||
if tail, err := d.blockchain.AncientTail(); err == nil && tail > uint64(floor) {
|
||||
floor = int64(tail)
|
||||
}
|
||||
|
||||
// If we're doing a light sync, ensure the floor doesn't go below the CHT, as
|
||||
// all headers before that point will be missing.
|
||||
if mode == LightSync {
|
||||
|
||||
@@ -60,7 +60,7 @@ func newTester(t *testing.T) *downloadTester {
|
||||
// newTester creates a new downloader test mocker.
|
||||
func newTesterWithNotification(t *testing.T, success func()) *downloadTester {
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -191,12 +191,6 @@ type Config struct {
|
||||
// OverrideCancun (TODO: remove after the fork)
|
||||
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 *uint64 `toml:",omitempty"`
|
||||
|
||||
|
||||
@@ -71,8 +71,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
RPCEVMTimeout time.Duration
|
||||
RPCTxFeeCap float64
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
OverrideHaber *uint64 `toml:",omitempty"`
|
||||
OverrideBohr *uint64 `toml:",omitempty"`
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
BlobExtraReserve uint64
|
||||
}
|
||||
@@ -131,8 +129,6 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.RPCEVMTimeout = c.RPCEVMTimeout
|
||||
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
||||
enc.OverrideCancun = c.OverrideCancun
|
||||
enc.OverrideHaber = c.OverrideHaber
|
||||
enc.OverrideBohr = c.OverrideBohr
|
||||
enc.OverrideVerkle = c.OverrideVerkle
|
||||
enc.BlobExtraReserve = c.BlobExtraReserve
|
||||
return &enc, nil
|
||||
@@ -195,8 +191,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
RPCEVMTimeout *time.Duration
|
||||
RPCTxFeeCap *float64
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
OverrideHaber *uint64 `toml:",omitempty"`
|
||||
OverrideBohr *uint64 `toml:",omitempty"`
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
BlobExtraReserve *uint64
|
||||
}
|
||||
@@ -366,12 +360,6 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.OverrideCancun != nil {
|
||||
c.OverrideCancun = dec.OverrideCancun
|
||||
}
|
||||
if dec.OverrideHaber != nil {
|
||||
c.OverrideHaber = dec.OverrideHaber
|
||||
}
|
||||
if dec.OverrideBohr != nil {
|
||||
c.OverrideBohr = dec.OverrideBohr
|
||||
}
|
||||
if dec.OverrideVerkle != nil {
|
||||
c.OverrideVerkle = dec.OverrideVerkle
|
||||
}
|
||||
|
||||
@@ -731,6 +731,9 @@ func (f *BlockFetcher) loop() {
|
||||
matched = true
|
||||
if f.getBlock(hash) == nil {
|
||||
block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i])
|
||||
if block.Header().EmptyWithdrawalsHash() {
|
||||
block = block.WithWithdrawals(make([]*types.Withdrawal, 0))
|
||||
}
|
||||
block = block.WithSidecars(task.sidecars[i])
|
||||
block.ReceivedAt = task.time
|
||||
blocks = append(blocks, block)
|
||||
@@ -916,10 +919,6 @@ func (f *BlockFetcher) importBlocks(op *blockOrHeaderInject) {
|
||||
return
|
||||
}
|
||||
|
||||
if block.Header().EmptyWithdrawalsHash() {
|
||||
block = block.WithWithdrawals(make([]*types.Withdrawal, 0))
|
||||
}
|
||||
|
||||
defer func() { f.done <- hash }()
|
||||
// Quickly validate the header and propagate the block if it passes
|
||||
switch err := f.verifyHeader(block.Header()); err {
|
||||
|
||||
@@ -158,7 +158,7 @@ func (f *fetcherTester) chainFinalizedHeight() uint64 {
|
||||
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) {
|
||||
f.lock.Lock()
|
||||
defer f.lock.Unlock()
|
||||
|
||||
@@ -320,22 +320,26 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
}
|
||||
|
||||
broadcastBlockWithCheck := func(block *types.Block, propagate bool) {
|
||||
// All the block fetcher activities should be disabled
|
||||
// after the transition. Print the warning log.
|
||||
if h.merger.PoSFinalized() {
|
||||
log.Warn("Unexpected validation activity", "hash", block.Hash(), "number", block.Number())
|
||||
return
|
||||
}
|
||||
// Reject all the PoS style headers in the first place. No matter
|
||||
// the chain has finished the transition or not, the PoS headers
|
||||
// should only come from the trusted consensus layer instead of
|
||||
// p2p network.
|
||||
if beacon, ok := h.chain.Engine().(*beacon.Beacon); ok {
|
||||
if beacon.IsPoSHeader(block.Header()) {
|
||||
log.Warn("unexpected post-merge header")
|
||||
return
|
||||
}
|
||||
}
|
||||
if propagate {
|
||||
checkErrs := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
checkErrs <- core.ValidateListsInBody(block)
|
||||
}()
|
||||
go func() {
|
||||
checkErrs <- core.IsDataAvailable(h.chain, block)
|
||||
}()
|
||||
|
||||
for i := 0; i < cap(checkErrs); i++ {
|
||||
err := <-checkErrs
|
||||
if err != nil {
|
||||
log.Error("Propagating invalid block", "number", block.Number(), "hash", block.Hash(), "err", err)
|
||||
return
|
||||
}
|
||||
if err := core.IsDataAvailable(h.chain, block); err != nil {
|
||||
log.Error("Propagating block with invalid sidecars", "number", block.Number(), "hash", block.Hash(), "err", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
h.BroadcastBlock(block, propagate)
|
||||
|
||||
@@ -633,9 +633,6 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) {
|
||||
go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error {
|
||||
return eth.Handle((*ethHandler)(source.handler), peer)
|
||||
})
|
||||
// Wait a bit for the above handlers to start
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
if err := sinkPeer.Handshake(1, td, genesis.Hash(), genesis.Hash(), forkid.NewIDWithChain(source.chain), forkid.NewFilter(source.chain), nil); err != nil {
|
||||
t.Fatalf("failed to run protocol handshake")
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
// Have N headers in the freezer
|
||||
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 {
|
||||
t.Fatalf("failed to create database with ancient backend")
|
||||
}
|
||||
|
||||
@@ -151,8 +151,6 @@ func testChainSyncWithBlobs(t *testing.T, mode downloader.SyncMode, preCancunBlk
|
||||
go full.handler.runEthPeer(fullPeerEth, func(peer *eth.Peer) error {
|
||||
return eth.Handle((*ethHandler)(full.handler), peer)
|
||||
})
|
||||
// Wait a bit for the above handlers to start
|
||||
time.Sleep(250 * time.Millisecond)
|
||||
|
||||
emptyPipeSnap, fullPipeSnap := p2p.MsgPipe()
|
||||
defer emptyPipeSnap.Close()
|
||||
|
||||
@@ -133,7 +133,7 @@ func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumb
|
||||
// BlobSidecars return the Sidecars of a given block number or hash.
|
||||
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) {
|
||||
var r []*types.BlobTxSidecar
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String())
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String(), true)
|
||||
if err == nil && r == nil {
|
||||
return nil, ethereum.NotFound
|
||||
}
|
||||
@@ -143,7 +143,7 @@ func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumbe
|
||||
// BlobSidecarByTxHash return a sidecar of a given blob transaction
|
||||
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) {
|
||||
var r *types.BlobTxSidecar
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecarByTxHash", hash)
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlockSidecarByTxHash", hash, true)
|
||||
if err == nil && r == nil {
|
||||
return nil, ethereum.NotFound
|
||||
}
|
||||
@@ -752,13 +752,6 @@ func (ec *Client) MevRunning(ctx context.Context) (bool, error) {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// HasBuilder returns whether the builder is registered
|
||||
func (ec *Client) HasBuilder(ctx context.Context, address common.Address) (bool, error) {
|
||||
var result bool
|
||||
err := ec.c.CallContext(ctx, &result, "mev_hasBuilder", address)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// SendBid sends a bid
|
||||
func (ec *Client) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, error) {
|
||||
var hash common.Hash
|
||||
|
||||
@@ -183,7 +183,6 @@ type StateStoreReader interface {
|
||||
type BlockStore interface {
|
||||
BlockStore() Database
|
||||
SetBlockStore(block Database)
|
||||
HasSeparateBlockStore() bool
|
||||
}
|
||||
|
||||
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) {
|
||||
options := configureOptions(customize)
|
||||
logger := log.New("database", file)
|
||||
usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
|
||||
logCtx := []interface{}{"cache", common.StorageSize(usedCache), "handles", options.GetOpenFilesCacheCapacity()}
|
||||
// usedCache := options.GetBlockCacheCapacity() + options.GetWriteBuffer()*2
|
||||
logCtx := []interface{}{"handles", options.GetOpenFilesCacheCapacity()}
|
||||
if options.ReadOnly {
|
||||
logCtx = append(logCtx, "readonly", "true")
|
||||
}
|
||||
logger.Info("Allocated cache and file handles", logCtx...)
|
||||
if options.BlockCacheCapacity != 0 {
|
||||
logCtx = append(logCtx, "block_cache_size", common.StorageSize(options.BlockCacheCapacity))
|
||||
}
|
||||
if options.WriteBuffer != 0 {
|
||||
logCtx = append(logCtx, "memory_table_size", common.StorageSize(options.WriteBuffer))
|
||||
}
|
||||
logger.Info("Level db Allocated cache and file handles", logCtx...)
|
||||
|
||||
// Open the db and recover any potential corruptions
|
||||
db, err := leveldb.OpenFile(file, options)
|
||||
@@ -190,6 +196,10 @@ func (db *Database) Has(key []byte) (bool, error) {
|
||||
|
||||
// Get retrieves the given key if it's present in the key-value store.
|
||||
func (db *Database) Get(key []byte) ([]byte, error) {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbGetTimer.UpdateSince(start) }()
|
||||
}
|
||||
dat, err := db.db.Get(key, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -199,11 +209,19 @@ func (db *Database) Get(key []byte) ([]byte, error) {
|
||||
|
||||
// Put inserts the given value into the key-value store.
|
||||
func (db *Database) Put(key []byte, value []byte) error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbPutTimer.UpdateSince(start) }()
|
||||
}
|
||||
return db.db.Put(key, value, nil)
|
||||
}
|
||||
|
||||
// Delete removes the key from the key-value store.
|
||||
func (db *Database) Delete(key []byte) error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbDeleteTimer.UpdateSince(start) }()
|
||||
}
|
||||
return db.db.Delete(key, nil)
|
||||
}
|
||||
|
||||
@@ -301,6 +319,8 @@ func (db *Database) meter(refresh time.Duration, namespace string) {
|
||||
merr = err
|
||||
continue
|
||||
}
|
||||
fmt.Printf("loop print level db stats db_metrics=\n%v\n", stats)
|
||||
db.log.Info("loop print level db stats", "stats", stats)
|
||||
// Iterate over all the leveldbTable rows, and accumulate the entries
|
||||
for j := 0; j < len(compactions[i%2]); j++ {
|
||||
compactions[i%2][j] = 0
|
||||
@@ -414,6 +434,10 @@ func (b *batch) ValueSize() int {
|
||||
|
||||
// Write flushes any accumulated data to disk.
|
||||
func (b *batch) Write() error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
|
||||
}
|
||||
return b.db.Write(b.b, nil)
|
||||
}
|
||||
|
||||
|
||||
11
ethdb/metrics.go
Normal file
11
ethdb/metrics.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package ethdb
|
||||
|
||||
import "github.com/ethereum/go-ethereum/metrics"
|
||||
|
||||
var (
|
||||
EthdbGetTimer = metrics.NewRegisteredTimer("ethdb/get/time", nil)
|
||||
EthdbInnerGetTimer = metrics.NewRegisteredTimer("ethdb/inner/get/time", nil)
|
||||
EthdbPutTimer = metrics.NewRegisteredTimer("ethdb/put/time", nil)
|
||||
EthdbDeleteTimer = metrics.NewRegisteredTimer("ethdb/delete/time", nil)
|
||||
EthdbBatchWriteTimer = metrics.NewRegisteredTimer("ethdb/batch/write/time", nil)
|
||||
)
|
||||
@@ -183,8 +183,8 @@ func New(file string, cache int, handles int, namespace string, readonly bool, e
|
||||
memTableSize = maxMemTableSize - 1
|
||||
}
|
||||
|
||||
logger.Info("Allocated cache and file handles", "cache", common.StorageSize(cache*1024*1024),
|
||||
"handles", handles, "memory table", common.StorageSize(memTableSize))
|
||||
logger.Info("Pebble db Allocated cache and file handles", "handles", handles, "block_cache_size", common.StorageSize(cache*1024*1024),
|
||||
"memory_table_size", common.StorageSize(memTableSize))
|
||||
|
||||
db := &Database{
|
||||
fn: file,
|
||||
@@ -309,23 +309,69 @@ func (d *Database) Has(key []byte) (bool, error) {
|
||||
|
||||
// Get retrieves the given key if it's present in the key-value store.
|
||||
func (d *Database) Get(key []byte) ([]byte, error) {
|
||||
var (
|
||||
step1Start time.Time
|
||||
step1End time.Time
|
||||
step2Start time.Time
|
||||
step2End time.Time
|
||||
step3Start time.Time
|
||||
step3End time.Time
|
||||
step4Start time.Time
|
||||
step4End time.Time
|
||||
keyLen int
|
||||
valueLen int
|
||||
)
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() {
|
||||
ethdb.EthdbGetTimer.UpdateSince(start)
|
||||
if time.Now().Sub(start) > 100*time.Millisecond {
|
||||
d.log.Error("perf pebble read",
|
||||
"key", key,
|
||||
"key_len", keyLen,
|
||||
"value_len", valueLen,
|
||||
"step1", common.PrettyDuration(step1End.Sub(step1Start)),
|
||||
"step2", common.PrettyDuration(step2End.Sub(step2Start)),
|
||||
"step3", common.PrettyDuration(step3End.Sub(step3Start)),
|
||||
"step4", common.PrettyDuration(step4End.Sub(step4Start)))
|
||||
}
|
||||
}()
|
||||
}
|
||||
keyLen = len(key)
|
||||
step1Start = time.Now()
|
||||
d.quitLock.RLock()
|
||||
step1End = time.Now()
|
||||
defer d.quitLock.RUnlock()
|
||||
if d.closed {
|
||||
return nil, pebble.ErrClosed
|
||||
}
|
||||
step2Start = time.Now()
|
||||
innerStart := time.Now()
|
||||
dat, closer, err := d.db.Get(key)
|
||||
valueLen = len(dat)
|
||||
ethdb.EthdbInnerGetTimer.UpdateSince(innerStart)
|
||||
step2End = time.Now()
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
step3Start = time.Now()
|
||||
ret := make([]byte, len(dat))
|
||||
copy(ret, dat)
|
||||
step3End = time.Now()
|
||||
|
||||
step4Start = time.Now()
|
||||
closer.Close()
|
||||
step4End = time.Now()
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Put inserts the given value into the key-value store.
|
||||
func (d *Database) Put(key []byte, value []byte) error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbPutTimer.UpdateSince(start) }()
|
||||
}
|
||||
d.quitLock.RLock()
|
||||
defer d.quitLock.RUnlock()
|
||||
if d.closed {
|
||||
@@ -336,6 +382,10 @@ func (d *Database) Put(key []byte, value []byte) error {
|
||||
|
||||
// Delete removes the key from the key-value store.
|
||||
func (d *Database) Delete(key []byte) error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbDeleteTimer.UpdateSince(start) }()
|
||||
}
|
||||
d.quitLock.RLock()
|
||||
defer d.quitLock.RUnlock()
|
||||
if d.closed {
|
||||
@@ -494,6 +544,9 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
|
||||
nonLevel0CompCount = int64(d.nonLevel0Comp.Load())
|
||||
level0CompCount = int64(d.level0Comp.Load())
|
||||
)
|
||||
fmt.Printf("loop print pebble db stats db_metrics=\n%v\n", stats)
|
||||
d.log.Info("loop print pebble db stats", "comp_time", compTime, "write_delay_count", writeDelayCount, "write_delay_time",
|
||||
writeDelayTime, "non_level0_comp_count", nonLevel0CompCount, "level0_comp_count", level0CompCount)
|
||||
writeDelayTimes[i%2] = writeDelayTime
|
||||
writeDelayCounts[i%2] = writeDelayCount
|
||||
compTimes[i%2] = compTime
|
||||
@@ -599,6 +652,10 @@ func (b *batch) ValueSize() int {
|
||||
|
||||
// Write flushes any accumulated data to disk.
|
||||
func (b *batch) Write() error {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { ethdb.EthdbBatchWriteTimer.UpdateSince(start) }()
|
||||
}
|
||||
b.db.quitLock.RLock()
|
||||
defer b.db.quitLock.RUnlock()
|
||||
if b.db.closed {
|
||||
|
||||
@@ -44,10 +44,6 @@ func (db *Database) BlockStore() ethdb.Database {
|
||||
return db
|
||||
}
|
||||
|
||||
func (db *Database) HasSeparateBlockStore() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (db *Database) SetBlockStore(block ethdb.Database) {
|
||||
panic("not supported")
|
||||
}
|
||||
|
||||
@@ -87,10 +87,6 @@ func (m *MevAPI) Params() *types.MevParams {
|
||||
return m.b.MevParams()
|
||||
}
|
||||
|
||||
func (m *MevAPI) HasBuilder(builder common.Address) bool {
|
||||
return m.b.HasBuilder(builder)
|
||||
}
|
||||
|
||||
// Running returns true if mev is running
|
||||
func (m *MevAPI) Running() bool {
|
||||
return m.b.MevRunning()
|
||||
|
||||
@@ -650,8 +650,7 @@ func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.Match
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (b *testBackend) MevRunning() bool { return false }
|
||||
func (b *testBackend) HasBuilder(builder common.Address) bool { return false }
|
||||
func (b *testBackend) MevRunning() bool { return false }
|
||||
func (b *testBackend) MevParams() *types.MevParams {
|
||||
return &types.MevParams{}
|
||||
}
|
||||
|
||||
@@ -115,8 +115,6 @@ type Backend interface {
|
||||
AddBuilder(builder common.Address, builderUrl string) error
|
||||
// RemoveBuilder removes a builder from the bid simulator.
|
||||
RemoveBuilder(builder common.Address) error
|
||||
// HasBuilder returns true if the builder is in the builder list.
|
||||
HasBuilder(builder common.Address) bool
|
||||
// SendBid receives bid from the builders.
|
||||
SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error)
|
||||
// BestBidGasFee returns the gas fee of the best bid for the given parent hash.
|
||||
|
||||
@@ -204,8 +204,7 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
|
||||
// Sanity check the EIP-1559 fee parameters if present.
|
||||
if args.GasPrice == nil && eip1559ParamsSet {
|
||||
if args.MaxFeePerGas.ToInt().Sign() == 0 {
|
||||
// return errors.New("maxFeePerGas must be non-zero")
|
||||
log.Warn("EIP-1559 Tx with zero maxFeePerGas") // BSC accepts zero gas price.
|
||||
return errors.New("maxFeePerGas must be non-zero")
|
||||
}
|
||||
if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
|
||||
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas)
|
||||
@@ -218,8 +217,7 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
|
||||
if args.GasPrice != nil && !eip1559ParamsSet {
|
||||
// Zero gas-price is not allowed after London fork
|
||||
if args.GasPrice.ToInt().Sign() == 0 && isLondon {
|
||||
// return errors.New("gasPrice must be non-zero after london fork")
|
||||
log.Warn("non EIP-1559 Tx with zero gasPrice") // BSC accepts zero gas price.
|
||||
return errors.New("gasPrice must be non-zero after london fork")
|
||||
}
|
||||
return nil // No need to set anything, user already set GasPrice
|
||||
}
|
||||
|
||||
@@ -85,8 +85,8 @@ func TestSetFeeDefaults(t *testing.T) {
|
||||
"legacy tx post-London with zero price",
|
||||
"london",
|
||||
&TransactionArgs{GasPrice: zero},
|
||||
&TransactionArgs{GasPrice: zero},
|
||||
nil, // errors.New("gasPrice must be non-zero after london fork"),
|
||||
nil,
|
||||
errors.New("gasPrice must be non-zero after london fork"),
|
||||
},
|
||||
|
||||
// Access list txs
|
||||
@@ -180,8 +180,8 @@ func TestSetFeeDefaults(t *testing.T) {
|
||||
"dynamic fee tx post-London, explicit gas price",
|
||||
"london",
|
||||
&TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero},
|
||||
&TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero},
|
||||
nil, // errors.New("maxFeePerGas must be non-zero"),
|
||||
nil,
|
||||
errors.New("maxFeePerGas must be non-zero"),
|
||||
},
|
||||
|
||||
// Misc
|
||||
@@ -416,8 +416,7 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
|
||||
|
||||
func (b *backendMock) Engine() consensus.Engine { return nil }
|
||||
|
||||
func (b *backendMock) MevRunning() bool { return false }
|
||||
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
|
||||
func (b *backendMock) MevRunning() bool { return false }
|
||||
func (b *backendMock) MevParams() *types.MevParams {
|
||||
return &types.MevParams{}
|
||||
}
|
||||
|
||||
@@ -659,30 +659,6 @@ web3._extend({
|
||||
name: '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({
|
||||
name: 'setEtherbase',
|
||||
call: 'miner_setEtherbase',
|
||||
|
||||
@@ -37,8 +37,8 @@ type Config struct {
|
||||
|
||||
// DefaultConfig is the default config for metrics used in go-ethereum.
|
||||
var DefaultConfig = Config{
|
||||
Enabled: false,
|
||||
EnabledExpensive: false,
|
||||
Enabled: true,
|
||||
EnabledExpensive: true,
|
||||
HTTP: "127.0.0.1",
|
||||
Port: 6060,
|
||||
EnableInfluxDB: false,
|
||||
|
||||
@@ -22,12 +22,12 @@ import (
|
||||
//
|
||||
// This global kill-switch helps quantify the observer effect and makes
|
||||
// for less cluttered pprof profiles.
|
||||
var Enabled = false
|
||||
var Enabled = true
|
||||
|
||||
// EnabledExpensive is a soft-flag meant for external packages to check if costly
|
||||
// metrics gathering is allowed or not. The goal is to separate standard metrics
|
||||
// for health monitoring and debug metrics that might impact runtime performance.
|
||||
var EnabledExpensive = false
|
||||
var EnabledExpensive = true
|
||||
|
||||
// enablerFlags is the CLI flag names to use to enable metrics collections.
|
||||
var enablerFlags = []string{"metrics"}
|
||||
|
||||
@@ -29,6 +29,11 @@ import (
|
||||
const (
|
||||
// maxBidPerBuilderPerBlock is the max bid number per builder
|
||||
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 (
|
||||
@@ -73,7 +78,6 @@ type simBidReq struct {
|
||||
type bidSimulator struct {
|
||||
config *MevConfig
|
||||
delayLeftOver time.Duration
|
||||
minGasPrice *big.Int
|
||||
chain *core.BlockChain
|
||||
chainConfig *params.ChainConfig
|
||||
engine consensus.Engine
|
||||
@@ -110,7 +114,6 @@ type bidSimulator struct {
|
||||
func newBidSimulator(
|
||||
config *MevConfig,
|
||||
delayLeftOver time.Duration,
|
||||
minGasPrice *big.Int,
|
||||
chain *core.BlockChain,
|
||||
chainConfig *params.ChainConfig,
|
||||
engine consensus.Engine,
|
||||
@@ -119,7 +122,6 @@ func newBidSimulator(
|
||||
b := &bidSimulator{
|
||||
config: config,
|
||||
delayLeftOver: delayLeftOver,
|
||||
minGasPrice: minGasPrice,
|
||||
chain: chain,
|
||||
chainConfig: chainConfig,
|
||||
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 := 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 {
|
||||
// each commit work will have its own interruptCh to stop work with a reason
|
||||
interruptCh <- reason
|
||||
@@ -353,7 +367,6 @@ func (b *bidSimulator) newBidLoop() {
|
||||
expectedValidatorReward: expectedValidatorReward,
|
||||
packedBlockReward: big.NewInt(0),
|
||||
packedValidatorReward: big.NewInt(0),
|
||||
finished: make(chan struct{}),
|
||||
}
|
||||
|
||||
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 {
|
||||
parentHeader := b.chain.GetHeaderByHash(parentHash)
|
||||
return bidutil.BidBetterBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver, b.config.BidSimulationLeftOver)
|
||||
@@ -419,6 +437,10 @@ func (b *bidSimulator) clearLoop() {
|
||||
b.bestBidMu.Unlock()
|
||||
|
||||
b.simBidMu.Lock()
|
||||
if bid, ok := b.simulatingBid[parentHash]; ok {
|
||||
bid.env.discard()
|
||||
}
|
||||
delete(b.simulatingBid, parentHash)
|
||||
for k, v := range b.simulatingBid {
|
||||
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
|
||||
v.env.discard()
|
||||
@@ -505,6 +527,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
|
||||
// ensure simulation exited then start next simulation
|
||||
b.SetSimulatingBid(parentHash, bidRuntime)
|
||||
start := time.Now()
|
||||
|
||||
defer func(simStart time.Time) {
|
||||
logCtx := []any{
|
||||
@@ -530,11 +553,10 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
}
|
||||
|
||||
b.RemoveSimulatingBid(parentHash)
|
||||
close(bidRuntime.finished)
|
||||
bidSimTimer.UpdateSince(start)
|
||||
|
||||
if success {
|
||||
bidRuntime.duration = time.Since(simStart)
|
||||
bidSimTimer.UpdateSince(simStart)
|
||||
|
||||
// only recommit self bid when newBidCh is empty
|
||||
if len(b.newBidCh) > 0 {
|
||||
@@ -558,14 +580,6 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
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
|
||||
if bidRuntime.env.gasPool == nil {
|
||||
bidRuntime.env.gasPool = new(core.GasPool).AddGas(gasLimit)
|
||||
@@ -578,7 +592,6 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
return
|
||||
}
|
||||
|
||||
// commit transactions in bid
|
||||
for _, tx := range bidRuntime.bid.Txs {
|
||||
select {
|
||||
case <-interruptCh:
|
||||
@@ -596,7 +609,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
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 {
|
||||
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)
|
||||
@@ -604,41 +617,26 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
||||
}
|
||||
}
|
||||
|
||||
// check if bid reward is valid
|
||||
{
|
||||
bidRuntime.packReward(b.config.ValidatorCommission)
|
||||
if !bidRuntime.validReward() {
|
||||
err = errors.New("reward does not achieve the expectation")
|
||||
return
|
||||
}
|
||||
bidRuntime.packReward(b.config.ValidatorCommission)
|
||||
|
||||
// return if bid is invalid, reportIssue issue to mev-sentry/builder if simulation is fully done
|
||||
if !bidRuntime.validReward() {
|
||||
err = errors.New("reward does not achieve the expectation")
|
||||
return
|
||||
}
|
||||
|
||||
// check if bid gas price is lower than min gas price
|
||||
{
|
||||
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
|
||||
// fill transactions from mempool
|
||||
if b.config.GreedyMergeTx {
|
||||
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
|
||||
if delay != nil && *delay > 0 {
|
||||
stopTimer := time.NewTimer(*delay)
|
||||
|
||||
bidTxsSet := mapset.NewSet[common.Hash]()
|
||||
for _, tx := range bidRuntime.bid.Txs {
|
||||
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,
|
||||
"builder", bidRuntime.bid.Builder, "tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr)
|
||||
|
||||
@@ -647,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)
|
||||
err = bidRuntime.commitTransaction(b.chain, b.chainConfig, payBidTx, true)
|
||||
err = bidRuntime.commitTransaction(b.chain, b.chainConfig, payBidTx)
|
||||
if err != nil {
|
||||
log.Error("BidSimulator: failed to commit tx", "builder", bidRuntime.bid.Builder,
|
||||
"bidHash", bidRuntime.bid.Hash(), "tx", payBidTx.Hash(), "err", err)
|
||||
@@ -714,7 +711,6 @@ type BidRuntime struct {
|
||||
packedBlockReward *big.Int
|
||||
packedValidatorReward *big.Int
|
||||
|
||||
finished chan struct{}
|
||||
duration time.Duration
|
||||
}
|
||||
|
||||
@@ -731,10 +727,12 @@ func (r *BidRuntime) packReward(validatorCommission uint64) {
|
||||
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 (
|
||||
env = r.env
|
||||
sc *types.BlobSidecar
|
||||
env = r.env
|
||||
snap = env.state.Snapshot()
|
||||
gp = env.gasPool.Gas()
|
||||
sc *types.BlobSidecar
|
||||
)
|
||||
|
||||
// Start executing the transaction
|
||||
@@ -757,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,
|
||||
&env.header.GasUsed, *chain.GetVMConfig(), core.NewReceiptBloomGenerator())
|
||||
if err != nil {
|
||||
env.state.RevertToSnapshot(snap)
|
||||
env.gasPool.SetGas(gp)
|
||||
return err
|
||||
} else if unRevertible && receipt.Status == types.ReceiptStatusFailed {
|
||||
return errors.New("no revertible transaction failed")
|
||||
}
|
||||
|
||||
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),
|
||||
}
|
||||
|
||||
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.wg.Add(1)
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
)
|
||||
|
||||
type BuilderConfig struct {
|
||||
@@ -60,11 +59,6 @@ func (miner *Miner) RemoveBuilder(builderAddr common.Address) error {
|
||||
return miner.bidSimulator.RemoveBuilder(builderAddr)
|
||||
}
|
||||
|
||||
// HasBuilder returns true if the builder is in the builder list.
|
||||
func (miner *Miner) HasBuilder(builder common.Address) bool {
|
||||
return miner.bidSimulator.ExistBuilder(builder)
|
||||
}
|
||||
|
||||
func (miner *Miner) SendBid(ctx context.Context, bidArgs *types.BidArgs) (common.Hash, error) {
|
||||
builder, err := bidArgs.EcrecoverSender()
|
||||
if err != nil {
|
||||
@@ -123,8 +117,6 @@ func (miner *Miner) MevParams() *types.MevParams {
|
||||
ValidatorCommission: miner.worker.config.Mev.ValidatorCommission,
|
||||
BidSimulationLeftOver: miner.worker.config.Mev.BidSimulationLeftOver,
|
||||
GasCeil: miner.worker.config.GasCeil,
|
||||
GasPrice: miner.worker.config.GasPrice,
|
||||
BuilderFeeCeil: builderFeeCeil,
|
||||
Version: params.Version,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,14 +67,13 @@ const (
|
||||
// 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,
|
||||
recentMinedCacheLimit = 20
|
||||
|
||||
// the default to wait for the mev miner to finish
|
||||
waitMEVMinerEndTimeLimit = 50 * time.Millisecond
|
||||
)
|
||||
|
||||
var (
|
||||
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil)
|
||||
finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil)
|
||||
writeBlockTimer = metrics.NewRegisteredTimer("worker/writeblock", nil)
|
||||
finalizeBlockTimer = metrics.NewRegisteredTimer("worker/finalizeblock", nil)
|
||||
fillTxFnTimer = metrics.NewRegisteredTimer("worker/filltransactions/all", nil)
|
||||
fillTxFnPartialTimer = metrics.NewRegisteredTimer("worker/filltransactions/partial", nil)
|
||||
|
||||
errBlockInterruptedByNewHead = errors.New("new head arrived while building block")
|
||||
errBlockInterruptedByRecommit = errors.New("recommit interrupt while building block")
|
||||
@@ -174,7 +173,6 @@ type getWorkReq struct {
|
||||
|
||||
type bidFetcher interface {
|
||||
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
|
||||
@@ -1060,6 +1058,8 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
||||
// into the given sealing block. The transaction selection and ordering strategy can
|
||||
// be customized with the plugin in the future.
|
||||
func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stopTimer *time.Timer, bidTxs mapset.Set[common.Hash]) (err error) {
|
||||
start := time.Now()
|
||||
|
||||
w.mu.RLock()
|
||||
tip := w.tip
|
||||
w.mu.RUnlock()
|
||||
@@ -1114,6 +1114,7 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
|
||||
localBlobTxs[account] = txs
|
||||
}
|
||||
}
|
||||
fillTxFnPartialTimer.UpdateSince(start)
|
||||
|
||||
// Fill the block with all available pending transactions.
|
||||
// we will abort when:
|
||||
@@ -1138,6 +1139,7 @@ func (w *worker) fillTransactions(interruptCh chan int32, env *environment, stop
|
||||
return err
|
||||
}
|
||||
}
|
||||
fillTxFnTimer.UpdateSince(start)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1340,15 +1342,6 @@ LOOP:
|
||||
// when in-turn, compare with remote work.
|
||||
from := bestWork.coinbase
|
||||
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)
|
||||
|
||||
if bestBid != nil {
|
||||
|
||||
13
node/node.go
13
node/node.go
@@ -773,13 +773,12 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r
|
||||
db = rawdb.NewMemoryDatabase()
|
||||
} else {
|
||||
db, err = rawdb.Open(rawdb.OpenOptions{
|
||||
Type: n.config.DBEngine,
|
||||
Directory: n.ResolvePath(name),
|
||||
Namespace: namespace,
|
||||
Cache: cache,
|
||||
Handles: handles,
|
||||
ReadOnly: readonly,
|
||||
MultiDataBase: n.CheckIfMultiDataBase(),
|
||||
Type: n.config.DBEngine,
|
||||
Directory: n.ResolvePath(name),
|
||||
Namespace: namespace,
|
||||
Cache: cache,
|
||||
Handles: handles,
|
||||
ReadOnly: readonly,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -152,9 +152,6 @@ var (
|
||||
FeynmanTime: 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
|
||||
HaberTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
|
||||
HaberFixTime: nil, // TBD
|
||||
BohrTime: nil,
|
||||
|
||||
Parlia: &ParliaConfig{
|
||||
Period: 3,
|
||||
@@ -193,9 +190,6 @@ var (
|
||||
FeynmanTime: newUint64(1710136800), // 2024-03-11 6: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
|
||||
HaberTime: newUint64(1716962820), // 2024-05-29 06:07:00 AM UTC
|
||||
HaberFixTime: newUint64(1719986788), // 2024-07-03 06:06:28 AM UTC
|
||||
BohrTime: nil,
|
||||
|
||||
Parlia: &ParliaConfig{
|
||||
Period: 3,
|
||||
@@ -235,9 +229,6 @@ var (
|
||||
FeynmanTime: newUint64(0),
|
||||
FeynmanFixTime: newUint64(0),
|
||||
CancunTime: newUint64(0),
|
||||
HaberTime: newUint64(0),
|
||||
HaberFixTime: newUint64(0),
|
||||
BohrTime: newUint64(0),
|
||||
|
||||
Parlia: &ParliaConfig{
|
||||
Period: 3,
|
||||
@@ -276,7 +267,6 @@ var (
|
||||
FeynmanTime: newUint64(0),
|
||||
FeynmanFixTime: newUint64(0),
|
||||
CancunTime: newUint64(0),
|
||||
|
||||
Parlia: &ParliaConfig{
|
||||
Period: 3,
|
||||
Epoch: 200,
|
||||
@@ -514,9 +504,6 @@ type ChainConfig struct {
|
||||
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)
|
||||
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)
|
||||
HaberFixTime *uint64 `json:"haberFixTime,omitempty"` // HaberFix switch time (nil = no fork, 0 = already on haberFix)
|
||||
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)
|
||||
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
|
||||
|
||||
@@ -622,22 +609,7 @@ func (c *ChainConfig) String() string {
|
||||
CancunTime = big.NewInt(0).SetUint64(*c.CancunTime)
|
||||
}
|
||||
|
||||
var HaberTime *big.Int
|
||||
if c.HaberTime != nil {
|
||||
HaberTime = big.NewInt(0).SetUint64(*c.HaberTime)
|
||||
}
|
||||
|
||||
var HaberFixTime *big.Int
|
||||
if c.HaberFixTime != nil {
|
||||
HaberFixTime = big.NewInt(0).SetUint64(*c.HaberFixTime)
|
||||
}
|
||||
|
||||
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, HaberFixTime: %v, BohrTime: %v, Engine: %v}",
|
||||
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}",
|
||||
c.ChainID,
|
||||
c.HomesteadBlock,
|
||||
c.DAOForkBlock,
|
||||
@@ -674,9 +646,6 @@ func (c *ChainConfig) String() string {
|
||||
FeynmanTime,
|
||||
FeynmanFixTime,
|
||||
CancunTime,
|
||||
HaberTime,
|
||||
HaberFixTime,
|
||||
BohrTime,
|
||||
engine,
|
||||
)
|
||||
}
|
||||
@@ -944,39 +913,6 @@ func (c *ChainConfig) IsCancun(num *big.Int, time uint64) bool {
|
||||
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)
|
||||
}
|
||||
|
||||
// IsHaberFix returns whether time is either equal to the HaberFix fork time or greater.
|
||||
func (c *ChainConfig) IsHaberFix(num *big.Int, time uint64) bool {
|
||||
return c.IsLondon(num) && isTimestampForked(c.HaberFixTime, time)
|
||||
}
|
||||
|
||||
// IsOnHaberFix returns whether currentBlockTime is either equal to the HaberFix fork time or greater firstly.
|
||||
func (c *ChainConfig) IsOnHaberFix(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.IsHaberFix(lastBlockNumber, lastBlockTime) && c.IsHaberFix(currentBlockNumber, currentBlockTime)
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (c *ChainConfig) IsPrague(num *big.Int, time uint64) bool {
|
||||
return c.IsLondon(num) && isTimestampForked(c.PragueTime, time)
|
||||
@@ -1040,9 +976,6 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
|
||||
{name: "feynmanTime", timestamp: c.FeynmanTime},
|
||||
{name: "feynmanFixTime", timestamp: c.FeynmanFixTime},
|
||||
{name: "cancunTime", timestamp: c.CancunTime},
|
||||
{name: "haberTime", timestamp: c.HaberTime},
|
||||
{name: "haberFixTime", timestamp: c.HaberFixTime},
|
||||
{name: "bohrTime", timestamp: c.BohrTime},
|
||||
{name: "pragueTime", timestamp: c.PragueTime, optional: true},
|
||||
{name: "verkleTime", timestamp: c.VerkleTime, optional: true},
|
||||
} {
|
||||
@@ -1190,15 +1123,6 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int,
|
||||
if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, headTimestamp) {
|
||||
return newTimestampCompatError("Cancun fork timestamp", c.CancunTime, newcfg.CancunTime)
|
||||
}
|
||||
if isForkTimestampIncompatible(c.HaberTime, newcfg.HaberTime, headTimestamp) {
|
||||
return newTimestampCompatError("Haber fork timestamp", c.HaberTime, newcfg.HaberTime)
|
||||
}
|
||||
if isForkTimestampIncompatible(c.HaberFixTime, newcfg.HaberFixTime, headTimestamp) {
|
||||
return newTimestampCompatError("HaberFix fork timestamp", c.HaberFixTime, newcfg.HaberFixTime)
|
||||
}
|
||||
if isForkTimestampIncompatible(c.BohrTime, newcfg.BohrTime, headTimestamp) {
|
||||
return newTimestampCompatError("Bohr fork timestamp", c.BohrTime, newcfg.BohrTime)
|
||||
}
|
||||
if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) {
|
||||
return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime)
|
||||
}
|
||||
@@ -1381,8 +1305,8 @@ type Rules struct {
|
||||
IsPlato bool
|
||||
IsHertz bool
|
||||
IsHertzfix bool
|
||||
IsShanghai, IsKepler, IsFeynman, IsCancun, IsHaber bool
|
||||
IsBohr, IsPrague, IsVerkle bool
|
||||
IsShanghai, IsKepler, IsFeynman, IsCancun, IsPrague bool
|
||||
IsVerkle bool
|
||||
}
|
||||
|
||||
// Rules ensures c's ChainID is not nil.
|
||||
@@ -1417,8 +1341,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
|
||||
IsKepler: c.IsKepler(num, timestamp),
|
||||
IsFeynman: c.IsFeynman(num, timestamp),
|
||||
IsCancun: c.IsCancun(num, timestamp),
|
||||
IsHaber: c.IsHaber(num, timestamp),
|
||||
IsBohr: c.IsBohr(num, timestamp),
|
||||
IsPrague: c.IsPrague(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
|
||||
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,
|
||||
// up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529
|
||||
RefundQuotient uint64 = 2
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
const (
|
||||
VersionMajor = 1 // Major version component of the current release
|
||||
VersionMinor = 4 // Minor version component of the current release
|
||||
VersionPatch = 11 // 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
|
||||
)
|
||||
|
||||
|
||||
@@ -4,15 +4,17 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sort"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -24,113 +26,63 @@ import (
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
Nonce uint64
|
||||
Balance *big.Int
|
||||
Root common.Hash // merkle root of the storage trie
|
||||
CodeHash []byte
|
||||
}
|
||||
|
||||
type Database interface {
|
||||
database.Database
|
||||
Scheme() string
|
||||
Cap(limit common.StorageSize) error
|
||||
DiskDB() ethdb.Database
|
||||
}
|
||||
|
||||
const TopN = 3
|
||||
|
||||
type Inspector struct {
|
||||
trie *Trie // traverse trie
|
||||
db Database
|
||||
stateRootHash common.Hash
|
||||
blockNum uint64
|
||||
blocknum uint64
|
||||
root node // root of triedb
|
||||
totalNum uint64
|
||||
wg sync.WaitGroup
|
||||
statLock sync.RWMutex
|
||||
result map[string]*TrieTreeStat
|
||||
sem *semaphore.Weighted
|
||||
eoaAccountNums uint64
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
results stat
|
||||
topN int
|
||||
|
||||
totalAccountNum atomic.Uint64
|
||||
totalStorageNum atomic.Uint64
|
||||
lastTime mclock.AbsTime
|
||||
}
|
||||
|
||||
type stat struct {
|
||||
lock sync.RWMutex
|
||||
account *trieStat
|
||||
storageTopN []*trieStat
|
||||
storageTopNTotal []uint64
|
||||
storageTotal nodeStat
|
||||
storageTrieNum uint64
|
||||
type TrieTreeStat struct {
|
||||
is_account_trie bool
|
||||
theNodeStatByLevel [15]NodeStat
|
||||
totalNodeStat NodeStat
|
||||
}
|
||||
|
||||
type trieStat struct {
|
||||
owner common.Hash
|
||||
totalNodeStat nodeStat
|
||||
nodeStatByLevel [16]nodeStat
|
||||
type NodeStat struct {
|
||||
ShortNodeCnt uint64
|
||||
FullNodeCnt uint64
|
||||
ValueNodeCnt uint64
|
||||
}
|
||||
|
||||
type nodeStat struct {
|
||||
ShortNodeCnt atomic.Uint64
|
||||
FullNodeCnt atomic.Uint64
|
||||
ValueNodeCnt atomic.Uint64
|
||||
}
|
||||
|
||||
func (ns *nodeStat) IsEmpty() bool {
|
||||
if ns.FullNodeCnt.Load() == 0 && ns.ShortNodeCnt.Load() == 0 && ns.ValueNodeCnt.Load() == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *stat) add(ts *trieStat, topN int) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
if ts.owner == (common.Hash{}) {
|
||||
s.account = ts
|
||||
return
|
||||
}
|
||||
|
||||
total := ts.totalNodeStat.ValueNodeCnt.Load() + ts.totalNodeStat.FullNodeCnt.Load() + ts.totalNodeStat.ShortNodeCnt.Load()
|
||||
if len(s.storageTopNTotal) == 0 || total > s.storageTopNTotal[len(s.storageTopNTotal)-1] {
|
||||
var (
|
||||
i int
|
||||
t uint64
|
||||
)
|
||||
for i, t = range s.storageTopNTotal {
|
||||
if total < t {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
s.storageTopNTotal = append(s.storageTopNTotal[:i], append([]uint64{total}, s.storageTopNTotal[i:]...)...)
|
||||
s.storageTopN = append(s.storageTopN[:i], append([]*trieStat{ts}, s.storageTopN[i:]...)...)
|
||||
if len(s.storageTopN) > topN {
|
||||
s.storageTopNTotal = s.storageTopNTotal[:topN]
|
||||
s.storageTopN = s.storageTopN[:topN]
|
||||
}
|
||||
}
|
||||
|
||||
s.storageTotal.ShortNodeCnt.Add(ts.totalNodeStat.ShortNodeCnt.Load())
|
||||
s.storageTotal.ValueNodeCnt.Add(ts.totalNodeStat.ValueNodeCnt.Load())
|
||||
s.storageTotal.FullNodeCnt.Add(ts.totalNodeStat.FullNodeCnt.Load())
|
||||
s.storageTrieNum++
|
||||
}
|
||||
|
||||
func (trieStat *trieStat) add(theNode node, height int) {
|
||||
func (trieStat *TrieTreeStat) AtomicAdd(theNode node, height uint32) {
|
||||
switch (theNode).(type) {
|
||||
case *shortNode:
|
||||
trieStat.totalNodeStat.ShortNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].ShortNodeCnt.Add(1)
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.ShortNodeCnt, 1)
|
||||
atomic.AddUint64(&(trieStat.theNodeStatByLevel[height].ShortNodeCnt), 1)
|
||||
case *fullNode:
|
||||
trieStat.totalNodeStat.FullNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].FullNodeCnt.Add(1)
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.FullNodeCnt, 1)
|
||||
atomic.AddUint64(&trieStat.theNodeStatByLevel[height].FullNodeCnt, 1)
|
||||
case valueNode:
|
||||
trieStat.totalNodeStat.ValueNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].ValueNodeCnt.Add(1)
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.ValueNodeCnt, 1)
|
||||
atomic.AddUint64(&((trieStat.theNodeStatByLevel[height]).ValueNodeCnt), 1)
|
||||
default:
|
||||
panic(errors.New("Invalid node type to statistics"))
|
||||
}
|
||||
}
|
||||
|
||||
func (trieStat *trieStat) Display(ownerAddress string, treeType string) string {
|
||||
sw := new(strings.Builder)
|
||||
table := tablewriter.NewWriter(sw)
|
||||
func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) {
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"})
|
||||
if ownerAddress == "" {
|
||||
table.SetCaption(true, fmt.Sprintf("%v", treeType))
|
||||
@@ -138,27 +90,38 @@ func (trieStat *trieStat) Display(ownerAddress string, treeType string) string {
|
||||
table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress))
|
||||
}
|
||||
table.SetAlignment(1)
|
||||
|
||||
for i := range trieStat.nodeStatByLevel {
|
||||
if trieStat.nodeStatByLevel[i].IsEmpty() {
|
||||
continue
|
||||
for i := 0; i < len(trieStat.theNodeStatByLevel); i++ {
|
||||
nodeStat := trieStat.theNodeStatByLevel[i]
|
||||
if nodeStat.FullNodeCnt == 0 && nodeStat.ShortNodeCnt == 0 && nodeStat.ValueNodeCnt == 0 {
|
||||
break
|
||||
}
|
||||
table.AppendBulk([][]string{
|
||||
{"-", fmt.Sprintf("%d", i),
|
||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ShortNodeCnt.Load()),
|
||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].FullNodeCnt.Load()),
|
||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ValueNodeCnt.Load())},
|
||||
{"-", strconv.Itoa(i), nodeStat.ShortNodeCount(), nodeStat.FullNodeCount(), nodeStat.ValueNodeCount()},
|
||||
})
|
||||
}
|
||||
table.AppendBulk([][]string{
|
||||
{"Total", "-", fmt.Sprintf("%d", trieStat.totalNodeStat.ShortNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.FullNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.ValueNodeCnt.Load())},
|
||||
{"Total", "-", trieStat.totalNodeStat.ShortNodeCount(), trieStat.totalNodeStat.FullNodeCount(), trieStat.totalNodeStat.ValueNodeCount()},
|
||||
})
|
||||
table.Render()
|
||||
return sw.String()
|
||||
}
|
||||
|
||||
func Uint64ToString(cnt uint64) string {
|
||||
return fmt.Sprintf("%v", cnt)
|
||||
}
|
||||
|
||||
func (nodeStat *NodeStat) ShortNodeCount() string {
|
||||
return Uint64ToString(nodeStat.ShortNodeCnt)
|
||||
}
|
||||
|
||||
func (nodeStat *NodeStat) FullNodeCount() string {
|
||||
return Uint64ToString(nodeStat.FullNodeCnt)
|
||||
}
|
||||
func (nodeStat *NodeStat) ValueNodeCount() string {
|
||||
return Uint64ToString(nodeStat.ValueNodeCnt)
|
||||
}
|
||||
|
||||
// NewInspector return a inspector obj
|
||||
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uint64, jobNum uint64, topN int) (*Inspector, error) {
|
||||
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uint64, jobnum uint64) (*Inspector, error) {
|
||||
if tr == nil {
|
||||
return nil, errors.New("trie is nil")
|
||||
}
|
||||
@@ -168,20 +131,15 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uin
|
||||
}
|
||||
|
||||
ins := &Inspector{
|
||||
trie: tr,
|
||||
db: db,
|
||||
stateRootHash: stateRootHash,
|
||||
blockNum: blockNum,
|
||||
root: tr.root,
|
||||
results: stat{},
|
||||
topN: topN,
|
||||
totalAccountNum: atomic.Uint64{},
|
||||
totalStorageNum: atomic.Uint64{},
|
||||
lastTime: mclock.Now(),
|
||||
sem: semaphore.NewWeighted(int64(jobNum)),
|
||||
|
||||
wg: sync.WaitGroup{},
|
||||
|
||||
trie: tr,
|
||||
db: db,
|
||||
stateRootHash: stateRootHash,
|
||||
blocknum: blocknum,
|
||||
root: tr.root,
|
||||
result: make(map[string]*TrieTreeStat),
|
||||
totalNum: (uint64)(0),
|
||||
wg: sync.WaitGroup{},
|
||||
sem: semaphore.NewWeighted(int64(jobnum)),
|
||||
eoaAccountNums: 0,
|
||||
}
|
||||
|
||||
@@ -189,123 +147,155 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uin
|
||||
}
|
||||
|
||||
// Run statistics, external call
|
||||
func (s *Inspector) Run() {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
if s.db.Scheme() == rawdb.HashScheme {
|
||||
s.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
}()
|
||||
|
||||
log.Info("Find Account Trie Tree", "rootHash: ", s.trie.Hash().String(), "BlockNum: ", s.blockNum)
|
||||
|
||||
ts := &trieStat{
|
||||
owner: common.Hash{},
|
||||
func (inspect *Inspector) Run() {
|
||||
accountTrieStat := &TrieTreeStat{
|
||||
is_account_trie: true,
|
||||
}
|
||||
s.traversal(s.trie, ts, s.root, 0, []byte{})
|
||||
s.results.add(ts, s.topN)
|
||||
s.wg.Wait()
|
||||
if inspect.db.Scheme() == rawdb.HashScheme {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if _, ok := inspect.result[""]; !ok {
|
||||
inspect.result[""] = accountTrieStat
|
||||
}
|
||||
log.Info("Find Account Trie Tree", "rootHash: ", inspect.trie.Hash().String(), "BlockNum: ", inspect.blocknum)
|
||||
|
||||
inspect.ConcurrentTraversal(inspect.trie, accountTrieStat, inspect.root, 0, []byte{})
|
||||
inspect.wg.Wait()
|
||||
}
|
||||
|
||||
func (s *Inspector) traversal(trie *Trie, ts *trieStat, n node, height int, path []byte) {
|
||||
func (inspect *Inspector) SubConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) {
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, theNode, height, path)
|
||||
inspect.wg.Done()
|
||||
}
|
||||
|
||||
func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) {
|
||||
// print process progress
|
||||
total_num := atomic.AddUint64(&inspect.totalNum, 1)
|
||||
if total_num%100000 == 0 {
|
||||
fmt.Printf("Complete progress: %v, go routines Num: %v\n", total_num, runtime.NumGoroutine())
|
||||
}
|
||||
|
||||
// nil node
|
||||
if n == nil {
|
||||
if theNode == nil {
|
||||
return
|
||||
}
|
||||
|
||||
ts.add(n, height)
|
||||
|
||||
switch current := (n).(type) {
|
||||
switch current := (theNode).(type) {
|
||||
case *shortNode:
|
||||
s.traversal(trie, ts, current.Val, height, append(path, current.Key...))
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, current.Val, height, append(path, current.Key...))
|
||||
case *fullNode:
|
||||
for idx, child := range current.Children {
|
||||
if child == nil {
|
||||
continue
|
||||
}
|
||||
p := common.CopyBytes(append(path, byte(idx)))
|
||||
s.traversal(trie, ts, child, height+1, p)
|
||||
childPath := append(path, byte(idx))
|
||||
if inspect.sem.TryAcquire(1) {
|
||||
inspect.wg.Add(1)
|
||||
dst := make([]byte, len(childPath))
|
||||
copy(dst, childPath)
|
||||
go inspect.SubConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, dst)
|
||||
} else {
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, childPath)
|
||||
}
|
||||
}
|
||||
case hashNode:
|
||||
tn, err := trie.resloveWithoutTrack(current, path)
|
||||
n, err := theTrie.resloveWithoutTrack(current, path)
|
||||
if err != nil {
|
||||
fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, trie.Hash().String(), height+1, path)
|
||||
fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, theTrie.Hash().String(), height+1, path)
|
||||
return
|
||||
}
|
||||
s.PrintProgress(trie)
|
||||
s.traversal(trie, ts, tn, height, path)
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, n, height, path)
|
||||
return
|
||||
case valueNode:
|
||||
if !hasTerm(path) {
|
||||
break
|
||||
}
|
||||
var account types.StateAccount
|
||||
var account Account
|
||||
if err := rlp.Decode(bytes.NewReader(current), &account); err != nil {
|
||||
break
|
||||
}
|
||||
if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash {
|
||||
s.eoaAccountNums++
|
||||
inspect.eoaAccountNums++
|
||||
}
|
||||
if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash {
|
||||
break
|
||||
}
|
||||
ownerAddress := common.BytesToHash(hexToCompact(path))
|
||||
contractTrie, err := New(StorageTrieID(s.stateRootHash, ownerAddress, account.Root), s.db)
|
||||
contractTrie, err := New(StorageTrieID(inspect.stateRootHash, ownerAddress, account.Root), inspect.db)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
fmt.Printf("New contract trie node: %v, error: %v, Height: %v, Path: %v\n", theNode, err, height, path)
|
||||
break
|
||||
}
|
||||
contractTrie.tracer.reset()
|
||||
|
||||
if s.sem.TryAcquire(1) {
|
||||
s.wg.Add(1)
|
||||
go func() {
|
||||
t := &trieStat{
|
||||
owner: ownerAddress,
|
||||
}
|
||||
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
|
||||
s.results.add(t, s.topN)
|
||||
s.sem.Release(1)
|
||||
s.wg.Done()
|
||||
}()
|
||||
} else {
|
||||
t := &trieStat{
|
||||
owner: ownerAddress,
|
||||
}
|
||||
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
|
||||
s.results.add(t, s.topN)
|
||||
trieStat := &TrieTreeStat{
|
||||
is_account_trie: false,
|
||||
}
|
||||
|
||||
inspect.statLock.Lock()
|
||||
if _, ok := inspect.result[ownerAddress.String()]; !ok {
|
||||
inspect.result[ownerAddress.String()] = trieStat
|
||||
}
|
||||
inspect.statLock.Unlock()
|
||||
|
||||
// log.Info("Find Contract Trie Tree, rootHash: ", contractTrie.Hash().String(), "")
|
||||
inspect.wg.Add(1)
|
||||
go inspect.SubConcurrentTraversal(contractTrie, trieStat, contractTrie.root, 0, []byte{})
|
||||
default:
|
||||
panic(errors.New("invalid node type to traverse"))
|
||||
panic(errors.New("Invalid node type to traverse."))
|
||||
}
|
||||
theTrieTreeStat.AtomicAdd(theNode, height)
|
||||
}
|
||||
|
||||
func (s *Inspector) PrintProgress(t *Trie) {
|
||||
var (
|
||||
elapsed = mclock.Now().Sub(s.lastTime)
|
||||
)
|
||||
if t.owner == (common.Hash{}) {
|
||||
s.totalAccountNum.Add(1)
|
||||
} else {
|
||||
s.totalStorageNum.Add(1)
|
||||
}
|
||||
if elapsed > 4*time.Second {
|
||||
log.Info("traversal progress", "TotalAccountNum", s.totalAccountNum.Load(), "TotalStorageNum", s.totalStorageNum.Load(), "Goroutine", runtime.NumGoroutine())
|
||||
s.lastTime = mclock.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Inspector) DisplayResult() {
|
||||
func (inspect *Inspector) DisplayResult() {
|
||||
// display root hash
|
||||
fmt.Println(s.results.account.Display("", "AccountTrie"))
|
||||
fmt.Println("EOA accounts num: ", s.eoaAccountNums)
|
||||
if _, ok := inspect.result[""]; !ok {
|
||||
log.Info("Display result error", "missing account trie")
|
||||
return
|
||||
}
|
||||
inspect.result[""].Display("", "AccountTrie")
|
||||
|
||||
type SortedTrie struct {
|
||||
totalNum uint64
|
||||
ownerAddress string
|
||||
}
|
||||
// display contract trie
|
||||
for _, st := range s.results.storageTopN {
|
||||
fmt.Println(st.Display(st.owner.String(), "StorageTrie"))
|
||||
var sortedTriesByNums []SortedTrie
|
||||
var totalContactsNodeStat NodeStat
|
||||
var contractTrieCnt uint64 = 0
|
||||
|
||||
for ownerAddress, stat := range inspect.result {
|
||||
if ownerAddress == "" {
|
||||
continue
|
||||
}
|
||||
contractTrieCnt++
|
||||
totalContactsNodeStat.ShortNodeCnt += stat.totalNodeStat.ShortNodeCnt
|
||||
totalContactsNodeStat.FullNodeCnt += stat.totalNodeStat.FullNodeCnt
|
||||
totalContactsNodeStat.ValueNodeCnt += stat.totalNodeStat.ValueNodeCnt
|
||||
totalNodeCnt := stat.totalNodeStat.ShortNodeCnt + stat.totalNodeStat.ValueNodeCnt + stat.totalNodeStat.FullNodeCnt
|
||||
sortedTriesByNums = append(sortedTriesByNums, SortedTrie{totalNum: totalNodeCnt, ownerAddress: ownerAddress})
|
||||
}
|
||||
sort.Slice(sortedTriesByNums, func(i, j int) bool {
|
||||
return sortedTriesByNums[i].totalNum > sortedTriesByNums[j].totalNum
|
||||
})
|
||||
fmt.Println("EOA accounts num: ", inspect.eoaAccountNums)
|
||||
// only display top 5
|
||||
for i, t := range sortedTriesByNums {
|
||||
if i > 5 {
|
||||
break
|
||||
}
|
||||
if stat, ok := inspect.result[t.ownerAddress]; !ok {
|
||||
log.Error("Storage trie stat not found", "ownerAddress", t.ownerAddress)
|
||||
} else {
|
||||
stat.Display(t.ownerAddress, "ContractTrie")
|
||||
}
|
||||
}
|
||||
fmt.Printf("Contract Trie, total trie num: %v, ShortNodeCnt: %v, FullNodeCnt: %v, ValueNodeCnt: %v\n",
|
||||
s.results.storageTrieNum, s.results.storageTotal.ShortNodeCnt.Load(), s.results.storageTotal.FullNodeCnt.Load(), s.results.storageTotal.ValueNodeCnt.Load())
|
||||
contractTrieCnt, totalContactsNodeStat.ShortNodeCnt, totalContactsNodeStat.FullNodeCnt, totalContactsNodeStat.ValueNodeCnt)
|
||||
}
|
||||
|
||||
20
trie/trie.go
20
trie/trie.go
@@ -21,14 +21,22 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"github.com/ethereum/go-ethereum/triedb/database"
|
||||
)
|
||||
|
||||
var (
|
||||
trieGetTimer = metrics.NewRegisteredTimer("trie/get/time", nil)
|
||||
trieReaderGetTimer = metrics.NewRegisteredTimer("trie/reader/get/time", nil)
|
||||
trieReaderTotalTimer = metrics.NewRegisteredTimer("trie/reader/total/time", nil)
|
||||
)
|
||||
|
||||
// Trie is a Merkle Patricia Trie. Use New to create a trie that sits on
|
||||
// top of a database. Whenever trie performs a commit operation, the generated
|
||||
// nodes will be gathered and returned in a set. Once the trie is committed,
|
||||
@@ -146,6 +154,10 @@ func (t *Trie) Get(key []byte) ([]byte, error) {
|
||||
if t.committed {
|
||||
return nil, ErrCommitted
|
||||
}
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { trieGetTimer.UpdateSince(start) }()
|
||||
}
|
||||
value, newroot, didResolve, err := t.get(t.root, keybytesToHex(key), 0)
|
||||
if err == nil && didResolve {
|
||||
t.root = newroot
|
||||
@@ -178,7 +190,11 @@ func (t *Trie) get(origNode node, key []byte, pos int) (value []byte, newnode no
|
||||
}
|
||||
return value, n, didResolve, err
|
||||
case hashNode:
|
||||
start := time.Now()
|
||||
child, err := t.resolveAndTrack(n, key[:pos])
|
||||
if metrics.EnabledExpensive {
|
||||
trieReaderGetTimer.UpdateSince(start)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, n, true, err
|
||||
}
|
||||
@@ -586,6 +602,10 @@ func (t *Trie) resolve(n node, prefix []byte) (node, error) {
|
||||
// node's original value. The rlp-encoded blob is preferred to be loaded from
|
||||
// database because it's easy to decode node while complex to encode node to blob.
|
||||
func (t *Trie) resolveAndTrack(n hashNode, prefix []byte) (node, error) {
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { trieReaderTotalTimer.UpdateSince(start) }()
|
||||
}
|
||||
blob, err := t.reader.node(prefix, common.BytesToHash(n))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -98,7 +98,7 @@ type tester struct {
|
||||
|
||||
func newTester(t *testing.T, historyLimit uint64) *tester {
|
||||
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{
|
||||
StateHistory: historyLimit,
|
||||
CleanCacheSize: 256 * 1024,
|
||||
|
||||
@@ -19,6 +19,7 @@ package pathdb
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
@@ -26,106 +27,6 @@ import (
|
||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
||||
)
|
||||
|
||||
type RefTrieNode struct {
|
||||
refCount uint32
|
||||
node *trienode.Node
|
||||
}
|
||||
|
||||
type HashNodeCache struct {
|
||||
lock sync.RWMutex
|
||||
cache map[common.Hash]*RefTrieNode
|
||||
}
|
||||
|
||||
func (h *HashNodeCache) length() int {
|
||||
if h == nil {
|
||||
return 0
|
||||
}
|
||||
h.lock.RLock()
|
||||
defer h.lock.RUnlock()
|
||||
return len(h.cache)
|
||||
}
|
||||
|
||||
func (h *HashNodeCache) set(hash common.Hash, node *trienode.Node) {
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
if n, ok := h.cache[hash]; ok {
|
||||
n.refCount++
|
||||
} else {
|
||||
h.cache[hash] = &RefTrieNode{1, node}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HashNodeCache) Get(hash common.Hash) *trienode.Node {
|
||||
if h == nil {
|
||||
return nil
|
||||
}
|
||||
h.lock.RLock()
|
||||
defer h.lock.RUnlock()
|
||||
if n, ok := h.cache[hash]; ok {
|
||||
return n.node
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *HashNodeCache) del(hash common.Hash) {
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
h.lock.Lock()
|
||||
defer h.lock.Unlock()
|
||||
n, ok := h.cache[hash]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
if n.refCount > 0 {
|
||||
n.refCount--
|
||||
}
|
||||
if n.refCount == 0 {
|
||||
delete(h.cache, hash)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *HashNodeCache) Add(ly layer) {
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
dl, ok := ly.(*diffLayer)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
beforeAdd := h.length()
|
||||
for _, subset := range dl.nodes {
|
||||
for _, node := range subset {
|
||||
h.set(node.Hash, node)
|
||||
}
|
||||
}
|
||||
diffHashCacheLengthGauge.Update(int64(h.length()))
|
||||
log.Debug("Add difflayer to hash map", "root", ly.rootHash(), "block_number", dl.block, "map_len", h.length(), "add_delta", h.length()-beforeAdd)
|
||||
}
|
||||
|
||||
func (h *HashNodeCache) Remove(ly layer) {
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
dl, ok := ly.(*diffLayer)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
beforeDel := h.length()
|
||||
for _, subset := range dl.nodes {
|
||||
for _, node := range subset {
|
||||
h.del(node.Hash)
|
||||
}
|
||||
}
|
||||
diffHashCacheLengthGauge.Update(int64(h.length()))
|
||||
log.Debug("Remove difflayer from hash map", "root", ly.rootHash(), "block_number", dl.block, "map_len", h.length(), "del_delta", beforeDel-h.length())
|
||||
}()
|
||||
}
|
||||
|
||||
// diffLayer represents a collection of modifications made to the in-memory tries
|
||||
// along with associated state changes after running a block on top.
|
||||
//
|
||||
@@ -139,10 +40,7 @@ type diffLayer struct {
|
||||
nodes map[common.Hash]map[string]*trienode.Node // Cached trie nodes indexed by owner and path
|
||||
states *triestate.Set // Associated state change set for building history
|
||||
memory uint64 // Approximate guess as to how much memory we use
|
||||
cache *HashNodeCache // trienode cache by hash key. cache is immutable, but cache's item can be add/del.
|
||||
|
||||
// mutables
|
||||
origin *diskLayer // The current difflayer corresponds to the underlying disklayer and is updated during cap.
|
||||
parent layer // Parent layer modified by this one, never nil, **can be changed**
|
||||
lock sync.RWMutex // Lock used to protect parent
|
||||
}
|
||||
@@ -161,20 +59,6 @@ func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes
|
||||
states: states,
|
||||
parent: parent,
|
||||
}
|
||||
|
||||
switch l := parent.(type) {
|
||||
case *diskLayer:
|
||||
dl.origin = l
|
||||
dl.cache = &HashNodeCache{
|
||||
cache: make(map[common.Hash]*RefTrieNode),
|
||||
}
|
||||
case *diffLayer:
|
||||
dl.origin = l.originDiskLayer()
|
||||
dl.cache = l.cache
|
||||
default:
|
||||
panic("unknown parent type")
|
||||
}
|
||||
|
||||
for _, subset := range nodes {
|
||||
for path, n := range subset {
|
||||
dl.memory += uint64(n.Size() + len(path))
|
||||
@@ -192,12 +76,6 @@ func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes
|
||||
return dl
|
||||
}
|
||||
|
||||
func (dl *diffLayer) originDiskLayer() *diskLayer {
|
||||
dl.lock.RLock()
|
||||
defer dl.lock.RUnlock()
|
||||
return dl.origin
|
||||
}
|
||||
|
||||
// rootHash implements the layer interface, returning the root hash of
|
||||
// corresponding state.
|
||||
func (dl *diffLayer) rootHash() common.Hash {
|
||||
@@ -227,6 +105,8 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
|
||||
dl.lock.RLock()
|
||||
defer dl.lock.RUnlock()
|
||||
|
||||
start := time.Now()
|
||||
|
||||
// If the trie node is known locally, return it
|
||||
subset, ok := dl.nodes[owner]
|
||||
if ok {
|
||||
@@ -237,14 +117,18 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
|
||||
if n.Hash != hash {
|
||||
dirtyFalseMeter.Mark(1)
|
||||
log.Error("Unexpected trie node in diff layer", "owner", owner, "path", path, "expect", hash, "got", n.Hash)
|
||||
pathGetDiffLayerTimer.UpdateSince(start)
|
||||
return nil, newUnexpectedNodeError("diff", hash, n.Hash, owner, path, n.Blob)
|
||||
}
|
||||
dirtyHitMeter.Mark(1)
|
||||
dirtyNodeHitDepthHist.Update(int64(depth))
|
||||
dirtyReadMeter.Mark(int64(len(n.Blob)))
|
||||
pathGetDiffLayerTimer.UpdateSince(start)
|
||||
return n.Blob, nil
|
||||
}
|
||||
}
|
||||
pathGetDiffLayerTimer.UpdateSince(start)
|
||||
|
||||
// Trie node unknown to this layer, resolve from parent
|
||||
if diff, ok := dl.parent.(*diffLayer); ok {
|
||||
return diff.node(owner, path, hash, depth+1)
|
||||
@@ -256,32 +140,6 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, hash common.Hash, dept
|
||||
// Node implements the layer interface, retrieving the trie node blob with the
|
||||
// provided node information. No error will be returned if the node is not found.
|
||||
func (dl *diffLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
|
||||
if n := dl.cache.Get(hash); n != nil {
|
||||
// The query from the hash map is fastpath,
|
||||
// avoiding recursive query of 128 difflayers.
|
||||
diffHashCacheHitMeter.Mark(1)
|
||||
diffHashCacheReadMeter.Mark(int64(len(n.Blob)))
|
||||
return n.Blob, nil
|
||||
}
|
||||
diffHashCacheMissMeter.Mark(1)
|
||||
|
||||
persistLayer := dl.originDiskLayer()
|
||||
if persistLayer != nil {
|
||||
blob, err := persistLayer.Node(owner, path, hash)
|
||||
if err != nil {
|
||||
// This is a bad case with a very low probability.
|
||||
// r/w the difflayer cache and r/w the disklayer are not in the same lock,
|
||||
// so in extreme cases, both reading the difflayer cache and reading the disklayer may fail, eg, disklayer is stale.
|
||||
// In this case, fallback to the original 128-layer recursive difflayer query path.
|
||||
diffHashCacheSlowPathMeter.Mark(1)
|
||||
log.Debug("Retry difflayer due to query origin failed", "owner", owner, "path", path, "hash", hash.String(), "error", err)
|
||||
return dl.node(owner, path, hash, 0)
|
||||
} else { // This is the fastpath.
|
||||
return blob, nil
|
||||
}
|
||||
}
|
||||
diffHashCacheSlowPathMeter.Mark(1)
|
||||
log.Debug("Retry difflayer due to origin is nil", "owner", owner, "path", path, "hash", hash.String())
|
||||
return dl.node(owner, path, hash, 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/fastcache"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -27,6 +28,7 @@ import (
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/metrics"
|
||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
||||
"golang.org/x/crypto/sha3"
|
||||
@@ -155,6 +157,10 @@ func (dl *diskLayer) markStale() {
|
||||
func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
|
||||
dl.lock.RLock()
|
||||
defer dl.lock.RUnlock()
|
||||
if metrics.EnabledExpensive {
|
||||
start := time.Now()
|
||||
defer func() { pathGetDiskLayerTimer.UpdateSince(start) }()
|
||||
}
|
||||
|
||||
if dl.stale {
|
||||
return nil, errSnapshotStale
|
||||
@@ -286,9 +292,6 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
|
||||
}
|
||||
log.Debug("Pruned state history", "items", pruned, "tailid", oldest)
|
||||
}
|
||||
|
||||
// The bottom has been eaten by disklayer, releasing the hash cache of bottom difflayer.
|
||||
bottom.cache.Remove(bottom)
|
||||
return ndl, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -152,13 +152,12 @@ func (kr *JournalKVReader) Close() {
|
||||
}
|
||||
|
||||
func newJournalWriter(file string, db ethdb.Database, journalType JournalType) JournalWriter {
|
||||
log.Info("New journal writer", "path", file, "journalType", journalType)
|
||||
if journalType == JournalKVType {
|
||||
log.Info("New journal writer for journal kv")
|
||||
return &JournalKVWriter{
|
||||
diskdb: db,
|
||||
}
|
||||
} 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)
|
||||
if err != 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) {
|
||||
log.Info("New journal reader", "path", file, "journalType", journalType)
|
||||
if journalType == JournalKVType {
|
||||
log.Info("New journal reader for journal kv")
|
||||
journal := rawdb.ReadTrieJournal(db)
|
||||
if len(journal) == 0 {
|
||||
return nil, errMissJournal
|
||||
@@ -180,7 +179,6 @@ func newJournalReader(file string, db ethdb.Database, journalType JournalType) (
|
||||
journalBuf: bytes.NewBuffer(journal),
|
||||
}, nil
|
||||
} else {
|
||||
log.Info("New journal reader for journal file", "path", file)
|
||||
fd, err := os.Open(file)
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
return nil, errMissJournal
|
||||
|
||||
@@ -51,20 +51,9 @@ func (tree *layerTree) reset(head layer) {
|
||||
tree.lock.Lock()
|
||||
defer tree.lock.Unlock()
|
||||
|
||||
for _, ly := range tree.layers {
|
||||
if dl, ok := ly.(*diffLayer); ok {
|
||||
// Clean up the hash cache of difflayers due to reset.
|
||||
dl.cache.Remove(dl)
|
||||
}
|
||||
}
|
||||
|
||||
var layers = make(map[common.Hash]layer)
|
||||
for head != nil {
|
||||
layers[head.rootHash()] = head
|
||||
if dl, ok := head.(*diffLayer); ok {
|
||||
// Add the hash cache of difflayers due to reset.
|
||||
dl.cache.Add(dl)
|
||||
}
|
||||
head = head.parentLayer()
|
||||
}
|
||||
tree.layers = layers
|
||||
@@ -109,19 +98,12 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6
|
||||
if root == parentRoot {
|
||||
return errors.New("layer cycle")
|
||||
}
|
||||
if tree.get(root) != nil {
|
||||
log.Info("Skip add repeated difflayer", "root", root.String(), "block_id", block)
|
||||
return nil
|
||||
}
|
||||
parent := tree.get(parentRoot)
|
||||
if parent == nil {
|
||||
return fmt.Errorf("triedb parent [%#x] layer missing", parentRoot)
|
||||
}
|
||||
l := parent.update(root, parent.stateID()+1, block, nodes.Flatten(), states)
|
||||
|
||||
// Before adding layertree, update the hash cache.
|
||||
l.cache.Add(l)
|
||||
|
||||
tree.lock.Lock()
|
||||
tree.layers[l.rootHash()] = l
|
||||
tree.lock.Unlock()
|
||||
@@ -150,15 +132,8 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ly := range tree.layers {
|
||||
if dl, ok := ly.(*diffLayer); ok {
|
||||
dl.cache.Remove(dl)
|
||||
log.Debug("Cleanup difflayer hash cache due to cap all", "diff_root", dl.root.String(), "diff_block_number", dl.block)
|
||||
}
|
||||
}
|
||||
// Replace the entire layer tree with the flat base
|
||||
tree.layers = map[common.Hash]layer{base.rootHash(): base}
|
||||
log.Debug("Cap all difflayers to disklayer", "disk_root", base.rootHash().String())
|
||||
return nil
|
||||
}
|
||||
// Dive until we run out of layers or reach the persistent database
|
||||
@@ -171,7 +146,6 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
var persisted *diskLayer
|
||||
// We're out of layers, flatten anything below, stopping if it's the disk or if
|
||||
// the memory limit is not yet exceeded.
|
||||
switch parent := diff.parentLayer().(type) {
|
||||
@@ -192,7 +166,6 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
|
||||
diff.parent = base
|
||||
|
||||
diff.lock.Unlock()
|
||||
persisted = base.(*diskLayer)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown data layer in triedb: %T", parent))
|
||||
@@ -207,13 +180,6 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
|
||||
}
|
||||
var remove func(root common.Hash)
|
||||
remove = func(root common.Hash) {
|
||||
if df, exist := tree.layers[root]; exist {
|
||||
if dl, ok := df.(*diffLayer); ok {
|
||||
// Clean up the hash cache of the child difflayer corresponding to the stale parent, include the re-org case.
|
||||
dl.cache.Remove(dl)
|
||||
log.Debug("Cleanup difflayer hash cache due to reorg", "diff_root", dl.root.String(), "diff_block_number", dl.block)
|
||||
}
|
||||
}
|
||||
delete(tree.layers, root)
|
||||
for _, child := range children[root] {
|
||||
remove(child)
|
||||
@@ -223,25 +189,8 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
|
||||
for root, layer := range tree.layers {
|
||||
if dl, ok := layer.(*diskLayer); ok && dl.isStale() {
|
||||
remove(root)
|
||||
log.Debug("Remove stale the disklayer", "disk_root", dl.root.String())
|
||||
}
|
||||
}
|
||||
|
||||
if persisted != nil {
|
||||
var updateOriginFunc func(root common.Hash)
|
||||
updateOriginFunc = func(root common.Hash) {
|
||||
if diff, ok := tree.layers[root].(*diffLayer); ok {
|
||||
diff.lock.Lock()
|
||||
diff.origin = persisted
|
||||
diff.lock.Unlock()
|
||||
}
|
||||
for _, child := range children[root] {
|
||||
updateOriginFunc(child)
|
||||
}
|
||||
}
|
||||
updateOriginFunc(persisted.root)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -48,9 +48,6 @@ var (
|
||||
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil)
|
||||
historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil)
|
||||
|
||||
diffHashCacheHitMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/hit", nil)
|
||||
diffHashCacheReadMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/read", nil)
|
||||
diffHashCacheMissMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/miss", nil)
|
||||
diffHashCacheSlowPathMeter = metrics.NewRegisteredMeter("pathdb/difflayer/hashcache/slowpath", nil)
|
||||
diffHashCacheLengthGauge = metrics.NewRegisteredGauge("pathdb/difflayer/hashcache/size", nil)
|
||||
pathGetDiffLayerTimer = metrics.NewRegisteredTimer("pathdb/get/difflayer/time", nil)
|
||||
pathGetDiskLayerTimer = metrics.NewRegisteredTimer("pathdb/get/disklayer/time", nil)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user