Compare commits

..

27 Commits

Author SHA1 Message Date
galaio
3a3eb1d34f metrics: add more metrics; 2024-06-12 20:26:16 +08:00
galaio
a702225a27 metrics: add more metrics; 2024-06-12 20:18:23 +08:00
galaio
78b0f2940a metrics: add more metrics; 2024-06-12 15:17:25 +08:00
galaio
31a16b3fb8 metrics: add more metrics; 2024-06-12 14:55:32 +08:00
galaio
adf9b91f8f log: opt some log format; 2024-06-12 14:23:02 +08:00
galaio
312f1208f8 dag: fix some unexpected writes; 2024-06-11 21:07:14 +08:00
galaio
6957903492 log: add some logs; 2024-06-11 18:06:54 +08:00
galaio
2da9923d4f log: add some logs; 2024-06-11 17:43:21 +08:00
galaio
c6368a513c log: add some logs; 2024-06-11 16:57:10 +08:00
galaio
a55650056a log: add some logs; 2024-06-11 16:32:42 +08:00
galaio
71520fb59e log: add some logs; 2024-06-11 16:04:45 +08:00
galaio
7cb7800397 log: add some logs; 2024-06-11 15:55:46 +08:00
galaio
d97a34b0cb log: add some logs; 2024-06-11 14:14:14 +08:00
galaio
c20c0e680c log: add some logs; 2024-06-11 14:08:04 +08:00
galaio
b5194c043b log: add some logs; 2024-06-11 12:20:58 +08:00
galaio
6f8e9c570c log: add some logs; 2024-06-11 11:25:34 +08:00
galaio
68fa227b0c dag: opt read recoder logic; 2024-06-10 22:31:39 +08:00
galaio
2d8613a296 dag: opt read recoder logic; 2024-06-10 21:51:37 +08:00
galaio
533f592a05 dag: opt read recoder logic; 2024-06-10 21:44:44 +08:00
galaio
6d1d2ddea5 dag: opt evaluate function; 2024-06-10 20:53:14 +08:00
galaio
bb578de461 dag: opt evaluate function; 2024-06-09 00:01:14 +08:00
galaio
2d0ddc1f67 dag: support stats; 2024-06-08 14:33:24 +08:00
galaio
eff9d23bd2 mvstates: fix val equal check issue; 2024-06-07 22:46:30 +08:00
galaio
98fa1e6c44 mvstates: fix val equal check issue; 2024-06-07 22:39:44 +08:00
galaio
eafdc65814 statedb: fix some system tx issues; 2024-06-07 17:08:23 +08:00
galaio
1a787b6081 rwset: support collect rwset from statedb;
mvstates: support export DAG;
dag: support travel all execution paths;
2024-06-07 16:46:13 +08:00
galaio
1cb6989a30 dag: add basic data structures; 2024-06-06 16:25:12 +08:00
100 changed files with 2402 additions and 1789 deletions

View File

@@ -1,2 +1 @@
CVE-2024-34478 # "CWE-754: Improper Check for Unusual or Exceptional Conditions." This vulnerability is BTC only, BSC does not have the issue. CVE-2024-34478 # "CWE-754: Improper Check for Unusual or Exceptional Conditions." This vulnerability is BTC only, BSC does not have the issue.
CVE-2024-6104 # "CWE-532: Information Exposure Through Log Files" This is caused by the vulnerabilities go-retryablehttp@v0.7.4, it is only used in cmd devp2p, impact is limited. will upgrade to v0.7.7 later

View File

@@ -1,79 +1,4 @@
# Changelog # Changelog
## v1.4.12
### BUGFIX
* [\#2557](https://github.com/bnb-chain/bsc/pull/2557) fix: fix state inspect error after pruned state
* [\#2562](https://github.com/bnb-chain/bsc/pull/2562) fix: delete unexpected block
* [\#2566](https://github.com/bnb-chain/bsc/pull/2566) core: avoid to cache block before wroten into db
* [\#2567](https://github.com/bnb-chain/bsc/pull/2567) fix: fix statedb copy
* [\#2574](https://github.com/bnb-chain/bsc/pull/2574) core: adapt highestVerifiedHeader to FastFinality
* [\#2542](https://github.com/bnb-chain/bsc/pull/2542) fix: pruneancient freeze from the previous position when the first time
* [\#2564](https://github.com/bnb-chain/bsc/pull/2564) fix: the bug of blobsidecars and downloader with multi-database
* [\#2582](https://github.com/bnb-chain/bsc/pull/2582) fix: remove delete and dangling side chains in prunefreezer
### FEATURE
* [\#2513](https://github.com/bnb-chain/bsc/pull/2513) cmd/jsutils: add a tool to get performance between a range of blocks
* [\#2569](https://github.com/bnb-chain/bsc/pull/2569) cmd/jsutils: add a tool to get slash count
* [\#2583](https://github.com/bnb-chain/bsc/pull/2583) cmd/jsutill: add log about validator name
### IMPROVEMENT
* [\#2546](https://github.com/bnb-chain/bsc/pull/2546) go.mod: update missing dependency
* [\#2559](https://github.com/bnb-chain/bsc/pull/2559) nancy: ignore go-retryablehttp@v0.7.4 in .nancy-ignore
* [\#2556](https://github.com/bnb-chain/bsc/pull/2556) chore: update greenfield cometbft version
* [\#2561](https://github.com/bnb-chain/bsc/pull/2561) tests: fix unstable test
* [\#2572](https://github.com/bnb-chain/bsc/pull/2572) core: clearup testflag for Cancun and Haber
* [\#2573](https://github.com/bnb-chain/bsc/pull/2573) cmd/utils: support use NetworkId to distinguish chapel when do syncing
* [\#2538](https://github.com/bnb-chain/bsc/pull/2538) feat: enhance bid comparison and reply bidding results && detail logs
* [\#2568](https://github.com/bnb-chain/bsc/pull/2568) core/vote: not vote if too late for next in turn validator
* [\#2576](https://github.com/bnb-chain/bsc/pull/2576) miner/worker: broadcast block immediately once sealed
* [\#2580](https://github.com/bnb-chain/bsc/pull/2580) freezer: Opt freezer env checking
## 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 ## v1.4.8
### FEATURE ### FEATURE
* [\#2483](https://github.com/bnb-chain/bsc/pull/2483) core/vm: add secp256r1 into PrecompiledContractsHaber * [\#2483](https://github.com/bnb-chain/bsc/pull/2483) core/vm: add secp256r1 into PrecompiledContractsHaber

View File

@@ -149,6 +149,8 @@ unzip testnet.zip
#### 3. Download snapshot #### 3. Download snapshot
Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files. Download latest chaindata snapshot from [here](https://github.com/bnb-chain/bsc-snapshots). Follow the guide to structure your files.
Note: If you encounter difficulties downloading the chaindata snapshot and prefer to synchronize from the genesis block on the Chapel testnet, remember to include the additional flag `--chapel` when initially launching Geth.
#### 4. Start a full node #### 4. Start a full node
```shell ```shell
./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0 ./geth --config ./config.toml --datadir ./node --cache 8000 --rpc.allow-unprotected-txs --history.transactions 0

View File

@@ -227,7 +227,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
return nil, nil, nil, err return nil, nil, nil, err
} }
vmConfig.Tracer = tracer vmConfig.Tracer = tracer
statedb.SetTxContext(tx.Hash(), txIndex) statedb.SetTxContext(tx.Hash(), txIndex, 0)
var ( var (
txContext = core.NewEVMTxContext(msg) txContext = core.NewEVMTxContext(msg)

View File

@@ -642,7 +642,7 @@ func (f *faucet) loop() {
f.lock.RUnlock() f.lock.RUnlock()
} }
}() }()
// Wait for various events and assign to the appropriate background threads // Wait for various events and assing to the appropriate background threads
for { for {
select { select {
case head := <-heads: case head := <-heads:

View File

@@ -62,9 +62,10 @@ var (
ArgsUsage: "<genesisPath>", ArgsUsage: "<genesisPath>",
Flags: flags.Merge([]cli.Flag{ Flags: flags.Merge([]cli.Flag{
utils.CachePreimagesFlag, utils.CachePreimagesFlag,
utils.OverrideCancun,
utils.OverrideHaber,
utils.OverrideBohr, utils.OverrideBohr,
utils.OverrideVerkle, utils.OverrideVerkle,
utils.MultiDataBaseFlag,
}, utils.DatabaseFlags), }, utils.DatabaseFlags),
Description: ` Description: `
The init command initializes a new genesis block and definition for the network. The init command initializes a new genesis block and definition for the network.
@@ -253,6 +254,14 @@ func initGenesis(ctx *cli.Context) error {
defer stack.Close() defer stack.Close()
var overrides core.ChainOverrides var overrides core.ChainOverrides
if ctx.IsSet(utils.OverrideCancun.Name) {
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) { if ctx.IsSet(utils.OverrideBohr.Name) {
v := ctx.Uint64(utils.OverrideBohr.Name) v := ctx.Uint64(utils.OverrideBohr.Name)
overrides.OverrideBohr = &v overrides.OverrideBohr = &v
@@ -760,7 +769,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
arg := ctx.Args().First() arg := ctx.Args().First()
if hashish(arg) { if hashish(arg) {
hash := common.HexToHash(arg) hash := common.HexToHash(arg)
if number := rawdb.ReadHeaderNumber(db, hash); number != nil { if number := rawdb.ReadHeaderNumber(db.BlockStore(), hash); number != nil {
header = rawdb.ReadHeader(db, hash, *number) header = rawdb.ReadHeader(db, hash, *number)
} else { } else {
return nil, nil, common.Hash{}, fmt.Errorf("block %x not found", hash) return nil, nil, common.Hash{}, fmt.Errorf("block %x not found", hash)

View File

@@ -185,6 +185,14 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
params.RialtoGenesisHash = common.HexToHash(v) params.RialtoGenesisHash = common.HexToHash(v)
} }
if ctx.IsSet(utils.OverrideCancun.Name) {
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) { if ctx.IsSet(utils.OverrideBohr.Name) {
v := ctx.Uint64(utils.OverrideBohr.Name) v := ctx.Uint64(utils.OverrideBohr.Name)
cfg.Eth.OverrideBohr = &v cfg.Eth.OverrideBohr = &v

View File

@@ -397,8 +397,8 @@ func inspectTrie(ctx *cli.Context) error {
var headerBlockHash common.Hash var headerBlockHash common.Hash
if ctx.NArg() >= 1 { if ctx.NArg() >= 1 {
if ctx.Args().Get(0) == "latest" { if ctx.Args().Get(0) == "latest" {
headerHash := rawdb.ReadHeadHeaderHash(db) headerHash := rawdb.ReadHeadHeaderHash(db.BlockStore())
blockNumber = *(rawdb.ReadHeaderNumber(db, headerHash)) blockNumber = *(rawdb.ReadHeaderNumber(db.BlockStore(), headerHash))
} else if ctx.Args().Get(0) == "snapshot" { } else if ctx.Args().Get(0) == "snapshot" {
trieRootHash = rawdb.ReadSnapshotRoot(db) trieRootHash = rawdb.ReadSnapshotRoot(db)
blockNumber = math.MaxUint64 blockNumber = math.MaxUint64
@@ -406,7 +406,7 @@ func inspectTrie(ctx *cli.Context) error {
var err error var err error
blockNumber, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64) blockNumber, err = strconv.ParseUint(ctx.Args().Get(0), 10, 64)
if err != nil { if err != nil {
return fmt.Errorf("failed to parse blocknum, Args[0]: %v, err: %v", ctx.Args().Get(0), err) return fmt.Errorf("failed to Parse blocknum, Args[0]: %v, err: %v", ctx.Args().Get(0), err)
} }
} }
@@ -417,26 +417,26 @@ func inspectTrie(ctx *cli.Context) error {
var err error var err error
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64) jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
if err != nil { if err != nil {
return fmt.Errorf("failed to parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err) return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
} }
topN = 10 topN = 10
} else { } else {
var err error var err error
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64) jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
if err != nil { if err != nil {
return fmt.Errorf("failed to parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err) return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
} }
topN, err = strconv.ParseUint(ctx.Args().Get(2), 10, 64) topN, err = strconv.ParseUint(ctx.Args().Get(2), 10, 64)
if err != nil { 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 topn, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
} }
} }
if blockNumber != math.MaxUint64 { if blockNumber != math.MaxUint64 {
headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber) headerBlockHash = rawdb.ReadCanonicalHash(db, blockNumber)
if headerBlockHash == (common.Hash{}) { if headerBlockHash == (common.Hash{}) {
return errors.New("ReadHeadBlockHash empty hash") return errors.New("ReadHeadBlockHash empry hash")
} }
blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber) blockHeader := rawdb.ReadHeader(db, headerBlockHash, blockNumber)
trieRootHash = blockHeader.Root trieRootHash = blockHeader.Root
@@ -508,7 +508,7 @@ func ancientInspect(ctx *cli.Context) error {
stack, _ := makeConfigNode(ctx) stack, _ := makeConfigNode(ctx)
defer stack.Close() defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, true, false) db := utils.MakeChainDatabase(ctx, stack, true, true)
defer db.Close() defer db.Close()
return rawdb.AncientInspect(db) return rawdb.AncientInspect(db)
} }
@@ -1212,7 +1212,7 @@ func showMetaData(ctx *cli.Context) error {
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err) fmt.Fprintf(os.Stderr, "Error accessing ancients: %v", err)
} }
data := rawdb.ReadChainMetadata(db) data := rawdb.ReadChainMetadataFromMultiDatabase(db)
data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)}) data = append(data, []string{"frozen", fmt.Sprintf("%d items", ancients)})
data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))}) data = append(data, []string{"snapshotGenerator", snapshot.ParseGeneratorStatus(rawdb.ReadSnapshotGenerator(db))})
if b := rawdb.ReadHeadBlock(db); b != nil { if b := rawdb.ReadHeadBlock(db); b != nil {
@@ -1255,7 +1255,7 @@ func hbss2pbss(ctx *cli.Context) error {
defer stack.Close() defer stack.Close()
db := utils.MakeChainDatabase(ctx, stack, false, false) db := utils.MakeChainDatabase(ctx, stack, false, false)
db.BlockStore().Sync() db.Sync()
stateDiskDb := db.StateStore() stateDiskDb := db.StateStore()
defer db.Close() defer db.Close()
@@ -1273,8 +1273,8 @@ func hbss2pbss(ctx *cli.Context) error {
log.Info("hbss2pbss triedb", "scheme", triedb.Scheme()) log.Info("hbss2pbss triedb", "scheme", triedb.Scheme())
defer triedb.Close() defer triedb.Close()
headerHash := rawdb.ReadHeadHeaderHash(db) headerHash := rawdb.ReadHeadHeaderHash(db.BlockStore())
blockNumber := rawdb.ReadHeaderNumber(db, headerHash) blockNumber := rawdb.ReadHeaderNumber(db.BlockStore(), headerHash)
if blockNumber == nil { if blockNumber == nil {
log.Error("read header number failed.") log.Error("read header number failed.")
return fmt.Errorf("read header number failed") return fmt.Errorf("read header number failed")

View File

@@ -72,6 +72,8 @@ var (
utils.USBFlag, utils.USBFlag,
utils.SmartCardDaemonPathFlag, utils.SmartCardDaemonPathFlag,
utils.RialtoHash, utils.RialtoHash,
utils.OverrideCancun,
utils.OverrideHaber,
utils.OverrideBohr, utils.OverrideBohr,
utils.OverrideVerkle, utils.OverrideVerkle,
utils.OverrideFullImmutabilityThreshold, utils.OverrideFullImmutabilityThreshold,
@@ -125,7 +127,6 @@ var (
utils.CacheSnapshotFlag, utils.CacheSnapshotFlag,
// utils.CacheNoPrefetchFlag, // utils.CacheNoPrefetchFlag,
utils.CachePreimagesFlag, utils.CachePreimagesFlag,
utils.MultiDataBaseFlag,
utils.PersistDiffFlag, utils.PersistDiffFlag,
utils.DiffBlockFlag, utils.DiffBlockFlag,
utils.PruneAncientDataFlag, utils.PruneAncientDataFlag,
@@ -335,6 +336,9 @@ func prepare(ctx *cli.Context) {
5. Networking is disabled; there is no listen-address, the maximum number of peers is set 5. Networking is disabled; there is no listen-address, the maximum number of peers is set
to 0, and discovery is disabled. to 0, and discovery is disabled.
`) `)
case !ctx.IsSet(utils.NetworkIdFlag.Name):
log.Info("Starting Geth on BSC mainnet...")
} }
// If we're a full node on mainnet without --cache specified, bump default cache allowance // If we're a full node on mainnet without --cache specified, bump default cache allowance
if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) { if !ctx.IsSet(utils.CacheFlag.Name) && !ctx.IsSet(utils.NetworkIdFlag.Name) {

View File

@@ -155,12 +155,6 @@ func BlockchainCreator(t *testing.T, chaindbPath, AncientPath string, blockRemai
triedb := triedb.NewDatabase(db, nil) triedb := triedb.NewDatabase(db, nil)
defer triedb.Close() defer triedb.Close()
if err = db.SetupFreezerEnv(&ethdb.FreezerEnv{
ChainCfg: gspec.Config,
BlobExtraReserve: params.DefaultExtraReserveForBlobRequests,
}); err != nil {
t.Fatalf("Failed to create chain: %v", err)
}
genesis := gspec.MustCommit(db, triedb) genesis := gspec.MustCommit(db, triedb)
// Initialize a fresh chain with only a genesis block // Initialize a fresh chain with only a genesis block
blockchain, err := core.NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) blockchain, err := core.NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)

View File

@@ -25,23 +25,3 @@ testnet validators version
```bash ```bash
node gettxcount.js --rpc ${url} --startNum ${start} --endNum ${end} --miner ${miner} (optional) node gettxcount.js --rpc ${url} --startNum ${start} --endNum ${end} --miner ${miner} (optional)
``` ```
### 3. Get Performance
```bash
node get_perf.js --rpc ${url} --startNum ${start} --endNum ${end}
```
output as following
```bash
Get the performance between [ 19470 , 19670 )
txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975
txCountPerSecond = 1045.8602329450914 avgGasUsedPerBlock = 250.02062627 avgGasUsedPerSecond = 83.20153952412646
```
### 4. Get validators slash count
```bash
use the latest block
node getslashcount.js --Rpc ${ArchiveRpc}
use a block number
node getslashcount.js --Rpc ${ArchiveRpc} --Num ${blockNum}
```

View File

@@ -1,58 +0,0 @@
import { ethers } from "ethers";
import program from "commander";
program.option("--rpc <rpc>", "Rpc");
program.option("--startNum <startNum>", "start num")
program.option("--endNum <endNum>", "end num")
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.rpc)
const main = async () => {
let txCountTotal = 0;
let gasUsedTotal = 0;
let inturnBlocks = 0;
for (let i = program.startNum; i < program.endNum; i++) {
let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]);
txCountTotal += ethers.toNumber(txCount)
let header = await provider.send("eth_getHeaderByNumber", [
ethers.toQuantity(i)]);
let gasUsed = eval(eval(header.gasUsed).toString(10))
gasUsedTotal += gasUsed
let difficulty = eval(eval(header.difficulty).toString(10))
if (difficulty == 2) {
inturnBlocks += 1
}
let timestamp = eval(eval(header.timestamp).toString(10))
console.log("BlockNumber =", i, "mod =", i%4, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp)
}
let blockCount = program.endNum - program.startNum
let txCountPerBlock = txCountTotal/blockCount
let startHeader = await provider.send("eth_getHeaderByNumber", [
ethers.toQuantity(program.startNum)]);
let startTime = eval(eval(startHeader.timestamp).toString(10))
let endHeader = await provider.send("eth_getHeaderByNumber", [
ethers.toQuantity(program.endNum)]);
let endTime = eval(eval(endHeader.timestamp).toString(10))
let timeCost = endTime - startTime
let avgBlockTime = timeCost/blockCount
let inturnBlocksRatio = inturnBlocks/blockCount
let tps = txCountTotal/timeCost
let M = 1000000
let avgGasUsedPerBlock = gasUsedTotal/blockCount/M
let avgGasUsedPerSecond = gasUsedTotal/timeCost/M
console.log("Get the performance between [", program.startNum, ",", program.endNum, ")");
console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio);
console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond);
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -1,119 +0,0 @@
import { ethers } from "ethers";
import program from "commander";
program.option("--Rpc <Rpc>", "Rpc");
program.option("--Num <Num>", "num", 0)
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.Rpc);
const slashAbi = [
"function getSlashIndicator(address validatorAddr) external view returns (uint256, uint256)"
]
const validatorSetAbi = [
"function getLivingValidators() external view returns (address[], bytes[])"
]
const stakeHubAbi = [
"function getValidatorDescription(address validatorAddr) external view returns (tuple(string, string, string, string))",
"function consensusToOperator(address consensusAddr) public view returns (address)"
]
const addrValidatorSet = '0x0000000000000000000000000000000000001000';
const validatorSet = new ethers.Contract(addrValidatorSet, validatorSetAbi, provider);
const addrSlash = '0x0000000000000000000000000000000000001001';
const slashIndicator = new ethers.Contract(addrSlash, slashAbi, provider)
const addrStakeHub = '0x0000000000000000000000000000000000002002';
const stakeHub = new ethers.Contract(addrStakeHub, stakeHubAbi, provider)
const validatorMap = new Map([
//BSC
["0x37e9627A91DD13e453246856D58797Ad6583D762", "LegendII"],
["0xB4647b856CB9C3856d559C885Bed8B43e0846a47", "CertiK"],
["0x75B851a27D7101438F45fce31816501193239A83", "Figment"],
["0x502aECFE253E6AA0e8D2A06E12438FFeD0Fe16a0", "BscScan"],
["0xCa503a7eD99eca485da2E875aedf7758472c378C", "InfStones"],
["0x5009317FD4F6F8FeEa9dAe41E5F0a4737BB7A7D5", "NodeReal"],
["0x1cFDBd2dFf70C6e2e30df5012726F87731F38164", "Tranchess"],
["0xF8de5e61322302b2c6e0a525cC842F10332811bf", "Namelix"],
["0xCcB42A9b8d6C46468900527Bc741938E78AB4577", "Turing"],
["0x9f1b7FAE54BE07F4FEE34Eb1aaCb39A1F7B6FC92", "TWStaking"],
["0x7E1FdF03Eb3aC35BF0256694D7fBe6B6d7b3E0c8","LegendIII"],
["0x7b501c7944185130DD4aD73293e8Aa84eFfDcee7","MathW"],
["0x58567F7A51a58708C8B40ec592A38bA64C0697De","Legend"],
["0x460A252B4fEEFA821d3351731220627D7B7d1F3d","Defibit"],
["0x8A239732871AdC8829EA2f47e94087C5FBad47b6","The48Club"],
["0xD3b0d838cCCEAe7ebF1781D11D1bB741DB7Fe1A7","BNBEve"],
["0xF8B99643fAfC79d9404DE68E48C4D49a3936f787","Avengers"],
["0x4e5acf9684652BEa56F2f01b7101a225Ee33d23f","HashKey"],
["0x9bb56C2B4DBE5a06d79911C9899B6f817696ACFc","Feynman"],
["0xbdcc079BBb23C1D9a6F36AA31309676C258aBAC7","Fuji"],
["0x38944092685a336CB6B9ea58836436709a2adC89","Shannon"],
["0xfC1004C0f296Ec3Df4F6762E9EabfcF20EB304a2","Aoraki"],
["0xa0884bb00E5F23fE2427f0E5eC9E51F812848563","Coda"],
["0xe7776De78740f28a96412eE5cbbB8f90896b11A5","Ankr"],
["0xA2D969E82524001Cb6a2357dBF5922B04aD2FCD8","Pexmons"],
["0x5cf810AB8C718ac065b45f892A5BAdAB2B2946B9","Zen"],
["0x4d15D9BCd0c2f33E7510c0de8b42697CA558234a","LegendVII"],
["0x1579ca96EBd49A0B173f86C372436ab1AD393380","LegendV"],
["0xd1F72d433f362922f6565FC77c25e095B29141c8","LegendVI"],
["0xf9814D93b4d904AaA855cBD4266D6Eb0Ec1Aa478","Legend8"],
["0x025a4e09Ea947b8d695f53ddFDD48ddB8F9B06b7","Ciscox"],
["0xE9436F6F30b4B01b57F2780B2898f3820EbD7B98","LegendIV"],
["0xC2d534F079444E6E7Ff9DabB3FD8a26c607932c8","Axion"],
["0x9F7110Ba7EdFda83Fc71BeA6BA3c0591117b440D","LegendIX"],
["0xB997Bf1E3b96919fBA592c1F61CE507E165Ec030","Seoraksan"],
["0x286C1b674d48cFF67b4096b6c1dc22e769581E91","Sigm8"],
["0x73A26778ef9509a6E94b55310eE7233795a9EB25","Coinlix"],
["0x18c44f4FBEde9826C7f257d500A65a3D5A8edebc","Nozti"],
["0xA100FCd08cE722Dc68Ddc3b54237070Cb186f118","Tiollo"],
["0x0F28847cfdbf7508B13Ebb9cEb94B2f1B32E9503","Raptas"],
["0xfD85346c8C991baC16b9c9157e6bdfDACE1cD7d7","Glorin"],
["0x978F05CED39A4EaFa6E8FD045Fe2dd6Da836c7DF","NovaX"],
["0xd849d1dF66bFF1c2739B4399425755C2E0fAbbAb","Nexa"],
["0xA015d9e9206859c13201BB3D6B324d6634276534","Star"],
["0x5ADde0151BfAB27f329e5112c1AeDeed7f0D3692","Veri"],
//Chapel
["0x08265dA01E1A65d62b903c7B34c08cB389bF3D99","Ararat"],
["0x7f5f2cF1aec83bF0c74DF566a41aa7ed65EA84Ea","Kita"],
["0x53387F3321FD69d1E030BB921230dFb188826AFF","Fuji"],
["0x76D76ee8823dE52A1A431884c2ca930C5e72bff3","Seoraksan"],
["0xd447b49CD040D20BC21e49ffEa6487F5638e4346","Everest"],
["0x1a3d9D7A717D64e6088aC937d5aAcDD3E20ca963","Elbrus"],
["0x40D3256EB0BaBE89f0ea54EDAa398513136612f5","Bloxroute"],
["0xF9a1Db0d6f22Bd78ffAECCbc8F47c83Df9FBdbCf","Test"]
]);
const main = async () => {
let blockNum = ethers.getNumber(program.Num)
if (blockNum === 0) {
blockNum = await provider.getBlockNumber()
}
let block = await provider.getBlock(blockNum)
console.log("At block", blockNum, "time", block.date)
const data = await validatorSet.getLivingValidators({blockTag:blockNum})
let totalSlash = 0
for (let i = 0; i < data[0].length; i++) {
let addr = data[0][i];
var val
if (!validatorMap.has(addr)) {
let opAddr = await stakeHub.consensusToOperator(addr, {blockTag:blockNum})
let value = await stakeHub.getValidatorDescription(opAddr, {blockTag:blockNum})
val = value[0]
console.log(addr, val)
} else {
val = validatorMap.get(addr)
}
let info = await slashIndicator.getSlashIndicator(addr, {blockTag:blockNum})
let count = ethers.toNumber(info[1])
totalSlash += count
console.log("Slash:", count, addr, val)
}
console.log("Total slash count", totalSlash)
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -305,6 +305,16 @@ var (
Usage: "Manually specify the Rialto Genesis Hash, to trigger builtin network logic", Usage: "Manually specify the Rialto Genesis Hash, to trigger builtin network logic",
Category: flags.EthCategory, Category: flags.EthCategory,
} }
OverrideCancun = &cli.Uint64Flag{
Name: "override.cancun",
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{ OverrideBohr = &cli.Uint64Flag{
Name: "override.bohr", Name: "override.bohr",
Usage: "Manually specify the Bohr fork timestamp, overriding the bundled setting", Usage: "Manually specify the Bohr fork timestamp, overriding the bundled setting",
@@ -1153,6 +1163,7 @@ var (
DBEngineFlag, DBEngineFlag,
StateSchemeFlag, StateSchemeFlag,
HttpHeaderFlag, HttpHeaderFlag,
MultiDataBaseFlag,
} }
) )
@@ -2072,7 +2083,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
} }
cfg.Genesis = core.DefaultBSCGenesisBlock() cfg.Genesis = core.DefaultBSCGenesisBlock()
SetDNSDiscoveryDefaults(cfg, params.BSCGenesisHash) SetDNSDiscoveryDefaults(cfg, params.BSCGenesisHash)
case ctx.Bool(ChapelFlag.Name) || cfg.NetworkId == 97: case ctx.Bool(ChapelFlag.Name):
if !ctx.IsSet(NetworkIdFlag.Name) { if !ctx.IsSet(NetworkIdFlag.Name) {
cfg.NetworkId = 97 cfg.NetworkId = 97
} }

View File

@@ -83,7 +83,7 @@ func TestHistoryImportAndExport(t *testing.T) {
t.Fatalf("unable to initialize chain: %v", err) t.Fatalf("unable to initialize chain: %v", err)
} }
if _, err := chain.InsertChain(blocks); err != nil { if _, err := chain.InsertChain(blocks); err != nil {
t.Fatalf("error inserting chain: %v", err) t.Fatalf("error insterting chain: %v", err)
} }
// Make temp directory for era files. // Make temp directory for era files.

View File

@@ -307,10 +307,6 @@ func New(
return c return c
} }
func (p *Parlia) Period() uint64 {
return p.config.Period
}
func (p *Parlia) IsSystemTransaction(tx *types.Transaction, header *types.Header) (bool, error) { func (p *Parlia) IsSystemTransaction(tx *types.Transaction, header *types.Header) (bool, error) {
// deploy a contract // deploy a contract
if tx.To() == nil { if tx.To() == nil {
@@ -1828,7 +1824,7 @@ func (p *Parlia) applyTransaction(
// move to next // move to next
*receivedTxs = (*receivedTxs)[1:] *receivedTxs = (*receivedTxs)[1:]
} }
state.SetTxContext(expectedTx.Hash(), len(*txs)) state.SetTxContext(expectedTx.Hash(), len(*txs), 0)
gasUsed, err := applyMessage(msg, state, header, p.chainConfig, chainContext) gasUsed, err := applyMessage(msg, state, header, p.chainConfig, chainContext)
if err != nil { if err != nil {
return err return err

View File

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

View File

@@ -74,7 +74,6 @@ var (
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil) blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil) chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
mGasPsGauge = metrics.NewRegisteredGauge("chain/process/gas", nil)
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil) accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil) accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
@@ -96,9 +95,6 @@ var (
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil) blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil) blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil) blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
blockValidationTotalTimer = metrics.NewRegisteredTimer("chain/total/validation", nil)
blockExecutionTotalTimer = metrics.NewRegisteredTimer("chain/total/execution", nil)
blockWriteTotalTimer = metrics.NewRegisteredTimer("chain/total/write", nil)
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil) blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil) blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
@@ -305,7 +301,6 @@ type BlockChain struct {
diffLayerFreezerBlockLimit uint64 diffLayerFreezerBlockLimit uint64
wg sync.WaitGroup wg sync.WaitGroup
dbWg sync.WaitGroup
quit chan struct{} // shutdown signal, closed in Stop. quit chan struct{} // shutdown signal, closed in Stop.
stopping atomic.Bool // false if chain is running, true when stopped stopping atomic.Bool // false if chain is running, true when stopped
procInterrupt atomic.Bool // interrupt signaler for block processing procInterrupt atomic.Bool // interrupt signaler for block processing
@@ -466,8 +461,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
} }
} }
// Ensure that a previous crash in SetHead doesn't leave extra ancients // Ensure that a previous crash in SetHead doesn't leave extra ancients
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 { if frozen, err := bc.db.ItemAmountInAncient(); err == nil && frozen > 0 {
frozen, err = bc.db.BlockStore().Ancients() frozen, err = bc.db.Ancients()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -661,13 +656,20 @@ func (bc *BlockChain) cacheDiffLayer(diffLayer *types.DiffLayer, diffLayerCh cha
} }
} }
func (bc *BlockChain) cacheBlock(hash common.Hash, block *types.Block) {
bc.blockCache.Add(hash, block)
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
bc.sidecarsCache.Add(hash, block.Sidecars())
}
}
// empty returns an indicator whether the blockchain is empty. // empty returns an indicator whether the blockchain is empty.
// Note, it's a special case that we connect a non-empty ancient // Note, it's a special case that we connect a non-empty ancient
// database with an empty node, so that we can plugin the ancient // database with an empty node, so that we can plugin the ancient
// into node seamlessly. // into node seamlessly.
func (bc *BlockChain) empty() bool { func (bc *BlockChain) empty() bool {
genesis := bc.genesisBlock.Hash() genesis := bc.genesisBlock.Hash()
for _, hash := range []common.Hash{rawdb.ReadHeadBlockHash(bc.db), rawdb.ReadHeadHeaderHash(bc.db), rawdb.ReadHeadFastBlockHash(bc.db)} { for _, hash := range []common.Hash{rawdb.ReadHeadBlockHash(bc.db.BlockStore()), rawdb.ReadHeadHeaderHash(bc.db.BlockStore()), rawdb.ReadHeadFastBlockHash(bc.db)} {
if hash != genesis { if hash != genesis {
return false return false
} }
@@ -703,7 +705,7 @@ func (bc *BlockChain) getFinalizedNumber(header *types.Header) uint64 {
// assumes that the chain manager mutex is held. // assumes that the chain manager mutex is held.
func (bc *BlockChain) loadLastState() error { func (bc *BlockChain) loadLastState() error {
// Restore the last known head block // Restore the last known head block
head := rawdb.ReadHeadBlockHash(bc.db) head := rawdb.ReadHeadBlockHash(bc.db.BlockStore())
if head == (common.Hash{}) { if head == (common.Hash{}) {
// Corrupt or empty database, init from scratch // Corrupt or empty database, init from scratch
log.Warn("Empty database, resetting chain") log.Warn("Empty database, resetting chain")
@@ -725,7 +727,7 @@ func (bc *BlockChain) loadLastState() error {
// Restore the last known head header // Restore the last known head header
headHeader := headBlock.Header() headHeader := headBlock.Header()
if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) { if head := rawdb.ReadHeadHeaderHash(bc.db.BlockStore()); head != (common.Hash{}) {
if header := bc.GetHeaderByHash(head); header != nil { if header := bc.GetHeaderByHash(head); header != nil {
headHeader = header headHeader = header
} }
@@ -1104,7 +1106,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// intent afterwards is full block importing, delete the chain segment // intent afterwards is full block importing, delete the chain segment
// between the stateful-block and the sethead target. // between the stateful-block and the sethead target.
var wipe bool var wipe bool
frozen, _ := bc.db.BlockStore().Ancients() frozen, _ := bc.db.Ancients()
if headNumber+1 < frozen { if headNumber+1 < frozen {
wipe = pivot == nil || headNumber >= *pivot wipe = pivot == nil || headNumber >= *pivot
} }
@@ -1113,11 +1115,11 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// Rewind the header chain, deleting all block bodies until then // Rewind the header chain, deleting all block bodies until then
delFn := func(db ethdb.KeyValueWriter, hash common.Hash, num uint64) { delFn := func(db ethdb.KeyValueWriter, hash common.Hash, num uint64) {
// Ignore the error here since light client won't hit this path // Ignore the error here since light client won't hit this path
frozen, _ := bc.db.BlockStore().Ancients() frozen, _ := bc.db.Ancients()
if num+1 <= frozen { if num+1 <= frozen {
// Truncate all relative data(header, total difficulty, body, receipt // Truncate all relative data(header, total difficulty, body, receipt
// and canonical hash) from ancient store. // and canonical hash) from ancient store.
if _, err := bc.db.BlockStore().TruncateHead(num); err != nil { if _, err := bc.db.TruncateHead(num); err != nil {
log.Crit("Failed to truncate ancient data", "number", num, "err", err) log.Crit("Failed to truncate ancient data", "number", num, "err", err)
} }
// Remove the hash <-> number mapping from the active store. // Remove the hash <-> number mapping from the active store.
@@ -1135,7 +1137,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 // If SetHead was only called as a chain reparation method, try to skip
// touching the header chain altogether, unless the freezer is broken // touching the header chain altogether, unless the freezer is broken
if repair { 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) bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn)
} }
} else { } else {
@@ -1296,33 +1298,19 @@ func (bc *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {
// //
// Note, this function assumes that the `mu` mutex is held! // Note, this function assumes that the `mu` mutex is held!
func (bc *BlockChain) writeHeadBlock(block *types.Block) { 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 // Add the block to the canonical chain number scheme and mark as the head
blockBatch := bc.db.BlockStore().NewBatch() rawdb.WriteCanonicalHash(bc.db.BlockStore(), block.Hash(), block.NumberU64())
rawdb.WriteCanonicalHash(blockBatch, block.Hash(), block.NumberU64()) rawdb.WriteHeadHeaderHash(bc.db.BlockStore(), block.Hash())
rawdb.WriteHeadHeaderHash(blockBatch, block.Hash()) rawdb.WriteHeadBlockHash(bc.db.BlockStore(), 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()
batch := bc.db.NewBatch() batch := bc.db.NewBatch()
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
rawdb.WriteTxLookupEntriesByBlock(batch, block) rawdb.WriteTxLookupEntriesByBlock(batch, block)
// Flush the whole batch into the disk, exit the node if failed // Flush the whole batch into the disk, exit the node if failed
if err := batch.Write(); err != nil { if err := batch.Write(); err != nil {
log.Crit("Failed to update chain indexes in chain db", "err", err) log.Crit("Failed to update chain indexes and markers", "err", err)
} }
}()
// Update all in-memory chain markers in the last step // Update all in-memory chain markers in the last step
bc.hc.SetCurrentHeader(block.Header()) bc.hc.SetCurrentHeader(block.Header())
@@ -1543,7 +1531,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
} else if !reorg { } else if !reorg {
return false return false
} }
rawdb.WriteHeadFastBlockHash(bc.db.BlockStore(), head.Hash()) rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
bc.currentSnapBlock.Store(head.Header()) bc.currentSnapBlock.Store(head.Header())
headFastBlockGauge.Update(int64(head.NumberU64())) headFastBlockGauge.Update(int64(head.NumberU64()))
return true return true
@@ -1560,9 +1548,9 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
// Ensure genesis is in ancients. // Ensure genesis is in ancients.
if first.NumberU64() == 1 { if first.NumberU64() == 1 {
if frozen, _ := bc.db.BlockStore().Ancients(); frozen == 0 { if frozen, _ := bc.db.Ancients(); frozen == 0 {
td := bc.genesisBlock.Difficulty() td := bc.genesisBlock.Difficulty()
writeSize, err := rawdb.WriteAncientBlocks(bc.db.BlockStore(), []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, td) writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, td)
if err != nil { if err != nil {
log.Error("Error writing genesis to ancients", "err", err) log.Error("Error writing genesis to ancients", "err", err)
return 0, err return 0, err
@@ -1580,7 +1568,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
// Write all chain data to ancients. // Write all chain data to ancients.
td := bc.GetTd(first.Hash(), first.NumberU64()) td := bc.GetTd(first.Hash(), first.NumberU64())
writeSize, err := rawdb.WriteAncientBlocksWithBlobs(bc.db.BlockStore(), blockChain, receiptChain, td) writeSize, err := rawdb.WriteAncientBlocksWithBlobs(bc.db, blockChain, receiptChain, td)
if err != nil { if err != nil {
log.Error("Error importing chain data to ancients", "err", err) log.Error("Error importing chain data to ancients", "err", err)
return 0, err return 0, err
@@ -1588,7 +1576,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
size += writeSize size += writeSize
// Sync the ancient store explicitly to ensure all data has been flushed to disk. // Sync the ancient store explicitly to ensure all data has been flushed to disk.
if err := bc.db.BlockStore().Sync(); err != nil { if err := bc.db.Sync(); err != nil {
return 0, err return 0, err
} }
// Update the current snap block because all block data is now present in DB. // Update the current snap block because all block data is now present in DB.
@@ -1596,7 +1584,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
if !updateHead(blockChain[len(blockChain)-1]) { if !updateHead(blockChain[len(blockChain)-1]) {
// We end up here if the header chain has reorg'ed, and the blocks/receipts // We end up here if the header chain has reorg'ed, and the blocks/receipts
// don't match the canonical chain. // don't match the canonical chain.
if _, err := bc.db.BlockStore().TruncateHead(previousSnapBlock + 1); err != nil { if _, err := bc.db.TruncateHead(previousSnapBlock + 1); err != nil {
log.Error("Can't truncate ancient store after failed insert", "err", err) log.Error("Can't truncate ancient store after failed insert", "err", err)
} }
return 0, errSideChainReceipts return 0, errSideChainReceipts
@@ -1616,7 +1604,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
rawdb.DeleteBlockWithoutNumber(blockBatch, block.Hash(), block.NumberU64()) rawdb.DeleteBlockWithoutNumber(blockBatch, block.Hash(), block.NumberU64())
} }
// Delete side chain hash-to-number mappings. // Delete side chain hash-to-number mappings.
for _, nh := range rawdb.ReadAllHashesInRange(bc.db.BlockStore(), first.NumberU64(), last.NumberU64()) { for _, nh := range rawdb.ReadAllHashesInRange(bc.db, first.NumberU64(), last.NumberU64()) {
if _, canon := canonHashes[nh.Hash]; !canon { if _, canon := canonHashes[nh.Hash]; !canon {
rawdb.DeleteHeader(blockBatch, nh.Hash, nh.Number) rawdb.DeleteHeader(blockBatch, nh.Hash, nh.Number)
} }
@@ -1786,6 +1774,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(1) wg.Add(1)
go func() { go func() {
rawdb.WritePreimages(bc.db, state.Preimages())
blockBatch := bc.db.BlockStore().NewBatch() blockBatch := bc.db.BlockStore().NewBatch()
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
rawdb.WriteBlock(blockBatch, block) rawdb.WriteBlock(blockBatch, block)
@@ -1794,20 +1783,10 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
if bc.chainConfig.IsCancun(block.Number(), block.Time()) { if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
rawdb.WriteBlobSidecars(blockBatch, block.Hash(), block.NumberU64(), block.Sidecars()) 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 { if err := blockBatch.Write(); err != nil {
log.Crit("Failed to write block into disk", "err", err) log.Crit("Failed to write block into disk", "err", err)
} }
bc.hc.tdCache.Add(block.Hash(), externTd)
bc.blockCache.Add(block.Hash(), block)
bc.receiptsCache.Add(block.Hash(), receipts)
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
bc.sidecarsCache.Add(block.Hash(), block.Sidecars())
}
wg.Done() wg.Done()
}() }()
@@ -2272,8 +2251,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
statedb.StopPrefetcher() statedb.StopPrefetcher()
return it.index, err return it.index, err
} }
blockExecutionTotalTimer.UpdateSince(pstart)
ptime := time.Since(pstart) ptime := time.Since(pstart)
// Validate the state using the default validator // Validate the state using the default validator
@@ -2284,11 +2261,11 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
statedb.StopPrefetcher() statedb.StopPrefetcher()
return it.index, err return it.index, err
} }
blockValidationTotalTimer.UpdateSince(vstart)
vtime := time.Since(vstart) vtime := time.Since(vstart)
proctime := time.Since(start) // processing + validation proctime := time.Since(start) // processing + validation
bc.cacheBlock(block.Hash(), block)
// Update the metrics touched during block processing and validation // Update the metrics touched during block processing and validation
accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing) accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing) storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
@@ -2319,7 +2296,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
if err != nil { if err != nil {
return it.index, err return it.index, err
} }
blockWriteTotalTimer.UpdateSince(wstart)
bc.cacheReceipts(block.Hash(), receipts, block) bc.cacheReceipts(block.Hash(), receipts, block)
@@ -2331,7 +2307,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits) blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
blockInsertTimer.UpdateSince(start) blockInsertTimer.UpdateSince(start)
// Report the import stats before returning the various results // Report the import stats before returning the various results
stats.processed++ stats.processed++
stats.usedGas += usedGas stats.usedGas += usedGas
@@ -2402,11 +2377,26 @@ func (bc *BlockChain) updateHighestVerifiedHeader(header *types.Header) {
if header == nil || header.Number == nil { if header == nil || header.Number == nil {
return return
} }
currentBlock := bc.CurrentBlock() currentHeader := bc.highestVerifiedHeader.Load()
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, header) if currentHeader == nil {
if err == nil && reorg {
bc.highestVerifiedHeader.Store(types.CopyHeader(header)) bc.highestVerifiedHeader.Store(types.CopyHeader(header))
log.Trace("updateHighestVerifiedHeader", "number", header.Number.Uint64(), "hash", header.Hash()) return
}
newParentTD := bc.GetTd(header.ParentHash, header.Number.Uint64()-1)
if newParentTD == nil {
newParentTD = big.NewInt(0)
}
oldParentTD := bc.GetTd(currentHeader.ParentHash, currentHeader.Number.Uint64()-1)
if oldParentTD == nil {
oldParentTD = big.NewInt(0)
}
newTD := big.NewInt(0).Add(newParentTD, header.Difficulty)
oldTD := big.NewInt(0).Add(oldParentTD, currentHeader.Difficulty)
if newTD.Cmp(oldTD) > 0 {
bc.highestVerifiedHeader.Store(types.CopyHeader(header))
return
} }
} }

View File

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

View File

@@ -231,7 +231,7 @@ func (bc *BlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts {
if receipts, ok := bc.receiptsCache.Get(hash); ok { if receipts, ok := bc.receiptsCache.Get(hash); ok {
return receipts return receipts
} }
number := rawdb.ReadHeaderNumber(bc.db, hash) number := rawdb.ReadHeaderNumber(bc.db.BlockStore(), hash)
if number == nil { if number == nil {
return nil return nil
} }
@@ -514,7 +514,7 @@ func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEve
// AncientTail retrieves the tail the ancients blocks // AncientTail retrieves the tail the ancients blocks
func (bc *BlockChain) AncientTail() (uint64, error) { func (bc *BlockChain) AncientTail() (uint64, error) {
tail, err := bc.db.BlockStore().Tail() tail, err := bc.db.Tail()
if err != nil { if err != nil {
return 0, err return 0, err
} }

View File

@@ -26,8 +26,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
@@ -1797,13 +1795,6 @@ func testRepairWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme s
config.SnapshotWait = true config.SnapshotWait = true
} }
config.TriesInMemory = 128 config.TriesInMemory = 128
if err = db.SetupFreezerEnv(&ethdb.FreezerEnv{
ChainCfg: gspec.Config,
BlobExtraReserve: params.DefaultExtraReserveForBlobRequests,
}); err != nil {
t.Fatalf("Failed to create chain: %v", err)
}
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to create chain: %v", err) t.Fatalf("Failed to create chain: %v", err)

View File

@@ -27,8 +27,6 @@ import (
"testing" "testing"
"time" "time"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
@@ -2000,13 +1998,6 @@ func testSetHeadWithScheme(t *testing.T, tt *rewindTest, snapshots bool, scheme
config.SnapshotWait = true config.SnapshotWait = true
} }
config.TriesInMemory = 128 config.TriesInMemory = 128
if err = db.SetupFreezerEnv(&ethdb.FreezerEnv{
ChainCfg: gspec.Config,
BlobExtraReserve: params.DefaultExtraReserveForBlobRequests,
}); err != nil {
t.Fatalf("Failed to create chain: %v", err)
}
chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(db, config, gspec, nil, engine, vm.Config{}, nil, nil)
if err != nil { if err != nil {
t.Fatalf("Failed to create chain: %v", err) t.Fatalf("Failed to create chain: %v", err)

View File

@@ -227,8 +227,8 @@ func (c *ChainIndexer) eventLoop(currentHeader *types.Header, events chan ChainH
// Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then) // Reorg to the common ancestor if needed (might not exist in light sync mode, skip reorg then)
// TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly? // TODO(karalabe, zsfelfoldi): This seems a bit brittle, can we detect this case explicitly?
if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash { if rawdb.ReadCanonicalHash(c.chainDb.BlockStore(), prevHeader.Number.Uint64()) != prevHash {
if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil { if h := rawdb.FindCommonAncestor(c.chainDb.BlockStore(), prevHeader, header); h != nil {
c.newHead(h.Number.Uint64(), true) c.newHead(h.Number.Uint64(), true)
} }
} }

View File

@@ -119,7 +119,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
if b.gasPool == nil { if b.gasPool == nil {
b.SetCoinbase(common.Address{}) b.SetCoinbase(common.Address{})
} }
b.statedb.SetTxContext(tx.Hash(), len(b.txs)) b.statedb.SetTxContext(tx.Hash(), len(b.txs), 0)
receipt, err := ApplyTransaction(b.cm.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig, NewReceiptBloomGenerator()) receipt, err := ApplyTransaction(b.cm.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig, NewReceiptBloomGenerator())
if err != nil { if err != nil {
panic(err) panic(err)

View File

@@ -86,16 +86,9 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64()) localTD = f.chain.GetTd(current.Hash(), current.Number.Uint64())
externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64()) externTd = f.chain.GetTd(extern.Hash(), extern.Number.Uint64())
) )
if localTD == nil { if localTD == nil || externTd == nil {
return false, errors.New("missing td") return false, errors.New("missing td")
} }
if externTd == nil {
ptd := f.chain.GetTd(extern.ParentHash, extern.Number.Uint64()-1)
if ptd == nil {
return false, consensus.ErrUnknownAncestor
}
externTd = new(big.Int).Add(ptd, extern.Difficulty)
}
// Accept the new header as the chain head if the transition // Accept the new header as the chain head if the transition
// is already triggered. We assume all the headers after the // is already triggered. We assume all the headers after the
// transition come from the trusted consensus layer. // transition come from the trusted consensus layer.
@@ -121,9 +114,7 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
if f.preserve != nil { if f.preserve != nil {
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern) currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
} }
reorg = !currentPreserve && (externPreserve || reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
extern.Time < current.Time ||
extern.Time == current.Time && f.rand.Float64() < 0.5)
} }
return reorg, nil return reorg, nil
} }

View File

@@ -216,6 +216,8 @@ func (e *GenesisMismatchError) Error() string {
// ChainOverrides contains the changes to chain config // ChainOverrides contains the changes to chain config
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes. // Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
type ChainOverrides struct { type ChainOverrides struct {
OverrideCancun *uint64
OverrideHaber *uint64
OverrideBohr *uint64 OverrideBohr *uint64
OverrideVerkle *uint64 OverrideVerkle *uint64
} }
@@ -243,6 +245,12 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
} }
applyOverrides := func(config *params.ChainConfig) { applyOverrides := func(config *params.ChainConfig) {
if config != nil { if config != nil {
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 { if overrides != nil && overrides.OverrideBohr != nil {
config.BohrTime = overrides.OverrideBohr config.BohrTime = overrides.OverrideBohr
} }
@@ -490,7 +498,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
rawdb.WriteReceipts(db.BlockStore(), block.Hash(), block.NumberU64(), nil) rawdb.WriteReceipts(db.BlockStore(), block.Hash(), block.NumberU64(), nil)
rawdb.WriteCanonicalHash(db.BlockStore(), block.Hash(), block.NumberU64()) rawdb.WriteCanonicalHash(db.BlockStore(), block.Hash(), block.NumberU64())
rawdb.WriteHeadBlockHash(db.BlockStore(), block.Hash()) rawdb.WriteHeadBlockHash(db.BlockStore(), block.Hash())
rawdb.WriteHeadFastBlockHash(db.BlockStore(), block.Hash()) rawdb.WriteHeadFastBlockHash(db, block.Hash())
rawdb.WriteHeadHeaderHash(db.BlockStore(), block.Hash()) rawdb.WriteHeadHeaderHash(db.BlockStore(), block.Hash())
rawdb.WriteChainConfig(db, block.Hash(), config) rawdb.WriteChainConfig(db, block.Hash(), config)
return block, nil return block, nil

View File

@@ -97,7 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
return nil, ErrNoGenesis return nil, ErrNoGenesis
} }
hc.currentHeader.Store(hc.genesisHeader) hc.currentHeader.Store(hc.genesisHeader)
if head := rawdb.ReadHeadBlockHash(chainDb); head != (common.Hash{}) { if head := rawdb.ReadHeadBlockHash(chainDb.BlockStore()); head != (common.Hash{}) {
if chead := hc.GetHeaderByHash(head); chead != nil { if chead := hc.GetHeaderByHash(head); chead != nil {
hc.currentHeader.Store(chead) hc.currentHeader.Store(chead)
} }
@@ -144,7 +144,7 @@ func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 {
if cached, ok := hc.numberCache.Get(hash); ok { if cached, ok := hc.numberCache.Get(hash); ok {
return &cached return &cached
} }
number := rawdb.ReadHeaderNumber(hc.chainDb, hash) number := rawdb.ReadHeaderNumber(hc.chainDb.BlockStore(), hash)
if number != nil { if number != nil {
hc.numberCache.Add(hash, *number) hc.numberCache.Add(hash, *number)
} }
@@ -668,7 +668,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
// first then remove the relative data from the database. // first then remove the relative data from the database.
// //
// Update head first(head fast block, head full block) before deleting the data. // 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 { if updateFn != nil {
newHead, force := updateFn(markerBatch, parent) newHead, force := updateFn(markerBatch, parent)
if force && ((headTime > 0 && newHead.Time < headTime) || (headTime == 0 && newHead.Number.Uint64() < headBlock)) { 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. // Update head header then.
rawdb.WriteHeadHeaderHash(markerBatch, parentHash) rawdb.WriteHeadHeaderHash(hc.chainDb.BlockStore(), parentHash)
if err := markerBatch.Write(); err != nil { if err := markerBatch.Write(); err != nil {
log.Crit("Failed to update chain markers", "error", err) log.Crit("Failed to update chain markers", "error", err)
} }
@@ -691,7 +691,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
// we don't end up with dangling daps in the database // we don't end up with dangling daps in the database
var nums []uint64 var nums []uint64
if origin { if origin {
for n := num + 1; len(rawdb.ReadAllHashes(hc.chainDb.BlockStore(), n)) > 0; n++ { for n := num + 1; len(rawdb.ReadAllHashes(hc.chainDb, n)) > 0; n++ {
nums = append([]uint64{n}, nums...) // suboptimal, but we don't really expect this path nums = append([]uint64{n}, nums...) // suboptimal, but we don't really expect this path
} }
origin = false origin = false
@@ -701,7 +701,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
// Remove the related data from the database on all sidechains // Remove the related data from the database on all sidechains
for _, num := range nums { for _, num := range nums {
// Gather all the side fork hashes // Gather all the side fork hashes
hashes := rawdb.ReadAllHashes(hc.chainDb.BlockStore(), num) hashes := rawdb.ReadAllHashes(hc.chainDb, num)
if len(hashes) == 0 { if len(hashes) == 0 {
// No hashes in the database whatsoever, probably frozen already // No hashes in the database whatsoever, probably frozen already
hashes = append(hashes, hdr.Hash()) hashes = append(hashes, hdr.Hash())

View File

@@ -34,15 +34,6 @@ import (
"golang.org/x/exp/slices" "golang.org/x/exp/slices"
) )
// Support Multi-Database Based on Data Pattern, the Chaindata will be divided into three stores: BlockStore, StateStore, and ChainStore,
// according to data schema and read/write behavior. When using the following data interfaces, you should take note of the following:
//
// 1) Block-Related Data: For CanonicalHash, Header, Body, Td, Receipts, and BlobSidecars, the Write, Delete, and Iterator
// operations should carefully ensure that the database being used is BlockStore.
// 2) Meta-Related Data: For HeaderNumber, HeadHeaderHash, HeadBlockHash, HeadFastBlockHash, and FinalizedBlockHash, the
// Write and Delete operations should carefully ensure that the database being used is BlockStore.
// 3) Ancient Data: When using a multi-database, Ancient data will use the BlockStore.
// ReadCanonicalHash retrieves the hash assigned to a canonical block number. // ReadCanonicalHash retrieves the hash assigned to a canonical block number.
func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash { func ReadCanonicalHash(db ethdb.Reader, number uint64) common.Hash {
var data []byte var data []byte
@@ -153,8 +144,8 @@ func ReadAllCanonicalHashes(db ethdb.Iteratee, from uint64, to uint64, limit int
} }
// ReadHeaderNumber returns the header number assigned to a hash. // ReadHeaderNumber returns the header number assigned to a hash.
func ReadHeaderNumber(db ethdb.MultiDatabaseReader, hash common.Hash) *uint64 { func ReadHeaderNumber(db ethdb.KeyValueReader, hash common.Hash) *uint64 {
data, _ := db.BlockStoreReader().Get(headerNumberKey(hash)) data, _ := db.Get(headerNumberKey(hash))
if len(data) != 8 { if len(data) != 8 {
return nil return nil
} }
@@ -179,8 +170,8 @@ func DeleteHeaderNumber(db ethdb.KeyValueWriter, hash common.Hash) {
} }
// ReadHeadHeaderHash retrieves the hash of the current canonical head header. // ReadHeadHeaderHash retrieves the hash of the current canonical head header.
func ReadHeadHeaderHash(db ethdb.MultiDatabaseReader) common.Hash { func ReadHeadHeaderHash(db ethdb.KeyValueReader) common.Hash {
data, _ := db.BlockStoreReader().Get(headHeaderKey) data, _ := db.Get(headHeaderKey)
if len(data) == 0 { if len(data) == 0 {
return common.Hash{} return common.Hash{}
} }
@@ -195,8 +186,8 @@ func WriteHeadHeaderHash(db ethdb.KeyValueWriter, hash common.Hash) {
} }
// ReadHeadBlockHash retrieves the hash of the current canonical head block. // ReadHeadBlockHash retrieves the hash of the current canonical head block.
func ReadHeadBlockHash(db ethdb.MultiDatabaseReader) common.Hash { func ReadHeadBlockHash(db ethdb.KeyValueReader) common.Hash {
data, _ := db.BlockStoreReader().Get(headBlockKey) data, _ := db.Get(headBlockKey)
if len(data) == 0 { if len(data) == 0 {
return common.Hash{} return common.Hash{}
} }
@@ -211,8 +202,8 @@ func WriteHeadBlockHash(db ethdb.KeyValueWriter, hash common.Hash) {
} }
// ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block. // ReadHeadFastBlockHash retrieves the hash of the current fast-sync head block.
func ReadHeadFastBlockHash(db ethdb.MultiDatabaseReader) common.Hash { func ReadHeadFastBlockHash(db ethdb.KeyValueReader) common.Hash {
data, _ := db.BlockStoreReader().Get(headFastBlockKey) data, _ := db.Get(headFastBlockKey)
if len(data) == 0 { if len(data) == 0 {
return common.Hash{} return common.Hash{}
} }
@@ -227,8 +218,8 @@ func WriteHeadFastBlockHash(db ethdb.KeyValueWriter, hash common.Hash) {
} }
// ReadFinalizedBlockHash retrieves the hash of the finalized block. // ReadFinalizedBlockHash retrieves the hash of the finalized block.
func ReadFinalizedBlockHash(db ethdb.MultiDatabaseReader) common.Hash { func ReadFinalizedBlockHash(db ethdb.KeyValueReader) common.Hash {
data, _ := db.BlockStoreReader().Get(headFinalizedBlockKey) data, _ := db.Get(headFinalizedBlockKey)
if len(data) == 0 { if len(data) == 0 {
return common.Hash{} return common.Hash{}
} }
@@ -306,7 +297,7 @@ func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValu
// It's ok to request block 0, 1 item // It's ok to request block 0, 1 item
count = number + 1 count = number + 1
} }
limit, _ := db.BlockStoreReader().Ancients() limit, _ := db.Ancients()
// First read live blocks // First read live blocks
if i >= limit { if i >= limit {
// If we need to read live blocks, we need to figure out the hash first // If we need to read live blocks, we need to figure out the hash first
@@ -326,7 +317,7 @@ func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValu
return rlpHeaders return rlpHeaders
} }
// read remaining from ancients, cap at 2M // read remaining from ancients, cap at 2M
data, err := db.BlockStoreReader().AncientRange(ChainFreezerHeaderTable, i+1-count, count, 2*1024*1024) data, err := db.AncientRange(ChainFreezerHeaderTable, i+1-count, count, 2*1024*1024)
if err != nil { if err != nil {
log.Error("Failed to read headers from freezer", "err", err) log.Error("Failed to read headers from freezer", "err", err)
return rlpHeaders return rlpHeaders
@@ -477,7 +468,7 @@ func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue {
// Block is not in ancients, read from leveldb by hash and number. // Block is not in ancients, read from leveldb by hash and number.
// Note: ReadCanonicalHash cannot be used here because it also // Note: ReadCanonicalHash cannot be used here because it also
// calls ReadAncients internally. // calls ReadAncients internally.
hash, _ := db.BlockStoreReader().Get(headerHashKey(number)) hash, _ := db.Get(headerHashKey(number))
data, _ = db.BlockStoreReader().Get(blockBodyKey(number, common.BytesToHash(hash))) data, _ = db.BlockStoreReader().Get(blockBodyKey(number, common.BytesToHash(hash)))
return nil return nil
}) })
@@ -525,13 +516,6 @@ func WriteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64, body *t
WriteBodyRLP(db, hash, number, data) WriteBodyRLP(db, hash, number, data)
} }
// DeleteBody removes all block body data associated with a hash.
func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
log.Crit("Failed to delete block body", "err", err)
}
}
func WriteDiffLayer(db ethdb.KeyValueWriter, hash common.Hash, layer *types.DiffLayer) { func WriteDiffLayer(db ethdb.KeyValueWriter, hash common.Hash, layer *types.DiffLayer) {
data, err := rlp.EncodeToBytes(layer) data, err := rlp.EncodeToBytes(layer)
if err != nil { if err != nil {
@@ -570,6 +554,13 @@ func DeleteDiffLayer(db ethdb.KeyValueWriter, blockHash common.Hash) {
} }
} }
// DeleteBody removes all block body data associated with a hash.
func DeleteBody(db ethdb.KeyValueWriter, hash common.Hash, number uint64) {
if err := db.Delete(blockBodyKey(number, hash)); err != nil {
log.Crit("Failed to delete block body", "err", err)
}
}
// ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding. // ReadTdRLP retrieves a block's total difficulty corresponding to the hash in RLP encoding.
func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { func ReadTdRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
var data []byte var data []byte
@@ -893,7 +884,7 @@ func WriteAncientBlocks(db ethdb.AncientWriter, blocks []*types.Block, receipts
// ReadBlobSidecarsRLP retrieves all the transaction blobs belonging to a block in RLP encoding. // ReadBlobSidecarsRLP retrieves all the transaction blobs belonging to a block in RLP encoding.
func ReadBlobSidecarsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue { func ReadBlobSidecarsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue {
var data []byte var data []byte
db.BlockStoreReader().ReadAncients(func(reader ethdb.AncientReaderOp) error { db.ReadAncients(func(reader ethdb.AncientReaderOp) error {
// Check if the data is in ancients // Check if the data is in ancients
if isCanon(reader, number, hash) { if isCanon(reader, number, hash) {
data, _ = reader.Ancient(ChainFreezerBlobSidecarTable, number) data, _ = reader.Ancient(ChainFreezerBlobSidecarTable, number)
@@ -1102,24 +1093,24 @@ func FindCommonAncestor(db ethdb.Reader, a, b *types.Header) *types.Header {
// ReadHeadHeader returns the current canonical head header. // ReadHeadHeader returns the current canonical head header.
func ReadHeadHeader(db ethdb.Reader) *types.Header { func ReadHeadHeader(db ethdb.Reader) *types.Header {
headHeaderHash := ReadHeadHeaderHash(db) headHeaderHash := ReadHeadHeaderHash(db.BlockStoreReader())
if headHeaderHash == (common.Hash{}) { if headHeaderHash == (common.Hash{}) {
return nil return nil
} }
headHeaderNumber := ReadHeaderNumber(db, headHeaderHash) headHeaderNumber := ReadHeaderNumber(db.BlockStoreReader(), headHeaderHash)
if headHeaderNumber == nil { if headHeaderNumber == nil {
return nil return nil
} }
return ReadHeader(db, headHeaderHash, *headHeaderNumber) return ReadHeader(db.BlockStoreReader(), headHeaderHash, *headHeaderNumber)
} }
// ReadHeadBlock returns the current canonical head block. // ReadHeadBlock returns the current canonical head block.
func ReadHeadBlock(db ethdb.Reader) *types.Block { func ReadHeadBlock(db ethdb.Reader) *types.Block {
headBlockHash := ReadHeadBlockHash(db) headBlockHash := ReadHeadBlockHash(db.BlockStoreReader())
if headBlockHash == (common.Hash{}) { if headBlockHash == (common.Hash{}) {
return nil return nil
} }
headBlockNumber := ReadHeaderNumber(db, headBlockHash) headBlockNumber := ReadHeaderNumber(db.BlockStoreReader(), headBlockHash)
if headBlockNumber == nil { if headBlockNumber == nil {
return nil return nil
} }

View File

@@ -42,7 +42,7 @@ func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 {
} }
// Database v4-v5 tx lookup format just stores the hash // Database v4-v5 tx lookup format just stores the hash
if len(data) == common.HashLength { if len(data) == common.HashLength {
return ReadHeaderNumber(db, common.BytesToHash(data)) return ReadHeaderNumber(db.BlockStoreReader(), common.BytesToHash(data))
} }
// Finally try database v3 tx lookup format // Finally try database v3 tx lookup format
var entry LegacyTxLookupEntry var entry LegacyTxLookupEntry

View File

@@ -18,8 +18,6 @@ package rawdb
import ( import (
"fmt" "fmt"
"io"
"os"
"path/filepath" "path/filepath"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@@ -100,18 +98,6 @@ func inspectFreezers(db ethdb.Database) ([]freezerInfo, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
file, err := os.Open(filepath.Join(datadir, StateFreezerName))
if err != nil {
return nil, err
}
defer file.Close()
// if state freezer folder has been pruned, there is no need for inspection
_, err = file.Readdirnames(1)
if err == io.EOF {
continue
}
f, err := NewStateFreezer(datadir, true, 0) f, err := NewStateFreezer(datadir, true, 0)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@@ -59,7 +59,6 @@ type chainFreezer struct {
trigger chan chan struct{} // Manual blocking freeze trigger, test determinism trigger chan chan struct{} // Manual blocking freeze trigger, test determinism
freezeEnv atomic.Value freezeEnv atomic.Value
waitEnvTimes int
multiDatabase bool multiDatabase bool
} }
@@ -92,7 +91,7 @@ func (f *chainFreezer) Close() error {
// readHeadNumber returns the number of chain head block. 0 is returned if the // readHeadNumber returns the number of chain head block. 0 is returned if the
// block is unknown or not available yet. // block is unknown or not available yet.
func (f *chainFreezer) readHeadNumber(db ethdb.Reader) uint64 { func (f *chainFreezer) readHeadNumber(db ethdb.KeyValueReader) uint64 {
hash := ReadHeadBlockHash(db) hash := ReadHeadBlockHash(db)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
log.Error("Head block is not reachable") log.Error("Head block is not reachable")
@@ -108,7 +107,7 @@ func (f *chainFreezer) readHeadNumber(db ethdb.Reader) uint64 {
// readFinalizedNumber returns the number of finalized block. 0 is returned // readFinalizedNumber returns the number of finalized block. 0 is returned
// if the block is unknown or not available yet. // if the block is unknown or not available yet.
func (f *chainFreezer) readFinalizedNumber(db ethdb.Reader) uint64 { func (f *chainFreezer) readFinalizedNumber(db ethdb.KeyValueReader) uint64 {
hash := ReadFinalizedBlockHash(db) hash := ReadFinalizedBlockHash(db)
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
return 0 return 0
@@ -123,7 +122,7 @@ func (f *chainFreezer) readFinalizedNumber(db ethdb.Reader) uint64 {
// freezeThreshold returns the threshold for chain freezing. It's determined // freezeThreshold returns the threshold for chain freezing. It's determined
// by formula: max(finality, HEAD-params.FullImmutabilityThreshold). // by formula: max(finality, HEAD-params.FullImmutabilityThreshold).
func (f *chainFreezer) freezeThreshold(db ethdb.Reader) (uint64, error) { func (f *chainFreezer) freezeThreshold(db ethdb.KeyValueReader) (uint64, error) {
var ( var (
head = f.readHeadNumber(db) head = f.readHeadNumber(db)
final = f.readFinalizedNumber(db) final = f.readFinalizedNumber(db)
@@ -179,6 +178,19 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
} }
} }
// check freezer env first, it must wait a while when the env is necessary
err := f.checkFreezerEnv()
if err == missFreezerEnvErr {
log.Warn("Freezer need related env, may wait for a while", "err", err)
backoff = true
continue
}
if err != nil {
log.Error("Freezer check FreezerEnv err", "err", err)
backoff = true
continue
}
var ( var (
frozen uint64 frozen uint64
threshold uint64 threshold uint64
@@ -188,7 +200,6 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
hash common.Hash hash common.Hash
number *uint64 number *uint64
head *types.Header head *types.Header
err error
) )
// use finalized block as the chain freeze indicator was used for multiDatabase feature, if multiDatabase is false, keep 9W blocks in db // use finalized block as the chain freeze indicator was used for multiDatabase feature, if multiDatabase is false, keep 9W blocks in db
@@ -271,18 +282,6 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
last = first + freezerBatchLimit last = first + freezerBatchLimit
} }
} }
// check env first before chain freeze, it must wait when the env is necessary
if err := f.checkFreezerEnv(); err != nil {
f.waitEnvTimes++
if f.waitEnvTimes%30 == 0 {
log.Warn("Freezer need related env, may wait for a while, and it's not a issue when non-import block", "err", err)
return
}
backoff = true
continue
}
// Seems we have data ready to be frozen, process in usable batches // Seems we have data ready to be frozen, process in usable batches
var ( var (
start = time.Now() start = time.Now()
@@ -545,7 +544,14 @@ func (f *chainFreezer) checkFreezerEnv() error {
if exist { if exist {
return nil return nil
} }
blobFrozen, err := f.TableAncients(ChainFreezerBlobSidecarTable)
if err != nil {
return err
}
if blobFrozen > 0 {
return missFreezerEnvErr return missFreezerEnvErr
}
return nil
} }
func isCancun(env *ethdb.FreezerEnv, num *big.Int, time uint64) bool { func isCancun(env *ethdb.FreezerEnv, num *big.Int, time uint64) bool {

View File

@@ -35,16 +35,16 @@ import (
// injects into the database the block hash->number mappings. // injects into the database the block hash->number mappings.
func InitDatabaseFromFreezer(db ethdb.Database) { func InitDatabaseFromFreezer(db ethdb.Database) {
// If we can't access the freezer or it's empty, abort // If we can't access the freezer or it's empty, abort
frozen, err := db.BlockStore().ItemAmountInAncient() frozen, err := db.ItemAmountInAncient()
if err != nil || frozen == 0 { if err != nil || frozen == 0 {
return return
} }
var ( var (
batch = db.BlockStore().NewBatch() batch = db.NewBatch()
start = time.Now() start = time.Now()
logged = start.Add(-7 * time.Second) // Unindex during import is fast, don't double log logged = start.Add(-7 * time.Second) // Unindex during import is fast, don't double log
hash common.Hash hash common.Hash
offset = db.BlockStore().AncientOffSet() offset = db.AncientOffSet()
) )
for i := uint64(0) + offset; i < frozen+offset; i++ { for i := uint64(0) + offset; i < frozen+offset; i++ {
// We read 100K hashes at a time, for a total of 3.2M // We read 100K hashes at a time, for a total of 3.2M
@@ -52,7 +52,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
if i+count > frozen+offset { if i+count > frozen+offset {
count = frozen + offset - i count = frozen + offset - i
} }
data, err := db.BlockStore().AncientRange(ChainFreezerHashTable, i, count, 32*count) data, err := db.AncientRange(ChainFreezerHashTable, i, count, 32*count)
if err != nil { if err != nil {
log.Crit("Failed to init database from freezer", "err", err) log.Crit("Failed to init database from freezer", "err", err)
} }
@@ -81,7 +81,7 @@ func InitDatabaseFromFreezer(db ethdb.Database) {
batch.Reset() batch.Reset()
WriteHeadHeaderHash(db.BlockStore(), hash) 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))) log.Info("Initialized database from freezer", "blocks", frozen, "elapsed", common.PrettyDuration(time.Since(start)))
} }
@@ -100,7 +100,7 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
number uint64 number uint64
rlp rlp.RawValue rlp rlp.RawValue
} }
if offset := db.BlockStore().AncientOffSet(); offset > from { if offset := db.AncientOffSet(); offset > from {
from = offset from = offset
} }
if to <= from { if to <= from {
@@ -122,7 +122,7 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
} }
defer close(rlpCh) defer close(rlpCh)
for n != end { for n != end {
data := ReadCanonicalBodyRLP(db, n) data := ReadCanonicalBodyRLP(db.BlockStore(), n)
// Feed the block to the aggregator, or abort on interrupt // Feed the block to the aggregator, or abort on interrupt
select { select {
case rlpCh <- &numberRlp{n, data}: case rlpCh <- &numberRlp{n, data}:
@@ -187,7 +187,7 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool
// signal received. // signal received.
func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) { func indexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) {
// short circuit for invalid range // short circuit for invalid range
if offset := db.BlockStore().AncientOffSet(); offset > from { if offset := db.AncientOffSet(); offset > from {
from = offset from = offset
} }
if from >= to { if from >= to {
@@ -286,7 +286,7 @@ func indexTransactionsForTesting(db ethdb.Database, from uint64, to uint64, inte
// signal received. // signal received.
func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) { func unindexTransactions(db ethdb.Database, from uint64, to uint64, interrupt chan struct{}, hook func(uint64) bool, report bool) {
// short circuit for invalid range // short circuit for invalid range
if offset := db.BlockStore().AncientOffSet(); offset > from { if offset := db.AncientOffSet(); offset > from {
from = offset from = offset
} }
if from >= to { if from >= to {

View File

@@ -61,10 +61,8 @@ func (frdb *freezerdb) BlockStoreReader() ethdb.Reader {
} }
func (frdb *freezerdb) BlockStoreWriter() ethdb.Writer { func (frdb *freezerdb) BlockStoreWriter() ethdb.Writer {
if frdb.blockStore == nil { //TODO implement me
return frdb panic("implement me")
}
return frdb.blockStore
} }
// AncientDatadir returns the path of root ancient directory. // AncientDatadir returns the path of root ancient directory.
@@ -118,13 +116,6 @@ func (frdb *freezerdb) StateStore() ethdb.Database {
return frdb.stateStore return frdb.stateStore
} }
func (frdb *freezerdb) GetStateStore() ethdb.Database {
if frdb.stateStore != nil {
return frdb.stateStore
}
return frdb
}
func (frdb *freezerdb) SetStateStore(state ethdb.Database) { func (frdb *freezerdb) SetStateStore(state ethdb.Database) {
if frdb.stateStore != nil { if frdb.stateStore != nil {
frdb.stateStore.Close() frdb.stateStore.Close()
@@ -202,7 +193,7 @@ func (db *nofreezedb) Ancients() (uint64, error) {
return 0, errNotSupported return 0, errNotSupported
} }
// ItemAmountInAncient returns an error as we don't have a backing chain freezer. // Ancients returns an error as we don't have a backing chain freezer.
func (db *nofreezedb) ItemAmountInAncient() (uint64, error) { func (db *nofreezedb) ItemAmountInAncient() (uint64, error) {
return 0, errNotSupported return 0, errNotSupported
} }
@@ -263,13 +254,6 @@ func (db *nofreezedb) SetStateStore(state ethdb.Database) {
db.stateStore = state db.stateStore = state
} }
func (db *nofreezedb) GetStateStore() ethdb.Database {
if db.stateStore != nil {
return db.stateStore
}
return db
}
func (db *nofreezedb) StateStoreReader() ethdb.Reader { func (db *nofreezedb) StateStoreReader() ethdb.Reader {
if db.stateStore != nil { if db.stateStore != nil {
return db.stateStore return db.stateStore
@@ -347,111 +331,6 @@ func NewDatabase(db ethdb.KeyValueStore) ethdb.Database {
return &nofreezedb{KeyValueStore: db} return &nofreezedb{KeyValueStore: db}
} }
type emptyfreezedb struct {
ethdb.KeyValueStore
}
// HasAncient returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) HasAncient(kind string, number uint64) (bool, error) {
return false, nil
}
// Ancient returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) Ancient(kind string, number uint64) ([]byte, error) {
return nil, nil
}
// AncientRange returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) AncientRange(kind string, start, max, maxByteSize uint64) ([][]byte, error) {
return nil, nil
}
// Ancients returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) Ancients() (uint64, error) {
return 0, nil
}
// ItemAmountInAncient returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) ItemAmountInAncient() (uint64, error) {
return 0, nil
}
// Tail returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) Tail() (uint64, error) {
return 0, nil
}
// AncientSize returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) AncientSize(kind string) (uint64, error) {
return 0, nil
}
// ModifyAncients returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) ModifyAncients(func(ethdb.AncientWriteOp) error) (int64, error) {
return 0, nil
}
// TruncateHead returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) TruncateHead(items uint64) (uint64, error) {
return 0, nil
}
// TruncateTail returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) TruncateTail(items uint64) (uint64, error) {
return 0, nil
}
// TruncateTableTail returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) TruncateTableTail(kind string, tail uint64) (uint64, error) {
return 0, nil
}
// ResetTable returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) ResetTable(kind string, startAt uint64, onlyEmpty bool) error {
return nil
}
// Sync returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) Sync() error {
return nil
}
func (db *emptyfreezedb) DiffStore() ethdb.KeyValueStore { return db }
func (db *emptyfreezedb) SetDiffStore(diff ethdb.KeyValueStore) {}
func (db *emptyfreezedb) StateStore() ethdb.Database { return db }
func (db *emptyfreezedb) GetStateStore() ethdb.Database { return db }
func (db *emptyfreezedb) SetStateStore(state ethdb.Database) {}
func (db *emptyfreezedb) StateStoreReader() ethdb.Reader { return db }
func (db *emptyfreezedb) BlockStore() ethdb.Database { return db }
func (db *emptyfreezedb) SetBlockStore(block ethdb.Database) {}
func (db *emptyfreezedb) HasSeparateBlockStore() bool { return false }
func (db *emptyfreezedb) BlockStoreReader() ethdb.Reader { return db }
func (db *emptyfreezedb) BlockStoreWriter() ethdb.Writer { return db }
func (db *emptyfreezedb) ReadAncients(fn func(reader ethdb.AncientReaderOp) error) (err error) {
return nil
}
func (db *emptyfreezedb) AncientOffSet() uint64 { return 0 }
// MigrateTable returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) MigrateTable(kind string, convert convertLegacyFn) error {
return nil
}
// AncientDatadir returns nil for pruned db that we don't have a backing chain freezer.
func (db *emptyfreezedb) AncientDatadir() (string, error) {
return "", nil
}
func (db *emptyfreezedb) SetupFreezerEnv(env *ethdb.FreezerEnv) error {
return nil
}
// NewEmptyFreezeDB is used for CLI such as `geth db inspect` in pruned db that we don't
// have a backing chain freezer.
// WARNING: it must be only used in the above case.
func NewEmptyFreezeDB(db ethdb.KeyValueStore) ethdb.Database {
return &emptyfreezedb{KeyValueStore: db}
}
// NewFreezerDb only create a freezer without statedb. // NewFreezerDb only create a freezer without statedb.
func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool, newOffSet uint64) (*Freezer, error) { func NewFreezerDb(db ethdb.KeyValueStore, frz, namespace string, readonly bool, newOffSet uint64) (*Freezer, error) {
// Create the idle freezer instance, this operation should be atomic to avoid mismatch between offset and acientDB. // Create the idle freezer instance, this operation should be atomic to avoid mismatch between offset and acientDB.
@@ -501,12 +380,6 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
offset = ReadOffSetOfCurrentAncientFreezer(db) offset = ReadOffSetOfCurrentAncientFreezer(db)
} }
// This case is used for someone who wants to execute geth db inspect CLI in a pruned db
if !disableFreeze && readonly && ReadAncientType(db) == PruneFreezerType {
log.Warn("Disk db is pruned, using an empty freezer db for CLI")
return NewEmptyFreezeDB(db), nil
}
if pruneAncientData && !disableFreeze && !readonly { if pruneAncientData && !disableFreeze && !readonly {
frdb, err := newPrunedFreezer(resolveChainFreezerDir(ancient), db, offset) frdb, err := newPrunedFreezer(resolveChainFreezerDir(ancient), db, offset)
if err != nil { if err != nil {
@@ -535,17 +408,8 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
// Create the idle freezer instance // Create the idle freezer instance
frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly, offset, multiDatabase) frdb, err := newChainFreezer(resolveChainFreezerDir(ancient), namespace, readonly, offset, multiDatabase)
// We are creating the freezerdb here because the validation logic for db and freezer below requires certain interfaces
// that need a database type. Therefore, we are pre-creating it for subsequent use.
freezerDb := &freezerdb{
ancientRoot: ancient,
KeyValueStore: db,
AncientStore: frdb,
AncientFreezer: frdb,
}
if err != nil { if err != nil {
printChainMetadata(freezerDb) printChainMetadata(db)
return nil, err return nil, err
} }
@@ -581,10 +445,10 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
// the freezer and the key-value store. // the freezer and the key-value store.
frgenesis, err := frdb.Ancient(ChainFreezerHashTable, 0) frgenesis, err := frdb.Ancient(ChainFreezerHashTable, 0)
if err != nil { if err != nil {
printChainMetadata(freezerDb) printChainMetadata(db)
return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err) return nil, fmt.Errorf("failed to retrieve genesis from ancient %v", err)
} else if !bytes.Equal(kvgenesis, frgenesis) { } else if !bytes.Equal(kvgenesis, frgenesis) {
printChainMetadata(freezerDb) printChainMetadata(db)
return nil, fmt.Errorf("genesis mismatch: %#x (leveldb) != %#x (ancients)", kvgenesis, frgenesis) return nil, fmt.Errorf("genesis mismatch: %#x (leveldb) != %#x (ancients)", kvgenesis, frgenesis)
} }
// Key-value store and freezer belong to the same network. Ensure that they // Key-value store and freezer belong to the same network. Ensure that they
@@ -592,7 +456,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 { if kvhash, _ := db.Get(headerHashKey(frozen)); len(kvhash) == 0 {
// Subsequent header after the freezer limit is missing from the database. // Subsequent header after the freezer limit is missing from the database.
// Reject startup if the database has a more recent head. // Reject startup if the database has a more recent head.
if head := *ReadHeaderNumber(freezerDb, ReadHeadHeaderHash(freezerDb)); head > frozen-1 { if head := *ReadHeaderNumber(db, ReadHeadHeaderHash(db)); head > frozen-1 {
// Find the smallest block stored in the key-value store // Find the smallest block stored in the key-value store
// in range of [frozen, head] // in range of [frozen, head]
var number uint64 var number uint64
@@ -602,7 +466,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
} }
} }
// We are about to exit on error. Print database metadata before exiting // We are about to exit on error. Print database metadata before exiting
printChainMetadata(freezerDb) printChainMetadata(db)
return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ", return nil, fmt.Errorf("gap in the chain between ancients [0 - #%d] and leveldb [#%d - #%d] ",
frozen-1, number, head) frozen-1, number, head)
} }
@@ -617,11 +481,11 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
// store, otherwise we'll end up missing data. We check block #1 to decide // store, otherwise we'll end up missing data. We check block #1 to decide
// if we froze anything previously or not, but do take care of databases with // if we froze anything previously or not, but do take care of databases with
// only the genesis block. // only the genesis block.
if ReadHeadHeaderHash(freezerDb) != common.BytesToHash(kvgenesis) { if ReadHeadHeaderHash(db) != common.BytesToHash(kvgenesis) {
// Key-value store contains more data than the genesis block, make sure we // Key-value store contains more data than the genesis block, make sure we
// didn't freeze anything yet. // didn't freeze anything yet.
if kvblob, _ := db.Get(headerHashKey(1)); len(kvblob) == 0 { if kvblob, _ := db.Get(headerHashKey(1)); len(kvblob) == 0 {
printChainMetadata(freezerDb) printChainMetadata(db)
return nil, errors.New("ancient chain segments already extracted, please set --datadir.ancient to the correct path") return nil, errors.New("ancient chain segments already extracted, please set --datadir.ancient to the correct path")
} }
// Block #1 is still in the database, we're allowed to init a new freezer // Block #1 is still in the database, we're allowed to init a new freezer
@@ -643,7 +507,12 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
frdb.wg.Done() frdb.wg.Done()
}() }()
} }
return freezerDb, nil return &freezerdb{
ancientRoot: ancient,
KeyValueStore: db,
AncientStore: frdb,
AncientFreezer: frdb,
}, nil
} }
// NewMemoryDatabase creates an ephemeral in-memory key-value database without a // NewMemoryDatabase creates an ephemeral in-memory key-value database without a
@@ -765,7 +634,7 @@ func Open(o OpenOptions) (ethdb.Database, error) {
} }
if ReadAncientType(kvdb) == PruneFreezerType { if ReadAncientType(kvdb) == PruneFreezerType {
if !o.PruneAncientData { if !o.PruneAncientData {
log.Warn("NOTICE: You're opening a pruned disk db!") log.Warn("Disk db is pruned")
} }
} }
if len(o.AncientsDirectory) == 0 { if len(o.AncientsDirectory) == 0 {
@@ -894,7 +763,7 @@ func DataTypeByKey(key []byte) DataType {
return StateDataType return StateDataType
} }
} }
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey, headBlockKey, headFastBlockKey} { for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey} {
if bytes.Equal(key, meta) { if bytes.Equal(key, meta) {
return BlockDataType return BlockDataType
} }
@@ -1109,7 +978,7 @@ func InspectDatabase(db ethdb.Database, keyPrefix, keyStart []byte) error {
hashNumPairings.Add(size) hashNumPairings.Add(size)
default: default:
var accounted bool var accounted bool
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey, headBlockKey, headFastBlockKey} { for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey} {
if bytes.Equal(key, meta) { if bytes.Equal(key, meta) {
metadata.Add(size) metadata.Add(size)
accounted = true accounted = true
@@ -1259,7 +1128,7 @@ func DeleteTrieState(db ethdb.Database) error {
} }
// printChainMetadata prints out chain metadata to stderr. // printChainMetadata prints out chain metadata to stderr.
func printChainMetadata(db ethdb.Reader) { func printChainMetadata(db ethdb.KeyValueStore) {
fmt.Fprintf(os.Stderr, "Chain metadata\n") fmt.Fprintf(os.Stderr, "Chain metadata\n")
for _, v := range ReadChainMetadata(db) { for _, v := range ReadChainMetadata(db) {
fmt.Fprintf(os.Stderr, " %s\n", strings.Join(v, ": ")) fmt.Fprintf(os.Stderr, " %s\n", strings.Join(v, ": "))
@@ -1270,7 +1139,7 @@ func printChainMetadata(db ethdb.Reader) {
// ReadChainMetadata returns a set of key/value pairs that contains information // ReadChainMetadata returns a set of key/value pairs that contains information
// about the database chain status. This can be used for diagnostic purposes // about the database chain status. This can be used for diagnostic purposes
// when investigating the state of the node. // when investigating the state of the node.
func ReadChainMetadata(db ethdb.Reader) [][]string { func ReadChainMetadata(db ethdb.KeyValueStore) [][]string {
pp := func(val *uint64) string { pp := func(val *uint64) string {
if val == nil { if val == nil {
return "<nil>" return "<nil>"
@@ -1292,3 +1161,26 @@ func ReadChainMetadata(db ethdb.Reader) [][]string {
} }
return data return data
} }
func ReadChainMetadataFromMultiDatabase(db ethdb.Database) [][]string {
pp := func(val *uint64) string {
if val == nil {
return "<nil>"
}
return fmt.Sprintf("%d (%#x)", *val, *val)
}
data := [][]string{
{"databaseVersion", pp(ReadDatabaseVersion(db))},
{"headBlockHash", fmt.Sprintf("%v", ReadHeadBlockHash(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)))},
{"snapshotDisabled", fmt.Sprintf("%v", ReadSnapshotDisabled(db))},
{"snapshotJournal", fmt.Sprintf("%d bytes", len(ReadSnapshotJournal(db)))},
{"snapshotRecoveryNumber", pp(ReadSnapshotRecoveryNumber(db))},
{"snapshotRoot", fmt.Sprintf("%v", ReadSnapshotRoot(db))},
{"txIndexTail", pp(ReadTxIndexTail(db))},
}
return data
}

View File

@@ -541,6 +541,41 @@ func gcKvStore(db ethdb.KeyValueStore, ancients []common.Hash, first uint64, fro
} }
batch.Reset() batch.Reset()
// Step into the future and delete and dangling side chains
if frozen > 0 {
tip := frozen
nfdb := &nofreezedb{KeyValueStore: db}
for len(dangling) > 0 {
drop := make(map[common.Hash]struct{})
for _, hash := range dangling {
log.Debug("Dangling parent from freezer", "number", tip-1, "hash", hash)
drop[hash] = struct{}{}
}
children := ReadAllHashes(db, tip)
for i := 0; i < len(children); i++ {
// Dig up the child and ensure it's dangling
child := ReadHeader(nfdb, children[i], tip)
if child == nil {
log.Error("Missing dangling header", "number", tip, "hash", children[i])
continue
}
if _, ok := drop[child.ParentHash]; !ok {
children = append(children[:i], children[i+1:]...)
i--
continue
}
// Delete all block data associated with the child
log.Debug("Deleting dangling block", "number", tip, "hash", children[i], "parent", child.ParentHash)
DeleteBlock(batch, children[i], tip)
}
dangling = children
tip++
}
if err := batch.Write(); err != nil {
log.Crit("Failed to delete dangling side blocks", "err", err)
}
}
// Log something friendly for the user // Log something friendly for the user
context := []interface{}{ context := []interface{}{
"blocks", frozen - first, "elapsed", common.PrettyDuration(time.Since(start)), "number", frozen - 1, "blocks", frozen - first, "elapsed", common.PrettyDuration(time.Since(start)), "number", frozen - 1,

View File

@@ -127,11 +127,6 @@ func newFreezerTable(path, name string, disableSnappy, readonly bool) (*freezerT
return newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, readonly) return newTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, readonly)
} }
// newAdditionTable opens the given path as a addition table.
func newAdditionTable(path, name string, disableSnappy, readonly bool) (*freezerTable, error) {
return openAdditionTable(path, name, metrics.NilMeter{}, metrics.NilMeter{}, metrics.NilGauge{}, freezerTableSize, disableSnappy, readonly)
}
// newTable opens a freezer table, creating the data and index files if they are // newTable opens a freezer table, creating the data and index files if they are
// non-existent. Both files are truncated to the shortest common length to ensure // non-existent. Both files are truncated to the shortest common length to ensure
// they don't go out of sync. // they don't go out of sync.

View File

@@ -8,8 +8,6 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"golang.org/x/exp/slices"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@@ -68,49 +66,28 @@ func newPrunedFreezer(datadir string, db ethdb.KeyValueStore, offset uint64) (*p
// repair init frozen , compatible disk-ancientdb and pruner-block-tool. // repair init frozen , compatible disk-ancientdb and pruner-block-tool.
func (f *prunedfreezer) repair(datadir string) error { func (f *prunedfreezer) repair(datadir string) error {
offset := atomic.LoadUint64(&f.frozen)
// compatible freezer // compatible freezer
minItems := uint64(math.MaxUint64) min := uint64(math.MaxUint64)
for name, disableSnappy := range chainFreezerNoSnappy { for name, disableSnappy := range chainFreezerNoSnappy {
var ( table, err := newFreezerTable(datadir, name, disableSnappy, false)
table *freezerTable
err error
)
if slices.Contains(additionTables, name) {
table, err = newAdditionTable(datadir, name, disableSnappy, false)
} else {
table, err = newFreezerTable(datadir, name, disableSnappy, false)
}
if err != nil { if err != nil {
return err return err
} }
// addition tables only align head
if slices.Contains(additionTables, name) {
if EmptyTable(table) {
continue
}
}
items := table.items.Load() items := table.items.Load()
if minItems > items { if min > items {
minItems = items min = items
} }
table.Close() table.Close()
} }
log.Info("Read ancientdb item counts", "items", min)
offset += min
// If minItems is non-zero, it indicates that the chain freezer was previously enabled, and we should use minItems as the current frozen value. if frozen := ReadFrozenOfAncientFreezer(f.db); frozen > offset {
// If minItems is zero, it indicates that the pruneAncient was previously enabled, and we should continue using frozen offset = frozen
// (retrieved from CurrentAncientFreezer) as the current frozen value.
offset := minItems
if offset == 0 {
// no item in ancientDB, init `offset` to the `f.frozen`
offset = atomic.LoadUint64(&f.frozen)
} }
log.Info("Read ancientdb item counts", "items", minItems, "offset", offset)
// FrozenOfAncientFreezer is the progress of the last prune-freezer freeze. atomic.StoreUint64(&f.frozen, offset)
frozenInDB := ReadFrozenOfAncientFreezer(f.db)
maxOffset := max(offset, frozenInDB)
atomic.StoreUint64(&f.frozen, maxOffset)
if err := f.Sync(); err != nil { if err := f.Sync(); err != nil {
return nil return nil
} }
@@ -322,9 +299,10 @@ func (f *prunedfreezer) freeze() {
log.Error("Append ancient err", "number", f.frozen, "hash", hash, "err", err) log.Error("Append ancient err", "number", f.frozen, "hash", hash, "err", err)
break break
} }
// may include common.Hash{}, will be delete in gcKvStore if hash != (common.Hash{}) {
ancients = append(ancients, hash) ancients = append(ancients, hash)
} }
}
// Batch of blocks have been frozen, flush them before wiping from leveldb // Batch of blocks have been frozen, flush them before wiping from leveldb
if err := f.Sync(); err != nil { if err := f.Sync(); err != nil {
log.Crit("Failed to flush frozen tables", "err", err) log.Crit("Failed to flush frozen tables", "err", err)

View File

@@ -251,10 +251,6 @@ func (t *table) SetStateStore(state ethdb.Database) {
panic("not implement") panic("not implement")
} }
func (t *table) GetStateStore() ethdb.Database {
return nil
}
func (t *table) StateStoreReader() ethdb.Reader { func (t *table) StateStoreReader() ethdb.Reader {
return nil return nil
} }

View File

@@ -164,7 +164,7 @@ func (ch createObjectChange) dirtied() *common.Address {
func (ch resetObjectChange) revert(s *StateDB) { func (ch resetObjectChange) revert(s *StateDB) {
s.setStateObject(ch.prev) s.setStateObject(ch.prev)
if !ch.prevdestruct { if !ch.prevdestruct {
delete(s.stateObjectsDestruct, ch.prev.address) s.deleteStateObjectsDestruct(ch.prev.address)
} }
if ch.prevAccount != nil { if ch.prevAccount != nil {
s.accounts[ch.prev.addrHash] = ch.prevAccount s.accounts[ch.prev.addrHash] = ch.prevAccount

View File

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

View File

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

View File

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

View File

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

View File

@@ -19,6 +19,7 @@ package state
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"golang.org/x/exp/slices"
"io" "io"
"sync" "sync"
"time" "time"
@@ -68,6 +69,11 @@ type stateObject struct {
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
data types.StateAccount // Account data with all mutations applied in the scope of block data types.StateAccount // Account data with all mutations applied in the scope of block
// dirty account state
dirtyBalance *uint256.Int
dirtyNonce *uint64
dirtyCodeHash []byte
// Write caches. // Write caches.
trie Trie // storage trie, which becomes non-nil on first access trie Trie // storage trie, which becomes non-nil on first access
code Code // contract bytecode, which gets set when code is loaded code Code // contract bytecode, which gets set when code is loaded
@@ -95,7 +101,7 @@ type stateObject struct {
// empty returns whether the account is considered empty. // empty returns whether the account is considered empty.
func (s *stateObject) empty() bool { func (s *stateObject) empty() bool {
return s.data.Nonce == 0 && s.data.Balance.IsZero() && bytes.Equal(s.data.CodeHash, types.EmptyCodeHash.Bytes()) return s.Nonce() == 0 && s.Balance().IsZero() && bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes())
} }
// newObject creates a state object. // newObject creates a state object.
@@ -113,7 +119,7 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
storageMap = db.GetStorage(address) storageMap = db.GetStorage(address)
} }
return &stateObject{ s := &stateObject{
db: db, db: db,
address: address, address: address,
addrHash: crypto.Keccak256Hash(address[:]), addrHash: crypto.Keccak256Hash(address[:]),
@@ -125,6 +131,15 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *s
dirtyStorage: make(Storage), dirtyStorage: make(Storage),
created: created, created: created,
} }
// dirty data when create a new account
if acct == nil {
s.dirtyBalance = acct.Balance.Clone()
s.dirtyNonce = new(uint64)
*s.dirtyNonce = acct.Nonce
s.dirtyCodeHash = acct.CodeHash
}
return s
} }
// EncodeRLP implements rlp.Encoder. // EncodeRLP implements rlp.Encoder.
@@ -219,18 +234,10 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
// 1) resurrect happened, and new slot values were set -- those should // 1) resurrect happened, and new slot values were set -- those should
// have been handles via pendingStorage above. // have been handles via pendingStorage above.
// 2) we don't have new values, and can deliver empty response back // 2) we don't have new values, and can deliver empty response back
if _, destructed := s.db.stateObjectsDestruct[s.address]; destructed { if _, destructed := s.db.queryStateObjectsDestruct(s.address); destructed {
return common.Hash{} return common.Hash{}
} }
// If no live objects are available, attempt to use snapshots // If no live objects are available, attempt to use snapshots
defer func(start time.Time) {
stateDBGetTimer.UpdateSince(start)
stateDBGetQPS.Mark(1)
stateDBGetStorageTimer.UpdateSince(start)
stateDBGetStorageQPS.Mark(1)
}(time.Now())
var ( var (
enc []byte enc []byte
err error err error
@@ -302,6 +309,18 @@ func (s *stateObject) finalise(prefetch bool) {
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure
} }
} }
if s.dirtyNonce != nil {
s.data.Nonce = *s.dirtyNonce
s.dirtyNonce = nil
}
if s.dirtyBalance != nil {
s.data.Balance = s.dirtyBalance
s.dirtyBalance = nil
}
if s.dirtyCodeHash != nil {
s.data.CodeHash = s.dirtyCodeHash
s.dirtyCodeHash = nil
}
if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash { if s.db.prefetcher != nil && prefetch && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch) s.db.prefetcher.prefetch(s.addrHash, s.data.Root, s.address, slotsToPrefetch)
} }
@@ -310,6 +329,26 @@ func (s *stateObject) finalise(prefetch bool) {
} }
} }
func (s *stateObject) finaliseRWSet() {
for key, value := range s.dirtyStorage {
// three are some unclean dirtyStorage from previous reverted txs, it will skip finalise
// so add a new rule, if val has no change, then skip it
if value == s.GetCommittedState(key) {
continue
}
s.db.RecordWrite(types.StorageStateKey(s.address, key), value)
}
if s.dirtyNonce != nil && *s.dirtyNonce != s.data.Nonce {
s.db.RecordWrite(types.AccountStateKey(s.address, types.AccountNonce), *s.dirtyNonce)
}
if s.dirtyBalance != nil && !s.dirtyBalance.Eq(s.data.Balance) {
s.db.RecordWrite(types.AccountStateKey(s.address, types.AccountBalance), s.dirtyBalance.Clone())
}
if s.dirtyCodeHash != nil && !slices.Equal(s.dirtyCodeHash, s.data.CodeHash) {
s.db.RecordWrite(types.AccountStateKey(s.address, types.AccountCodeHash), s.dirtyCodeHash)
}
}
// updateTrie is responsible for persisting cached storage changes into the // updateTrie is responsible for persisting cached storage changes into the
// object's storage trie. In case the storage trie is not yet loaded, this // object's storage trie. In case the storage trie is not yet loaded, this
// function will load the trie automatically. If any issues arise during the // function will load the trie automatically. If any issues arise during the
@@ -509,13 +548,13 @@ func (s *stateObject) SubBalance(amount *uint256.Int) {
func (s *stateObject) SetBalance(amount *uint256.Int) { func (s *stateObject) SetBalance(amount *uint256.Int) {
s.db.journal.append(balanceChange{ s.db.journal.append(balanceChange{
account: &s.address, account: &s.address,
prev: new(uint256.Int).Set(s.data.Balance), prev: new(uint256.Int).Set(s.Balance()),
}) })
s.setBalance(amount) s.setBalance(amount)
} }
func (s *stateObject) setBalance(amount *uint256.Int) { func (s *stateObject) setBalance(amount *uint256.Int) {
s.data.Balance = amount s.dirtyBalance = amount
} }
func (s *stateObject) deepCopy(db *StateDB) *stateObject { func (s *stateObject) deepCopy(db *StateDB) *stateObject {
@@ -536,6 +575,17 @@ func (s *stateObject) deepCopy(db *StateDB) *stateObject {
obj.selfDestructed = s.selfDestructed obj.selfDestructed = s.selfDestructed
obj.dirtyCode = s.dirtyCode obj.dirtyCode = s.dirtyCode
obj.deleted = s.deleted obj.deleted = s.deleted
// dirty states
if s.dirtyNonce != nil {
obj.dirtyNonce = new(uint64)
*obj.dirtyNonce = *s.dirtyNonce
}
if s.dirtyBalance != nil {
obj.dirtyBalance = s.dirtyBalance.Clone()
}
obj.dirtyCodeHash = s.dirtyCodeHash
return obj return obj
} }
@@ -593,32 +643,44 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) {
func (s *stateObject) setCode(codeHash common.Hash, code []byte) { func (s *stateObject) setCode(codeHash common.Hash, code []byte) {
s.code = code s.code = code
s.data.CodeHash = codeHash[:] s.dirtyCodeHash = codeHash[:]
s.dirtyCode = true s.dirtyCode = true
} }
func (s *stateObject) SetNonce(nonce uint64) { func (s *stateObject) SetNonce(nonce uint64) {
s.db.journal.append(nonceChange{ s.db.journal.append(nonceChange{
account: &s.address, account: &s.address,
prev: s.data.Nonce, prev: s.Nonce(),
}) })
s.setNonce(nonce) s.setNonce(nonce)
} }
func (s *stateObject) setNonce(nonce uint64) { func (s *stateObject) setNonce(nonce uint64) {
s.data.Nonce = nonce s.dirtyNonce = &nonce
} }
func (s *stateObject) CodeHash() []byte { func (s *stateObject) CodeHash() []byte {
return s.data.CodeHash if len(s.dirtyCodeHash) > 0 {
return s.dirtyCodeHash
}
ret := s.data.CodeHash
return ret
} }
func (s *stateObject) Balance() *uint256.Int { func (s *stateObject) Balance() *uint256.Int {
return s.data.Balance if s.dirtyBalance != nil {
return s.dirtyBalance
}
ret := s.data.Balance
return ret
} }
func (s *stateObject) Nonce() uint64 { func (s *stateObject) Nonce() uint64 {
return s.data.Nonce if s.dirtyNonce != nil {
return *s.dirtyNonce
}
ret := s.data.Nonce
return ret
} }
func (s *stateObject) Root() common.Hash { func (s *stateObject) Root() common.Hash {

View File

@@ -54,16 +54,6 @@ type revision struct {
journalIndex int journalIndex int
} }
var (
stateDBGetTimer = metrics.NewRegisteredTimer("statedb/get/time", nil)
stateDBGetQPS = metrics.NewRegisteredMeter("statedb/get/qps", nil)
stateDBGetAccountTimer = metrics.NewRegisteredTimer("statedb/account/get/time", nil)
stateDBGetAccountQPS = metrics.NewRegisteredMeter("statedb/account/get/qps", nil)
stateDBGetStorageTimer = metrics.NewRegisteredTimer("statedb/storage/get/time", nil)
stateDBGetStorageQPS = metrics.NewRegisteredMeter("statedb/storage/get/qps", nil)
)
// StateDB structs within the ethereum protocol are used to store anything // StateDB structs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing // within the merkle trie. StateDBs take care of caching and storing
// nested states. It's the general query interface to retrieve: // nested states. It's the general query interface to retrieve:
@@ -109,6 +99,7 @@ type StateDB struct {
stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie stateObjectsPending map[common.Address]struct{} // State objects finalized but not yet written to the trie
stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution stateObjectsDirty map[common.Address]struct{} // State objects modified in the current execution
stateObjectsDestruct map[common.Address]*types.StateAccount // State objects destructed in the block along with its previous value stateObjectsDestruct map[common.Address]*types.StateAccount // State objects destructed in the block along with its previous value
stateObjectsDestructDirty map[common.Address]*types.StateAccount
storagePool *StoragePool // sharedPool to store L1 originStorage of stateObjects storagePool *StoragePool // sharedPool to store L1 originStorage of stateObjects
writeOnSharedStorage bool // Write to the shared origin storage of a stateObject while reading from the underlying storage layer. writeOnSharedStorage bool // Write to the shared origin storage of a stateObject while reading from the underlying storage layer.
@@ -127,9 +118,15 @@ type StateDB struct {
// The tx context and all occurred logs in the scope of transaction. // The tx context and all occurred logs in the scope of transaction.
thash common.Hash thash common.Hash
txIndex int txIndex int
txIncarnation int
logs map[common.Hash][]*types.Log logs map[common.Hash][]*types.Log
logSize uint logSize uint
// parallel EVM related
rwSet *types.RWSet
mvStates *types.MVStates
es *types.ExeStat
// Preimages occurred seen by VM in the scope of block. // Preimages occurred seen by VM in the scope of block.
preimages map[common.Hash][]byte preimages map[common.Hash][]byte
@@ -176,7 +173,7 @@ func NewWithSharedPool(root common.Hash, db Database, snaps *snapshot.Tree) (*St
if err != nil { if err != nil {
return nil, err return nil, err
} }
//statedb.storagePool = NewStoragePool() statedb.storagePool = NewStoragePool()
return statedb, nil return statedb, nil
} }
@@ -194,6 +191,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
stateObjectsPending: make(map[common.Address]struct{}, defaultNumOfSlots), stateObjectsPending: make(map[common.Address]struct{}, defaultNumOfSlots),
stateObjectsDirty: make(map[common.Address]struct{}, defaultNumOfSlots), stateObjectsDirty: make(map[common.Address]struct{}, defaultNumOfSlots),
stateObjectsDestruct: make(map[common.Address]*types.StateAccount, defaultNumOfSlots), stateObjectsDestruct: make(map[common.Address]*types.StateAccount, defaultNumOfSlots),
stateObjectsDestructDirty: make(map[common.Address]*types.StateAccount, defaultNumOfSlots),
logs: make(map[common.Hash][]*types.Log), logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte), preimages: make(map[common.Hash][]byte),
journal: newJournal(), journal: newJournal(),
@@ -435,7 +433,10 @@ func (s *StateDB) Empty(addr common.Address) bool {
} }
// GetBalance retrieves the balance from the given address or 0 if object not found // GetBalance retrieves the balance from the given address or 0 if object not found
func (s *StateDB) GetBalance(addr common.Address) *uint256.Int { func (s *StateDB) GetBalance(addr common.Address) (ret *uint256.Int) {
defer func() {
s.RecordRead(types.AccountStateKey(addr, types.AccountBalance), ret)
}()
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Balance() return stateObject.Balance()
@@ -444,7 +445,10 @@ func (s *StateDB) GetBalance(addr common.Address) *uint256.Int {
} }
// GetNonce retrieves the nonce from the given address or 0 if object not found // GetNonce retrieves the nonce from the given address or 0 if object not found
func (s *StateDB) GetNonce(addr common.Address) uint64 { func (s *StateDB) GetNonce(addr common.Address) (ret uint64) {
defer func() {
s.RecordRead(types.AccountStateKey(addr, types.AccountNonce), ret)
}()
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Nonce() return stateObject.Nonce()
@@ -492,7 +496,10 @@ func (s *StateDB) GetCodeSize(addr common.Address) int {
return 0 return 0
} }
func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { func (s *StateDB) GetCodeHash(addr common.Address) (ret common.Hash) {
defer func() {
s.RecordRead(types.AccountStateKey(addr, types.AccountCodeHash), ret.Bytes())
}()
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return common.BytesToHash(stateObject.CodeHash()) return common.BytesToHash(stateObject.CodeHash())
@@ -501,7 +508,10 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
} }
// GetState retrieves a value from the given account's storage trie. // GetState retrieves a value from the given account's storage trie.
func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { func (s *StateDB) GetState(addr common.Address, hash common.Hash) (ret common.Hash) {
defer func() {
s.RecordRead(types.StorageStateKey(addr, hash), ret)
}()
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.GetState(hash) return stateObject.GetState(hash)
@@ -510,7 +520,10 @@ func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
} }
// GetCommittedState retrieves a value from the given account's committed storage trie. // GetCommittedState retrieves a value from the given account's committed storage trie.
func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { func (s *StateDB) GetCommittedState(addr common.Address, hash common.Hash) (ret common.Hash) {
defer func() {
s.RecordRead(types.StorageStateKey(addr, hash), ret)
}()
stateObject := s.getStateObject(addr) stateObject := s.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.GetCommittedState(hash) return stateObject.GetCommittedState(hash)
@@ -539,6 +552,7 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) { func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) {
stateObject := s.getOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
s.RecordRead(types.AccountStateKey(addr, types.AccountBalance), stateObject.Balance())
stateObject.AddBalance(amount) stateObject.AddBalance(amount)
} }
} }
@@ -547,6 +561,7 @@ func (s *StateDB) AddBalance(addr common.Address, amount *uint256.Int) {
func (s *StateDB) SubBalance(addr common.Address, amount *uint256.Int) { func (s *StateDB) SubBalance(addr common.Address, amount *uint256.Int) {
stateObject := s.getOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
if stateObject != nil { if stateObject != nil {
s.RecordRead(types.AccountStateKey(addr, types.AccountBalance), stateObject.Balance())
stateObject.SubBalance(amount) stateObject.SubBalance(amount)
} }
} }
@@ -591,8 +606,8 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
// //
// TODO(rjl493456442) this function should only be supported by 'unwritable' // TODO(rjl493456442) this function should only be supported by 'unwritable'
// state and all mutations made should all be discarded afterwards. // state and all mutations made should all be discarded afterwards.
if _, ok := s.stateObjectsDestruct[addr]; !ok { if _, ok := s.queryStateObjectsDestruct(addr); !ok {
s.stateObjectsDestruct[addr] = nil s.tagStateObjectsDestruct(addr, nil)
} }
stateObject := s.getOrNewStateObject(addr) stateObject := s.getOrNewStateObject(addr)
for k, v := range storage { for k, v := range storage {
@@ -616,7 +631,7 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
prevbalance: new(uint256.Int).Set(stateObject.Balance()), prevbalance: new(uint256.Int).Set(stateObject.Balance()),
}) })
stateObject.markSelfdestructed() stateObject.markSelfdestructed()
stateObject.data.Balance = new(uint256.Int) stateObject.setBalance(new(uint256.Int))
} }
func (s *StateDB) Selfdestruct6780(addr common.Address) { func (s *StateDB) Selfdestruct6780(addr common.Address) {
@@ -722,18 +737,11 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
// flag set. This is needed by the state journal to revert to the correct s- // flag set. This is needed by the state journal to revert to the correct s-
// destructed object instead of wiping all knowledge about the state object. // destructed object instead of wiping all knowledge about the state object.
func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject { func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
s.RecordRead(types.AccountStateKey(addr, types.AccountSelf), struct{}{})
// Prefer live objects if any is available // Prefer live objects if any is available
if obj := s.stateObjects[addr]; obj != nil { if obj := s.stateObjects[addr]; obj != nil {
return obj return obj
} }
defer func(start time.Time) {
stateDBGetTimer.UpdateSince(start)
stateDBGetQPS.Mark(1)
stateDBGetAccountTimer.UpdateSince(start)
stateDBGetAccountQPS.Mark(1)
}(time.Now())
// If no live objects are available, attempt to use snapshots // If no live objects are available, attempt to use snapshots
var data *types.StateAccount var data *types.StateAccount
if s.snap != nil { if s.snap != nil {
@@ -816,9 +824,9 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
// account and storage data should be cleared as well. Note, it must // account and storage data should be cleared as well. Note, it must
// be done here, otherwise the destruction event of "original account" // be done here, otherwise the destruction event of "original account"
// will be lost. // will be lost.
_, prevdestruct := s.stateObjectsDestruct[prev.address] _, prevdestruct := s.queryStateObjectsDestruct(prev.address)
if !prevdestruct { if !prevdestruct {
s.stateObjectsDestruct[prev.address] = prev.origin s.tagStateObjectsDestruct(prev.address, prev.origin)
} }
// There may be some cached account/storage data already since IntermediateRoot // There may be some cached account/storage data already since IntermediateRoot
// will be called for each transaction before byzantium fork which will always // will be called for each transaction before byzantium fork which will always
@@ -859,7 +867,7 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
func (s *StateDB) CreateAccount(addr common.Address) { func (s *StateDB) CreateAccount(addr common.Address) {
newObj, prev := s.createObject(addr) newObj, prev := s.createObject(addr)
if prev != nil { if prev != nil {
newObj.setBalance(prev.data.Balance) newObj.setBalance(prev.Balance())
} }
} }
@@ -895,6 +903,7 @@ func (s *StateDB) copyInternal(doPrefetch bool) *StateDB {
stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)), stateObjectsPending: make(map[common.Address]struct{}, len(s.stateObjectsPending)),
stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)), stateObjectsDirty: make(map[common.Address]struct{}, len(s.journal.dirties)),
stateObjectsDestruct: make(map[common.Address]*types.StateAccount, len(s.stateObjectsDestruct)), stateObjectsDestruct: make(map[common.Address]*types.StateAccount, len(s.stateObjectsDestruct)),
stateObjectsDestructDirty: make(map[common.Address]*types.StateAccount, len(s.stateObjectsDestructDirty)),
storagePool: s.storagePool, storagePool: s.storagePool,
// writeOnSharedStorage: s.writeOnSharedStorage, // writeOnSharedStorage: s.writeOnSharedStorage,
refund: s.refund, refund: s.refund,
@@ -947,12 +956,15 @@ func (s *StateDB) copyInternal(doPrefetch bool) *StateDB {
for addr, value := range s.stateObjectsDestruct { for addr, value := range s.stateObjectsDestruct {
state.stateObjectsDestruct[addr] = value state.stateObjectsDestruct[addr] = value
} }
for addr, value := range s.stateObjectsDestructDirty {
state.stateObjectsDestructDirty[addr] = value
}
// Deep copy the state changes made in the scope of block // Deep copy the state changes made in the scope of block
// along with their original values. // along with their original values.
state.accounts = copySet(s.accounts) state.accounts = copySet(s.accounts)
state.storages = copy2DSet(s.storages) state.storages = copy2DSet(s.storages)
state.accountsOrigin = copySet(s.accountsOrigin) state.accountsOrigin = copySet(state.accountsOrigin)
state.storagesOrigin = copy2DSet(s.storagesOrigin) state.storagesOrigin = copy2DSet(state.storagesOrigin)
// Deep copy the logs occurred in the scope of block // Deep copy the logs occurred in the scope of block
for hash, logs := range s.logs { for hash, logs := range s.logs {
@@ -985,6 +997,12 @@ func (s *StateDB) copyInternal(doPrefetch bool) *StateDB {
// know that they need to explicitly terminate an active copy). // know that they need to explicitly terminate an active copy).
state.prefetcher = state.prefetcher.copy() state.prefetcher = state.prefetcher.copy()
} }
// parallel EVM related
if s.mvStates != nil {
state.mvStates = s.mvStates
}
return state return state
} }
@@ -1033,6 +1051,11 @@ func (s *StateDB) WaitPipeVerification() error {
// into the tries just yet. Only IntermediateRoot or Commit will do that. // into the tries just yet. Only IntermediateRoot or Commit will do that.
func (s *StateDB) Finalise(deleteEmptyObjects bool) { func (s *StateDB) Finalise(deleteEmptyObjects bool) {
addressesToPrefetch := make([][]byte, 0, len(s.journal.dirties)) addressesToPrefetch := make([][]byte, 0, len(s.journal.dirties))
// finalise stateObjectsDestruct
for addr, acc := range s.stateObjectsDestructDirty {
s.stateObjectsDestruct[addr] = acc
}
s.stateObjectsDestructDirty = make(map[common.Address]*types.StateAccount)
for addr := range s.journal.dirties { for addr := range s.journal.dirties {
obj, exist := s.stateObjects[addr] obj, exist := s.stateObjects[addr]
if !exist { if !exist {
@@ -1165,10 +1188,6 @@ func (s *StateDB) populateSnapStorage(obj *stateObject) bool {
} }
func (s *StateDB) AccountsIntermediateRoot() { func (s *StateDB) AccountsIntermediateRoot() {
defer func(start time.Time) {
storageIntermediateRootTimer.UpdateSince(start)
}(time.Now())
tasks := make(chan func()) tasks := make(chan func())
finishCh := make(chan struct{}) finishCh := make(chan struct{})
defer close(finishCh) defer close(finishCh)
@@ -1213,9 +1232,6 @@ func (s *StateDB) AccountsIntermediateRoot() {
} }
func (s *StateDB) StateIntermediateRoot() common.Hash { func (s *StateDB) StateIntermediateRoot() common.Hash {
defer func(start time.Time) {
accountIntermediateRootTimer.UpdateSince(start)
}(time.Now())
// If there was a trie prefetcher operating, it gets aborted and irrevocably // If there was a trie prefetcher operating, it gets aborted and irrevocably
// modified after we start retrieving tries. Remove it from the statedb after // modified after we start retrieving tries. Remove it from the statedb after
// this round of use. // this round of use.
@@ -1274,9 +1290,10 @@ func (s *StateDB) StateIntermediateRoot() common.Hash {
// SetTxContext sets the current transaction hash and index which are // SetTxContext sets the current transaction hash and index which are
// used when the EVM emits new state logs. It should be invoked before // used when the EVM emits new state logs. It should be invoked before
// transaction execution. // transaction execution.
func (s *StateDB) SetTxContext(thash common.Hash, ti int) { func (s *StateDB) SetTxContext(thash common.Hash, txIndex int, incarnation int) {
s.thash = thash s.thash = thash
s.txIndex = ti s.txIndex = txIndex
s.txIncarnation = incarnation
s.accessList = nil // can't delete this line now, because StateDB.Prepare is not called before processsing a system transaction s.accessList = nil // can't delete this line now, because StateDB.Prepare is not called before processsing a system transaction
} }
@@ -1925,6 +1942,131 @@ func (s *StateDB) GetSnap() snapshot.Snapshot {
return s.snap return s.snap
} }
func (s *StateDB) BeforeTxTransition() {
log.Debug("BeforeTxTransition", "mvStates", s.mvStates == nil, "rwSet", s.rwSet == nil)
if s.mvStates == nil {
return
}
s.rwSet = types.NewRWSet(types.StateVersion{
TxIndex: s.txIndex,
TxIncarnation: s.txIncarnation,
})
}
func (s *StateDB) BeginTxStat(index int) {
if s.mvStates == nil {
return
}
s.es = types.NewExeStat(index).Begin()
}
func (s *StateDB) StopTxStat(usedGas uint64) {
if s.mvStates == nil {
return
}
// record stat first
if s.es != nil {
s.es.Done().WithGas(usedGas).WithRead(len(s.rwSet.ReadSet()))
}
}
func (s *StateDB) RecordRead(key types.RWKey, val interface{}) {
if s.mvStates == nil || s.rwSet == nil {
return
}
// TODO: read from MVStates, record with ver
s.rwSet.RecordRead(key, types.StateVersion{
TxIndex: -1,
}, val)
}
func (s *StateDB) RecordWrite(key types.RWKey, val interface{}) {
if s.mvStates == nil || s.rwSet == nil {
return
}
s.rwSet.RecordWrite(key, val)
}
func (s *StateDB) ResetMVStates(txCount int) {
log.Debug("ResetMVStates", "mvStates", s.mvStates == nil, "rwSet", s.rwSet == nil)
s.mvStates = types.NewMVStates(txCount)
s.rwSet = nil
}
func (s *StateDB) FinaliseRWSet() error {
log.Debug("FinaliseRWSet", "mvStates", s.mvStates == nil, "rwSet", s.rwSet == nil)
if s.mvStates == nil || s.rwSet == nil {
return nil
}
// finalise stateObjectsDestruct
for addr, acc := range s.stateObjectsDestructDirty {
s.stateObjectsDestruct[addr] = acc
s.RecordWrite(types.AccountStateKey(addr, types.AccountSuicide), struct{}{})
}
for addr := range s.journal.dirties {
obj, exist := s.stateObjects[addr]
if !exist {
continue
}
if obj.selfDestructed || obj.empty() {
// We need to maintain account deletions explicitly (will remain
// set indefinitely). Note only the first occurred self-destruct
// event is tracked.
if _, ok := s.stateObjectsDestruct[obj.address]; !ok {
log.Debug("FinaliseRWSet find Destruct", "tx", s.txIndex, "addr", addr, "selfDestructed", obj.selfDestructed)
s.RecordWrite(types.AccountStateKey(addr, types.AccountSuicide), struct{}{})
}
} else {
// finalise account & storages
obj.finaliseRWSet()
}
}
ver := types.StateVersion{
TxIndex: s.txIndex,
TxIncarnation: s.txIncarnation,
}
if ver != s.rwSet.Version() {
return errors.New("you finalize a wrong ver of RWSet")
}
log.Debug("FinaliseRWSet", "rwset", s.rwSet)
return s.mvStates.FulfillRWSet(s.rwSet, s.es)
}
func (s *StateDB) queryStateObjectsDestruct(addr common.Address) (*types.StateAccount, bool) {
if acc, ok := s.stateObjectsDestructDirty[addr]; ok {
return acc, ok
}
acc, ok := s.stateObjectsDestruct[addr]
return acc, ok
}
func (s *StateDB) tagStateObjectsDestruct(addr common.Address, acc *types.StateAccount) {
s.stateObjectsDestructDirty[addr] = acc
}
func (s *StateDB) deleteStateObjectsDestruct(addr common.Address) {
delete(s.stateObjectsDestructDirty, addr)
}
func (s *StateDB) MVStates2TxDAG() (*types.TxDAG, []*types.ExeStat) {
if s.mvStates == nil {
return nil, nil
}
return s.mvStates.ResolveTxDAG(), s.mvStates.Stats()
}
func (s *StateDB) RecordSystemTxRWSet(index int) {
if s.mvStates == nil {
return
}
s.mvStates.FulfillRWSet(types.NewRWSet(types.StateVersion{
TxIndex: index,
TxIncarnation: 0,
}).WithSerialFlag(), types.NewExeStat(index).WithSerialFlag())
}
// copySet returns a deep-copied set. // copySet returns a deep-copied set.
func copySet[k comparable](set map[k][]byte) map[k][]byte { func copySet[k comparable](set map[k][]byte) map[k][]byte {
copied := make(map[k][]byte, len(set)) copied := make(map[k][]byte, len(set))

View File

@@ -25,7 +25,7 @@ import (
) )
// NewStateSync creates a new state trie download scheduler. // NewStateSync creates a new state trie download scheduler.
func NewStateSync(root common.Hash, database ethdb.Database, onLeaf func(keys [][]byte, leaf []byte) error, scheme string) *trie.Sync { func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme string) *trie.Sync {
// Register the storage slot callback if the external callback is specified. // Register the storage slot callback if the external callback is specified.
var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error
if onLeaf != nil { if onLeaf != nil {

View File

@@ -268,7 +268,7 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s
} }
} }
batch := dstDb.NewBatch() batch := dstDb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -369,7 +369,7 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) {
nodeProcessed = len(nodeResults) nodeProcessed = len(nodeResults)
} }
batch := dstDb.NewBatch() batch := dstDb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -469,7 +469,7 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) {
} }
} }
batch := dstDb.NewBatch() batch := dstDb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -575,7 +575,7 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) {
} }
} }
batch := dstDb.NewBatch() batch := dstDb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -688,7 +688,7 @@ func testIncompleteStateSync(t *testing.T, scheme string) {
} }
} }
batch := dstDb.NewBatch() batch := dstDb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()

View File

@@ -76,7 +76,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
if err != nil { if err != nil {
return // Also invalid block, bail out return // Also invalid block, bail out
} }
newStatedb.SetTxContext(tx.Hash(), txIndex) newStatedb.SetTxContext(tx.Hash(), txIndex, 0)
precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm) precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm)
case <-interruptCh: case <-interruptCh:
@@ -125,7 +125,7 @@ func (p *statePrefetcher) PrefetchMining(txs TransactionsByPriceAndNonce, header
return // Also invalid block, bail out return // Also invalid block, bail out
} }
idx++ idx++
newStatedb.SetTxContext(tx.Hash(), idx) newStatedb.SetTxContext(tx.Hash(), idx, 0)
precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm) precacheTransaction(msg, p.config, gaspool, newStatedb, header, evm)
gaspool = new(GasPool).AddGas(gasLimit) gaspool = new(GasPool).AddGas(gasLimit)
case <-stopCh: case <-stopCh:

View File

@@ -19,8 +19,6 @@ package core
import ( import (
"errors" "errors"
"fmt" "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/consensus/misc"
@@ -29,7 +27,11 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"math/big"
"time"
) )
// StateProcessor is a basic Processor, which takes care of transitioning // StateProcessor is a basic Processor, which takes care of transitioning
@@ -51,6 +53,12 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen
} }
} }
var (
dagExecutionTimer = metrics.NewRegisteredTimer("dag/executiontime", nil)
dagAccountReadTimer = metrics.NewRegisteredTimer("dag/accountreadtime", nil)
dagStorageReadTimer = metrics.NewRegisteredTimer("dag/storagereadtime", nil)
)
// Process processes the state changes according to the Ethereum rules by running // Process processes the state changes according to the Ethereum rules by running
// the transaction messages using the statedb and applying any rewards to both // the transaction messages using the statedb and applying any rewards to both
// the processor (coinbase) and any included uncles. // the processor (coinbase) and any included uncles.
@@ -59,6 +67,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen
// returns the amount of gas that was used in the process. If any of the // returns the amount of gas that was used in the process. If any of the
// transactions failed to execute due to insufficient gas it will return an error. // transactions failed to execute due to insufficient gas it will return an error.
func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) { func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*state.StateDB, types.Receipts, []*types.Log, uint64, error) {
var ( var (
usedGas = new(uint64) usedGas = new(uint64)
header = block.Header() header = block.Header()
@@ -99,16 +108,20 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// initialise bloom processors // initialise bloom processors
bloomProcessors := NewAsyncReceiptBloomGenerator(txNum) bloomProcessors := NewAsyncReceiptBloomGenerator(txNum)
statedb.MarkFullProcessed() statedb.MarkFullProcessed()
statedb.ResetMVStates(len(block.Transactions()))
log.Debug("ResetMVStates", "block", block.NumberU64(), "txs", len(block.Transactions()))
// usually do have two tx, one for validator set contract, another for system reward contract. // usually do have two tx, one for validator set contract, another for system reward contract.
systemTxs := make([]*types.Transaction, 0, 2) systemTxs := make([]*types.Transaction, 0, 2)
start := time.Now()
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
statedb.BeginTxStat(i)
if isPoSA { if isPoSA {
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
bloomProcessors.Close() bloomProcessors.Close()
return statedb, nil, nil, 0, err return statedb, nil, nil, 0, err
} else if isSystemTx { } else if isSystemTx {
statedb.RecordSystemTxRWSet(i)
systemTxs = append(systemTxs, tx) systemTxs = append(systemTxs, tx)
continue continue
} }
@@ -125,7 +138,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
bloomProcessors.Close() bloomProcessors.Close()
return statedb, nil, nil, 0, err return statedb, nil, nil, 0, err
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i, 0)
receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, bloomProcessors) receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, bloomProcessors)
if err != nil { if err != nil {
@@ -134,7 +147,10 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
commonTxs = append(commonTxs, tx) commonTxs = append(commonTxs, tx)
receipts = append(receipts, receipt) receipts = append(receipts, receipt)
statedb.StopTxStat(receipt.GasUsed)
} }
eTime := time.Since(start)
// this bloomProcessors may take ~20ms
bloomProcessors.Close() bloomProcessors.Close()
// Fail if Shanghai not enabled and len(withdrawals) is non-zero. // Fail if Shanghai not enabled and len(withdrawals) is non-zero.
@@ -143,7 +159,20 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return nil, nil, nil, 0, errors.New("withdrawals before shanghai") return nil, nil, nil, 0, errors.New("withdrawals before shanghai")
} }
// TODO: temporary add time metrics
dag, exrStats := statedb.MVStates2TxDAG()
//log.Info("MVStates2TxDAG", "block", block.NumberU64(), "tx", len(block.Transactions()), "dag", dag)
fmt.Printf("MVStates2TxDAG, block: %v|%v, tx: %v, time: %v\n", block.NumberU64(), block.Hash(), len(block.Transactions()), time.Now().Format(time.DateTime))
fmt.Print(types.EvaluateTxDAGPerformance(dag, exrStats))
fmt.Printf("block: %v, execution: %.2fms, accountRead: %.2fms, storageRead: %.2fms\n",
block.NumberU64(), float64(eTime.Microseconds())/1000, float64((statedb.SnapshotAccountReads+statedb.AccountReads).Microseconds())/1000,
float64((statedb.SnapshotStorageReads+statedb.StorageReads).Microseconds())/1000)
dagExecutionTimer.Update(eTime)
dagAccountReadTimer.Update(statedb.SnapshotAccountReads + statedb.AccountReads)
dagStorageReadTimer.Update(statedb.SnapshotStorageReads + statedb.StorageReads)
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards) // Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
// TODO: system txs must execute at last
err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), withdrawals, &receipts, &systemTxs, usedGas) err := p.engine.Finalize(p.bc, header, statedb, &commonTxs, block.Uncles(), withdrawals, &receipts, &systemTxs, usedGas)
if err != nil { if err != nil {
return statedb, receipts, allLogs, *usedGas, err return statedb, receipts, allLogs, *usedGas, err

View File

@@ -367,6 +367,8 @@ func (st *StateTransition) preCheck() error {
// However if any consensus issue encountered, return the error directly with // However if any consensus issue encountered, return the error directly with
// nil evm execution result. // nil evm execution result.
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) { func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// start record rw set in here
st.state.BeforeTxTransition()
// First check this message satisfies all consensus rules before // First check this message satisfies all consensus rules before
// applying the message. The rules include these clauses // applying the message. The rules include these clauses
// //
@@ -446,6 +448,10 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value) ret, st.gasRemaining, vmerr = st.evm.Call(sender, st.to(), msg.Data, st.gasRemaining, value)
} }
// stop record rw set in here
if err := st.state.FinaliseRWSet(); err != nil {
return nil, err
}
var gasRefund uint64 var gasRefund uint64
if !rules.IsLondon { if !rules.IsLondon {
// Before EIP-3529: refunds were capped to gasUsed / 2 // Before EIP-3529: refunds were capped to gasUsed / 2

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

View File

@@ -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
)

View File

@@ -4,16 +4,17 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"math/big" "math/big"
"strings"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state" "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/bruno"
"github.com/ethereum/go-ethereum/core/systemcontracts/euler" "github.com/ethereum/go-ethereum/core/systemcontracts/euler"
"github.com/ethereum/go-ethereum/core/systemcontracts/feynman" "github.com/ethereum/go-ethereum/core/systemcontracts/feynman"
feynmanFix "github.com/ethereum/go-ethereum/core/systemcontracts/feynman_fix" feynmanFix "github.com/ethereum/go-ethereum/core/systemcontracts/feynman_fix"
"github.com/ethereum/go-ethereum/core/systemcontracts/gibbs" "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/kepler"
"github.com/ethereum/go-ethereum/core/systemcontracts/luban" "github.com/ethereum/go-ethereum/core/systemcontracts/luban"
"github.com/ethereum/go-ethereum/core/systemcontracts/mirror" "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/planck"
"github.com/ethereum/go-ethereum/core/systemcontracts/plato" "github.com/ethereum/go-ethereum/core/systemcontracts/plato"
"github.com/ethereum/go-ethereum/core/systemcontracts/ramanujan" "github.com/ethereum/go-ethereum/core/systemcontracts/ramanujan"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
) )
type UpgradeConfig struct { type UpgradeConfig struct {
@@ -76,8 +75,6 @@ var (
feynmanUpgrade = make(map[string]*Upgrade) feynmanUpgrade = make(map[string]*Upgrade)
feynmanFixUpgrade = make(map[string]*Upgrade) feynmanFixUpgrade = make(map[string]*Upgrade)
haberFixUpgrade = make(map[string]*Upgrade)
) )
func init() { 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) { 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) applySystemContractUpgrade(feynmanFixUpgrade[network], blockNumber, statedb, logger)
} }
if config.IsOnHaberFix(blockNumber, lastBlockTime, blockTime) {
applySystemContractUpgrade(haberFixUpgrade[network], blockNumber, statedb, logger)
}
/* /*
apply other upgrades 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 { if err != nil {
panic(fmt.Errorf("failed to decode new contract code: %s", err.Error())) panic(fmt.Errorf("failed to decode new contract code: %s", err.Error()))
} }

View File

@@ -193,7 +193,5 @@ type MevParams struct {
ValidatorCommission uint64 // 100 means 1% ValidatorCommission uint64 // 100 means 1%
BidSimulationLeftOver time.Duration BidSimulationLeftOver time.Duration
GasCeil uint64 GasCeil uint64
GasPrice *big.Int // Minimum avg gas price for bid block
BuilderFeeCeil *big.Int BuilderFeeCeil *big.Int
Version string
} }

View File

@@ -204,6 +204,8 @@ type Body struct {
Transactions []*Transaction Transactions []*Transaction
Uncles []*Header Uncles []*Header
Withdrawals []*Withdrawal `rlp:"optional"` Withdrawals []*Withdrawal `rlp:"optional"`
// TODO: add TxDAG in block body
//TxDAG *TxDAG `rlp:"optional"`
} }
// Block represents an Ethereum block. // Block represents an Ethereum block.

698
core/types/dag.go Normal file
View File

@@ -0,0 +1,698 @@
package types
import (
"encoding/hex"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
"github.com/holiman/uint256"
"golang.org/x/exp/slices"
"sort"
"strings"
"sync"
"time"
)
// TxDep store the current tx dependency relation with other txs
type TxDep struct {
// It describes the Relation with below txs
// 0: this tx depends on below txs
// 1: this transaction does not depend on below txs, all other previous txs depend on
Relation uint8
TxIndexes []int
}
func (d *TxDep) AppendDep(i int) {
d.TxIndexes = append(d.TxIndexes, i)
}
func (d *TxDep) Exist(i int) bool {
for _, index := range d.TxIndexes {
if index == i {
return true
}
}
return false
}
// TxDAG indicate how to use the dependency of txs
type TxDAG struct {
// The TxDAG type
// 0: delay the distribution of GasFee, it will ignore all gas fee distribution when tx execute
// 1: timely distribution of transaction fees, it will keep partial serial execution when tx cannot delay the distribution
Type uint8
// Tx Dependency List, the list index is equal to TxIndex
TxDeps []TxDep
// It indicates the scheduling priority of the transactions
SchedulePriority []int
}
func NewTxDAG(txLen int) *TxDAG {
return &TxDAG{
Type: 0,
TxDeps: make([]TxDep, txLen),
}
}
func (d *TxDAG) String() string {
builder := strings.Builder{}
exePaths := d.travelExecutionPaths()
for _, path := range exePaths {
builder.WriteString(fmt.Sprintf("%v\n", path))
}
return builder.String()
}
func (d *TxDAG) travelExecutionPaths() [][]int {
// regenerate TxDAG
nd := NewTxDAG(len(d.TxDeps))
for i, txDep := range d.TxDeps {
nd.TxDeps[i].Relation = 0
if txDep.Relation == 0 {
nd.TxDeps[i] = txDep
continue
}
// recover to relation 0
for j := 0; j < i; j++ {
if !txDep.Exist(j) {
nd.TxDeps[i].AppendDep(j)
}
}
}
exePaths := make([][]int, 0)
// travel tx deps with BFS
for i := 0; i < len(nd.TxDeps); i++ {
exePaths = append(exePaths, travelTargetPath(nd.TxDeps, i))
}
return exePaths
}
var (
longestTimeTimer = metrics.NewRegisteredTimer("dag/longesttime", nil)
longestGasTimer = metrics.NewRegisteredTimer("dag/longestgas", nil)
serialTimeTimer = metrics.NewRegisteredTimer("dag/serialtime", nil)
totalTxMeter = metrics.NewRegisteredMeter("dag/txcnt", nil)
totalNoDepMeter = metrics.NewRegisteredMeter("dag/nodepcntcnt", nil)
total2DepMeter = metrics.NewRegisteredMeter("dag/2depcntcnt", nil)
total4DepMeter = metrics.NewRegisteredMeter("dag/4depcntcnt", nil)
total8DepMeter = metrics.NewRegisteredMeter("dag/8depcntcnt", nil)
total16DepMeter = metrics.NewRegisteredMeter("dag/16depcntcnt", nil)
total32DepMeter = metrics.NewRegisteredMeter("dag/32depcntcnt", nil)
)
func EvaluateTxDAGPerformance(dag *TxDAG, stats []*ExeStat) string {
if len(stats) != len(dag.TxDeps) || len(dag.TxDeps) == 0 {
return ""
}
sb := strings.Builder{}
sb.WriteString("TxDAG:\n")
for i, dep := range dag.TxDeps {
if stats[i].mustSerialFlag {
continue
}
sb.WriteString(fmt.Sprintf("%v: %v\n", i, dep.TxIndexes))
}
sb.WriteString("Parallel Execution Path:\n")
paths := dag.travelExecutionPaths()
// Attention: this is based on best schedule, it will reduce a lot by executing previous txs in parallel
// It assumes that there is no parallel thread limit
var (
maxGasIndex int
maxGas uint64
maxTimeIndex int
maxTime time.Duration
txTimes = make([]time.Duration, len(dag.TxDeps))
txGases = make([]uint64, len(dag.TxDeps))
txReads = make([]int, len(dag.TxDeps))
noDepdencyCount int
)
totalTxMeter.Mark(int64(len(dag.TxDeps)))
for i, path := range paths {
if stats[i].mustSerialFlag {
continue
}
if len(path) <= 1 {
noDepdencyCount++
totalNoDepMeter.Mark(1)
}
if len(path) <= 3 {
total2DepMeter.Mark(1)
}
if len(path) <= 5 {
total4DepMeter.Mark(1)
}
if len(path) <= 9 {
total8DepMeter.Mark(1)
}
if len(path) <= 17 {
total16DepMeter.Mark(1)
}
if len(path) <= 33 {
total32DepMeter.Mark(1)
}
// find the biggest cost time from dependency txs
for j := 0; j < len(path)-1; j++ {
prev := path[j]
if txTimes[prev] > txTimes[i] {
txTimes[i] = txTimes[prev]
}
if txGases[prev] > txGases[i] {
txGases[i] = txGases[prev]
}
if txReads[prev] > txReads[i] {
txReads[i] = txReads[prev]
}
}
txTimes[i] += stats[i].costTime
txGases[i] += stats[i].usedGas
txReads[i] += stats[i].readCount
//sb.WriteString(fmt.Sprintf("Tx%v, %.2fms|%vgas|%vreads\npath: %v\n", i, float64(txTimes[i].Microseconds())/1000, txGases[i], txReads[i], path))
sb.WriteString(fmt.Sprintf("%v: %v\n", i, path))
// try to find max gas
if txGases[i] > maxGas {
maxGas = txGases[i]
maxGasIndex = i
}
if txTimes[i] > maxTime {
maxTime = txTimes[i]
maxTimeIndex = i
}
}
sb.WriteString(fmt.Sprintf("LargestGasPath: %.2fms|%vgas|%vreads\npath: %v\n", float64(txTimes[maxGasIndex].Microseconds())/1000, txGases[maxGasIndex], txReads[maxGasIndex], paths[maxGasIndex]))
sb.WriteString(fmt.Sprintf("LongestTimePath: %.2fms|%vgas|%vreads\npath: %v\n", float64(txTimes[maxTimeIndex].Microseconds())/1000, txGases[maxTimeIndex], txReads[maxTimeIndex], paths[maxTimeIndex]))
longestTimeTimer.Update(txTimes[maxTimeIndex])
longestGasTimer.Update(txTimes[maxGasIndex])
// serial path
var (
sTime time.Duration
sGas uint64
sRead int
sPath []int
)
for i, stat := range stats {
if stat.mustSerialFlag {
continue
}
sPath = append(sPath, i)
sTime += stat.costTime
sGas += stat.usedGas
sRead += stat.readCount
}
if sTime == 0 {
return ""
}
sb.WriteString(fmt.Sprintf("SerialPath: %.2fms|%vgas|%vreads\npath: %v\n", float64(sTime.Microseconds())/1000, sGas, sRead, sPath))
maxParaTime := txTimes[maxTimeIndex]
sb.WriteString(fmt.Sprintf("Estimated saving: %.2fms, %.2f%%, %.2fX, noDepCnt: %v|%.2f%%\n",
float64((sTime-maxParaTime).Microseconds())/1000, float64(sTime-maxParaTime)/float64(sTime)*100,
float64(sTime)/float64(maxParaTime), noDepdencyCount, float64(noDepdencyCount)/float64(len(dag.TxDeps))*100))
serialTimeTimer.Update(sTime)
return sb.String()
}
func travelTargetPath(deps []TxDep, from int) []int {
q := make([]int, 0, len(deps))
path := make([]int, 0, len(deps))
q = append(q, from)
path = append(path, from)
for len(q) > 0 {
t := make([]int, 0, len(deps))
for _, i := range q {
for _, dep := range deps[i].TxIndexes {
if !slices.Contains(path, dep) {
path = append(path, dep)
t = append(t, dep)
}
}
}
q = t
}
sort.Ints(path)
return path
}
type ValidatorExtraItem struct {
ValidatorAddress common.Address
VoteAddress BLSPublicKey
}
type HeaderCustomExtra struct {
ValidatorSet ValidatorExtraItem
TxDAG TxDAG
}
// StateVersion record specific TxIndex & TxIncarnation
// if TxIndex equals to -1, it means the state read from DB.
type StateVersion struct {
TxIndex int
TxIncarnation int
}
// ReadRecord keep read value & its version
type ReadRecord struct {
StateVersion
Val interface{}
}
// WriteRecord keep latest state value & change count
type WriteRecord struct {
Val interface{}
}
// RWSet record all read & write set in txs
// Attention: this is not a concurrent safety structure
type RWSet struct {
ver StateVersion
readSet map[RWKey]*ReadRecord
writeSet map[RWKey]*WriteRecord
// some flags
mustSerial bool
}
func NewRWSet(ver StateVersion) *RWSet {
return &RWSet{
ver: ver,
readSet: make(map[RWKey]*ReadRecord),
writeSet: make(map[RWKey]*WriteRecord),
}
}
func (s *RWSet) RecordRead(key RWKey, ver StateVersion, val interface{}) {
// only record the first read version
if _, exist := s.readSet[key]; exist {
return
}
s.readSet[key] = &ReadRecord{
StateVersion: ver,
Val: val,
}
}
func (s *RWSet) RecordWrite(key RWKey, val interface{}) {
wr, exist := s.writeSet[key]
if !exist {
s.writeSet[key] = &WriteRecord{
Val: val,
}
return
}
wr.Val = val
}
func (s *RWSet) Version() StateVersion {
return s.ver
}
func (s *RWSet) ReadSet() map[RWKey]*ReadRecord {
return s.readSet
}
func (s *RWSet) WriteSet() map[RWKey]*WriteRecord {
return s.writeSet
}
func (s *RWSet) WithSerialFlag() *RWSet {
s.mustSerial = true
return s
}
func (s *RWSet) String() string {
builder := strings.Builder{}
builder.WriteString(fmt.Sprintf("tx: %v, inc: %v\nreadSet: [", s.ver.TxIndex, s.ver.TxIncarnation))
i := 0
for key, _ := range s.readSet {
if i > 0 {
builder.WriteString(fmt.Sprintf(", %v", key.String()))
continue
}
builder.WriteString(fmt.Sprintf("%v", key.String()))
i++
}
builder.WriteString("]\nwriteSet: [")
i = 0
for key, _ := range s.writeSet {
if i > 0 {
builder.WriteString(fmt.Sprintf(", %v", key.String()))
continue
}
builder.WriteString(fmt.Sprintf("%v", key.String()))
i++
}
builder.WriteString("]\n")
return builder.String()
}
const (
AccountStatePrefix = 'a'
StorageStatePrefix = 's'
)
type RWKey [1 + common.AddressLength + common.HashLength]byte
type AccountState byte
const (
AccountSelf AccountState = iota
AccountNonce
AccountBalance
AccountCodeHash
AccountSuicide
)
func AccountStateKey(account common.Address, state AccountState) RWKey {
var key RWKey
key[0] = AccountStatePrefix
copy(key[1:], account.Bytes())
key[1+common.AddressLength] = byte(state)
return key
}
func StorageStateKey(account common.Address, state common.Hash) RWKey {
var key RWKey
key[0] = StorageStatePrefix
copy(key[1:], account.Bytes())
copy(key[1+common.AddressLength:], state.Bytes())
return key
}
func (key *RWKey) IsAccountState() (bool, AccountState) {
return AccountStatePrefix == key[0], AccountState(key[1+common.AddressLength])
}
func (key *RWKey) IsAccountSelf() bool {
ok, s := key.IsAccountState()
if !ok {
return false
}
return s == AccountSelf
}
func (key *RWKey) IsAccountSuicide() bool {
ok, s := key.IsAccountState()
if !ok {
return false
}
return s == AccountSuicide
}
func (key *RWKey) ToAccountSelf() RWKey {
return AccountStateKey(key.Addr(), AccountSelf)
}
func (key *RWKey) IsStorageState() bool {
return StorageStatePrefix == key[0]
}
func (key *RWKey) String() string {
return hex.EncodeToString(key[:])
}
func (key *RWKey) Addr() common.Address {
return common.BytesToAddress(key[1 : 1+common.AddressLength])
}
type PendingWrite struct {
Ver StateVersion
Val interface{}
}
func NewPendingWrite(ver StateVersion, wr *WriteRecord) *PendingWrite {
return &PendingWrite{
Ver: ver,
Val: wr.Val,
}
}
func (w *PendingWrite) TxIndex() int {
return w.Ver.TxIndex
}
func (w *PendingWrite) TxIncarnation() int {
return w.Ver.TxIncarnation
}
type PendingWrites struct {
list []*PendingWrite
}
func NewPendingWrites() *PendingWrites {
return &PendingWrites{
list: make([]*PendingWrite, 0),
}
}
func (w *PendingWrites) Append(pw *PendingWrite) {
if i, found := w.SearchTxIndex(pw.TxIndex()); found {
w.list[i] = pw
return
}
w.list = append(w.list, pw)
for i := len(w.list) - 1; i > 0; i-- {
if w.list[i].TxIndex() > w.list[i-1].TxIndex() {
break
}
w.list[i-1], w.list[i] = w.list[i], w.list[i-1]
}
}
func (w *PendingWrites) SearchTxIndex(txIndex int) (int, bool) {
n := len(w.list)
i, j := 0, n
for i < j {
h := int(uint(i+j) >> 1)
// i ≤ h < j
if w.list[h].TxIndex() < txIndex {
i = h + 1
} else {
j = h
}
}
return i, i < n && w.list[i].TxIndex() == txIndex
}
func (w *PendingWrites) FindLastWrite(txIndex int) *PendingWrite {
var i, _ = w.SearchTxIndex(txIndex)
for j := i - 1; j >= 0; j-- {
if w.list[j].TxIndex() < txIndex {
return w.list[j]
}
}
return nil
}
type MVStates struct {
rwSets []*RWSet
stats []*ExeStat
pendingWriteSet map[RWKey]*PendingWrites
lock sync.RWMutex
}
func NewMVStates(txCount int) *MVStates {
return &MVStates{
rwSets: make([]*RWSet, txCount),
stats: make([]*ExeStat, txCount),
pendingWriteSet: make(map[RWKey]*PendingWrites, txCount*8),
}
}
func (s *MVStates) RWSets() []*RWSet {
s.lock.RLock()
defer s.lock.RUnlock()
return s.rwSets
}
func (s *MVStates) Stats() []*ExeStat {
s.lock.RLock()
defer s.lock.RUnlock()
return s.stats
}
func (s *MVStates) RWSet(index int) *RWSet {
s.lock.RLock()
defer s.lock.RUnlock()
return s.rwSets[index]
}
func (s *MVStates) FulfillRWSet(rwSet *RWSet, stat *ExeStat) error {
s.lock.Lock()
defer s.lock.Unlock()
index := rwSet.ver.TxIndex
if index >= len(s.rwSets) {
return errors.New("refill out of bound")
}
if s := s.rwSets[index]; s != nil {
return errors.New("refill a exist RWSet")
}
if stat != nil {
if stat.txIndex != index {
return errors.New("wrong execution stat")
}
s.stats[index] = stat
}
for k, v := range rwSet.writeSet {
// ignore no changed write record
checkRWSetInconsistent(index, k, rwSet.readSet, rwSet.writeSet)
// this will be handled by state object
//if rwSet.readSet[k] != nil && isEqualRWVal(k, rwSet.readSet[k].Val, v.Val) {
// delete(rwSet.writeSet, k)
// continue
//}
if _, exist := s.pendingWriteSet[k]; !exist {
s.pendingWriteSet[k] = NewPendingWrites()
}
s.pendingWriteSet[k].Append(NewPendingWrite(rwSet.ver, v))
}
s.rwSets[index] = rwSet
return nil
}
func checkRWSetInconsistent(index int, k RWKey, readSet map[RWKey]*ReadRecord, writeSet map[RWKey]*WriteRecord) bool {
var (
readOk bool
writeOk bool
r *WriteRecord
)
if k.IsAccountSuicide() {
_, readOk = readSet[k.ToAccountSelf()]
} else {
_, readOk = readSet[k]
}
r, writeOk = writeSet[k]
if readOk != writeOk {
// check if it's correct? read nil, write non-nil
log.Info("checkRWSetInconsistent find inconsistent", "tx", index, "k", k.String(), "read", readOk, "write", writeOk, "val", r.Val)
return true
}
return false
}
func isEqualRWVal(key RWKey, src interface{}, compared interface{}) bool {
if ok, state := key.IsAccountState(); ok {
switch state {
case AccountBalance:
if src != nil && compared != nil {
return equalUint256(src.(*uint256.Int), compared.(*uint256.Int))
}
return src == compared
case AccountNonce:
return src.(uint64) == compared.(uint64)
case AccountCodeHash:
if src != nil && compared != nil {
return slices.Equal(src.([]byte), compared.([]byte))
}
return src == compared
}
return false
}
if src != nil && compared != nil {
return src.(common.Hash) == compared.(common.Hash)
}
return src == compared
}
func equalUint256(s, c *uint256.Int) bool {
if s != nil && c != nil {
return s.Eq(c)
}
return s == c
}
func (s *MVStates) ResolveTxDAG() *TxDAG {
rwSets := s.RWSets()
txDAG := NewTxDAG(len(rwSets))
for i := len(rwSets) - 1; i >= 0; i-- {
txDAG.TxDeps[i].TxIndexes = []int{}
if rwSets[i].mustSerial {
txDAG.TxDeps[i].Relation = 1
continue
}
readSet := rwSets[i].ReadSet()
// TODO: check if there are RW with system address
// check if there has written op before i
for j := 0; j < i; j++ {
if checkDependency(rwSets[j].writeSet, readSet) {
txDAG.TxDeps[i].AppendDep(j)
}
}
}
return txDAG
}
func checkDependency(writeSet map[RWKey]*WriteRecord, readSet map[RWKey]*ReadRecord) bool {
// check tx dependency, only check key, skip version
for k, _ := range writeSet {
// check suicide, add read address flag, it only for check suicide quickly, and cannot for other scenarios.
if k.IsAccountSuicide() {
if _, ok := readSet[k.ToAccountSelf()]; ok {
return true
}
continue
}
if _, ok := readSet[k]; ok {
return true
}
}
return false
}
type ExeStat struct {
txIndex int
usedGas uint64
readCount int
startTime time.Time
costTime time.Duration
// TODO: consider system tx, gas fee issues, may need to use different flag
mustSerialFlag bool
}
func NewExeStat(txIndex int) *ExeStat {
return &ExeStat{
txIndex: txIndex,
}
}
func (s *ExeStat) Begin() *ExeStat {
s.startTime = time.Now()
return s
}
func (s *ExeStat) Done() *ExeStat {
s.costTime = time.Since(s.startTime)
return s
}
func (s *ExeStat) WithSerialFlag() *ExeStat {
s.mustSerialFlag = true
return s
}
func (s *ExeStat) WithGas(gas uint64) *ExeStat {
s.usedGas = gas
return s
}
func (s *ExeStat) WithRead(rc int) *ExeStat {
s.readCount = rc
return s
}

239
core/types/dag_test.go Normal file
View File

@@ -0,0 +1,239 @@
package types
import (
"github.com/ethereum/go-ethereum/common"
"github.com/holiman/uint256"
"github.com/stretchr/testify/require"
"testing"
)
var (
mockAddr = common.HexToAddress("0x482bA86399ab6Dcbe54071f8d22258688B4509b1")
mockHash = common.HexToHash("0xdc13f8d7bdb8ec4de02cd4a50a1aa2ab73ec8814e0cdb550341623be3dd8ab7a")
)
func TestTxDAG(t *testing.T) {
dag := mockSimpleDAG()
t.Log(dag.String())
dag = mockSystemTxDAG()
t.Log(dag.String())
}
func TestEvaluateTxDAG(t *testing.T) {
dag := mockSystemTxDAG()
stats := make([]*ExeStat, len(dag.TxDeps))
for i, dep := range dag.TxDeps {
stats[i] = NewExeStat(i).WithGas(uint64(i)).WithRead(i)
stats[i].costTime = int64(i)
if dep.Relation == 1 {
stats[i].WithSerialFlag()
}
}
t.Log(EvaluateTxDAGPerformance(dag, stats))
}
func TestSimpleMVStates2TxDAG(t *testing.T) {
ms := NewMVStates(10)
ms.rwSets[0] = mockRWSet(0, []string{"0x00"}, []string{"0x00"})
ms.rwSets[1] = mockRWSet(1, []string{"0x01"}, []string{"0x01"})
ms.rwSets[2] = mockRWSet(2, []string{"0x02"}, []string{"0x02"})
ms.rwSets[3] = mockRWSet(3, []string{"0x00", "0x03"}, []string{"0x03"})
ms.rwSets[4] = mockRWSet(4, []string{"0x00", "0x04"}, []string{"0x04"})
ms.rwSets[5] = mockRWSet(5, []string{"0x01", "0x02", "0x05"}, []string{"0x05"})
ms.rwSets[6] = mockRWSet(6, []string{"0x02", "0x05", "0x06"}, []string{"0x06"})
ms.rwSets[7] = mockRWSet(7, []string{"0x06", "0x07"}, []string{"0x07"})
ms.rwSets[8] = mockRWSet(8, []string{"0x08"}, []string{"0x08"})
ms.rwSets[9] = mockRWSet(9, []string{"0x08", "0x09"}, []string{"0x09"})
dag := ms.ResolveTxDAG()
require.Equal(t, mockSimpleDAG(), dag)
t.Log(dag.String())
}
func TestSystemTxMVStates2TxDAG(t *testing.T) {
ms := NewMVStates(12)
ms.rwSets[0] = mockRWSet(0, []string{"0x00"}, []string{"0x00"})
ms.rwSets[1] = mockRWSet(1, []string{"0x01"}, []string{"0x01"})
ms.rwSets[2] = mockRWSet(2, []string{"0x02"}, []string{"0x02"})
ms.rwSets[3] = mockRWSet(3, []string{"0x00", "0x03"}, []string{"0x03"})
ms.rwSets[4] = mockRWSet(4, []string{"0x00", "0x04"}, []string{"0x04"})
ms.rwSets[5] = mockRWSet(5, []string{"0x01", "0x02", "0x05"}, []string{"0x05"})
ms.rwSets[6] = mockRWSet(6, []string{"0x02", "0x05", "0x06"}, []string{"0x06"})
ms.rwSets[7] = mockRWSet(7, []string{"0x06", "0x07"}, []string{"0x07"})
ms.rwSets[8] = mockRWSet(8, []string{"0x08"}, []string{"0x08"})
ms.rwSets[9] = mockRWSet(9, []string{"0x08", "0x09"}, []string{"0x09"})
ms.rwSets[10] = mockRWSet(10, []string{"0x10"}, []string{"0x10"}).WithSerialFlag()
ms.rwSets[11] = mockRWSet(11, []string{"0x11"}, []string{"0x11"}).WithSerialFlag()
dag := ms.ResolveTxDAG()
require.Equal(t, mockSystemTxDAG(), dag)
t.Log(dag.String())
}
func TestIsEqualRWVal(t *testing.T) {
tests := []struct {
key RWKey
src interface{}
compared interface{}
isEqual bool
}{
{
key: AccountStateKey(mockAddr, AccountNonce),
src: uint64(0),
compared: uint64(0),
isEqual: true,
},
{
key: AccountStateKey(mockAddr, AccountNonce),
src: uint64(0),
compared: uint64(1),
isEqual: false,
},
{
key: AccountStateKey(mockAddr, AccountBalance),
src: new(uint256.Int).SetUint64(1),
compared: new(uint256.Int).SetUint64(1),
isEqual: true,
},
{
key: AccountStateKey(mockAddr, AccountBalance),
src: nil,
compared: new(uint256.Int).SetUint64(1),
isEqual: false,
},
{
key: AccountStateKey(mockAddr, AccountBalance),
src: (*uint256.Int)(nil),
compared: new(uint256.Int).SetUint64(1),
isEqual: false,
},
{
key: AccountStateKey(mockAddr, AccountBalance),
src: (*uint256.Int)(nil),
compared: (*uint256.Int)(nil),
isEqual: true,
},
{
key: AccountStateKey(mockAddr, AccountCodeHash),
src: []byte{1},
compared: []byte{1},
isEqual: true,
},
{
key: AccountStateKey(mockAddr, AccountCodeHash),
src: nil,
compared: []byte{1},
isEqual: false,
},
{
key: AccountStateKey(mockAddr, AccountCodeHash),
src: ([]byte)(nil),
compared: []byte{1},
isEqual: false,
},
{
key: AccountStateKey(mockAddr, AccountCodeHash),
src: ([]byte)(nil),
compared: ([]byte)(nil),
isEqual: true,
},
{
key: AccountStateKey(mockAddr, AccountSuicide),
src: struct{}{},
compared: struct{}{},
isEqual: false,
},
{
key: AccountStateKey(mockAddr, AccountSuicide),
src: nil,
compared: struct{}{},
isEqual: false,
},
{
key: StorageStateKey(mockAddr, mockHash),
src: mockHash,
compared: mockHash,
isEqual: true,
},
{
key: StorageStateKey(mockAddr, mockHash),
src: nil,
compared: mockHash,
isEqual: false,
},
}
for i, item := range tests {
require.Equal(t, item.isEqual, isEqualRWVal(item.key, item.src, item.compared), i)
}
}
func mockSimpleDAG() *TxDAG {
dag := NewTxDAG(10)
dag.TxDeps[0].TxIndexes = []int{}
dag.TxDeps[1].TxIndexes = []int{}
dag.TxDeps[2].TxIndexes = []int{}
dag.TxDeps[3].TxIndexes = []int{0}
dag.TxDeps[4].TxIndexes = []int{0}
dag.TxDeps[5].TxIndexes = []int{1, 2}
dag.TxDeps[6].TxIndexes = []int{2, 5}
dag.TxDeps[7].TxIndexes = []int{6}
dag.TxDeps[8].TxIndexes = []int{}
dag.TxDeps[9].TxIndexes = []int{8}
return dag
}
func mockSystemTxDAG() *TxDAG {
dag := NewTxDAG(12)
dag.TxDeps[0].TxIndexes = []int{}
dag.TxDeps[1].TxIndexes = []int{}
dag.TxDeps[2].TxIndexes = []int{}
dag.TxDeps[3].TxIndexes = []int{0}
dag.TxDeps[4].TxIndexes = []int{0}
dag.TxDeps[5].TxIndexes = []int{1, 2}
dag.TxDeps[6].TxIndexes = []int{2, 5}
dag.TxDeps[7].TxIndexes = []int{6}
dag.TxDeps[8].TxIndexes = []int{}
dag.TxDeps[9].TxIndexes = []int{8}
dag.TxDeps[10] = TxDep{
Relation: 1,
TxIndexes: []int{},
}
dag.TxDeps[11] = TxDep{
Relation: 1,
TxIndexes: []int{},
}
return dag
}
func mockRWSet(index int, read []string, write []string) *RWSet {
ver := StateVersion{
TxIndex: index,
}
set := NewRWSet(ver)
for _, k := range read {
key := RWKey{}
if len(k) > len(key) {
k = k[:len(key)]
}
copy(key[:], k)
set.readSet[key] = &ReadRecord{
StateVersion: ver,
Val: struct{}{},
}
}
for _, k := range write {
key := RWKey{}
if len(k) > len(key) {
k = k[:len(key)]
}
copy(key[:], k)
set.writeSet[key] = &WriteRecord{
Val: struct{}{},
}
}
return set
}

View File

@@ -79,6 +79,10 @@ type StateDB interface {
AddLog(*types.Log) AddLog(*types.Log)
AddPreimage(common.Hash, []byte) AddPreimage(common.Hash, []byte)
// parallel DAG related
BeforeTxTransition()
FinaliseRWSet() error
} }
// CallContext provides a basic interface for the EVM calling conventions. The EVM // CallContext provides a basic interface for the EVM calling conventions. The EVM

View File

@@ -4,11 +4,9 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"sync" "sync"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/parlia"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
@@ -141,15 +139,6 @@ func (voteManager *VoteManager) loop() {
} }
curHead := cHead.Block.Header() curHead := cHead.Block.Header()
if p, ok := voteManager.engine.(*parlia.Parlia); ok {
nextBlockMinedTime := time.Unix(int64((curHead.Time + p.Period())), 0)
timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote
if time.Now().Add(timeForBroadcast).After(nextBlockMinedTime) {
log.Warn("too late to vote", "Head.Time(Second)", curHead.Time, "Now(Millisecond)", time.Now().UnixMilli())
continue
}
}
// Check if cur validator is within the validatorSet at curHead // Check if cur validator is within the validatorSet at curHead
if !voteManager.engine.IsActiveValidatorAt(voteManager.chain, curHead, if !voteManager.engine.IsActiveValidatorAt(voteManager.chain, curHead,
func(bLSPublicKey *types.BLSPublicKey) bool { func(bLSPublicKey *types.BLSPublicKey) bool {

View File

@@ -484,10 +484,6 @@ func (b *EthAPIBackend) RemoveBuilder(builder common.Address) error {
return b.Miner().RemoveBuilder(builder) 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) { func (b *EthAPIBackend) SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error) {
return b.Miner().SendBid(ctx, bid) return b.Miner().SendBid(ctx, bid)
} }

View File

@@ -161,18 +161,12 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
// Optimize memory distribution by reallocating surplus allowance from the // Optimize memory distribution by reallocating surplus allowance from the
// dirty cache to the clean cache. // dirty cache to the clean cache.
if config.StateScheme == rawdb.PathScheme && config.TrieDirtyCache > pathdb.MaxDirtyBufferSize/1024/1024 { if config.StateScheme == rawdb.PathScheme && config.TrieDirtyCache > pathdb.MaxDirtyBufferSize/1024/1024 {
log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024, log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024, "adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize))
"adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize)) log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024)
log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024,
"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 config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
} }
log.Info("Allocated memory caches", log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
"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)
// Try to recover offline state pruning only in hash-based. // Try to recover offline state pruning only in hash-based.
if config.StateScheme == rawdb.HashScheme { if config.StateScheme == rawdb.HashScheme {
if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, config.TriesInMemory); err != nil { if err := pruner.RecoverPruning(stack.ResolvePath(""), chainDb, config.TriesInMemory); err != nil {
@@ -185,6 +179,14 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
} }
// Override the chain config with provided settings. // Override the chain config with provided settings.
var overrides core.ChainOverrides var overrides core.ChainOverrides
if config.OverrideCancun != nil {
chainConfig.CancunTime = config.OverrideCancun
overrides.OverrideCancun = config.OverrideCancun
}
if config.OverrideHaber != nil {
chainConfig.HaberTime = config.OverrideHaber
overrides.OverrideHaber = config.OverrideHaber
}
if config.OverrideBohr != nil { if config.OverrideBohr != nil {
chainConfig.BohrTime = config.OverrideBohr chainConfig.BohrTime = config.OverrideBohr
overrides.OverrideBohr = config.OverrideBohr overrides.OverrideBohr = config.OverrideBohr

View File

@@ -558,8 +558,8 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td, ttd *
} else { } else {
d.ancientLimit = 0 d.ancientLimit = 0
} }
frozen, _ := d.stateDB.BlockStore().Ancients() // Ignore the error here since light client can also hit here. frozen, _ := d.stateDB.Ancients() // Ignore the error here since light client can also hit here.
itemAmountInAncient, _ := d.stateDB.BlockStore().ItemAmountInAncient() itemAmountInAncient, _ := d.stateDB.ItemAmountInAncient()
// If a part of blockchain data has already been written into active store, // If a part of blockchain data has already been written into active store,
// disable the ancient style insertion explicitly. // disable the ancient style insertion explicitly.
if origin >= frozen && itemAmountInAncient != 0 { if origin >= frozen && itemAmountInAncient != 0 {
@@ -1671,9 +1671,9 @@ func (d *Downloader) reportSnapSyncProgress(force bool) {
} }
// Don't report anything until we have a meaningful progress // Don't report anything until we have a meaningful progress
var ( var (
headerBytes, _ = d.stateDB.BlockStore().AncientSize(rawdb.ChainFreezerHeaderTable) headerBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerHeaderTable)
bodyBytes, _ = d.stateDB.BlockStore().AncientSize(rawdb.ChainFreezerBodiesTable) bodyBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerBodiesTable)
receiptBytes, _ = d.stateDB.BlockStore().AncientSize(rawdb.ChainFreezerReceiptTable) receiptBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerReceiptTable)
) )
syncedBytes := common.StorageSize(headerBytes + bodyBytes + receiptBytes) syncedBytes := common.StorageSize(headerBytes + bodyBytes + receiptBytes)
if syncedBytes == 0 { if syncedBytes == 0 {

View File

@@ -188,6 +188,12 @@ type Config struct {
// send-transaction variants. The unit is ether. // send-transaction variants. The unit is ether.
RPCTxFeeCap float64 RPCTxFeeCap float64
// 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 (TODO: remove after the fork)
OverrideBohr *uint64 `toml:",omitempty"` OverrideBohr *uint64 `toml:",omitempty"`

View File

@@ -70,6 +70,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
RPCGasCap uint64 RPCGasCap uint64
RPCEVMTimeout time.Duration RPCEVMTimeout time.Duration
RPCTxFeeCap float64 RPCTxFeeCap float64
OverrideCancun *uint64 `toml:",omitempty"`
OverrideHaber *uint64 `toml:",omitempty"`
OverrideBohr *uint64 `toml:",omitempty"` OverrideBohr *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"`
BlobExtraReserve uint64 BlobExtraReserve uint64
@@ -128,6 +130,8 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.RPCGasCap = c.RPCGasCap enc.RPCGasCap = c.RPCGasCap
enc.RPCEVMTimeout = c.RPCEVMTimeout enc.RPCEVMTimeout = c.RPCEVMTimeout
enc.RPCTxFeeCap = c.RPCTxFeeCap enc.RPCTxFeeCap = c.RPCTxFeeCap
enc.OverrideCancun = c.OverrideCancun
enc.OverrideHaber = c.OverrideHaber
enc.OverrideBohr = c.OverrideBohr enc.OverrideBohr = c.OverrideBohr
enc.OverrideVerkle = c.OverrideVerkle enc.OverrideVerkle = c.OverrideVerkle
enc.BlobExtraReserve = c.BlobExtraReserve enc.BlobExtraReserve = c.BlobExtraReserve
@@ -190,6 +194,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
RPCGasCap *uint64 RPCGasCap *uint64
RPCEVMTimeout *time.Duration RPCEVMTimeout *time.Duration
RPCTxFeeCap *float64 RPCTxFeeCap *float64
OverrideCancun *uint64 `toml:",omitempty"`
OverrideHaber *uint64 `toml:",omitempty"`
OverrideBohr *uint64 `toml:",omitempty"` OverrideBohr *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"` OverrideVerkle *uint64 `toml:",omitempty"`
BlobExtraReserve *uint64 BlobExtraReserve *uint64
@@ -357,6 +363,12 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.RPCTxFeeCap != nil { if dec.RPCTxFeeCap != nil {
c.RPCTxFeeCap = *dec.RPCTxFeeCap c.RPCTxFeeCap = *dec.RPCTxFeeCap
} }
if dec.OverrideCancun != nil {
c.OverrideCancun = dec.OverrideCancun
}
if dec.OverrideHaber != nil {
c.OverrideHaber = dec.OverrideHaber
}
if dec.OverrideBohr != nil { if dec.OverrideBohr != nil {
c.OverrideBohr = dec.OverrideBohr c.OverrideBohr = dec.OverrideBohr
} }

View File

@@ -731,6 +731,9 @@ func (f *BlockFetcher) loop() {
matched = true matched = true
if f.getBlock(hash) == nil { if f.getBlock(hash) == nil {
block := types.NewBlockWithHeader(announce.header).WithBody(task.transactions[i], task.uncles[i]) 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 = block.WithSidecars(task.sidecars[i])
block.ReceivedAt = task.time block.ReceivedAt = task.time
blocks = append(blocks, block) blocks = append(blocks, block)
@@ -916,10 +919,6 @@ func (f *BlockFetcher) importBlocks(op *blockOrHeaderInject) {
return return
} }
if block.Header().EmptyWithdrawalsHash() {
block = block.WithWithdrawals(make([]*types.Withdrawal, 0))
}
defer func() { f.done <- hash }() defer func() { f.done <- hash }()
// Quickly validate the header and propagate the block if it passes // Quickly validate the header and propagate the block if it passes
switch err := f.verifyHeader(block.Header()); err { switch err := f.verifyHeader(block.Header()); err {

View File

@@ -158,7 +158,7 @@ func (f *fetcherTester) chainFinalizedHeight() uint64 {
return f.blocks[f.hashes[len(f.hashes)-3]].NumberU64() return f.blocks[f.hashes[len(f.hashes)-3]].NumberU64()
} }
// insertHeaders injects a new headers into the simulated chain. // insertChain injects a new headers into the simulated chain.
func (f *fetcherTester) insertHeaders(headers []*types.Header) (int, error) { func (f *fetcherTester) insertHeaders(headers []*types.Header) (int, error) {
f.lock.Lock() f.lock.Lock()
defer f.lock.Unlock() defer f.lock.Unlock()

View File

@@ -633,9 +633,6 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) {
go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error { go source.handler.runEthPeer(sourcePeer, func(peer *eth.Peer) error {
return eth.Handle((*ethHandler)(source.handler), peer) 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 { 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") t.Fatalf("failed to run protocol handshake")
} }

View File

@@ -409,7 +409,7 @@ type SyncPeer interface {
// - The peer delivers a stale response after a previous timeout // - The peer delivers a stale response after a previous timeout
// - The peer delivers a refusal to serve the requested state // - The peer delivers a refusal to serve the requested state
type Syncer struct { type Syncer struct {
db ethdb.Database // Database to store the trie nodes into (and dedup) db ethdb.KeyValueStore // Database to store the trie nodes into (and dedup)
scheme string // Node scheme used in node database scheme string // Node scheme used in node database
root common.Hash // Current state trie root being synced root common.Hash // Current state trie root being synced
@@ -478,7 +478,7 @@ type Syncer struct {
// NewSyncer creates a new snapshot syncer to download the Ethereum state over the // NewSyncer creates a new snapshot syncer to download the Ethereum state over the
// snap protocol. // snap protocol.
func NewSyncer(db ethdb.Database, scheme string) *Syncer { func NewSyncer(db ethdb.KeyValueStore, scheme string) *Syncer {
return &Syncer{ return &Syncer{
db: db, db: db,
scheme: scheme, scheme: scheme,
@@ -719,11 +719,11 @@ func (s *Syncer) Sync(root common.Hash, cancel chan struct{}) error {
// cleanPath is used to remove the dangling nodes in the stackTrie. // cleanPath is used to remove the dangling nodes in the stackTrie.
func (s *Syncer) cleanPath(batch ethdb.Batch, owner common.Hash, path []byte) { func (s *Syncer) cleanPath(batch ethdb.Batch, owner common.Hash, path []byte) {
if owner == (common.Hash{}) && rawdb.ExistsAccountTrieNode(s.db.StateStoreReader(), path) { if owner == (common.Hash{}) && rawdb.ExistsAccountTrieNode(s.db, path) {
rawdb.DeleteAccountTrieNode(batch, path) rawdb.DeleteAccountTrieNode(batch, path)
deletionGauge.Inc(1) deletionGauge.Inc(1)
} }
if owner != (common.Hash{}) && rawdb.ExistsStorageTrieNode(s.db.StateStoreReader(), owner, path) { if owner != (common.Hash{}) && rawdb.ExistsStorageTrieNode(s.db, owner, path) {
rawdb.DeleteStorageTrieNode(batch, owner, path) rawdb.DeleteStorageTrieNode(batch, owner, path)
deletionGauge.Inc(1) deletionGauge.Inc(1)
} }
@@ -735,7 +735,6 @@ func (s *Syncer) cleanPath(batch ethdb.Batch, owner common.Hash, path []byte) {
func (s *Syncer) loadSyncStatus() { func (s *Syncer) loadSyncStatus() {
var progress SyncProgress var progress SyncProgress
stateDiskDB := s.db.GetStateStore()
if status := rawdb.ReadSnapshotSyncStatus(s.db); status != nil { if status := rawdb.ReadSnapshotSyncStatus(s.db); status != nil {
if err := json.Unmarshal(status, &progress); err != nil { if err := json.Unmarshal(status, &progress); err != nil {
log.Error("Failed to decode snap sync status", "err", err) log.Error("Failed to decode snap sync status", "err", err)
@@ -748,7 +747,7 @@ func (s *Syncer) loadSyncStatus() {
task := task // closure for task.genBatch in the stacktrie writer callback task := task // closure for task.genBatch in the stacktrie writer callback
task.genBatch = ethdb.HookedBatch{ task.genBatch = ethdb.HookedBatch{
Batch: stateDiskDB.NewBatch(), Batch: s.db.NewBatch(),
OnPut: func(key []byte, value []byte) { OnPut: func(key []byte, value []byte) {
s.accountBytes += common.StorageSize(len(key) + len(value)) s.accountBytes += common.StorageSize(len(key) + len(value))
}, },
@@ -774,7 +773,7 @@ func (s *Syncer) loadSyncStatus() {
subtask := subtask // closure for subtask.genBatch in the stacktrie writer callback subtask := subtask // closure for subtask.genBatch in the stacktrie writer callback
subtask.genBatch = ethdb.HookedBatch{ subtask.genBatch = ethdb.HookedBatch{
Batch: stateDiskDB.NewBatch(), Batch: s.db.NewBatch(),
OnPut: func(key []byte, value []byte) { OnPut: func(key []byte, value []byte) {
s.storageBytes += common.StorageSize(len(key) + len(value)) s.storageBytes += common.StorageSize(len(key) + len(value))
}, },
@@ -842,7 +841,7 @@ func (s *Syncer) loadSyncStatus() {
last = common.MaxHash last = common.MaxHash
} }
batch := ethdb.HookedBatch{ batch := ethdb.HookedBatch{
Batch: stateDiskDB.NewBatch(), Batch: s.db.NewBatch(),
OnPut: func(key []byte, value []byte) { OnPut: func(key []byte, value []byte) {
s.accountBytes += common.StorageSize(len(key) + len(value)) s.accountBytes += common.StorageSize(len(key) + len(value))
}, },
@@ -1895,7 +1894,7 @@ func (s *Syncer) processAccountResponse(res *accountResponse) {
} }
// Check if the account is a contract with an unknown storage trie // Check if the account is a contract with an unknown storage trie
if account.Root != types.EmptyRootHash { if account.Root != types.EmptyRootHash {
if !rawdb.HasTrieNode(s.db.StateStoreReader(), res.hashes[i], nil, account.Root, s.scheme) { if !rawdb.HasTrieNode(s.db, res.hashes[i], nil, account.Root, s.scheme) {
// If there was a previous large state retrieval in progress, // If there was a previous large state retrieval in progress,
// don't restart it from scratch. This happens if a sync cycle // don't restart it from scratch. This happens if a sync cycle
// is interrupted and resumed later. However, *do* update the // is interrupted and resumed later. However, *do* update the
@@ -1987,25 +1986,12 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
if res.subTask != nil { if res.subTask != nil {
res.subTask.req = nil res.subTask.req = nil
} }
var usingMultDatabase bool
batch := ethdb.HookedBatch{ batch := ethdb.HookedBatch{
Batch: s.db.GetStateStore().NewBatch(),
OnPut: func(key []byte, value []byte) {
s.storageBytes += common.StorageSize(len(key) + len(value))
},
}
var snapBatch ethdb.HookedBatch
if s.db.StateStore() != nil {
usingMultDatabase = true
snapBatch = ethdb.HookedBatch{
Batch: s.db.NewBatch(), Batch: s.db.NewBatch(),
OnPut: func(key []byte, value []byte) { OnPut: func(key []byte, value []byte) {
s.storageBytes += common.StorageSize(len(key) + len(value)) s.storageBytes += common.StorageSize(len(key) + len(value))
}, },
} }
}
var ( var (
slots int slots int
oldStorageBytes = s.storageBytes oldStorageBytes = s.storageBytes
@@ -2075,7 +2061,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
} }
// Our first task is the one that was just filled by this response. // Our first task is the one that was just filled by this response.
batch := ethdb.HookedBatch{ batch := ethdb.HookedBatch{
Batch: s.db.GetStateStore().NewBatch(), Batch: s.db.NewBatch(),
OnPut: func(key []byte, value []byte) { OnPut: func(key []byte, value []byte) {
s.storageBytes += common.StorageSize(len(key) + len(value)) s.storageBytes += common.StorageSize(len(key) + len(value))
}, },
@@ -2102,7 +2088,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
}) })
for r.Next() { for r.Next() {
batch := ethdb.HookedBatch{ batch := ethdb.HookedBatch{
Batch: s.db.GetStateStore().NewBatch(), Batch: s.db.NewBatch(),
OnPut: func(key []byte, value []byte) { OnPut: func(key []byte, value []byte) {
s.storageBytes += common.StorageSize(len(key) + len(value)) s.storageBytes += common.StorageSize(len(key) + len(value))
}, },
@@ -2198,11 +2184,8 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
// outdated during the sync, but it can be fixed later during the // outdated during the sync, but it can be fixed later during the
// snapshot generation. // snapshot generation.
for j := 0; j < len(res.hashes[i]); j++ { for j := 0; j < len(res.hashes[i]); j++ {
if usingMultDatabase {
rawdb.WriteStorageSnapshot(snapBatch, account, res.hashes[i][j], res.slots[i][j])
} else {
rawdb.WriteStorageSnapshot(batch, account, res.hashes[i][j], res.slots[i][j]) rawdb.WriteStorageSnapshot(batch, account, res.hashes[i][j], res.slots[i][j])
}
// If we're storing large contracts, generate the trie nodes // If we're storing large contracts, generate the trie nodes
// on the fly to not trash the gluing points // on the fly to not trash the gluing points
if i == len(res.hashes)-1 && res.subTask != nil { if i == len(res.hashes)-1 && res.subTask != nil {
@@ -2222,7 +2205,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
// If the chunk's root is an overflown but full delivery, // If the chunk's root is an overflown but full delivery,
// clear the heal request. // clear the heal request.
accountHash := res.accounts[len(res.accounts)-1] accountHash := res.accounts[len(res.accounts)-1]
if root == res.subTask.root && rawdb.HasStorageTrieNode(s.db.StateStoreReader(), accountHash, nil, root) { if root == res.subTask.root && rawdb.HasStorageTrieNode(s.db, accountHash, nil, root) {
for i, account := range res.mainTask.res.hashes { for i, account := range res.mainTask.res.hashes {
if account == accountHash { if account == accountHash {
res.mainTask.needHeal[i] = false res.mainTask.needHeal[i] = false
@@ -2242,11 +2225,6 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
if err := batch.Write(); err != nil { if err := batch.Write(); err != nil {
log.Crit("Failed to persist storage slots", "err", err) log.Crit("Failed to persist storage slots", "err", err)
} }
if usingMultDatabase {
if err := snapBatch.Write(); err != nil {
log.Crit("Failed to persist storage slots", "err", err)
}
}
s.storageSynced += uint64(slots) s.storageSynced += uint64(slots)
log.Debug("Persisted set of storage slots", "accounts", len(res.hashes), "slots", slots, "bytes", s.storageBytes-oldStorageBytes) log.Debug("Persisted set of storage slots", "accounts", len(res.hashes), "slots", slots, "bytes", s.storageBytes-oldStorageBytes)
@@ -2345,25 +2323,12 @@ func (s *Syncer) commitHealer(force bool) {
return return
} }
batch := s.db.NewBatch() batch := s.db.NewBatch()
var stateBatch ethdb.Batch if err := s.healer.scheduler.Commit(batch); err != nil {
var err error
if s.db.StateStore() != nil {
stateBatch = s.db.StateStore().NewBatch()
err = s.healer.scheduler.Commit(batch, stateBatch)
} else {
err = s.healer.scheduler.Commit(batch, nil)
}
if err != nil {
log.Error("Failed to commit healing data", "err", err) log.Error("Failed to commit healing data", "err", err)
} }
if err := batch.Write(); err != nil { if err := batch.Write(); err != nil {
log.Crit("Failed to persist healing data", "err", err) log.Crit("Failed to persist healing data", "err", err)
} }
if s.db.StateStore() != nil {
if err := stateBatch.Write(); err != nil {
log.Crit("Failed to persist healing data", "err", err)
}
}
log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize())) log.Debug("Persisted set of healing data", "type", "trienodes", "bytes", common.StorageSize(batch.ValueSize()))
} }

View File

@@ -281,7 +281,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
} }
// Not yet the searched for transaction, execute on top of the current state // Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{}) vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
statedb.SetTxContext(tx.Hash(), idx) statedb.SetTxContext(tx.Hash(), idx, 0)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
} }

View File

@@ -112,14 +112,7 @@ func testChainSyncWithBlobs(t *testing.T, mode downloader.SyncMode, preCancunBlk
cancunTime := (preCancunBlks + 1) * 10 cancunTime := (preCancunBlks + 1) * 10
config.CancunTime = &cancunTime config.CancunTime = &cancunTime
// Create an empty handler // Create a full handler and ensure snap sync ends up disabled
empty := newTestParliaHandlerAfterCancun(t, &config, mode, 0, 0)
defer empty.close()
if downloader.SnapSync == mode && !empty.handler.snapSync.Load() {
t.Fatalf("snap sync disabled on pristine blockchain")
}
// Create a full handler
full := newTestParliaHandlerAfterCancun(t, &config, mode, preCancunBlks, postCancunBlks) full := newTestParliaHandlerAfterCancun(t, &config, mode, preCancunBlks, postCancunBlks)
defer full.close() defer full.close()
if downloader.SnapSync == mode && full.handler.snapSync.Load() { if downloader.SnapSync == mode && full.handler.snapSync.Load() {
@@ -129,6 +122,13 @@ func testChainSyncWithBlobs(t *testing.T, mode downloader.SyncMode, preCancunBlk
// check blocks and blobs // check blocks and blobs
checkChainWithBlobs(t, full.chain, preCancunBlks, postCancunBlks) checkChainWithBlobs(t, full.chain, preCancunBlks, postCancunBlks)
// Create an empty handler and ensure it's in snap sync mode
empty := newTestParliaHandlerAfterCancun(t, &config, mode, 0, 0)
defer empty.close()
if downloader.SnapSync == mode && !empty.handler.snapSync.Load() {
t.Fatalf("snap sync disabled on pristine blockchain")
}
// Sync up the two handlers via both `eth` and `snap` // Sync up the two handlers via both `eth` and `snap`
ethVer := uint(eth.ETH68) ethVer := uint(eth.ETH68)
snapVer := uint(snap.SNAP1) snapVer := uint(snap.SNAP1)
@@ -165,17 +165,14 @@ func testChainSyncWithBlobs(t *testing.T, mode downloader.SyncMode, preCancunBlk
go full.handler.runSnapExtension(fullPeerSnap, func(peer *snap.Peer) error { go full.handler.runSnapExtension(fullPeerSnap, func(peer *snap.Peer) error {
return snap.Handle((*snapHandler)(full.handler), peer) return snap.Handle((*snapHandler)(full.handler), peer)
}) })
for empty.handler.peers.snapLen() < 1 {
// Wait a bit for the above handlers to start // Wait a bit for the above handlers to start
time.Sleep(100 * time.Millisecond) time.Sleep(250 * time.Millisecond)
}
// Check that snap sync was disabled
op := peerToSyncOp(mode, empty.handler.peers.peerWithHighestTD()) op := peerToSyncOp(mode, empty.handler.peers.peerWithHighestTD())
if err := empty.handler.doSync(op); err != nil { if err := empty.handler.doSync(op); err != nil {
t.Fatal("sync failed:", err) t.Fatal("sync failed:", err)
} }
// Check that snap sync was disabled
if !empty.handler.synced.Load() { if !empty.handler.synced.Load() {
t.Fatalf("full sync not done after successful synchronisation") t.Fatalf("full sync not done after successful synchronisation")
} }

View File

@@ -587,7 +587,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
} }
} }
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i, 0)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err) log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
// We intentionally don't return the error here: if we do, then the RPC server will not // We intentionally don't return the error here: if we do, then the RPC server will not
@@ -786,7 +786,7 @@ txloop:
// Generate the next state snapshot fast without tracing // Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i, 0)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{}) vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil { if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
failed = err failed = err
@@ -919,7 +919,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
} }
// Execute the transaction and flush any traces to disk // Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf) vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
statedb.SetTxContext(tx.Hash(), i) statedb.SetTxContext(tx.Hash(), i, 0)
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)) _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
if writer != nil { if writer != nil {
writer.Flush() writer.Flush()
@@ -1127,7 +1127,7 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
} }
// Call Prepare to clear out the statedb access list // Call Prepare to clear out the statedb access list
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex) statedb.SetTxContext(txctx.TxHash, txctx.TxIndex, 0)
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil { if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
return nil, fmt.Errorf("tracing failed: %w", err) return nil, fmt.Errorf("tracing failed: %w", err)
} }

View File

@@ -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. // BlobSidecars return the Sidecars of a given block number or hash.
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) { func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) {
var r []*types.BlobTxSidecar 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 { if err == nil && r == nil {
return nil, ethereum.NotFound 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 // BlobSidecarByTxHash return a sidecar of a given blob transaction
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) { func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) {
var r *types.BlobTxSidecar 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 { if err == nil && r == nil {
return nil, ethereum.NotFound return nil, ethereum.NotFound
} }
@@ -752,13 +752,6 @@ func (ec *Client) MevRunning(ctx context.Context) (bool, error) {
return result, err 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 // SendBid sends a bid
func (ec *Client) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, error) { func (ec *Client) SendBid(ctx context.Context, args types.BidArgs) (common.Hash, error) {
var hash common.Hash var hash common.Hash

View File

@@ -180,6 +180,12 @@ type StateStoreReader interface {
StateStoreReader() Reader StateStoreReader() Reader
} }
type BlockStore interface {
BlockStore() Database
SetBlockStore(block Database)
HasSeparateBlockStore() bool
}
type BlockStoreReader interface { type BlockStoreReader interface {
BlockStoreReader() Reader BlockStoreReader() Reader
} }
@@ -188,14 +194,6 @@ type BlockStoreWriter interface {
BlockStoreWriter() Writer BlockStoreWriter() Writer
} }
// MultiDatabaseReader contains the methods required to read data from both key-value as well as
// blockStore or stateStore.
type MultiDatabaseReader interface {
KeyValueReader
StateStoreReader
BlockStoreReader
}
// Reader contains the methods required to read data from both key-value as well as // Reader contains the methods required to read data from both key-value as well as
// immutable ancient data. // immutable ancient data.
type Reader interface { type Reader interface {
@@ -236,13 +234,6 @@ type DiffStore interface {
type StateStore interface { type StateStore interface {
StateStore() Database StateStore() Database
SetStateStore(state Database) SetStateStore(state Database)
GetStateStore() Database
}
type BlockStore interface {
BlockStore() Database
SetBlockStore(block Database)
HasSeparateBlockStore() bool
} }
// Database contains all the methods required by the high level database to not // Database contains all the methods required by the high level database to not

View File

@@ -39,9 +39,6 @@ var (
// errSnapshotReleased is returned if callers want to retrieve data from a // errSnapshotReleased is returned if callers want to retrieve data from a
// released snapshot. // released snapshot.
errSnapshotReleased = errors.New("snapshot released") errSnapshotReleased = errors.New("snapshot released")
// errNotSupported is returned if the database doesn't support the required operation.
errNotSupported = errors.New("this operation is not supported")
) )
// Database is an ephemeral key-value store. Apart from basic data storage // Database is an ephemeral key-value store. Apart from basic data storage
@@ -50,84 +47,6 @@ var (
type Database struct { type Database struct {
db map[string][]byte db map[string][]byte
lock sync.RWMutex lock sync.RWMutex
stateStore ethdb.Database
blockStore ethdb.Database
}
func (db *Database) ModifyAncients(f func(ethdb.AncientWriteOp) error) (int64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) TruncateHead(n uint64) (uint64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) TruncateTail(n uint64) (uint64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) Sync() error {
//TODO implement me
panic("implement me")
}
func (db *Database) TruncateTableTail(kind string, tail uint64) (uint64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) ResetTable(kind string, startAt uint64, onlyEmpty bool) error {
//TODO implement me
panic("implement me")
}
func (db *Database) HasAncient(kind string, number uint64) (bool, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) Ancient(kind string, number uint64) ([]byte, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) Ancients() (uint64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) Tail() (uint64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) AncientSize(kind string) (uint64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) ItemAmountInAncient() (uint64, error) {
//TODO implement me
panic("implement me")
}
func (db *Database) AncientOffSet() uint64 {
//TODO implement me
panic("implement me")
}
func (db *Database) ReadAncients(fn func(ethdb.AncientReaderOp) error) (err error) {
//TODO implement me
panic("implement me")
} }
// New returns a wrapped map with all the required database interface methods // New returns a wrapped map with all the required database interface methods
@@ -285,37 +204,6 @@ func (db *Database) Len() int {
return len(db.db) return len(db.db)
} }
func (db *Database) StateStoreReader() ethdb.Reader {
if db.stateStore == nil {
return db
}
return db.stateStore
}
func (db *Database) BlockStoreReader() ethdb.Reader {
if db.blockStore == nil {
return db
}
return db.blockStore
}
func (db *Database) BlockStoreWriter() ethdb.Writer {
if db.blockStore == nil {
return db
}
return db.blockStore
}
// convertLegacyFn takes a raw freezer entry in an older format and
// returns it in the new format.
type convertLegacyFn = func([]byte) ([]byte, error)
// MigrateTable processes the entries in a given table in sequence
// converting them to a new format if they're of an old format.
func (db *Database) MigrateTable(kind string, convert convertLegacyFn) error {
return errNotSupported
}
// keyvalue is a key-value tuple tagged with a deletion field to allow creating // keyvalue is a key-value tuple tagged with a deletion field to allow creating
// memory-database write batches. // memory-database write batches.
type keyvalue struct { type keyvalue struct {

View File

@@ -122,10 +122,6 @@ func (db *Database) SetStateStore(state ethdb.Database) {
panic("not supported") panic("not supported")
} }
func (db *Database) GetStateStore() ethdb.Database {
panic("not supported")
}
func (db *Database) StateStoreReader() ethdb.Reader { func (db *Database) StateStoreReader() ethdb.Reader {
return db return db
} }

29
go.mod
View File

@@ -2,6 +2,8 @@ module github.com/ethereum/go-ethereum
go 1.21 go 1.21
toolchain go1.21.5
require ( require (
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0 github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.0
github.com/Microsoft/go-winio v0.6.1 github.com/Microsoft/go-winio v0.6.1
@@ -15,8 +17,8 @@ require (
github.com/btcsuite/btcd/btcec/v2 v2.3.2 github.com/btcsuite/btcd/btcec/v2 v2.3.2
github.com/cespare/cp v1.1.1 github.com/cespare/cp v1.1.1
github.com/cloudflare/cloudflare-go v0.79.0 github.com/cloudflare/cloudflare-go v0.79.0
github.com/cockroachdb/pebble v1.1.0
github.com/cometbft/cometbft v0.37.0 github.com/cometbft/cometbft v0.37.0
github.com/cockroachdb/pebble v1.1.0
github.com/consensys/gnark-crypto v0.12.1 github.com/consensys/gnark-crypto v0.12.1
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233 github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233
github.com/crate-crypto/go-kzg-4844 v0.7.0 github.com/crate-crypto/go-kzg-4844 v0.7.0
@@ -24,7 +26,7 @@ require (
github.com/deckarep/golang-set/v2 v2.5.0 github.com/deckarep/golang-set/v2 v2.5.0
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127 github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
github.com/ethereum/c-kzg-4844 v0.4.0 github.com/ethereum/c-kzg-4844 v0.4.0
github.com/fatih/color v1.16.0 github.com/fatih/color v1.13.0
github.com/fatih/structs v1.1.0 github.com/fatih/structs v1.1.0
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.2 github.com/fjl/memsize v0.0.2
@@ -37,7 +39,7 @@ require (
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb
github.com/google/gofuzz v1.2.0 github.com/google/gofuzz v1.2.0
github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5
github.com/google/uuid v1.5.0 github.com/google/uuid v1.4.0
github.com/gorilla/websocket v1.5.1 github.com/gorilla/websocket v1.5.1
github.com/graph-gophers/graphql-go v1.3.0 github.com/graph-gophers/graphql-go v1.3.0
github.com/hashicorp/go-bexpr v0.1.10 github.com/hashicorp/go-bexpr v0.1.10
@@ -82,7 +84,7 @@ require (
golang.org/x/crypto v0.21.0 golang.org/x/crypto v0.21.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/sync v0.6.0 golang.org/x/sync v0.6.0
golang.org/x/sys v0.20.0 golang.org/x/sys v0.18.0
golang.org/x/text v0.14.0 golang.org/x/text v0.14.0
golang.org/x/time v0.5.0 golang.org/x/time v0.5.0
golang.org/x/tools v0.18.0 golang.org/x/tools v0.18.0
@@ -96,7 +98,6 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect github.com/BurntSushi/toml v1.3.2 // indirect
github.com/DataDog/zstd v1.5.5 // indirect github.com/DataDog/zstd v1.5.5 // indirect
github.com/allegro/bigcache v1.2.1 // indirect
github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96 // indirect github.com/aristanetworks/goarista v0.0.0-20200805130819-fd197cf57d96 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.13 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.43 // indirect
@@ -159,7 +160,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
github.com/gtank/merlin v0.1.1 // indirect github.com/gtank/merlin v0.1.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
@@ -232,10 +233,12 @@ require (
github.com/prometheus/common v0.47.0 // indirect github.com/prometheus/common v0.47.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/prometheus/prom2json v1.3.0 // indirect github.com/prometheus/prom2json v1.3.0 // indirect
github.com/prysmaticlabs/eth2-types v0.0.0-20210303084904-c9735a06829d // indirect
github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44 // indirect github.com/prysmaticlabs/fastssz v0.0.0-20221107182844-78142813af44 // indirect
github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect github.com/prysmaticlabs/go-bitfield v0.0.0-20210809151128-385d8c5e3fb7 // indirect
github.com/prysmaticlabs/gohashtree v0.0.4-beta // indirect github.com/prysmaticlabs/gohashtree v0.0.4-beta // indirect
github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect github.com/prysmaticlabs/prombbolt v0.0.0-20210126082820-9b7adba6db7c // indirect
github.com/prysmaticlabs/prysm v0.0.0-20220124113610-e26cde5e091b // indirect
github.com/quic-go/qpack v0.4.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/quic-go v0.42.0 // indirect github.com/quic-go/quic-go v0.42.0 // indirect
github.com/quic-go/webtransport-go v0.6.0 // indirect github.com/quic-go/webtransport-go v0.6.0 // indirect
@@ -246,10 +249,9 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/schollz/progressbar/v3 v3.3.4 // indirect github.com/schollz/progressbar/v3 v3.3.4 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.0 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/spf13/afero v1.10.0 // indirect github.com/spf13/afero v1.10.0 // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect github.com/thomaso-mirodin/intmath v0.0.0-20160323211736-5dc6d854e46e // indirect
github.com/tidwall/gjson v1.10.2 // indirect github.com/tidwall/gjson v1.10.2 // indirect
github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect
@@ -264,7 +266,7 @@ require (
github.com/wealdtech/go-eth2-util v1.6.3 // indirect github.com/wealdtech/go-eth2-util v1.6.3 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.etcd.io/bbolt v1.3.9 // indirect go.etcd.io/bbolt v1.3.7 // indirect
go.opencensus.io v0.24.0 // indirect go.opencensus.io v0.24.0 // indirect
go.uber.org/dig v1.17.1 // indirect go.uber.org/dig v1.17.1 // indirect
go.uber.org/fx v1.20.1 // indirect go.uber.org/fx v1.20.1 // indirect
@@ -277,10 +279,8 @@ require (
golang.org/x/term v0.18.0 // indirect golang.org/x/term v0.18.0 // indirect
google.golang.org/api v0.44.0 // indirect google.golang.org/api v0.44.0 // indirect
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a // indirect google.golang.org/grpc v1.56.3 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.33.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect
@@ -295,7 +295,8 @@ require (
) )
replace ( replace (
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v1.3.1 github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.23.0
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-tendermint v0.0.0-20230417032003-4cda1f296fb2
github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1 github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1
github.com/syndtr/goleveldb v1.0.1 => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/syndtr/goleveldb v1.0.1 => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.16 github.com/tendermint/tendermint => github.com/bnb-chain/tendermint v0.31.16

604
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -87,10 +87,6 @@ func (m *MevAPI) Params() *types.MevParams {
return m.b.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 // Running returns true if mev is running
func (m *MevAPI) Running() bool { func (m *MevAPI) Running() bool {
return m.b.MevRunning() return m.b.MevRunning()

View File

@@ -651,7 +651,6 @@ func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.Match
} }
func (b *testBackend) MevRunning() bool { return false } func (b *testBackend) MevRunning() bool { return false }
func (b *testBackend) HasBuilder(builder common.Address) bool { return false }
func (b *testBackend) MevParams() *types.MevParams { func (b *testBackend) MevParams() *types.MevParams {
return &types.MevParams{} return &types.MevParams{}
} }

View File

@@ -115,8 +115,6 @@ type Backend interface {
AddBuilder(builder common.Address, builderUrl string) error AddBuilder(builder common.Address, builderUrl string) error
// RemoveBuilder removes a builder from the bid simulator. // RemoveBuilder removes a builder from the bid simulator.
RemoveBuilder(builder common.Address) error 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 receives bid from the builders.
SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error) SendBid(ctx context.Context, bid *types.BidArgs) (common.Hash, error)
// BestBidGasFee returns the gas fee of the best bid for the given parent hash. // BestBidGasFee returns the gas fee of the best bid for the given parent hash.

View File

@@ -33,11 +33,11 @@ func (api *DebugAPI) DbGet(key string) (hexutil.Bytes, error) {
// DbAncient retrieves an ancient binary blob from the append-only immutable files. // DbAncient retrieves an ancient binary blob from the append-only immutable files.
// It is a mapping to the `AncientReaderOp.Ancient` method // It is a mapping to the `AncientReaderOp.Ancient` method
func (api *DebugAPI) DbAncient(kind string, number uint64) (hexutil.Bytes, error) { func (api *DebugAPI) DbAncient(kind string, number uint64) (hexutil.Bytes, error) {
return api.b.ChainDb().BlockStore().Ancient(kind, number) return api.b.ChainDb().Ancient(kind, number)
} }
// DbAncients returns the ancient item numbers in the ancient store. // DbAncients returns the ancient item numbers in the ancient store.
// It is a mapping to the `AncientReaderOp.Ancients` method // It is a mapping to the `AncientReaderOp.Ancients` method
func (api *DebugAPI) DbAncients() (uint64, error) { func (api *DebugAPI) DbAncients() (uint64, error) {
return api.b.ChainDb().BlockStore().Ancients() return api.b.ChainDb().Ancients()
} }

View File

@@ -204,8 +204,7 @@ func (args *TransactionArgs) setFeeDefaults(ctx context.Context, b Backend) erro
// Sanity check the EIP-1559 fee parameters if present. // Sanity check the EIP-1559 fee parameters if present.
if args.GasPrice == nil && eip1559ParamsSet { if args.GasPrice == nil && eip1559ParamsSet {
if args.MaxFeePerGas.ToInt().Sign() == 0 { if args.MaxFeePerGas.ToInt().Sign() == 0 {
// return errors.New("maxFeePerGas must be non-zero") return errors.New("maxFeePerGas must be non-zero")
log.Warn("EIP-1559 Tx with zero maxFeePerGas") // BSC accepts zero gas price.
} }
if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 { if args.MaxFeePerGas.ToInt().Cmp(args.MaxPriorityFeePerGas.ToInt()) < 0 {
return fmt.Errorf("maxFeePerGas (%v) < maxPriorityFeePerGas (%v)", args.MaxFeePerGas, args.MaxPriorityFeePerGas) 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 { if args.GasPrice != nil && !eip1559ParamsSet {
// Zero gas-price is not allowed after London fork // Zero gas-price is not allowed after London fork
if args.GasPrice.ToInt().Sign() == 0 && isLondon { if args.GasPrice.ToInt().Sign() == 0 && isLondon {
// return errors.New("gasPrice must be non-zero after london fork") 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 nil // No need to set anything, user already set GasPrice return nil // No need to set anything, user already set GasPrice
} }

View File

@@ -85,8 +85,8 @@ func TestSetFeeDefaults(t *testing.T) {
"legacy tx post-London with zero price", "legacy tx post-London with zero price",
"london", "london",
&TransactionArgs{GasPrice: zero}, &TransactionArgs{GasPrice: zero},
&TransactionArgs{GasPrice: zero}, nil,
nil, // errors.New("gasPrice must be non-zero after london fork"), errors.New("gasPrice must be non-zero after london fork"),
}, },
// Access list txs // Access list txs
@@ -180,8 +180,8 @@ func TestSetFeeDefaults(t *testing.T) {
"dynamic fee tx post-London, explicit gas price", "dynamic fee tx post-London, explicit gas price",
"london", "london",
&TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero}, &TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero},
&TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero}, nil,
nil, // errors.New("maxFeePerGas must be non-zero"), errors.New("maxFeePerGas must be non-zero"),
}, },
// Misc // Misc
@@ -417,7 +417,6 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
func (b *backendMock) Engine() consensus.Engine { return nil } func (b *backendMock) Engine() consensus.Engine { return nil }
func (b *backendMock) MevRunning() bool { return false } func (b *backendMock) MevRunning() bool { return false }
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
func (b *backendMock) MevParams() *types.MevParams { func (b *backendMock) MevParams() *types.MevParams {
return &types.MevParams{} return &types.MevParams{}
} }

View File

@@ -7,7 +7,6 @@ import (
"math/big" "math/big"
"net" "net"
"net/http" "net/http"
"strconv"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -30,6 +29,11 @@ import (
const ( const (
// maxBidPerBuilderPerBlock is the max bid number per builder // maxBidPerBuilderPerBlock is the max bid number per builder
maxBidPerBuilderPerBlock = 3 maxBidPerBuilderPerBlock = 3
// leftOverTimeRate is the rate of left over time to simulate a bid
leftOverTimeRate = 11
// leftOverTimeScale is the scale of left over time to simulate a bid
leftOverTimeScale = 10
) )
var ( var (
@@ -69,12 +73,6 @@ type simBidReq struct {
interruptCh chan int32 interruptCh chan int32
} }
// newBidPackage is the warp of a new bid and a feedback channel
type newBidPackage struct {
bid *types.Bid
feedback chan error
}
// bidSimulator is in charge of receiving bid from builders, reporting issue to builders. // bidSimulator is in charge of receiving bid from builders, reporting issue to builders.
// And take care of bid simulation, rewards computing, best bid maintaining. // And take care of bid simulation, rewards computing, best bid maintaining.
type bidSimulator struct { type bidSimulator struct {
@@ -102,7 +100,7 @@ type bidSimulator struct {
// channels // channels
simBidCh chan *simBidReq simBidCh chan *simBidReq
newBidCh chan newBidPackage newBidCh chan *types.Bid
pendingMu sync.RWMutex pendingMu sync.RWMutex
pending map[uint64]map[common.Address]map[common.Hash]struct{} // blockNumber -> builder -> bidHash -> struct{} pending map[uint64]map[common.Address]map[common.Hash]struct{} // blockNumber -> builder -> bidHash -> struct{}
@@ -135,7 +133,7 @@ func newBidSimulator(
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
builders: make(map[common.Address]*builderclient.Client), builders: make(map[common.Address]*builderclient.Client),
simBidCh: make(chan *simBidReq), simBidCh: make(chan *simBidReq),
newBidCh: make(chan newBidPackage, 100), newBidCh: make(chan *types.Bid, 100),
pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}), pending: make(map[uint64]map[common.Address]map[common.Hash]struct{}),
bestBid: make(map[common.Hash]*BidRuntime), bestBid: make(map[common.Hash]*BidRuntime),
simulatingBid: make(map[common.Hash]*BidRuntime), simulatingBid: make(map[common.Hash]*BidRuntime),
@@ -320,6 +318,18 @@ func (b *bidSimulator) newBidLoop() {
// commit aborts in-flight bid execution with given signal and resubmits a new one. // commit aborts in-flight bid execution with given signal and resubmits a new one.
commit := func(reason int32, bidRuntime *BidRuntime) { commit := func(reason int32, bidRuntime *BidRuntime) {
// if the left time is not enough to do simulation, return
var simDuration time.Duration
if lastBid := b.GetBestBid(bidRuntime.bid.ParentHash); lastBid != nil && lastBid.duration != 0 {
simDuration = lastBid.duration
}
if time.Until(b.bidMustBefore(bidRuntime.bid.ParentHash)) <= simDuration*leftOverTimeRate/leftOverTimeScale {
log.Debug("BidSimulator: abort commit, not enough time to simulate",
"builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
return
}
if interruptCh != nil { if interruptCh != nil {
// each commit work will have its own interruptCh to stop work with a reason // each commit work will have its own interruptCh to stop work with a reason
interruptCh <- reason interruptCh <- reason
@@ -334,10 +344,6 @@ func (b *bidSimulator) newBidLoop() {
} }
} }
genDiscardedReply := func(betterBid *BidRuntime) error {
return fmt.Errorf("bid is discarded, current bestBid is [blockReward: %s, validatorReward: %s]", betterBid.expectedBlockReward, betterBid.expectedValidatorReward)
}
for { for {
select { select {
case newBid := <-b.newBidCh: case newBid := <-b.newBidCh:
@@ -345,53 +351,70 @@ func (b *bidSimulator) newBidLoop() {
continue continue
} }
bidRuntime, err := newBidRuntime(newBid.bid, b.config.ValidatorCommission) // check the block reward and validator reward of the newBid
if err != nil { expectedBlockReward := newBid.GasFee
if newBid.feedback != nil { expectedValidatorReward := new(big.Int).Mul(expectedBlockReward, big.NewInt(int64(b.config.ValidatorCommission)))
newBid.feedback <- err expectedValidatorReward.Div(expectedValidatorReward, big.NewInt(10000))
} expectedValidatorReward.Sub(expectedValidatorReward, newBid.BuilderFee)
if expectedValidatorReward.Cmp(big.NewInt(0)) < 0 {
// damage self profit, ignore
log.Debug("BidSimulator: invalid bid, validator reward is less than 0, ignore",
"builder", newBid.Builder, "bidHash", newBid.Hash().Hex())
continue continue
} }
var replyErr error bidRuntime := &BidRuntime{
// simulatingBid will be nil if there is no bid in simulation, compare with the bestBid instead bid: newBid,
if simulatingBid := b.GetSimulatingBid(newBid.bid.ParentHash); simulatingBid != nil { expectedBlockReward: expectedBlockReward,
// simulatingBid always better than bestBid, so only compare with simulatingBid if a simulatingBid exists expectedValidatorReward: expectedValidatorReward,
if bidRuntime.isExpectedBetterThan(simulatingBid) { packedBlockReward: big.NewInt(0),
packedValidatorReward: big.NewInt(0),
}
simulatingBid := b.GetSimulatingBid(newBid.ParentHash)
// simulatingBid is nil means there is no bid in simulation
if simulatingBid == nil {
// bestBid is nil means bid is the first bid
bestBid := b.GetBestBid(newBid.ParentHash)
if bestBid == nil {
commit(commitInterruptBetterBid, bidRuntime) commit(commitInterruptBetterBid, bidRuntime)
} else { continue
replyErr = genDiscardedReply(simulatingBid)
} }
} else {
// bestBid is nil means the bid is the first bid, otherwise the bid should compare with the bestBid // if bestBid is not nil, check if newBid is better than bestBid
if bestBid := b.GetBestBid(newBid.bid.ParentHash); bestBid == nil || if bidRuntime.expectedBlockReward.Cmp(bestBid.expectedBlockReward) >= 0 &&
bidRuntime.isExpectedBetterThan(bestBid) { bidRuntime.expectedValidatorReward.Cmp(bestBid.expectedValidatorReward) >= 0 {
// if both reward are better than last simulating newBid, commit for simulation
commit(commitInterruptBetterBid, bidRuntime) commit(commitInterruptBetterBid, bidRuntime)
} else { continue
replyErr = genDiscardedReply(bestBid)
}
} }
if newBid.feedback != nil { log.Debug("BidSimulator: lower reward, ignore",
newBid.feedback <- replyErr "builder", bidRuntime.bid.Builder, "bidHash", newBid.Hash().Hex())
continue
log.Info("[BID ARRIVED]",
"block", newBid.bid.BlockNumber,
"builder", newBid.bid.Builder,
"accepted", replyErr == nil,
"blockReward", weiToEtherStringF6(bidRuntime.expectedBlockReward),
"validatorReward", weiToEtherStringF6(bidRuntime.expectedValidatorReward),
"tx", len(newBid.bid.Txs),
"hash", newBid.bid.Hash().TerminalString(),
)
} }
// simulatingBid must be better than bestBid, if newBid is better than simulatingBid, commit for simulation
if bidRuntime.expectedBlockReward.Cmp(simulatingBid.expectedBlockReward) >= 0 &&
bidRuntime.expectedValidatorReward.Cmp(simulatingBid.expectedValidatorReward) >= 0 {
// if both reward are better than last simulating newBid, commit for simulation
commit(commitInterruptBetterBid, bidRuntime)
continue
}
log.Debug("BidSimulator: lower reward, ignore", "builder", newBid.Builder, "bidHash", newBid.Hash().Hex())
case <-b.exitCh: case <-b.exitCh:
return return
} }
} }
} }
func (b *bidSimulator) bidMustBefore(parentHash common.Hash) time.Time {
parentHeader := b.chain.GetHeaderByHash(parentHash)
return bidutil.BidMustBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver)
}
func (b *bidSimulator) bidBetterBefore(parentHash common.Hash) time.Time { func (b *bidSimulator) bidBetterBefore(parentHash common.Hash) time.Time {
parentHeader := b.chain.GetHeaderByHash(parentHash) parentHeader := b.chain.GetHeaderByHash(parentHash)
return bidutil.BidBetterBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver, b.config.BidSimulationLeftOver) return bidutil.BidBetterBefore(parentHeader, b.chainConfig.Parlia.Period, b.delayLeftOver, b.config.BidSimulationLeftOver)
@@ -417,6 +440,10 @@ func (b *bidSimulator) clearLoop() {
b.bestBidMu.Unlock() b.bestBidMu.Unlock()
b.simBidMu.Lock() b.simBidMu.Lock()
if bid, ok := b.simulatingBid[parentHash]; ok {
bid.env.discard()
}
delete(b.simulatingBid, parentHash)
for k, v := range b.simulatingBid { for k, v := range b.simulatingBid {
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory { if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
v.env.discard() v.env.discard()
@@ -440,19 +467,10 @@ func (b *bidSimulator) clearLoop() {
func (b *bidSimulator) sendBid(_ context.Context, bid *types.Bid) error { func (b *bidSimulator) sendBid(_ context.Context, bid *types.Bid) error {
timer := time.NewTimer(1 * time.Second) timer := time.NewTimer(1 * time.Second)
defer timer.Stop() defer timer.Stop()
replyCh := make(chan error, 1)
select { select {
case b.newBidCh <- newBidPackage{bid: bid, feedback: replyCh}: case b.newBidCh <- bid:
b.AddPending(bid.BlockNumber, bid.Builder, bid.Hash()) b.AddPending(bid.BlockNumber, bid.Builder, bid.Hash())
case <-timer.C: return nil
return types.ErrMevBusy
}
select {
case reply := <-replyCh:
return reply
case <-timer.C: case <-timer.C:
return types.ErrMevBusy return types.ErrMevBusy
} }
@@ -498,8 +516,6 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
} }
var ( var (
startTS = time.Now()
blockNumber = bidRuntime.bid.BlockNumber blockNumber = bidRuntime.bid.BlockNumber
parentHash = bidRuntime.bid.ParentHash parentHash = bidRuntime.bid.ParentHash
builder = bidRuntime.bid.Builder builder = bidRuntime.bid.Builder
@@ -514,6 +530,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
// ensure simulation exited then start next simulation // ensure simulation exited then start next simulation
b.SetSimulatingBid(parentHash, bidRuntime) b.SetSimulatingBid(parentHash, bidRuntime)
start := time.Now()
defer func(simStart time.Time) { defer func(simStart time.Time) {
logCtx := []any{ logCtx := []any{
@@ -539,11 +556,10 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
} }
b.RemoveSimulatingBid(parentHash) b.RemoveSimulatingBid(parentHash)
close(bidRuntime.finished) bidSimTimer.UpdateSince(start)
if success { if success {
bidRuntime.duration = time.Since(simStart) bidRuntime.duration = time.Since(simStart)
bidSimTimer.UpdateSince(simStart)
// only recommit self bid when newBidCh is empty // only recommit self bid when newBidCh is empty
if len(b.newBidCh) > 0 { if len(b.newBidCh) > 0 {
@@ -551,12 +567,12 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
} }
select { select {
case b.newBidCh <- newBidPackage{bid: bidRuntime.bid}: case b.newBidCh <- bidRuntime.bid:
log.Debug("BidSimulator: recommit", "builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex()) log.Debug("BidSimulator: recommit", "builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
default: default:
} }
} }
}(startTS) }(time.Now())
// prepareWork will configure header with a suitable time according to consensus // prepareWork will configure header with a suitable time according to consensus
// prepareWork will start trie prefetching // prepareWork will start trie prefetching
@@ -567,14 +583,6 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
return return
} }
// if the left time is not enough to do simulation, return
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
if delay == nil || *delay <= 0 {
log.Info("BidSimulator: abort commit, not enough time to simulate",
"builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
return
}
gasLimit := bidRuntime.env.header.GasLimit gasLimit := bidRuntime.env.header.GasLimit
if bidRuntime.env.gasPool == nil { if bidRuntime.env.gasPool == nil {
bidRuntime.env.gasPool = new(core.GasPool).AddGas(gasLimit) bidRuntime.env.gasPool = new(core.GasPool).AddGas(gasLimit)
@@ -642,12 +650,14 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
if b.config.GreedyMergeTx { if b.config.GreedyMergeTx {
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver) delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
if delay != nil && *delay > 0 { if delay != nil && *delay > 0 {
bidTxsSet := mapset.NewThreadUnsafeSetWithSize[common.Hash](len(bidRuntime.bid.Txs)) stopTimer := time.NewTimer(*delay)
bidTxsSet := mapset.NewSet[common.Hash]()
for _, tx := range bidRuntime.bid.Txs { for _, tx := range bidRuntime.bid.Txs {
bidTxsSet.Add(tx.Hash()) bidTxsSet.Add(tx.Hash())
} }
fillErr := b.bidWorker.fillTransactions(interruptCh, bidRuntime.env, nil, bidTxsSet) fillErr := b.bidWorker.fillTransactions(interruptCh, bidRuntime.env, stopTimer, bidTxsSet)
log.Trace("BidSimulator: greedy merge stopped", "block", bidRuntime.env.header.Number, log.Trace("BidSimulator: greedy merge stopped", "block", bidRuntime.env.header.Number,
"builder", bidRuntime.bid.Builder, "tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr) "builder", bidRuntime.bid.Builder, "tx count", bidRuntime.env.tcount-bidTxLen+1, "err", fillErr)
@@ -667,30 +677,13 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
} }
bestBid := b.GetBestBid(parentHash) bestBid := b.GetBestBid(parentHash)
if bestBid == nil { if bestBid == nil {
log.Info("[BID RESULT]", "win", "true[first]", "builder", bidRuntime.bid.Builder, "hash", bidRuntime.bid.Hash().TerminalString())
b.SetBestBid(bidRuntime.bid.ParentHash, bidRuntime) b.SetBestBid(bidRuntime.bid.ParentHash, bidRuntime)
success = true success = true
return return
} }
if bidRuntime.bid.Hash() != bestBid.bid.Hash() {
log.Info("[BID RESULT]",
"win", bidRuntime.packedBlockReward.Cmp(bestBid.packedBlockReward) >= 0,
"bidHash", bidRuntime.bid.Hash().TerminalString(),
"bestHash", bestBid.bid.Hash().TerminalString(),
"bidGasFee", weiToEtherStringF6(bidRuntime.packedBlockReward),
"bestGasFee", weiToEtherStringF6(bestBid.packedBlockReward),
"bidBlockTx", bidRuntime.env.tcount,
"bestBlockTx", bestBid.env.tcount,
"simElapsed", time.Since(startTS),
)
}
// this is the simplest strategy: best for all the delegators. // this is the simplest strategy: best for all the delegators.
if bidRuntime.packedBlockReward.Cmp(bestBid.packedBlockReward) >= 0 { if bidRuntime.packedBlockReward.Cmp(bestBid.packedBlockReward) >= 0 {
b.SetBestBid(bidRuntime.bid.ParentHash, bidRuntime) b.SetBestBid(bidRuntime.bid.ParentHash, bidRuntime)
@@ -704,7 +697,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
} }
select { select {
case b.newBidCh <- newBidPackage{bid: bestBid.bid}: case b.newBidCh <- bestBid.bid:
log.Debug("BidSimulator: recommit last bid", "builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex()) log.Debug("BidSimulator: recommit last bid", "builder", bidRuntime.bid.Builder, "bidHash", bidRuntime.bid.Hash().Hex())
default: default:
} }
@@ -724,7 +717,7 @@ func (b *bidSimulator) reportIssue(bidRuntime *BidRuntime, err error) {
}) })
if err != nil { if err != nil {
log.Warn("BidSimulator: failed to report issue", "builder", bidRuntime.bid.Builder, "err", err) log.Error("BidSimulator: failed to report issue", "builder", bidRuntime.bid.Builder, "err", err)
} }
} }
} }
@@ -740,46 +733,14 @@ type BidRuntime struct {
packedBlockReward *big.Int packedBlockReward *big.Int
packedValidatorReward *big.Int packedValidatorReward *big.Int
finished chan struct{}
duration time.Duration duration time.Duration
} }
func newBidRuntime(newBid *types.Bid, validatorCommission uint64) (*BidRuntime, error) {
// check the block reward and validator reward of the newBid
expectedBlockReward := newBid.GasFee
expectedValidatorReward := new(big.Int).Mul(expectedBlockReward, big.NewInt(int64(validatorCommission)))
expectedValidatorReward.Div(expectedValidatorReward, big.NewInt(10000))
expectedValidatorReward.Sub(expectedValidatorReward, newBid.BuilderFee)
if expectedValidatorReward.Cmp(big.NewInt(0)) < 0 {
// damage self profit, ignore
log.Debug("BidSimulator: invalid bid, validator reward is less than 0, ignore",
"builder", newBid.Builder, "bidHash", newBid.Hash().Hex())
return nil, fmt.Errorf("validator reward is less than 0, value: %s, commissionConfig: %d", expectedValidatorReward, validatorCommission)
}
bidRuntime := &BidRuntime{
bid: newBid,
expectedBlockReward: expectedBlockReward,
expectedValidatorReward: expectedValidatorReward,
packedBlockReward: big.NewInt(0),
packedValidatorReward: big.NewInt(0),
finished: make(chan struct{}),
}
return bidRuntime, nil
}
func (r *BidRuntime) validReward() bool { func (r *BidRuntime) validReward() bool {
return r.packedBlockReward.Cmp(r.expectedBlockReward) >= 0 && return r.packedBlockReward.Cmp(r.expectedBlockReward) >= 0 &&
r.packedValidatorReward.Cmp(r.expectedValidatorReward) >= 0 r.packedValidatorReward.Cmp(r.expectedValidatorReward) >= 0
} }
func (r *BidRuntime) isExpectedBetterThan(other *BidRuntime) bool {
return r.expectedBlockReward.Cmp(other.expectedBlockReward) >= 0 &&
r.expectedValidatorReward.Cmp(other.expectedValidatorReward) >= 0
}
// packReward calculates packedBlockReward and packedValidatorReward // packReward calculates packedBlockReward and packedValidatorReward
func (r *BidRuntime) packReward(validatorCommission uint64) { func (r *BidRuntime) packReward(validatorCommission uint64) {
r.packedBlockReward = r.env.state.GetBalance(consensus.SystemAddress).ToBig() r.packedBlockReward = r.env.state.GetBalance(consensus.SystemAddress).ToBig()
@@ -795,7 +756,7 @@ func (r *BidRuntime) commitTransaction(chain *core.BlockChain, chainConfig *para
) )
// Start executing the transaction // Start executing the transaction
r.env.state.SetTxContext(tx.Hash(), r.env.tcount) r.env.state.SetTxContext(tx.Hash(), r.env.tcount, 0)
if tx.Type() == types.BlobTxType { if tx.Type() == types.BlobTxType {
sc = types.NewBlobSidecarFromTx(tx) sc = types.NewBlobSidecarFromTx(tx)
@@ -835,8 +796,3 @@ func (r *BidRuntime) commitTransaction(chain *core.BlockChain, chainConfig *para
return nil return nil
} }
func weiToEtherStringF6(wei *big.Int) string {
f, _ := new(big.Float).Quo(new(big.Float).SetInt(wei), big.NewFloat(params.Ether)).Float64()
return strconv.FormatFloat(f, 'f', 6, 64)
}

View File

@@ -9,7 +9,6 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
) )
type BuilderConfig struct { type BuilderConfig struct {
@@ -60,11 +59,6 @@ func (miner *Miner) RemoveBuilder(builderAddr common.Address) error {
return miner.bidSimulator.RemoveBuilder(builderAddr) 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) { func (miner *Miner) SendBid(ctx context.Context, bidArgs *types.BidArgs) (common.Hash, error) {
builder, err := bidArgs.EcrecoverSender() builder, err := bidArgs.EcrecoverSender()
if err != nil { if err != nil {
@@ -123,8 +117,6 @@ func (miner *Miner) MevParams() *types.MevParams {
ValidatorCommission: miner.worker.config.Mev.ValidatorCommission, ValidatorCommission: miner.worker.config.Mev.ValidatorCommission,
BidSimulationLeftOver: miner.worker.config.Mev.BidSimulationLeftOver, BidSimulationLeftOver: miner.worker.config.Mev.BidSimulationLeftOver,
GasCeil: miner.worker.config.GasCeil, GasCeil: miner.worker.config.GasCeil,
GasPrice: miner.worker.config.GasPrice,
BuilderFeeCeil: builderFeeCeil, BuilderFeeCeil: builderFeeCeil,
Version: params.Version,
} }
} }

View File

@@ -67,9 +67,6 @@ const (
// the current 4 mining loops could have asynchronous risk of mining block with // the current 4 mining loops could have asynchronous risk of mining block with
// save height, keep recently mined blocks to avoid double sign for safety, // save height, keep recently mined blocks to avoid double sign for safety,
recentMinedCacheLimit = 20 recentMinedCacheLimit = 20
// the default to wait for the mev miner to finish
waitMEVMinerEndTimeLimit = 50 * time.Millisecond
) )
var ( var (
@@ -174,7 +171,6 @@ type getWorkReq struct {
type bidFetcher interface { type bidFetcher interface {
GetBestBid(parentHash common.Hash) *BidRuntime GetBestBid(parentHash common.Hash) *BidRuntime
GetSimulatingBid(prevBlockHash common.Hash) *BidRuntime
} }
// worker is the main object which takes care of submitting new work to consensus engine // worker is the main object which takes care of submitting new work to consensus engine
@@ -907,7 +903,7 @@ LOOP:
continue continue
} }
// Start executing the transaction // Start executing the transaction
env.state.SetTxContext(tx.Hash(), env.tcount) env.state.SetTxContext(tx.Hash(), env.tcount, 0)
logs, err := w.commitTransaction(env, tx, bloomProcessors) logs, err := w.commitTransaction(env, tx, bloomProcessors)
switch { switch {
@@ -1340,15 +1336,6 @@ LOOP:
// when in-turn, compare with remote work. // when in-turn, compare with remote work.
from := bestWork.coinbase from := bestWork.coinbase
if w.bidFetcher != nil && bestWork.header.Difficulty.Cmp(diffInTurn) == 0 { if w.bidFetcher != nil && bestWork.header.Difficulty.Cmp(diffInTurn) == 0 {
if pendingBid := w.bidFetcher.GetSimulatingBid(bestWork.header.ParentHash); pendingBid != nil {
waitBidTimer := time.NewTimer(waitMEVMinerEndTimeLimit)
defer waitBidTimer.Stop()
select {
case <-waitBidTimer.C:
case <-pendingBid.finished:
}
}
bestBid := w.bidFetcher.GetBestBid(bestWork.header.ParentHash) bestBid := w.bidFetcher.GetBestBid(bestWork.header.ParentHash)
if bestBid != nil { if bestBid != nil {
@@ -1371,13 +1358,7 @@ LOOP:
bestWork = bestBid.env bestWork = bestBid.env
from = bestBid.bid.Builder from = bestBid.bid.Builder
log.Info("[BUILDER BLOCK]", log.Debug("BidSimulator: bid win", "block", bestWork.header.Number.Uint64(), "bid", bestBid.bid.Hash())
"block", bestWork.header.Number.Uint64(),
"builder", from,
"blockReward", weiToEtherStringF6(bestBid.packedBlockReward),
"validatorReward", weiToEtherStringF6(bestBid.packedValidatorReward),
"bid", bestBid.bid.Hash().TerminalString(),
)
} }
} }
} }

View File

@@ -78,7 +78,7 @@ const (
blockDbHandlesMinSize = 1000 blockDbHandlesMinSize = 1000
blockDbHandlesMaxSize = 2000 blockDbHandlesMaxSize = 2000
chainDbMemoryPercentage = 50 chainDbMemoryPercentage = 50
chainDbHandlesPercentage = 50 chainDbHandlesPercentage
diffStoreHandlesPercentage = 20 diffStoreHandlesPercentage = 20
) )
@@ -799,7 +799,6 @@ func (n *Node) OpenAndMergeDatabase(name string, namespace string, readonly bool
diffStoreHandles int diffStoreHandles int
chainDataHandles = config.DatabaseHandles chainDataHandles = config.DatabaseHandles
chainDbCache = config.DatabaseCache chainDbCache = config.DatabaseCache
stateDbCache, stateDbHandles int
) )
if config.PersistDiff { if config.PersistDiff {
@@ -819,17 +818,10 @@ func (n *Node) OpenAndMergeDatabase(name string, namespace string, readonly bool
} else { } else {
blockDbHandlesSize = blockDbHandlesMinSize blockDbHandlesSize = blockDbHandlesMinSize
} }
stateDbCache = config.DatabaseCache - chainDbCache - blockDbCacheSize stateDbCache := config.DatabaseCache - chainDbCache - blockDbCacheSize
stateDbHandles = config.DatabaseHandles - chainDataHandles - blockDbHandlesSize stateDbHandles := config.DatabaseHandles - chainDataHandles - blockDbHandlesSize
disableChainDbFreeze = true disableChainDbFreeze = true
}
chainDB, err := n.OpenDatabaseWithFreezer(name, chainDbCache, chainDataHandles, config.DatabaseFreezer, namespace, readonly, disableChainDbFreeze, false, config.PruneAncientData)
if err != nil {
return nil, err
}
if isMultiDatabase {
// Allocate half of the handles and chainDbCache to this separate state data database // Allocate half of the handles and chainDbCache to this separate state data database
stateDiskDb, err = n.OpenDatabaseWithFreezer(name+"/state", stateDbCache, stateDbHandles, "", "eth/db/statedata/", readonly, true, false, config.PruneAncientData) stateDiskDb, err = n.OpenDatabaseWithFreezer(name+"/state", stateDbCache, stateDbHandles, "", "eth/db/statedata/", readonly, true, false, config.PruneAncientData)
if err != nil { if err != nil {
@@ -841,6 +833,14 @@ func (n *Node) OpenAndMergeDatabase(name string, namespace string, readonly bool
return nil, err return nil, err
} }
log.Warn("Multi-database is an experimental feature") log.Warn("Multi-database is an experimental feature")
}
chainDB, err := n.OpenDatabaseWithFreezer(name, chainDbCache, chainDataHandles, config.DatabaseFreezer, namespace, readonly, disableChainDbFreeze, false, config.PruneAncientData)
if err != nil {
return nil, err
}
if isMultiDatabase {
chainDB.SetStateStore(stateDiskDb) chainDB.SetStateStore(stateDiskDb)
chainDB.SetBlockStore(blockDb) chainDB.SetBlockStore(blockDb)
} }

View File

@@ -153,7 +153,6 @@ var (
FeynmanFixTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC FeynmanFixTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
CancunTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC CancunTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
HaberTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC HaberTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
HaberFixTime: nil, // TBD
BohrTime: nil, BohrTime: nil,
Parlia: &ParliaConfig{ Parlia: &ParliaConfig{
@@ -194,7 +193,6 @@ var (
FeynmanFixTime: newUint64(1711342800), // 2024-03-25 5:00:00 AM UTC FeynmanFixTime: newUint64(1711342800), // 2024-03-25 5:00:00 AM UTC
CancunTime: newUint64(1713330442), // 2024-04-17 05:07:22 AM UTC CancunTime: newUint64(1713330442), // 2024-04-17 05:07:22 AM UTC
HaberTime: newUint64(1716962820), // 2024-05-29 06:07:00 AM UTC HaberTime: newUint64(1716962820), // 2024-05-29 06:07:00 AM UTC
HaberFixTime: newUint64(1719986788), // 2024-07-03 06:06:28 AM UTC
BohrTime: nil, BohrTime: nil,
Parlia: &ParliaConfig{ Parlia: &ParliaConfig{
@@ -236,7 +234,6 @@ var (
FeynmanFixTime: newUint64(0), FeynmanFixTime: newUint64(0),
CancunTime: newUint64(0), CancunTime: newUint64(0),
HaberTime: newUint64(0), HaberTime: newUint64(0),
HaberFixTime: newUint64(0),
BohrTime: newUint64(0), BohrTime: newUint64(0),
Parlia: &ParliaConfig{ Parlia: &ParliaConfig{
@@ -515,7 +512,6 @@ type ChainConfig struct {
FeynmanFixTime *uint64 `json:"feynmanFixTime,omitempty"` // FeynmanFix switch time (nil = no fork, 0 = already activated) FeynmanFixTime *uint64 `json:"feynmanFixTime,omitempty"` // FeynmanFix switch time (nil = no fork, 0 = already activated)
CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun) CancunTime *uint64 `json:"cancunTime,omitempty"` // Cancun switch time (nil = no fork, 0 = already on cancun)
HaberTime *uint64 `json:"haberTime,omitempty"` // Haber switch time (nil = no fork, 0 = already on haber) 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) BohrTime *uint64 `json:"bohrTime,omitempty"` // Bohr switch time (nil = no fork, 0 = already on bohr)
PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague) PragueTime *uint64 `json:"pragueTime,omitempty"` // Prague switch time (nil = no fork, 0 = already on prague)
VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle) VerkleTime *uint64 `json:"verkleTime,omitempty"` // Verkle switch time (nil = no fork, 0 = already on verkle)
@@ -627,17 +623,12 @@ func (c *ChainConfig) String() string {
HaberTime = big.NewInt(0).SetUint64(*c.HaberTime) 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 var BohrTime *big.Int
if c.BohrTime != nil { if c.BohrTime != nil {
BohrTime = big.NewInt(0).SetUint64(*c.BohrTime) 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, HaberTime: %v, BohrTime: %v, Engine: %v}",
c.ChainID, c.ChainID,
c.HomesteadBlock, c.HomesteadBlock,
c.DAOForkBlock, c.DAOForkBlock,
@@ -675,7 +666,6 @@ func (c *ChainConfig) String() string {
FeynmanFixTime, FeynmanFixTime,
CancunTime, CancunTime,
HaberTime, HaberTime,
HaberFixTime,
BohrTime, BohrTime,
engine, engine,
) )
@@ -949,20 +939,6 @@ func (c *ChainConfig) IsHaber(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.HaberTime, time) 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. // IsBohr returns whether time is either equal to the Bohr fork time or greater.
func (c *ChainConfig) IsBohr(num *big.Int, time uint64) bool { func (c *ChainConfig) IsBohr(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.BohrTime, time) return c.IsLondon(num) && isTimestampForked(c.BohrTime, time)
@@ -1041,7 +1017,6 @@ func (c *ChainConfig) CheckConfigForkOrder() error {
{name: "feynmanFixTime", timestamp: c.FeynmanFixTime}, {name: "feynmanFixTime", timestamp: c.FeynmanFixTime},
{name: "cancunTime", timestamp: c.CancunTime}, {name: "cancunTime", timestamp: c.CancunTime},
{name: "haberTime", timestamp: c.HaberTime}, {name: "haberTime", timestamp: c.HaberTime},
{name: "haberFixTime", timestamp: c.HaberFixTime},
{name: "bohrTime", timestamp: c.BohrTime}, {name: "bohrTime", timestamp: c.BohrTime},
{name: "pragueTime", timestamp: c.PragueTime, optional: true}, {name: "pragueTime", timestamp: c.PragueTime, optional: true},
{name: "verkleTime", timestamp: c.VerkleTime, optional: true}, {name: "verkleTime", timestamp: c.VerkleTime, optional: true},
@@ -1190,15 +1165,6 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, headNumber *big.Int,
if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, headTimestamp) { if isForkTimestampIncompatible(c.CancunTime, newcfg.CancunTime, headTimestamp) {
return newTimestampCompatError("Cancun fork timestamp", c.CancunTime, newcfg.CancunTime) 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) { if isForkTimestampIncompatible(c.PragueTime, newcfg.PragueTime, headTimestamp) {
return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime) return newTimestampCompatError("Prague fork timestamp", c.PragueTime, newcfg.PragueTime)
} }

View File

@@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 4 // Minor version component of the current release VersionMinor = 4 // Minor version component of the current release
VersionPatch = 12 // Patch version component of the current release VersionPatch = 8 // Patch version component of the current release
VersionMeta = "" // Version metadata to append to the version string VersionMeta = "" // Version metadata to append to the version string
) )

View File

@@ -98,7 +98,7 @@ func parseCallData(calldata []byte, unescapedAbidata string) (*decodedCallData,
if len(argdata)%32 != 0 { if len(argdata)%32 != 0 {
return nil, fmt.Errorf("invalid call data; length should be a multiple of 32 bytes (was %d)", len(argdata)) return nil, fmt.Errorf("invalid call data; length should be a multiple of 32 bytes (was %d)", len(argdata))
} }
// Validate the called method and unpack the call data accordingly // Validate the called method and upack the call data accordingly
abispec, err := abi.JSON(strings.NewReader(unescapedAbidata)) abispec, err := abi.JSON(strings.NewReader(unescapedAbidata))
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid method signature (%q): %v", unescapedAbidata, err) return nil, fmt.Errorf("invalid method signature (%q): %v", unescapedAbidata, err)

View File

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

View File

@@ -229,7 +229,7 @@ func (batch *syncMemBatch) delNode(owner common.Hash, path []byte) {
// and reconstructs the trie step by step until all is done. // and reconstructs the trie step by step until all is done.
type Sync struct { type Sync struct {
scheme string // Node scheme descriptor used in database. scheme string // Node scheme descriptor used in database.
database ethdb.Database // Persistent database to check for existing entries database ethdb.KeyValueReader // Persistent database to check for existing entries
membatch *syncMemBatch // Memory buffer to avoid frequent database writes membatch *syncMemBatch // Memory buffer to avoid frequent database writes
nodeReqs map[string]*nodeRequest // Pending requests pertaining to a trie node path nodeReqs map[string]*nodeRequest // Pending requests pertaining to a trie node path
codeReqs map[common.Hash]*codeRequest // Pending requests pertaining to a code hash codeReqs map[common.Hash]*codeRequest // Pending requests pertaining to a code hash
@@ -238,7 +238,7 @@ type Sync struct {
} }
// NewSync creates a new trie data download scheduler. // NewSync creates a new trie data download scheduler.
func NewSync(root common.Hash, database ethdb.Database, callback LeafCallback, scheme string) *Sync { func NewSync(root common.Hash, database ethdb.KeyValueReader, callback LeafCallback, scheme string) *Sync {
ts := &Sync{ ts := &Sync{
scheme: scheme, scheme: scheme,
database: database, database: database,
@@ -420,7 +420,7 @@ func (s *Sync) ProcessNode(result NodeSyncResult) error {
// Commit flushes the data stored in the internal membatch out to persistent // Commit flushes the data stored in the internal membatch out to persistent
// storage, returning any occurred error. The whole data set will be flushed // storage, returning any occurred error. The whole data set will be flushed
// in an atomic database batch. // in an atomic database batch.
func (s *Sync) Commit(dbw ethdb.Batch, stateBatch ethdb.Batch) error { func (s *Sync) Commit(dbw ethdb.Batch) error {
// Flush the pending node writes into database batch. // Flush the pending node writes into database batch.
var ( var (
account int account int
@@ -430,18 +430,10 @@ func (s *Sync) Commit(dbw ethdb.Batch, stateBatch ethdb.Batch) error {
if op.isDelete() { if op.isDelete() {
// node deletion is only supported in path mode. // node deletion is only supported in path mode.
if op.owner == (common.Hash{}) { if op.owner == (common.Hash{}) {
if stateBatch != nil {
rawdb.DeleteAccountTrieNode(stateBatch, op.path)
} else {
rawdb.DeleteAccountTrieNode(dbw, op.path) rawdb.DeleteAccountTrieNode(dbw, op.path)
}
} else {
if stateBatch != nil {
rawdb.DeleteStorageTrieNode(stateBatch, op.owner, op.path)
} else { } else {
rawdb.DeleteStorageTrieNode(dbw, op.owner, op.path) rawdb.DeleteStorageTrieNode(dbw, op.owner, op.path)
} }
}
deletionGauge.Inc(1) deletionGauge.Inc(1)
} else { } else {
if op.owner == (common.Hash{}) { if op.owner == (common.Hash{}) {
@@ -449,13 +441,9 @@ func (s *Sync) Commit(dbw ethdb.Batch, stateBatch ethdb.Batch) error {
} else { } else {
storage += 1 storage += 1
} }
if stateBatch != nil {
rawdb.WriteTrieNode(stateBatch, op.owner, op.path, op.hash, op.blob, s.scheme)
} else {
rawdb.WriteTrieNode(dbw, op.owner, op.path, op.hash, op.blob, s.scheme) rawdb.WriteTrieNode(dbw, op.owner, op.path, op.hash, op.blob, s.scheme)
} }
} }
}
accountNodeSyncedGauge.Inc(int64(account)) accountNodeSyncedGauge.Inc(int64(account))
storageNodeSyncedGauge.Inc(int64(storage)) storageNodeSyncedGauge.Inc(int64(storage))
@@ -558,9 +546,9 @@ func (s *Sync) children(req *nodeRequest, object node) ([]*nodeRequest, error) {
// the performance impact negligible. // the performance impact negligible.
var exists bool var exists bool
if owner == (common.Hash{}) { if owner == (common.Hash{}) {
exists = rawdb.ExistsAccountTrieNode(s.database.StateStoreReader(), append(inner, key[:i]...)) exists = rawdb.ExistsAccountTrieNode(s.database, append(inner, key[:i]...))
} else { } else {
exists = rawdb.ExistsStorageTrieNode(s.database.StateStoreReader(), owner, append(inner, key[:i]...)) exists = rawdb.ExistsStorageTrieNode(s.database, owner, append(inner, key[:i]...))
} }
if exists { if exists {
s.membatch.delNode(owner, append(inner, key[:i]...)) s.membatch.delNode(owner, append(inner, key[:i]...))
@@ -699,15 +687,15 @@ func (s *Sync) commitCodeRequest(req *codeRequest) error {
func (s *Sync) hasNode(owner common.Hash, path []byte, hash common.Hash) (exists bool, inconsistent bool) { func (s *Sync) hasNode(owner common.Hash, path []byte, hash common.Hash) (exists bool, inconsistent bool) {
// If node is running with hash scheme, check the presence with node hash. // If node is running with hash scheme, check the presence with node hash.
if s.scheme == rawdb.HashScheme { if s.scheme == rawdb.HashScheme {
return rawdb.HasLegacyTrieNode(s.database.StateStoreReader(), hash), false return rawdb.HasLegacyTrieNode(s.database, hash), false
} }
// If node is running with path scheme, check the presence with node path. // If node is running with path scheme, check the presence with node path.
var blob []byte var blob []byte
var dbHash common.Hash var dbHash common.Hash
if owner == (common.Hash{}) { if owner == (common.Hash{}) {
blob, dbHash = rawdb.ReadAccountTrieNode(s.database.StateStoreReader(), path) blob, dbHash = rawdb.ReadAccountTrieNode(s.database, path)
} else { } else {
blob, dbHash = rawdb.ReadStorageTrieNode(s.database.StateStoreReader(), owner, path) blob, dbHash = rawdb.ReadStorageTrieNode(s.database, owner, path)
} }
exists = hash == dbHash exists = hash == dbHash
inconsistent = !exists && len(blob) != 0 inconsistent = !exists && len(blob) != 0

View File

@@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/trie/trienode" "github.com/ethereum/go-ethereum/trie/trienode"
) )
@@ -142,7 +143,7 @@ func TestEmptySync(t *testing.T) {
emptyD, _ := New(TrieID(types.EmptyRootHash), dbD) emptyD, _ := New(TrieID(types.EmptyRootHash), dbD)
for i, trie := range []*Trie{emptyA, emptyB, emptyC, emptyD} { for i, trie := range []*Trie{emptyA, emptyB, emptyC, emptyD} {
sync := NewSync(trie.Hash(), rawdb.NewMemoryDatabase(), nil, []*testDb{dbA, dbB, dbC, dbD}[i].Scheme()) sync := NewSync(trie.Hash(), memorydb.New(), nil, []*testDb{dbA, dbB, dbC, dbD}[i].Scheme())
if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 { if paths, nodes, codes := sync.Missing(1); len(paths) != 0 || len(nodes) != 0 || len(codes) != 0 {
t.Errorf("test %d: content requested for empty trie: %v, %v, %v", i, paths, nodes, codes) t.Errorf("test %d: content requested for empty trie: %v, %v, %v", i, paths, nodes, codes)
} }
@@ -211,7 +212,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool, scheme string) {
} }
} }
batch := diskdb.NewBatch() batch := diskdb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -277,7 +278,7 @@ func testIterativeDelayedSync(t *testing.T, scheme string) {
} }
} }
batch := diskdb.NewBatch() batch := diskdb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -347,7 +348,7 @@ func testIterativeRandomSync(t *testing.T, count int, scheme string) {
} }
} }
batch := diskdb.NewBatch() batch := diskdb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -418,7 +419,7 @@ func testIterativeRandomDelayedSync(t *testing.T, scheme string) {
} }
} }
batch := diskdb.NewBatch() batch := diskdb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -490,7 +491,7 @@ func testDuplicateAvoidanceSync(t *testing.T, scheme string) {
} }
} }
batch := diskdb.NewBatch() batch := diskdb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -562,7 +563,7 @@ func testIncompleteSync(t *testing.T, scheme string) {
} }
} }
batch := diskdb.NewBatch() batch := diskdb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -652,7 +653,7 @@ func testSyncOrdering(t *testing.T, scheme string) {
} }
} }
batch := diskdb.NewBatch() batch := diskdb.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
batch.Write() batch.Write()
@@ -722,7 +723,7 @@ func syncWithHookWriter(t *testing.T, root common.Hash, db ethdb.Database, srcDb
} }
} }
batch := db.NewBatch() batch := db.NewBatch()
if err := sched.Commit(batch, nil); err != nil { if err := sched.Commit(batch); err != nil {
t.Fatalf("failed to commit data: %v", err) t.Fatalf("failed to commit data: %v", err)
} }
if hookWriter != nil { if hookWriter != nil {

View File

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

View File

@@ -26,106 +26,6 @@ import (
"github.com/ethereum/go-ethereum/trie/triestate" "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 // diffLayer represents a collection of modifications made to the in-memory tries
// along with associated state changes after running a block on top. // along with associated state changes after running a block on top.
// //
@@ -139,10 +39,7 @@ type diffLayer struct {
nodes map[common.Hash]map[string]*trienode.Node // Cached trie nodes indexed by owner and path 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 states *triestate.Set // Associated state change set for building history
memory uint64 // Approximate guess as to how much memory we use 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** parent layer // Parent layer modified by this one, never nil, **can be changed**
lock sync.RWMutex // Lock used to protect parent lock sync.RWMutex // Lock used to protect parent
} }
@@ -161,20 +58,6 @@ func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes
states: states, states: states,
parent: parent, 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 _, subset := range nodes {
for path, n := range subset { for path, n := range subset {
dl.memory += uint64(n.Size() + len(path)) dl.memory += uint64(n.Size() + len(path))
@@ -192,12 +75,6 @@ func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes
return dl 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 // rootHash implements the layer interface, returning the root hash of
// corresponding state. // corresponding state.
func (dl *diffLayer) rootHash() common.Hash { func (dl *diffLayer) rootHash() common.Hash {
@@ -256,32 +133,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 // 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. // 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) { 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) return dl.node(owner, path, hash, 0)
} }

View File

@@ -20,7 +20,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"sync" "sync"
"time"
"github.com/VictoriaMetrics/fastcache" "github.com/VictoriaMetrics/fastcache"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@@ -198,15 +197,11 @@ func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]b
nBlob []byte nBlob []byte
nHash common.Hash nHash common.Hash
) )
// TODO:
trieNodeQPS.Mark(1)
startLoadTrieNode := time.Now()
if owner == (common.Hash{}) { if owner == (common.Hash{}) {
nBlob, nHash = rawdb.ReadAccountTrieNode(dl.db.diskdb, path) nBlob, nHash = rawdb.ReadAccountTrieNode(dl.db.diskdb, path)
} else { } else {
nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path) nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path)
} }
trieNodeTime.Mark(time.Since(startLoadTrieNode).Nanoseconds())
if nHash != hash { if nHash != hash {
diskFalseMeter.Mark(1) diskFalseMeter.Mark(1)
log.Error("Unexpected trie node in disk", "owner", owner, "path", path, "expect", hash, "got", nHash) log.Error("Unexpected trie node in disk", "owner", owner, "path", path, "expect", hash, "got", nHash)
@@ -291,9 +286,6 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
} }
log.Debug("Pruned state history", "items", pruned, "tailid", oldest) 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 return ndl, nil
} }

View File

@@ -51,20 +51,9 @@ func (tree *layerTree) reset(head layer) {
tree.lock.Lock() tree.lock.Lock()
defer tree.lock.Unlock() 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) var layers = make(map[common.Hash]layer)
for head != nil { for head != nil {
layers[head.rootHash()] = head 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() head = head.parentLayer()
} }
tree.layers = layers tree.layers = layers
@@ -109,19 +98,12 @@ func (tree *layerTree) add(root common.Hash, parentRoot common.Hash, block uint6
if root == parentRoot { if root == parentRoot {
return errors.New("layer cycle") 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) parent := tree.get(parentRoot)
if parent == nil { if parent == nil {
return fmt.Errorf("triedb parent [%#x] layer missing", parentRoot) return fmt.Errorf("triedb parent [%#x] layer missing", parentRoot)
} }
l := parent.update(root, parent.stateID()+1, block, nodes.Flatten(), states) 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.lock.Lock()
tree.layers[l.rootHash()] = l tree.layers[l.rootHash()] = l
tree.lock.Unlock() tree.lock.Unlock()
@@ -150,15 +132,8 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
if err != nil { if err != nil {
return err 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 // Replace the entire layer tree with the flat base
tree.layers = map[common.Hash]layer{base.rootHash(): base} tree.layers = map[common.Hash]layer{base.rootHash(): base}
log.Debug("Cap all difflayers to disklayer", "disk_root", base.rootHash().String())
return nil return nil
} }
// Dive until we run out of layers or reach the persistent database // 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 return nil
} }
} }
var persisted *diskLayer
// We're out of layers, flatten anything below, stopping if it's the disk or if // We're out of layers, flatten anything below, stopping if it's the disk or if
// the memory limit is not yet exceeded. // the memory limit is not yet exceeded.
switch parent := diff.parentLayer().(type) { switch parent := diff.parentLayer().(type) {
@@ -192,7 +166,6 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
diff.parent = base diff.parent = base
diff.lock.Unlock() diff.lock.Unlock()
persisted = base.(*diskLayer)
default: default:
panic(fmt.Sprintf("unknown data layer in triedb: %T", parent)) 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) var remove func(root common.Hash)
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) delete(tree.layers, root)
for _, child := range children[root] { for _, child := range children[root] {
remove(child) remove(child)
@@ -223,25 +189,8 @@ func (tree *layerTree) cap(root common.Hash, layers int) error {
for root, layer := range tree.layers { for root, layer := range tree.layers {
if dl, ok := layer.(*diskLayer); ok && dl.isStale() { if dl, ok := layer.(*diskLayer); ok && dl.isStale() {
remove(root) 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 return nil
} }

View File

@@ -47,16 +47,4 @@ var (
historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil) historyBuildTimeMeter = metrics.NewRegisteredTimer("pathdb/history/time", nil)
historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil) historyDataBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/data", nil)
historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil) historyIndexBytesMeter = metrics.NewRegisteredMeter("pathdb/history/bytes/index", nil)
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)
PbssUpdateDiffQPS = metrics.NewRegisteredMeter("pbss/difflayer/update/qps", nil)
PbssUpdateDiffTime = metrics.NewRegisteredTimer("pbss/difflayer/update/time", nil)
trieNodeQPS = metrics.NewRegisteredMeter("pbss/trie/node/qps", nil)
trieNodeTime = metrics.NewRegisteredMeter("pbss/trie/node/time", nil)
) )