Compare commits
59 Commits
no-discard
...
versa_base
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5b5805359 | ||
|
|
34bc9e02aa | ||
|
|
8a3d62e756 | ||
|
|
d4879836c0 | ||
|
|
4b00174821 | ||
|
|
3082da4e86 | ||
|
|
d334f520be | ||
|
|
cef6acec23 | ||
|
|
092fbafa3c | ||
|
|
c4e8ec7fea | ||
|
|
83a9b13771 | ||
|
|
c6cb43b7ca | ||
|
|
222e10810e | ||
|
|
26b236fb5f | ||
|
|
900cf26c65 | ||
|
|
21e6dcfc79 | ||
|
|
a262acfb00 | ||
|
|
87e622e51f | ||
|
|
13d454796f | ||
|
|
c6af48100d | ||
|
|
6d5b4ad64d | ||
|
|
d35b57ae36 | ||
|
|
21fc2d3ac4 | ||
|
|
c96fab04a3 | ||
|
|
27d86948fa | ||
|
|
a04e287cb6 | ||
|
|
c3d6155fff | ||
|
|
a00ffa762c | ||
|
|
863fdea026 | ||
|
|
90e67970ae | ||
|
|
e8456c2d08 | ||
|
|
bc970e5893 | ||
|
|
a5810fefc9 | ||
|
|
971c0fa380 | ||
|
|
88225c1a4b | ||
|
|
51e27f9e3b | ||
|
|
f1a85ec306 | ||
|
|
75d162983a | ||
|
|
727c07116d | ||
|
|
719412551a | ||
|
|
c2226a0c9f | ||
|
|
d52628aa82 | ||
|
|
f7de51f74e | ||
|
|
55cbf31f18 | ||
|
|
f0c7795542 | ||
|
|
1548452def | ||
|
|
f2e7f1dd24 | ||
|
|
27a3ec5d72 | ||
|
|
6094d7157e | ||
|
|
be0fbfb79e | ||
|
|
00f094c37e | ||
|
|
7b08a70a23 | ||
|
|
99d31aeb28 | ||
|
|
f467c6018b | ||
|
|
4566ac7659 | ||
|
|
aab4b8812a | ||
|
|
af7e9b95bd | ||
|
|
1047f0e59a | ||
|
|
9bb4fed1bf |
@@ -1 +1,2 @@
|
|||||||
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
|
||||||
|
|||||||
75
CHANGELOG.md
75
CHANGELOG.md
@@ -1,4 +1,79 @@
|
|||||||
# 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
|
||||||
|
|||||||
@@ -149,8 +149,6 @@ 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
|
||||||
|
|||||||
@@ -642,7 +642,7 @@ func (f *faucet) loop() {
|
|||||||
f.lock.RUnlock()
|
f.lock.RUnlock()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
// Wait for various events and assing to the appropriate background threads
|
// Wait for various events and assign to the appropriate background threads
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case head := <-heads:
|
case head := <-heads:
|
||||||
|
|||||||
@@ -62,10 +62,9 @@ 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.
|
||||||
@@ -254,14 +253,6 @@ 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
|
||||||
@@ -769,7 +760,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.BlockStore(), hash); number != nil {
|
if number := rawdb.ReadHeaderNumber(db, 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)
|
||||||
|
|||||||
@@ -185,14 +185,6 @@ 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
|
||||||
|
|||||||
@@ -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.BlockStore())
|
headerHash := rawdb.ReadHeadHeaderHash(db)
|
||||||
blockNumber = *(rawdb.ReadHeaderNumber(db.BlockStore(), headerHash))
|
blockNumber = *(rawdb.ReadHeaderNumber(db, 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 empry hash")
|
return errors.New("ReadHeadBlockHash empty 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, true)
|
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||||
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.ReadChainMetadataFromMultiDatabase(db)
|
data := rawdb.ReadChainMetadata(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.Sync()
|
db.BlockStore().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.BlockStore())
|
headerHash := rawdb.ReadHeadHeaderHash(db)
|
||||||
blockNumber := rawdb.ReadHeaderNumber(db.BlockStore(), headerHash)
|
blockNumber := rawdb.ReadHeaderNumber(db, 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")
|
||||||
|
|||||||
@@ -72,8 +72,6 @@ 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,
|
||||||
@@ -127,6 +125,7 @@ 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,
|
||||||
@@ -336,9 +335,6 @@ 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) {
|
||||||
|
|||||||
@@ -155,6 +155,12 @@ 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(ðdb.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)
|
||||||
|
|||||||
@@ -24,4 +24,24 @@ testnet validators version
|
|||||||
### 2.Get Transaction Count
|
### 2.Get Transaction Count
|
||||||
```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}
|
||||||
|
```
|
||||||
|
|
||||||
|
|||||||
58
cmd/jsutils/get_perf.js
Normal file
58
cmd/jsutils/get_perf.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
119
cmd/jsutils/getslashcount.js
Normal file
119
cmd/jsutils/getslashcount.js
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
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);
|
||||||
|
});
|
||||||
@@ -305,16 +305,6 @@ 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",
|
||||||
@@ -1163,7 +1153,6 @@ var (
|
|||||||
DBEngineFlag,
|
DBEngineFlag,
|
||||||
StateSchemeFlag,
|
StateSchemeFlag,
|
||||||
HttpHeaderFlag,
|
HttpHeaderFlag,
|
||||||
MultiDataBaseFlag,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -2083,7 +2072,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):
|
case ctx.Bool(ChapelFlag.Name) || cfg.NetworkId == 97:
|
||||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||||
cfg.NetworkId = 97
|
cfg.NetworkId = 97
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 insterting chain: %v", err)
|
t.Fatalf("error inserting chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make temp directory for era files.
|
// Make temp directory for era files.
|
||||||
|
|||||||
@@ -307,6 +307,10 @@ 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 {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
@@ -40,6 +41,12 @@ func EnableRemoteVerifyManager(remoteValidator *remoteVerifyManager) BlockValida
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
validateBloomTimer = metrics.NewRegisteredTimer("validate/bloom/time", nil)
|
||||||
|
validateReceiptTimer = metrics.NewRegisteredTimer("validate/receipt/time", nil)
|
||||||
|
validateRootTimer = metrics.NewRegisteredTimer("validate/root/time", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// BlockValidator is responsible for validating block headers, uncles and
|
// BlockValidator is responsible for validating block headers, uncles and
|
||||||
// processed state.
|
// processed state.
|
||||||
//
|
//
|
||||||
@@ -184,6 +191,10 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||||||
// For valid blocks this should always validate to true.
|
// For valid blocks this should always validate to true.
|
||||||
validateFuns := []func() error{
|
validateFuns := []func() error{
|
||||||
func() error {
|
func() error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
validateBloomTimer.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
rbloom := types.CreateBloom(receipts)
|
rbloom := types.CreateBloom(receipts)
|
||||||
if rbloom != header.Bloom {
|
if rbloom != header.Bloom {
|
||||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||||
@@ -191,6 +202,9 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
func() error {
|
func() error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
validateReceiptTimer.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||||
if receiptSha != header.ReceiptHash {
|
if receiptSha != header.ReceiptHash {
|
||||||
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
||||||
@@ -209,6 +223,9 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
validateFuns = append(validateFuns, func() error {
|
validateFuns = append(validateFuns, func() error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
validateRootTimer.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||||
return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
|
return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ var (
|
|||||||
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
|
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
|
||||||
|
|
||||||
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
||||||
|
mGasPsGauge = metrics.NewRegisteredGauge("chain/process/gas", nil)
|
||||||
|
|
||||||
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
||||||
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
||||||
@@ -91,10 +92,13 @@ var (
|
|||||||
|
|
||||||
triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil)
|
triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil)
|
||||||
|
|
||||||
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
||||||
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)
|
||||||
@@ -301,6 +305,7 @@ 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
|
||||||
@@ -461,8 +466,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.ItemAmountInAncient(); err == nil && frozen > 0 {
|
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
|
||||||
frozen, err = bc.db.Ancients()
|
frozen, err = bc.db.BlockStore().Ancients()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -656,20 +661,13 @@ 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.BlockStore()), rawdb.ReadHeadHeaderHash(bc.db.BlockStore()), rawdb.ReadHeadFastBlockHash(bc.db)} {
|
for _, hash := range []common.Hash{rawdb.ReadHeadBlockHash(bc.db), rawdb.ReadHeadHeaderHash(bc.db), rawdb.ReadHeadFastBlockHash(bc.db)} {
|
||||||
if hash != genesis {
|
if hash != genesis {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -705,7 +703,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.BlockStore())
|
head := rawdb.ReadHeadBlockHash(bc.db)
|
||||||
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")
|
||||||
@@ -727,7 +725,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.BlockStore()); head != (common.Hash{}) {
|
if head := rawdb.ReadHeadHeaderHash(bc.db); head != (common.Hash{}) {
|
||||||
if header := bc.GetHeaderByHash(head); header != nil {
|
if header := bc.GetHeaderByHash(head); header != nil {
|
||||||
headHeader = header
|
headHeader = header
|
||||||
}
|
}
|
||||||
@@ -1106,7 +1104,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.Ancients()
|
frozen, _ := bc.db.BlockStore().Ancients()
|
||||||
if headNumber+1 < frozen {
|
if headNumber+1 < frozen {
|
||||||
wipe = pivot == nil || headNumber >= *pivot
|
wipe = pivot == nil || headNumber >= *pivot
|
||||||
}
|
}
|
||||||
@@ -1115,11 +1113,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.Ancients()
|
frozen, _ := bc.db.BlockStore().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.TruncateHead(num); err != nil {
|
if _, err := bc.db.BlockStore().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.
|
||||||
@@ -1137,7 +1135,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, bc.CurrentBlock()); force {
|
if target, force := updateFn(bc.db.BlockStore(), bc.CurrentBlock()); force {
|
||||||
bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn)
|
bc.hc.SetHead(target.Number.Uint64(), updateFn, delFn)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1298,19 +1296,33 @@ 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) {
|
||||||
// Add the block to the canonical chain number scheme and mark as the head
|
bc.dbWg.Add(2)
|
||||||
rawdb.WriteCanonicalHash(bc.db.BlockStore(), block.Hash(), block.NumberU64())
|
defer bc.dbWg.Wait()
|
||||||
rawdb.WriteHeadHeaderHash(bc.db.BlockStore(), block.Hash())
|
go func() {
|
||||||
rawdb.WriteHeadBlockHash(bc.db.BlockStore(), block.Hash())
|
defer bc.dbWg.Done()
|
||||||
|
// Add the block to the canonical chain number scheme and mark as the head
|
||||||
|
blockBatch := bc.db.BlockStore().NewBatch()
|
||||||
|
rawdb.WriteCanonicalHash(blockBatch, block.Hash(), block.NumberU64())
|
||||||
|
rawdb.WriteHeadHeaderHash(blockBatch, block.Hash())
|
||||||
|
rawdb.WriteHeadBlockHash(blockBatch, block.Hash())
|
||||||
|
rawdb.WriteHeadFastBlockHash(blockBatch, block.Hash())
|
||||||
|
// Flush the whole batch into the disk, exit the node if failed
|
||||||
|
if err := blockBatch.Write(); err != nil {
|
||||||
|
log.Crit("Failed to update chain indexes and markers in block db", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
go func() {
|
||||||
|
defer bc.dbWg.Done()
|
||||||
|
|
||||||
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
|
||||||
|
if err := batch.Write(); err != nil {
|
||||||
|
log.Crit("Failed to update chain indexes in chain db", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Flush the whole batch into the disk, exit the node if failed
|
|
||||||
if err := batch.Write(); err != nil {
|
|
||||||
log.Crit("Failed to update chain indexes and markers", "err", err)
|
|
||||||
}
|
|
||||||
// Update all in-memory chain markers in the last step
|
// Update all in-memory chain markers in the last step
|
||||||
bc.hc.SetCurrentHeader(block.Header())
|
bc.hc.SetCurrentHeader(block.Header())
|
||||||
|
|
||||||
@@ -1531,7 +1543,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [
|
|||||||
} else if !reorg {
|
} else if !reorg {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
rawdb.WriteHeadFastBlockHash(bc.db, head.Hash())
|
rawdb.WriteHeadFastBlockHash(bc.db.BlockStore(), 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
|
||||||
@@ -1548,9 +1560,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.Ancients(); frozen == 0 {
|
if frozen, _ := bc.db.BlockStore().Ancients(); frozen == 0 {
|
||||||
td := bc.genesisBlock.Difficulty()
|
td := bc.genesisBlock.Difficulty()
|
||||||
writeSize, err := rawdb.WriteAncientBlocks(bc.db, []*types.Block{bc.genesisBlock}, []types.Receipts{nil}, td)
|
writeSize, err := rawdb.WriteAncientBlocks(bc.db.BlockStore(), []*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
|
||||||
@@ -1568,7 +1580,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, blockChain, receiptChain, td)
|
writeSize, err := rawdb.WriteAncientBlocksWithBlobs(bc.db.BlockStore(), 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
|
||||||
@@ -1576,7 +1588,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.Sync(); err != nil {
|
if err := bc.db.BlockStore().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.
|
||||||
@@ -1584,7 +1596,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.TruncateHead(previousSnapBlock + 1); err != nil {
|
if _, err := bc.db.BlockStore().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
|
||||||
@@ -1604,7 +1616,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, first.NumberU64(), last.NumberU64()) {
|
for _, nh := range rawdb.ReadAllHashesInRange(bc.db.BlockStore(), 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)
|
||||||
}
|
}
|
||||||
@@ -1774,7 +1786,6 @@ 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)
|
||||||
@@ -1783,10 +1794,20 @@ 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())
|
||||||
}
|
}
|
||||||
rawdb.WritePreimages(blockBatch, state.Preimages())
|
if bc.db.StateStore() != nil {
|
||||||
|
rawdb.WritePreimages(bc.db.StateStore(), state.Preimages())
|
||||||
|
} else {
|
||||||
|
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()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -2251,6 +2272,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||||||
statedb.StopPrefetcher()
|
statedb.StopPrefetcher()
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
|
blockExecutionTotalTimer.UpdateSince(pstart)
|
||||||
|
|
||||||
ptime := time.Since(pstart)
|
ptime := time.Since(pstart)
|
||||||
|
|
||||||
// Validate the state using the default validator
|
// Validate the state using the default validator
|
||||||
@@ -2261,11 +2284,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)
|
||||||
@@ -2296,6 +2319,7 @@ 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)
|
||||||
|
|
||||||
@@ -2378,26 +2402,11 @@ func (bc *BlockChain) updateHighestVerifiedHeader(header *types.Header) {
|
|||||||
if header == nil || header.Number == nil {
|
if header == nil || header.Number == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
currentHeader := bc.highestVerifiedHeader.Load()
|
currentBlock := bc.CurrentBlock()
|
||||||
if currentHeader == nil {
|
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, header)
|
||||||
|
if err == nil && reorg {
|
||||||
bc.highestVerifiedHeader.Store(types.CopyHeader(header))
|
bc.highestVerifiedHeader.Store(types.CopyHeader(header))
|
||||||
return
|
log.Trace("updateHighestVerifiedHeader", "number", header.Number.Uint64(), "hash", header.Hash())
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
|
|||||||
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
|
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
|
||||||
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
|
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
|
||||||
}
|
}
|
||||||
|
mGasPsGauge.Update(int64(mgasps))
|
||||||
blockInsertMgaspsGauge.Update(int64(mgasps))
|
blockInsertMgaspsGauge.Update(int64(mgasps))
|
||||||
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
||||||
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
||||||
|
|||||||
@@ -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.BlockStore(), hash)
|
number := rawdb.ReadHeaderNumber(bc.db, 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.Tail()
|
tail, err := bc.db.BlockStore().Tail()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ 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"
|
||||||
@@ -1795,6 +1797,13 @@ 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(ðdb.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)
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ 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"
|
||||||
@@ -1998,6 +2000,13 @@ 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(ðdb.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)
|
||||||
|
|||||||
@@ -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.BlockStore(), prevHeader.Number.Uint64()) != prevHash {
|
if rawdb.ReadCanonicalHash(c.chainDb, prevHeader.Number.Uint64()) != prevHash {
|
||||||
if h := rawdb.FindCommonAncestor(c.chainDb.BlockStore(), prevHeader, header); h != nil {
|
if h := rawdb.FindCommonAncestor(c.chainDb, prevHeader, header); h != nil {
|
||||||
c.newHead(h.Number.Uint64(), true)
|
c.newHead(h.Number.Uint64(), true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,9 +86,16 @@ 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 || externTd == nil {
|
if localTD == 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.
|
||||||
@@ -114,7 +121,9 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
|
|||||||
if f.preserve != nil {
|
if f.preserve != nil {
|
||||||
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
||||||
}
|
}
|
||||||
reorg = !currentPreserve && (externPreserve || f.rand.Float64() < 0.5)
|
reorg = !currentPreserve && (externPreserve ||
|
||||||
|
extern.Time < current.Time ||
|
||||||
|
extern.Time == current.Time && f.rand.Float64() < 0.5)
|
||||||
}
|
}
|
||||||
return reorg, nil
|
return reorg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,8 +216,6 @@ 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
|
||||||
}
|
}
|
||||||
@@ -245,12 +243,6 @@ 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
|
||||||
}
|
}
|
||||||
@@ -498,7 +490,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
|
|||||||
rawdb.WriteReceipts(db.BlockStore(), block.Hash(), block.NumberU64(), nil)
|
rawdb.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, block.Hash())
|
rawdb.WriteHeadFastBlockHash(db.BlockStore(), 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
|
||||||
|
|||||||
@@ -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.BlockStore()); head != (common.Hash{}) {
|
if head := rawdb.ReadHeadBlockHash(chainDb); 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.BlockStore(), hash)
|
number := rawdb.ReadHeaderNumber(hc.chainDb, 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.NewBatch()
|
markerBatch := hc.chainDb.BlockStore().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(hc.chainDb.BlockStore(), parentHash)
|
rawdb.WriteHeadHeaderHash(markerBatch, 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, n)) > 0; n++ {
|
for n := num + 1; len(rawdb.ReadAllHashes(hc.chainDb.BlockStore(), 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, num)
|
hashes := rawdb.ReadAllHashes(hc.chainDb.BlockStore(), 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())
|
||||||
|
|||||||
@@ -34,6 +34,15 @@ 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
|
||||||
@@ -144,8 +153,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.KeyValueReader, hash common.Hash) *uint64 {
|
func ReadHeaderNumber(db ethdb.MultiDatabaseReader, hash common.Hash) *uint64 {
|
||||||
data, _ := db.Get(headerNumberKey(hash))
|
data, _ := db.BlockStoreReader().Get(headerNumberKey(hash))
|
||||||
if len(data) != 8 {
|
if len(data) != 8 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -170,8 +179,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.KeyValueReader) common.Hash {
|
func ReadHeadHeaderHash(db ethdb.MultiDatabaseReader) common.Hash {
|
||||||
data, _ := db.Get(headHeaderKey)
|
data, _ := db.BlockStoreReader().Get(headHeaderKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
@@ -186,8 +195,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.KeyValueReader) common.Hash {
|
func ReadHeadBlockHash(db ethdb.MultiDatabaseReader) common.Hash {
|
||||||
data, _ := db.Get(headBlockKey)
|
data, _ := db.BlockStoreReader().Get(headBlockKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
@@ -202,8 +211,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.KeyValueReader) common.Hash {
|
func ReadHeadFastBlockHash(db ethdb.MultiDatabaseReader) common.Hash {
|
||||||
data, _ := db.Get(headFastBlockKey)
|
data, _ := db.BlockStoreReader().Get(headFastBlockKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
@@ -218,8 +227,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.KeyValueReader) common.Hash {
|
func ReadFinalizedBlockHash(db ethdb.MultiDatabaseReader) common.Hash {
|
||||||
data, _ := db.Get(headFinalizedBlockKey)
|
data, _ := db.BlockStoreReader().Get(headFinalizedBlockKey)
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
@@ -297,7 +306,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.Ancients()
|
limit, _ := db.BlockStoreReader().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
|
||||||
@@ -317,7 +326,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.AncientRange(ChainFreezerHeaderTable, i+1-count, count, 2*1024*1024)
|
data, err := db.BlockStoreReader().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
|
||||||
@@ -468,7 +477,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.Get(headerHashKey(number))
|
hash, _ := db.BlockStoreReader().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
|
||||||
})
|
})
|
||||||
@@ -516,6 +525,13 @@ 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 {
|
||||||
@@ -554,13 +570,6 @@ 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
|
||||||
@@ -884,7 +893,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.ReadAncients(func(reader ethdb.AncientReaderOp) error {
|
db.BlockStoreReader().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)
|
||||||
@@ -1093,24 +1102,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.BlockStoreReader())
|
headHeaderHash := ReadHeadHeaderHash(db)
|
||||||
if headHeaderHash == (common.Hash{}) {
|
if headHeaderHash == (common.Hash{}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
headHeaderNumber := ReadHeaderNumber(db.BlockStoreReader(), headHeaderHash)
|
headHeaderNumber := ReadHeaderNumber(db, headHeaderHash)
|
||||||
if headHeaderNumber == nil {
|
if headHeaderNumber == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return ReadHeader(db.BlockStoreReader(), headHeaderHash, *headHeaderNumber)
|
return ReadHeader(db, 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.BlockStoreReader())
|
headBlockHash := ReadHeadBlockHash(db)
|
||||||
if headBlockHash == (common.Hash{}) {
|
if headBlockHash == (common.Hash{}) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
headBlockNumber := ReadHeaderNumber(db.BlockStoreReader(), headBlockHash)
|
headBlockNumber := ReadHeaderNumber(db, headBlockHash)
|
||||||
if headBlockNumber == nil {
|
if headBlockNumber == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.BlockStoreReader(), common.BytesToHash(data))
|
return ReadHeaderNumber(db, common.BytesToHash(data))
|
||||||
}
|
}
|
||||||
// Finally try database v3 tx lookup format
|
// Finally try database v3 tx lookup format
|
||||||
var entry LegacyTxLookupEntry
|
var entry LegacyTxLookupEntry
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package rawdb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@@ -98,6 +100,18 @@ 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
|
||||||
|
|||||||
@@ -58,7 +58,8 @@ type chainFreezer struct {
|
|||||||
wg sync.WaitGroup
|
wg sync.WaitGroup
|
||||||
trigger chan chan struct{} // Manual blocking freeze trigger, test determinism
|
trigger chan chan struct{} // Manual blocking freeze trigger, test determinism
|
||||||
|
|
||||||
freezeEnv atomic.Value
|
freezeEnv atomic.Value
|
||||||
|
waitEnvTimes int
|
||||||
|
|
||||||
multiDatabase bool
|
multiDatabase bool
|
||||||
}
|
}
|
||||||
@@ -91,7 +92,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.KeyValueReader) uint64 {
|
func (f *chainFreezer) readHeadNumber(db ethdb.Reader) 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")
|
||||||
@@ -107,7 +108,7 @@ func (f *chainFreezer) readHeadNumber(db ethdb.KeyValueReader) 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.KeyValueReader) uint64 {
|
func (f *chainFreezer) readFinalizedNumber(db ethdb.Reader) uint64 {
|
||||||
hash := ReadFinalizedBlockHash(db)
|
hash := ReadFinalizedBlockHash(db)
|
||||||
if hash == (common.Hash{}) {
|
if hash == (common.Hash{}) {
|
||||||
return 0
|
return 0
|
||||||
@@ -122,7 +123,7 @@ func (f *chainFreezer) readFinalizedNumber(db ethdb.KeyValueReader) 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.KeyValueReader) (uint64, error) {
|
func (f *chainFreezer) freezeThreshold(db ethdb.Reader) (uint64, error) {
|
||||||
var (
|
var (
|
||||||
head = f.readHeadNumber(db)
|
head = f.readHeadNumber(db)
|
||||||
final = f.readFinalizedNumber(db)
|
final = f.readFinalizedNumber(db)
|
||||||
@@ -178,19 +179,6 @@ 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
|
||||||
@@ -200,6 +188,7 @@ 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
|
||||||
@@ -282,6 +271,18 @@ 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()
|
||||||
@@ -544,14 +545,7 @@ func (f *chainFreezer) checkFreezerEnv() error {
|
|||||||
if exist {
|
if exist {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
blobFrozen, err := f.TableAncients(ChainFreezerBlobSidecarTable)
|
return missFreezerEnvErr
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if blobFrozen > 0 {
|
|
||||||
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 {
|
||||||
|
|||||||
@@ -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.ItemAmountInAncient()
|
frozen, err := db.BlockStore().ItemAmountInAncient()
|
||||||
if err != nil || frozen == 0 {
|
if err != nil || frozen == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
batch = db.NewBatch()
|
batch = db.BlockStore().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.AncientOffSet()
|
offset = db.BlockStore().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.AncientRange(ChainFreezerHashTable, i, count, 32*count)
|
data, err := db.BlockStore().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, hash)
|
WriteHeadFastBlockHash(db.BlockStore(), 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.AncientOffSet(); offset > from {
|
if offset := db.BlockStore().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.BlockStore(), n)
|
data := ReadCanonicalBodyRLP(db, 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.AncientOffSet(); offset > from {
|
if offset := db.BlockStore().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.AncientOffSet(); offset > from {
|
if offset := db.BlockStore().AncientOffSet(); offset > from {
|
||||||
from = offset
|
from = offset
|
||||||
}
|
}
|
||||||
if from >= to {
|
if from >= to {
|
||||||
|
|||||||
@@ -61,8 +61,10 @@ func (frdb *freezerdb) BlockStoreReader() ethdb.Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (frdb *freezerdb) BlockStoreWriter() ethdb.Writer {
|
func (frdb *freezerdb) BlockStoreWriter() ethdb.Writer {
|
||||||
//TODO implement me
|
if frdb.blockStore == nil {
|
||||||
panic("implement me")
|
return frdb
|
||||||
|
}
|
||||||
|
return frdb.blockStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// AncientDatadir returns the path of root ancient directory.
|
// AncientDatadir returns the path of root ancient directory.
|
||||||
@@ -116,6 +118,13 @@ 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()
|
||||||
@@ -193,7 +202,7 @@ func (db *nofreezedb) Ancients() (uint64, error) {
|
|||||||
return 0, errNotSupported
|
return 0, errNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ancients returns an error as we don't have a backing chain freezer.
|
// ItemAmountInAncient 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
|
||||||
}
|
}
|
||||||
@@ -254,6 +263,13 @@ 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
|
||||||
@@ -331,6 +347,111 @@ 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.
|
||||||
@@ -380,6 +501,12 @@ 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 {
|
||||||
@@ -408,8 +535,17 @@ 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(db)
|
printChainMetadata(freezerDb)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -445,10 +581,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(db)
|
printChainMetadata(freezerDb)
|
||||||
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(db)
|
printChainMetadata(freezerDb)
|
||||||
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
|
||||||
@@ -456,7 +592,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(db, ReadHeadHeaderHash(db)); head > frozen-1 {
|
if head := *ReadHeaderNumber(freezerDb, ReadHeadHeaderHash(freezerDb)); 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
|
||||||
@@ -466,7 +602,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(db)
|
printChainMetadata(freezerDb)
|
||||||
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)
|
||||||
}
|
}
|
||||||
@@ -481,11 +617,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(db) != common.BytesToHash(kvgenesis) {
|
if ReadHeadHeaderHash(freezerDb) != 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(db)
|
printChainMetadata(freezerDb)
|
||||||
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
|
||||||
@@ -507,12 +643,7 @@ func NewDatabaseWithFreezer(db ethdb.KeyValueStore, ancient string, namespace st
|
|||||||
frdb.wg.Done()
|
frdb.wg.Done()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
return &freezerdb{
|
return freezerDb, nil
|
||||||
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
|
||||||
@@ -634,7 +765,7 @@ func Open(o OpenOptions) (ethdb.Database, error) {
|
|||||||
}
|
}
|
||||||
if ReadAncientType(kvdb) == PruneFreezerType {
|
if ReadAncientType(kvdb) == PruneFreezerType {
|
||||||
if !o.PruneAncientData {
|
if !o.PruneAncientData {
|
||||||
log.Warn("Disk db is pruned")
|
log.Warn("NOTICE: You're opening a pruned disk db!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(o.AncientsDirectory) == 0 {
|
if len(o.AncientsDirectory) == 0 {
|
||||||
@@ -763,7 +894,7 @@ func DataTypeByKey(key []byte) DataType {
|
|||||||
return StateDataType
|
return StateDataType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey} {
|
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey, headBlockKey, headFastBlockKey} {
|
||||||
if bytes.Equal(key, meta) {
|
if bytes.Equal(key, meta) {
|
||||||
return BlockDataType
|
return BlockDataType
|
||||||
}
|
}
|
||||||
@@ -978,7 +1109,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} {
|
for _, meta := range [][]byte{headHeaderKey, headFinalizedBlockKey, headBlockKey, headFastBlockKey} {
|
||||||
if bytes.Equal(key, meta) {
|
if bytes.Equal(key, meta) {
|
||||||
metadata.Add(size)
|
metadata.Add(size)
|
||||||
accounted = true
|
accounted = true
|
||||||
@@ -1128,7 +1259,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.KeyValueStore) {
|
func printChainMetadata(db ethdb.Reader) {
|
||||||
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, ": "))
|
||||||
@@ -1139,7 +1270,7 @@ func printChainMetadata(db ethdb.KeyValueStore) {
|
|||||||
// 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.KeyValueStore) [][]string {
|
func ReadChainMetadata(db ethdb.Reader) [][]string {
|
||||||
pp := func(val *uint64) string {
|
pp := func(val *uint64) string {
|
||||||
if val == nil {
|
if val == nil {
|
||||||
return "<nil>"
|
return "<nil>"
|
||||||
@@ -1161,26 +1292,3 @@ func ReadChainMetadata(db ethdb.KeyValueStore) [][]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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -541,41 +541,6 @@ 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,
|
||||||
|
|||||||
@@ -127,6 +127,11 @@ 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.
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ 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"
|
||||||
@@ -66,28 +68,49 @@ 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
|
||||||
min := uint64(math.MaxUint64)
|
minItems := uint64(math.MaxUint64)
|
||||||
for name, disableSnappy := range chainFreezerNoSnappy {
|
for name, disableSnappy := range chainFreezerNoSnappy {
|
||||||
table, err := newFreezerTable(datadir, name, disableSnappy, false)
|
var (
|
||||||
|
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 min > items {
|
if minItems > items {
|
||||||
min = items
|
minItems = items
|
||||||
}
|
}
|
||||||
table.Close()
|
table.Close()
|
||||||
}
|
}
|
||||||
log.Info("Read ancientdb item counts", "items", min)
|
|
||||||
offset += min
|
|
||||||
|
|
||||||
if frozen := ReadFrozenOfAncientFreezer(f.db); frozen > offset {
|
// If minItems is non-zero, it indicates that the chain freezer was previously enabled, and we should use minItems as the current frozen value.
|
||||||
offset = frozen
|
// If minItems is zero, it indicates that the pruneAncient was previously enabled, and we should continue using 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)
|
||||||
|
|
||||||
atomic.StoreUint64(&f.frozen, offset)
|
// FrozenOfAncientFreezer is the progress of the last prune-freezer freeze.
|
||||||
|
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
|
||||||
}
|
}
|
||||||
@@ -299,9 +322,8 @@ 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
|
||||||
}
|
}
|
||||||
if hash != (common.Hash{}) {
|
// may include common.Hash{}, will be delete in gcKvStore
|
||||||
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 {
|
||||||
|
|||||||
@@ -251,6 +251,10 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,4 +34,7 @@ var (
|
|||||||
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
|
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
|
||||||
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
|
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
|
||||||
slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil)
|
slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil)
|
||||||
|
|
||||||
|
accountIntermediateRootTimer = metrics.NewRegisteredTimer("state/account/intermediate/root/time", nil)
|
||||||
|
storageIntermediateRootTimer = metrics.NewRegisteredTimer("state/storage/intermediate/root/time", nil)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -286,6 +286,13 @@ func (dl *diffLayer) Stale() bool {
|
|||||||
// Account directly retrieves the account associated with a particular hash in
|
// Account directly retrieves the account associated with a particular hash in
|
||||||
// the snapshot slim data format.
|
// the snapshot slim data format.
|
||||||
func (dl *diffLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
|
func (dl *diffLayer) Account(hash common.Hash) (*types.SlimAccount, error) {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
snapGetTimer.UpdateSince(start)
|
||||||
|
snapGetQPS.Mark(1)
|
||||||
|
snapGetAccountTimer.UpdateSince(start)
|
||||||
|
snapGetAccountQPS.Mark(1)
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
data, err := dl.AccountRLP(hash)
|
data, err := dl.AccountRLP(hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -394,6 +401,13 @@ func (dl *diffLayer) accountRLP(hash common.Hash, depth int) ([]byte, error) {
|
|||||||
//
|
//
|
||||||
// Note the returned slot is not a copy, please don't modify it.
|
// Note the returned slot is not a copy, please don't modify it.
|
||||||
func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, error) {
|
func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, error) {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
snapGetTimer.UpdateSince(start)
|
||||||
|
snapGetQPS.Mark(1)
|
||||||
|
snapGetStorageTimer.UpdateSince(start)
|
||||||
|
snapGetStorageQPS.Mark(1)
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
// Check the bloom filter first whether there's even a point in reaching into
|
// Check the bloom filter first whether there's even a point in reaching into
|
||||||
// all the maps in all the layers below
|
// all the maps in all the layers below
|
||||||
dl.lock.RLock()
|
dl.lock.RLock()
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package snapshot
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@@ -136,7 +137,12 @@ func (dl *diskLayer) AccountRLP(hash common.Hash) ([]byte, error) {
|
|||||||
return blob, nil
|
return blob, nil
|
||||||
}
|
}
|
||||||
// Cache doesn't contain account, pull from disk and cache for later
|
// Cache doesn't contain account, pull from disk and cache for later
|
||||||
|
// TODO:
|
||||||
|
snapNodeQPS.Mark(1)
|
||||||
|
startLoadSnapNode := time.Now()
|
||||||
blob := rawdb.ReadAccountSnapshot(dl.diskdb, hash)
|
blob := rawdb.ReadAccountSnapshot(dl.diskdb, hash)
|
||||||
|
snapNodeTime.Mark(time.Since(startLoadSnapNode).Nanoseconds())
|
||||||
|
|
||||||
dl.cache.Set(hash[:], blob)
|
dl.cache.Set(hash[:], blob)
|
||||||
|
|
||||||
snapshotCleanAccountMissMeter.Mark(1)
|
snapshotCleanAccountMissMeter.Mark(1)
|
||||||
@@ -176,7 +182,11 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
|
|||||||
return blob, nil
|
return blob, nil
|
||||||
}
|
}
|
||||||
// Cache doesn't contain storage slot, pull from disk and cache for later
|
// Cache doesn't contain storage slot, pull from disk and cache for later
|
||||||
|
// TODO:
|
||||||
|
snapNodeQPS.Mark(1)
|
||||||
|
startLoadSnapNode := time.Now()
|
||||||
blob := rawdb.ReadStorageSnapshot(dl.diskdb, accountHash, storageHash)
|
blob := rawdb.ReadStorageSnapshot(dl.diskdb, accountHash, storageHash)
|
||||||
|
snapNodeTime.Mark(time.Since(startLoadSnapNode).Nanoseconds())
|
||||||
dl.cache.Set(key, blob)
|
dl.cache.Set(key, blob)
|
||||||
|
|
||||||
snapshotCleanStorageMissMeter.Mark(1)
|
snapshotCleanStorageMissMeter.Mark(1)
|
||||||
|
|||||||
@@ -50,4 +50,15 @@ var (
|
|||||||
snapStorageWriteCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/write", nil)
|
snapStorageWriteCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/write", nil)
|
||||||
// snapStorageCleanCounter measures time spent on deleting storages
|
// snapStorageCleanCounter measures time spent on deleting storages
|
||||||
snapStorageCleanCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/clean", nil)
|
snapStorageCleanCounter = metrics.NewRegisteredCounter("state/snapshot/generation/duration/storage/clean", nil)
|
||||||
|
|
||||||
|
snapNodeQPS = metrics.NewRegisteredMeter("pbss/snap/node/qps", nil)
|
||||||
|
snapNodeTime = metrics.NewRegisteredMeter("pbss/snap/node/time", nil)
|
||||||
|
|
||||||
|
snapGetTimer = metrics.NewRegisteredTimer("snap/get/time", nil)
|
||||||
|
snapGetQPS = metrics.NewRegisteredMeter("snap/get/qps", nil)
|
||||||
|
|
||||||
|
snapGetAccountTimer = metrics.NewRegisteredTimer("snap/account/get/time", nil)
|
||||||
|
snapGetAccountQPS = metrics.NewRegisteredMeter("snap/account/get/qps", nil)
|
||||||
|
snapGetStorageTimer = metrics.NewRegisteredTimer("snap/storage/get/time", nil)
|
||||||
|
snapGetStorageQPS = metrics.NewRegisteredMeter("snap/storage/get/qps", nil)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -223,6 +223,14 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
|||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
// If no live objects are available, attempt to use snapshots
|
// If no live objects are available, attempt to use snapshots
|
||||||
|
|
||||||
|
defer func(start time.Time) {
|
||||||
|
stateDBGetTimer.UpdateSince(start)
|
||||||
|
stateDBGetQPS.Mark(1)
|
||||||
|
stateDBGetStorageTimer.UpdateSince(start)
|
||||||
|
stateDBGetStorageQPS.Mark(1)
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
var (
|
var (
|
||||||
enc []byte
|
enc []byte
|
||||||
err error
|
err error
|
||||||
|
|||||||
@@ -54,6 +54,16 @@ type revision struct {
|
|||||||
journalIndex int
|
journalIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
stateDBGetTimer = metrics.NewRegisteredTimer("statedb/get/time", nil)
|
||||||
|
stateDBGetQPS = metrics.NewRegisteredMeter("statedb/get/qps", nil)
|
||||||
|
|
||||||
|
stateDBGetAccountTimer = metrics.NewRegisteredTimer("statedb/account/get/time", nil)
|
||||||
|
stateDBGetAccountQPS = metrics.NewRegisteredMeter("statedb/account/get/qps", nil)
|
||||||
|
stateDBGetStorageTimer = metrics.NewRegisteredTimer("statedb/storage/get/time", nil)
|
||||||
|
stateDBGetStorageQPS = metrics.NewRegisteredMeter("statedb/storage/get/qps", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// StateDB structs within the ethereum protocol are used to store anything
|
// StateDB structs within the ethereum protocol are used to store anything
|
||||||
// within the merkle trie. StateDBs take care of caching and storing
|
// within the merkle trie. StateDBs take care of caching and storing
|
||||||
// nested states. It's the general query interface to retrieve:
|
// nested states. It's the general query interface to retrieve:
|
||||||
@@ -166,7 +176,7 @@ func NewWithSharedPool(root common.Hash, db Database, snaps *snapshot.Tree) (*St
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
statedb.storagePool = NewStoragePool()
|
//statedb.storagePool = NewStoragePool()
|
||||||
return statedb, nil
|
return statedb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -716,6 +726,14 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
|||||||
if obj := s.stateObjects[addr]; obj != nil {
|
if obj := s.stateObjects[addr]; obj != nil {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer func(start time.Time) {
|
||||||
|
stateDBGetTimer.UpdateSince(start)
|
||||||
|
stateDBGetQPS.Mark(1)
|
||||||
|
stateDBGetAccountTimer.UpdateSince(start)
|
||||||
|
stateDBGetAccountQPS.Mark(1)
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
// If no live objects are available, attempt to use snapshots
|
// If no live objects are available, attempt to use snapshots
|
||||||
var data *types.StateAccount
|
var data *types.StateAccount
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
@@ -933,8 +951,8 @@ func (s *StateDB) copyInternal(doPrefetch bool) *StateDB {
|
|||||||
// 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(state.accountsOrigin)
|
state.accountsOrigin = copySet(s.accountsOrigin)
|
||||||
state.storagesOrigin = copy2DSet(state.storagesOrigin)
|
state.storagesOrigin = copy2DSet(s.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 {
|
||||||
@@ -1147,6 +1165,10 @@ func (s *StateDB) populateSnapStorage(obj *stateObject) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) AccountsIntermediateRoot() {
|
func (s *StateDB) AccountsIntermediateRoot() {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
storageIntermediateRootTimer.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
tasks := make(chan func())
|
tasks := make(chan func())
|
||||||
finishCh := make(chan struct{})
|
finishCh := make(chan struct{})
|
||||||
defer close(finishCh)
|
defer close(finishCh)
|
||||||
@@ -1191,6 +1213,9 @@ func (s *StateDB) AccountsIntermediateRoot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) StateIntermediateRoot() common.Hash {
|
func (s *StateDB) StateIntermediateRoot() common.Hash {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
accountIntermediateRootTimer.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
// If there was a trie prefetcher operating, it gets aborted and irrevocably
|
// If there was a trie prefetcher operating, it gets aborted and irrevocably
|
||||||
// modified after we start retrieving tries. Remove it from the statedb after
|
// modified after we start retrieving tries. Remove it from the statedb after
|
||||||
// this round of use.
|
// this round of use.
|
||||||
|
|||||||
@@ -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.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme string) *trie.Sync {
|
func NewStateSync(root common.Hash, database ethdb.Database, 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 {
|
||||||
|
|||||||
@@ -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); err != nil {
|
if err := sched.Commit(batch, nil); 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); err != nil {
|
if err := sched.Commit(batch, nil); 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); err != nil {
|
if err := sched.Commit(batch, nil); 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); err != nil {
|
if err := sched.Commit(batch, nil); 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); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
|
|||||||
1
core/systemcontracts/haber_fix/chapel/SlashContract
Normal file
1
core/systemcontracts/haber_fix/chapel/SlashContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/haber_fix/chapel/ValidatorContract
Normal file
1
core/systemcontracts/haber_fix/chapel/ValidatorContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/haber_fix/mainnet/SlashContract
Normal file
1
core/systemcontracts/haber_fix/mainnet/SlashContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/haber_fix/mainnet/ValidatorContract
Normal file
1
core/systemcontracts/haber_fix/mainnet/ValidatorContract
Normal file
File diff suppressed because one or more lines are too long
19
core/systemcontracts/haber_fix/types.go
Normal file
19
core/systemcontracts/haber_fix/types.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package haber_fix
|
||||||
|
|
||||||
|
import _ "embed"
|
||||||
|
|
||||||
|
// contract codes for Chapel upgrade
|
||||||
|
var (
|
||||||
|
//go:embed chapel/ValidatorContract
|
||||||
|
ChapelValidatorContract string
|
||||||
|
//go:embed chapel/SlashContract
|
||||||
|
ChapelSlashContract string
|
||||||
|
)
|
||||||
|
|
||||||
|
// contract codes for Mainnet upgrade
|
||||||
|
var (
|
||||||
|
//go:embed mainnet/ValidatorContract
|
||||||
|
MainnetValidatorContract string
|
||||||
|
//go:embed mainnet/SlashContract
|
||||||
|
MainnetSlashContract string
|
||||||
|
)
|
||||||
@@ -4,17 +4,16 @@ 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"
|
||||||
@@ -23,6 +22,8 @@ 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 {
|
||||||
@@ -75,6 +76,8 @@ 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() {
|
||||||
@@ -701,6 +704,38 @@ 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) {
|
||||||
@@ -777,6 +812,10 @@ 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
|
||||||
*/
|
*/
|
||||||
@@ -799,7 +838,7 @@ func applySystemContractUpgrade(upgrade *Upgrade, blockNumber *big.Int, statedb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newContractCode, err := hex.DecodeString(cfg.Code)
|
newContractCode, err := hex.DecodeString(strings.TrimSpace(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()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,8 +55,6 @@ const (
|
|||||||
|
|
||||||
// txReannoMaxNum is the maximum number of transactions a reannounce action can include.
|
// txReannoMaxNum is the maximum number of transactions a reannounce action can include.
|
||||||
txReannoMaxNum = 1024
|
txReannoMaxNum = 1024
|
||||||
|
|
||||||
maxBufferSize = 1000 // maximum size of tx buffer
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -246,10 +244,6 @@ type LegacyPool struct {
|
|||||||
initDoneCh chan struct{} // is closed once the pool is initialized (for tests)
|
initDoneCh chan struct{} // is closed once the pool is initialized (for tests)
|
||||||
|
|
||||||
changesSinceReorg int // A counter for how many drops we've performed in-between reorg.
|
changesSinceReorg int // A counter for how many drops we've performed in-between reorg.
|
||||||
|
|
||||||
// A buffer to store transactions that would otherwise be discarded
|
|
||||||
buffer []*types.Transaction
|
|
||||||
bufferLock sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type txpoolResetRequest struct {
|
type txpoolResetRequest struct {
|
||||||
@@ -361,13 +355,11 @@ func (pool *LegacyPool) loop() {
|
|||||||
evict = time.NewTicker(evictionInterval)
|
evict = time.NewTicker(evictionInterval)
|
||||||
reannounce = time.NewTicker(reannounceInterval)
|
reannounce = time.NewTicker(reannounceInterval)
|
||||||
journal = time.NewTicker(pool.config.Rejournal)
|
journal = time.NewTicker(pool.config.Rejournal)
|
||||||
readd = time.NewTicker(time.Minute) // ticker to re-add buffered transactions periodically
|
|
||||||
)
|
)
|
||||||
defer report.Stop()
|
defer report.Stop()
|
||||||
defer evict.Stop()
|
defer evict.Stop()
|
||||||
defer reannounce.Stop()
|
defer reannounce.Stop()
|
||||||
defer journal.Stop()
|
defer journal.Stop()
|
||||||
defer readd.Stop() // Stop the ticker when the loop exits
|
|
||||||
|
|
||||||
// Notify tests that the init phase is done
|
// Notify tests that the init phase is done
|
||||||
close(pool.initDoneCh)
|
close(pool.initDoneCh)
|
||||||
@@ -444,9 +436,6 @@ func (pool *LegacyPool) loop() {
|
|||||||
}
|
}
|
||||||
pool.mu.Unlock()
|
pool.mu.Unlock()
|
||||||
}
|
}
|
||||||
// Handle re-adding buffered transactions
|
|
||||||
case <-readd.C:
|
|
||||||
pool.readdBufferedTransactions()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -792,21 +781,12 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
// If the transaction pool is full, buffer underpriced transactions
|
// If the transaction pool is full, discard underpriced transactions
|
||||||
if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue {
|
if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue {
|
||||||
// If the new transaction is underpriced, buffer it
|
// If the new transaction is underpriced, don't accept it
|
||||||
if !isLocal && pool.priced.Underpriced(tx) {
|
if !isLocal && pool.priced.Underpriced(tx) {
|
||||||
log.Trace("Buffering underpriced transaction", "hash", hash, "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
log.Trace("Discarding underpriced transaction", "hash", hash, "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
|
||||||
underpricedTxMeter.Mark(1)
|
underpricedTxMeter.Mark(1)
|
||||||
|
|
||||||
pool.bufferLock.Lock()
|
|
||||||
if len(pool.buffer) < maxBufferSize {
|
|
||||||
pool.buffer = append(pool.buffer, tx)
|
|
||||||
} else {
|
|
||||||
log.Warn("Buffer is full, discarding transaction", "hash", hash)
|
|
||||||
}
|
|
||||||
pool.bufferLock.Unlock()
|
|
||||||
|
|
||||||
return false, txpool.ErrUnderpriced
|
return false, txpool.ErrUnderpriced
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -824,16 +804,6 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
|
|||||||
// Otherwise if we can't make enough room for new one, abort the operation.
|
// Otherwise if we can't make enough room for new one, abort the operation.
|
||||||
drop, success := pool.priced.Discard(pool.all.Slots()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+numSlots(tx), isLocal)
|
drop, success := pool.priced.Discard(pool.all.Slots()-int(pool.config.GlobalSlots+pool.config.GlobalQueue)+numSlots(tx), isLocal)
|
||||||
|
|
||||||
// Add dropped transactions to the buffer
|
|
||||||
pool.bufferLock.Lock()
|
|
||||||
availableSpace := maxBufferSize - len(pool.buffer)
|
|
||||||
// Determine how many elements to take from drop
|
|
||||||
if availableSpace > len(drop) {
|
|
||||||
availableSpace = len(drop)
|
|
||||||
}
|
|
||||||
pool.buffer = append(pool.buffer, drop[:availableSpace]...)
|
|
||||||
pool.bufferLock.Unlock()
|
|
||||||
|
|
||||||
// Special case, we still can't make the room for the new remote one.
|
// Special case, we still can't make the room for the new remote one.
|
||||||
if !isLocal && !success {
|
if !isLocal && !success {
|
||||||
log.Trace("Discarding overflown transaction", "hash", hash)
|
log.Trace("Discarding overflown transaction", "hash", hash)
|
||||||
@@ -1809,51 +1779,6 @@ func (pool *LegacyPool) SetMaxGas(maxGas uint64) {
|
|||||||
pool.maxGas.Store(maxGas)
|
pool.maxGas.Store(maxGas)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *LegacyPool) readdBufferedTransactions() {
|
|
||||||
pool.mu.Lock()
|
|
||||||
defer pool.mu.Unlock()
|
|
||||||
|
|
||||||
// Check if there is space in the pool
|
|
||||||
if uint64(pool.all.Slots()) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
|
|
||||||
return // No space available, skip re-adding
|
|
||||||
}
|
|
||||||
|
|
||||||
var readded []*types.Transaction
|
|
||||||
|
|
||||||
pool.bufferLock.Lock()
|
|
||||||
for _, tx := range pool.buffer {
|
|
||||||
// Check if adding this transaction will exceed the pool capacity
|
|
||||||
if uint64(pool.all.Slots()+numSlots(tx)) > pool.config.GlobalSlots+pool.config.GlobalQueue {
|
|
||||||
break // Stop if adding the transaction will exceed the pool capacity
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := pool.add(tx, false); err == nil {
|
|
||||||
readded = append(readded, tx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pool.bufferLock.Unlock()
|
|
||||||
|
|
||||||
// Remove successfully re-added transactions from the buffer
|
|
||||||
if len(readded) > 0 {
|
|
||||||
remaining := pool.buffer[:0]
|
|
||||||
for _, tx := range pool.buffer {
|
|
||||||
if !containsTransaction(readded, tx) {
|
|
||||||
remaining = append(remaining, tx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pool.buffer = remaining
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsTransaction(txs []*types.Transaction, tx *types.Transaction) bool {
|
|
||||||
for _, t := range txs {
|
|
||||||
if t.Hash() == tx.Hash() {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// addressByHeartbeat is an account address tagged with its last activity timestamp.
|
// addressByHeartbeat is an account address tagged with its last activity timestamp.
|
||||||
type addressByHeartbeat struct {
|
type addressByHeartbeat struct {
|
||||||
address common.Address
|
address common.Address
|
||||||
|
|||||||
@@ -193,5 +193,7 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ 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"
|
||||||
@@ -139,6 +141,15 @@ 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 {
|
||||||
|
|||||||
@@ -484,6 +484,10 @@ 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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -161,12 +161,18 @@ 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, "adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize))
|
log.Info("Capped dirty cache size", "provided", common.StorageSize(config.TrieDirtyCache)*1024*1024,
|
||||||
log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024)
|
"adjusted", common.StorageSize(pathdb.MaxDirtyBufferSize))
|
||||||
|
log.Info("Clean cache size", "provided", common.StorageSize(config.TrieCleanCache)*1024*1024,
|
||||||
|
"adjusted", common.StorageSize(config.TrieCleanCache+config.TrieDirtyCache-pathdb.MaxDirtyBufferSize/1024/1024)*1024*1024)
|
||||||
|
config.TrieCleanCache += config.TrieDirtyCache - pathdb.MaxDirtyBufferSize/1024/1024
|
||||||
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
|
config.TrieDirtyCache = pathdb.MaxDirtyBufferSize / 1024 / 1024
|
||||||
}
|
}
|
||||||
log.Info("Allocated trie memory caches", "clean", common.StorageSize(config.TrieCleanCache)*1024*1024, "dirty", common.StorageSize(config.TrieDirtyCache)*1024*1024)
|
log.Info("Allocated memory caches",
|
||||||
|
"state_scheme", config.StateScheme,
|
||||||
|
"trie_clean_cache", common.StorageSize(config.TrieCleanCache)*1024*1024,
|
||||||
|
"trie_dirty_cache", common.StorageSize(config.TrieDirtyCache)*1024*1024,
|
||||||
|
"snapshot_cache", common.StorageSize(config.SnapshotCache)*1024*1024)
|
||||||
// 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 {
|
||||||
@@ -179,14 +185,6 @@ 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
|
||||||
|
|||||||
@@ -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.Ancients() // Ignore the error here since light client can also hit here.
|
frozen, _ := d.stateDB.BlockStore().Ancients() // Ignore the error here since light client can also hit here.
|
||||||
itemAmountInAncient, _ := d.stateDB.ItemAmountInAncient()
|
itemAmountInAncient, _ := d.stateDB.BlockStore().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.AncientSize(rawdb.ChainFreezerHeaderTable)
|
headerBytes, _ = d.stateDB.BlockStore().AncientSize(rawdb.ChainFreezerHeaderTable)
|
||||||
bodyBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerBodiesTable)
|
bodyBytes, _ = d.stateDB.BlockStore().AncientSize(rawdb.ChainFreezerBodiesTable)
|
||||||
receiptBytes, _ = d.stateDB.AncientSize(rawdb.ChainFreezerReceiptTable)
|
receiptBytes, _ = d.stateDB.BlockStore().AncientSize(rawdb.ChainFreezerReceiptTable)
|
||||||
)
|
)
|
||||||
syncedBytes := common.StorageSize(headerBytes + bodyBytes + receiptBytes)
|
syncedBytes := common.StorageSize(headerBytes + bodyBytes + receiptBytes)
|
||||||
if syncedBytes == 0 {
|
if syncedBytes == 0 {
|
||||||
|
|||||||
@@ -188,12 +188,6 @@ 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"`
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ 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
|
||||||
@@ -130,8 +128,6 @@ 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
|
||||||
@@ -194,8 +190,6 @@ 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
|
||||||
@@ -363,12 +357,6 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -731,9 +731,6 @@ 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)
|
||||||
@@ -919,6 +916,10 @@ 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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
// insertChain injects a new headers into the simulated chain.
|
// insertHeaders 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()
|
||||||
|
|||||||
@@ -633,6 +633,9 @@ 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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -409,8 +409,8 @@ 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.KeyValueStore // Database to store the trie nodes into (and dedup)
|
db ethdb.Database // 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
|
||||||
tasks []*accountTask // Current account task set being synced
|
tasks []*accountTask // Current account task set 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.KeyValueStore, scheme string) *Syncer {
|
func NewSyncer(db ethdb.Database, 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, path) {
|
if owner == (common.Hash{}) && rawdb.ExistsAccountTrieNode(s.db.StateStoreReader(), path) {
|
||||||
rawdb.DeleteAccountTrieNode(batch, path)
|
rawdb.DeleteAccountTrieNode(batch, path)
|
||||||
deletionGauge.Inc(1)
|
deletionGauge.Inc(1)
|
||||||
}
|
}
|
||||||
if owner != (common.Hash{}) && rawdb.ExistsStorageTrieNode(s.db, owner, path) {
|
if owner != (common.Hash{}) && rawdb.ExistsStorageTrieNode(s.db.StateStoreReader(), owner, path) {
|
||||||
rawdb.DeleteStorageTrieNode(batch, owner, path)
|
rawdb.DeleteStorageTrieNode(batch, owner, path)
|
||||||
deletionGauge.Inc(1)
|
deletionGauge.Inc(1)
|
||||||
}
|
}
|
||||||
@@ -735,6 +735,7 @@ 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)
|
||||||
@@ -747,7 +748,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: s.db.NewBatch(),
|
Batch: stateDiskDB.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))
|
||||||
},
|
},
|
||||||
@@ -773,7 +774,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: s.db.NewBatch(),
|
Batch: stateDiskDB.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))
|
||||||
},
|
},
|
||||||
@@ -841,7 +842,7 @@ func (s *Syncer) loadSyncStatus() {
|
|||||||
last = common.MaxHash
|
last = common.MaxHash
|
||||||
}
|
}
|
||||||
batch := ethdb.HookedBatch{
|
batch := ethdb.HookedBatch{
|
||||||
Batch: s.db.NewBatch(),
|
Batch: stateDiskDB.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))
|
||||||
},
|
},
|
||||||
@@ -1894,7 +1895,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, res.hashes[i], nil, account.Root, s.scheme) {
|
if !rawdb.HasTrieNode(s.db.StateStoreReader(), 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
|
||||||
@@ -1986,12 +1987,25 @@ 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.NewBatch(),
|
Batch: s.db.GetStateStore().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 snapBatch ethdb.HookedBatch
|
||||||
|
if s.db.StateStore() != nil {
|
||||||
|
usingMultDatabase = true
|
||||||
|
snapBatch = ethdb.HookedBatch{
|
||||||
|
Batch: s.db.NewBatch(),
|
||||||
|
OnPut: func(key []byte, value []byte) {
|
||||||
|
s.storageBytes += common.StorageSize(len(key) + len(value))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
slots int
|
slots int
|
||||||
oldStorageBytes = s.storageBytes
|
oldStorageBytes = s.storageBytes
|
||||||
@@ -2061,7 +2075,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.NewBatch(),
|
Batch: s.db.GetStateStore().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))
|
||||||
},
|
},
|
||||||
@@ -2088,7 +2102,7 @@ func (s *Syncer) processStorageResponse(res *storageResponse) {
|
|||||||
})
|
})
|
||||||
for r.Next() {
|
for r.Next() {
|
||||||
batch := ethdb.HookedBatch{
|
batch := ethdb.HookedBatch{
|
||||||
Batch: s.db.NewBatch(),
|
Batch: s.db.GetStateStore().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))
|
||||||
},
|
},
|
||||||
@@ -2184,8 +2198,11 @@ 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++ {
|
||||||
rawdb.WriteStorageSnapshot(batch, account, res.hashes[i][j], res.slots[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])
|
||||||
|
}
|
||||||
// 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 {
|
||||||
@@ -2205,7 +2222,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, accountHash, nil, root) {
|
if root == res.subTask.root && rawdb.HasStorageTrieNode(s.db.StateStoreReader(), 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
|
||||||
@@ -2225,6 +2242,11 @@ 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)
|
||||||
@@ -2323,12 +2345,25 @@ func (s *Syncer) commitHealer(force bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
batch := s.db.NewBatch()
|
batch := s.db.NewBatch()
|
||||||
if err := s.healer.scheduler.Commit(batch); err != nil {
|
var stateBatch ethdb.Batch
|
||||||
|
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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,14 @@ func testChainSyncWithBlobs(t *testing.T, mode downloader.SyncMode, preCancunBlk
|
|||||||
cancunTime := (preCancunBlks + 1) * 10
|
cancunTime := (preCancunBlks + 1) * 10
|
||||||
config.CancunTime = &cancunTime
|
config.CancunTime = &cancunTime
|
||||||
|
|
||||||
// Create a full handler and ensure snap sync ends up disabled
|
// Create an empty handler
|
||||||
|
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() {
|
||||||
@@ -122,13 +129,6 @@ 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,14 +165,17 @@ 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)
|
||||||
})
|
})
|
||||||
// Wait a bit for the above handlers to start
|
|
||||||
time.Sleep(250 * time.Millisecond)
|
|
||||||
|
|
||||||
// Check that snap sync was disabled
|
for empty.handler.peers.snapLen() < 1 {
|
||||||
|
// Wait a bit for the above handlers to start
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
}
|
||||||
|
|
||||||
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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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(), true)
|
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String())
|
||||||
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_getBlockSidecarByTxHash", hash, true)
|
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecarByTxHash", hash)
|
||||||
if err == nil && r == nil {
|
if err == nil && r == nil {
|
||||||
return nil, ethereum.NotFound
|
return nil, ethereum.NotFound
|
||||||
}
|
}
|
||||||
@@ -752,6 +752,13 @@ 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
|
||||||
|
|||||||
@@ -180,12 +180,6 @@ 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
|
||||||
}
|
}
|
||||||
@@ -194,6 +188,14 @@ 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 {
|
||||||
@@ -234,6 +236,13 @@ 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
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ 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
|
||||||
@@ -47,6 +50,84 @@ 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
|
||||||
@@ -204,6 +285,37 @@ 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 {
|
||||||
|
|||||||
@@ -122,6 +122,10 @@ 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
29
go.mod
@@ -2,8 +2,6 @@ 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
|
||||||
@@ -17,8 +15,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/cometbft/cometbft v0.37.0
|
|
||||||
github.com/cockroachdb/pebble v1.1.0
|
github.com/cockroachdb/pebble v1.1.0
|
||||||
|
github.com/cometbft/cometbft v0.37.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
|
||||||
@@ -26,7 +24,7 @@ require (
|
|||||||
github.com/deckarep/golang-set/v2 v2.5.0
|
github.com/deckarep/golang-set/v2 v2.5.0
|
||||||
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
|
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
|
||||||
github.com/ethereum/c-kzg-4844 v0.4.0
|
github.com/ethereum/c-kzg-4844 v0.4.0
|
||||||
github.com/fatih/color v1.13.0
|
github.com/fatih/color v1.16.0
|
||||||
github.com/fatih/structs v1.1.0
|
github.com/fatih/structs v1.1.0
|
||||||
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
|
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
|
||||||
github.com/fjl/memsize v0.0.2
|
github.com/fjl/memsize v0.0.2
|
||||||
@@ -39,7 +37,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.4.0
|
github.com/google/uuid v1.5.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
|
||||||
@@ -84,7 +82,7 @@ require (
|
|||||||
golang.org/x/crypto v0.21.0
|
golang.org/x/crypto v0.21.0
|
||||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
|
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
|
||||||
golang.org/x/sync v0.6.0
|
golang.org/x/sync v0.6.0
|
||||||
golang.org/x/sys v0.18.0
|
golang.org/x/sys v0.20.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.14.0
|
||||||
golang.org/x/time v0.5.0
|
golang.org/x/time v0.5.0
|
||||||
golang.org/x/tools v0.18.0
|
golang.org/x/tools v0.18.0
|
||||||
@@ -98,6 +96,7 @@ 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
|
||||||
@@ -160,7 +159,7 @@ require (
|
|||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
|
||||||
github.com/gtank/merlin v0.1.1 // indirect
|
github.com/gtank/merlin v0.1.1 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
|
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
|
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
|
||||||
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect
|
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect
|
||||||
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect
|
||||||
@@ -233,12 +232,10 @@ 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
|
||||||
@@ -249,9 +246,10 @@ 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.0 // indirect
|
github.com/sirupsen/logrus v1.9.3 // 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
|
||||||
@@ -266,7 +264,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.7 // indirect
|
go.etcd.io/bbolt v1.3.9 // 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
|
||||||
@@ -279,8 +277,10 @@ 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-20230410155749-daa745c078e1 // indirect
|
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||||
google.golang.org/grpc v1.56.3 // indirect
|
google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a // 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,8 +295,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
github.com/btcsuite/btcd => github.com/btcsuite/btcd v0.23.0
|
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v1.3.1
|
||||||
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
|
||||||
|
|||||||
@@ -87,6 +87,10 @@ 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()
|
||||||
|
|||||||
@@ -650,7 +650,8 @@ func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.Match
|
|||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
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{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,8 @@ 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.
|
||||||
|
|||||||
@@ -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().Ancient(kind, number)
|
return api.b.ChainDb().BlockStore().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().Ancients()
|
return api.b.ChainDb().BlockStore().Ancients()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,8 @@ 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)
|
||||||
@@ -217,7 +218,8 @@ 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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},
|
||||||
nil,
|
&TransactionArgs{GasPrice: zero},
|
||||||
errors.New("gasPrice must be non-zero after london fork"),
|
nil, // 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},
|
||||||
nil,
|
&TransactionArgs{MaxFeePerGas: zero, MaxPriorityFeePerGas: zero},
|
||||||
errors.New("maxFeePerGas must be non-zero"),
|
nil, // errors.New("maxFeePerGas must be non-zero"),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
@@ -416,7 +416,8 @@ 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{}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -29,11 +30,6 @@ import (
|
|||||||
const (
|
const (
|
||||||
// maxBidPerBuilderPerBlock is the max bid number per builder
|
// maxBidPerBuilderPerBlock is the max bid number per builder
|
||||||
maxBidPerBuilderPerBlock = 3
|
maxBidPerBuilderPerBlock = 3
|
||||||
|
|
||||||
// leftOverTimeRate is the rate of left over time to simulate a bid
|
|
||||||
leftOverTimeRate = 11
|
|
||||||
// leftOverTimeScale is the scale of left over time to simulate a bid
|
|
||||||
leftOverTimeScale = 10
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -73,6 +69,12 @@ 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 {
|
||||||
@@ -100,7 +102,7 @@ type bidSimulator struct {
|
|||||||
|
|
||||||
// channels
|
// channels
|
||||||
simBidCh chan *simBidReq
|
simBidCh chan *simBidReq
|
||||||
newBidCh chan *types.Bid
|
newBidCh chan newBidPackage
|
||||||
|
|
||||||
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{}
|
||||||
@@ -133,7 +135,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 *types.Bid, 100),
|
newBidCh: make(chan newBidPackage, 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),
|
||||||
@@ -318,18 +320,6 @@ 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
|
||||||
@@ -344,6 +334,10 @@ 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:
|
||||||
@@ -351,70 +345,53 @@ func (b *bidSimulator) newBidLoop() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// check the block reward and validator reward of the newBid
|
bidRuntime, err := newBidRuntime(newBid.bid, b.config.ValidatorCommission)
|
||||||
expectedBlockReward := newBid.GasFee
|
if err != nil {
|
||||||
expectedValidatorReward := new(big.Int).Mul(expectedBlockReward, big.NewInt(int64(b.config.ValidatorCommission)))
|
if newBid.feedback != nil {
|
||||||
expectedValidatorReward.Div(expectedValidatorReward, big.NewInt(10000))
|
newBid.feedback <- err
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
bidRuntime := &BidRuntime{
|
|
||||||
bid: newBid,
|
|
||||||
expectedBlockReward: expectedBlockReward,
|
|
||||||
expectedValidatorReward: expectedValidatorReward,
|
|
||||||
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)
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// if bestBid is not nil, check if newBid is better than bestBid
|
var replyErr error
|
||||||
if bidRuntime.expectedBlockReward.Cmp(bestBid.expectedBlockReward) >= 0 &&
|
// simulatingBid will be nil if there is no bid in simulation, compare with the bestBid instead
|
||||||
bidRuntime.expectedValidatorReward.Cmp(bestBid.expectedValidatorReward) >= 0 {
|
if simulatingBid := b.GetSimulatingBid(newBid.bid.ParentHash); simulatingBid != nil {
|
||||||
// if both reward are better than last simulating newBid, commit for simulation
|
// simulatingBid always better than bestBid, so only compare with simulatingBid if a simulatingBid exists
|
||||||
|
if bidRuntime.isExpectedBetterThan(simulatingBid) {
|
||||||
commit(commitInterruptBetterBid, bidRuntime)
|
commit(commitInterruptBetterBid, bidRuntime)
|
||||||
continue
|
} else {
|
||||||
|
replyErr = genDiscardedReply(simulatingBid)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// bestBid is nil means the bid is the first bid, otherwise the bid should compare with the bestBid
|
||||||
|
if bestBid := b.GetBestBid(newBid.bid.ParentHash); bestBid == nil ||
|
||||||
|
bidRuntime.isExpectedBetterThan(bestBid) {
|
||||||
|
commit(commitInterruptBetterBid, bidRuntime)
|
||||||
|
} else {
|
||||||
|
replyErr = genDiscardedReply(bestBid)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("BidSimulator: lower reward, ignore",
|
|
||||||
"builder", bidRuntime.bid.Builder, "bidHash", newBid.Hash().Hex())
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulatingBid must be better than bestBid, if newBid is better than simulatingBid, commit for simulation
|
if newBid.feedback != nil {
|
||||||
if bidRuntime.expectedBlockReward.Cmp(simulatingBid.expectedBlockReward) >= 0 &&
|
newBid.feedback <- replyErr
|
||||||
bidRuntime.expectedValidatorReward.Cmp(simulatingBid.expectedValidatorReward) >= 0 {
|
|
||||||
// if both reward are better than last simulating newBid, commit for simulation
|
log.Info("[BID ARRIVED]",
|
||||||
commit(commitInterruptBetterBid, bidRuntime)
|
"block", newBid.bid.BlockNumber,
|
||||||
continue
|
"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(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -440,10 +417,6 @@ 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()
|
||||||
@@ -467,10 +440,19 @@ 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 <- bid:
|
case b.newBidCh <- newBidPackage{bid: bid, feedback: replyCh}:
|
||||||
b.AddPending(bid.BlockNumber, bid.Builder, bid.Hash())
|
b.AddPending(bid.BlockNumber, bid.Builder, bid.Hash())
|
||||||
return nil
|
case <-timer.C:
|
||||||
|
return types.ErrMevBusy
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case reply := <-replyCh:
|
||||||
|
return reply
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
return types.ErrMevBusy
|
return types.ErrMevBusy
|
||||||
}
|
}
|
||||||
@@ -516,6 +498,8 @@ 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
|
||||||
@@ -530,7 +514,6 @@ 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{
|
||||||
@@ -556,10 +539,11 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.RemoveSimulatingBid(parentHash)
|
b.RemoveSimulatingBid(parentHash)
|
||||||
bidSimTimer.UpdateSince(start)
|
close(bidRuntime.finished)
|
||||||
|
|
||||||
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 {
|
||||||
@@ -567,12 +551,12 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case b.newBidCh <- bidRuntime.bid:
|
case b.newBidCh <- newBidPackage{bid: 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:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}(time.Now())
|
}(startTS)
|
||||||
|
|
||||||
// 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
|
||||||
@@ -583,6 +567,14 @@ 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)
|
||||||
@@ -650,14 +642,12 @@ 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 {
|
||||||
stopTimer := time.NewTimer(*delay)
|
bidTxsSet := mapset.NewThreadUnsafeSetWithSize[common.Hash](len(bidRuntime.bid.Txs))
|
||||||
|
|
||||||
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, stopTimer, bidTxsSet)
|
fillErr := b.bidWorker.fillTransactions(interruptCh, bidRuntime.env, nil, 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)
|
||||||
|
|
||||||
@@ -677,13 +667,30 @@ 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)
|
||||||
@@ -697,7 +704,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case b.newBidCh <- bestBid.bid:
|
case b.newBidCh <- newBidPackage{bid: 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:
|
||||||
}
|
}
|
||||||
@@ -717,7 +724,7 @@ func (b *bidSimulator) reportIssue(bidRuntime *BidRuntime, err error) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("BidSimulator: failed to report issue", "builder", bidRuntime.bid.Builder, "err", err)
|
log.Warn("BidSimulator: failed to report issue", "builder", bidRuntime.bid.Builder, "err", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -733,14 +740,46 @@ 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()
|
||||||
@@ -796,3 +835,8 @@ 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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ 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 {
|
||||||
@@ -59,6 +60,11 @@ 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 {
|
||||||
@@ -117,6 +123,8 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,9 @@ 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 (
|
||||||
@@ -171,6 +174,7 @@ 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
|
||||||
@@ -1336,6 +1340,15 @@ 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 {
|
||||||
@@ -1358,7 +1371,13 @@ LOOP:
|
|||||||
bestWork = bestBid.env
|
bestWork = bestBid.env
|
||||||
from = bestBid.bid.Builder
|
from = bestBid.bid.Builder
|
||||||
|
|
||||||
log.Debug("BidSimulator: bid win", "block", bestWork.header.Number.Uint64(), "bid", bestBid.bid.Hash())
|
log.Info("[BUILDER BLOCK]",
|
||||||
|
"block", bestWork.header.Number.Uint64(),
|
||||||
|
"builder", from,
|
||||||
|
"blockReward", weiToEtherStringF6(bestBid.packedBlockReward),
|
||||||
|
"validatorReward", weiToEtherStringF6(bestBid.packedValidatorReward),
|
||||||
|
"bid", bestBid.bid.Hash().TerminalString(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
46
node/node.go
46
node/node.go
@@ -74,11 +74,11 @@ const (
|
|||||||
initializingState = iota
|
initializingState = iota
|
||||||
runningState
|
runningState
|
||||||
closedState
|
closedState
|
||||||
blockDbCacheSize = 256
|
blockDbCacheSize = 256
|
||||||
blockDbHandlesMinSize = 1000
|
blockDbHandlesMinSize = 1000
|
||||||
blockDbHandlesMaxSize = 2000
|
blockDbHandlesMaxSize = 2000
|
||||||
chainDbMemoryPercentage = 50
|
chainDbMemoryPercentage = 50
|
||||||
chainDbHandlesPercentage
|
chainDbHandlesPercentage = 50
|
||||||
diffStoreHandlesPercentage = 20
|
diffStoreHandlesPercentage = 20
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -791,14 +791,15 @@ func (n *Node) OpenDatabase(name string, cache, handles int, namespace string, r
|
|||||||
|
|
||||||
func (n *Node) OpenAndMergeDatabase(name string, namespace string, readonly bool, config *ethconfig.Config) (ethdb.Database, error) {
|
func (n *Node) OpenAndMergeDatabase(name string, namespace string, readonly bool, config *ethconfig.Config) (ethdb.Database, error) {
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
stateDiskDb ethdb.Database
|
stateDiskDb ethdb.Database
|
||||||
blockDb ethdb.Database
|
blockDb ethdb.Database
|
||||||
disableChainDbFreeze = false
|
disableChainDbFreeze = false
|
||||||
blockDbHandlesSize int
|
blockDbHandlesSize int
|
||||||
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 {
|
||||||
@@ -818,10 +819,17 @@ 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 {
|
||||||
@@ -833,14 +841,6 @@ 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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,6 +153,7 @@ 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{
|
||||||
@@ -193,6 +194,7 @@ 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{
|
||||||
@@ -234,6 +236,7 @@ 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{
|
||||||
@@ -512,6 +515,7 @@ 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)
|
||||||
@@ -623,12 +627,17 @@ 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, 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, HaberFixTime: %v, BohrTime: %v, Engine: %v}",
|
||||||
c.ChainID,
|
c.ChainID,
|
||||||
c.HomesteadBlock,
|
c.HomesteadBlock,
|
||||||
c.DAOForkBlock,
|
c.DAOForkBlock,
|
||||||
@@ -666,6 +675,7 @@ func (c *ChainConfig) String() string {
|
|||||||
FeynmanFixTime,
|
FeynmanFixTime,
|
||||||
CancunTime,
|
CancunTime,
|
||||||
HaberTime,
|
HaberTime,
|
||||||
|
HaberFixTime,
|
||||||
BohrTime,
|
BohrTime,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
@@ -939,6 +949,20 @@ 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)
|
||||||
@@ -1017,6 +1041,7 @@ 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},
|
||||||
@@ -1165,6 +1190,15 @@ 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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 = 8 // Patch version component of the current release
|
VersionPatch = 12 // 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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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 upack the call data accordingly
|
// Validate the called method and unpack 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)
|
||||||
|
|||||||
@@ -17,13 +17,48 @@
|
|||||||
package trie
|
package trie
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
"github.com/ethereum/go-ethereum/triedb/database"
|
"github.com/ethereum/go-ethereum/triedb/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
StateTreeOpenQPS = metrics.NewRegisteredMeter("state/tree/open/qps", nil)
|
||||||
|
StateTreeOpenTime = metrics.NewRegisteredTimer("state/tree/open/time", nil)
|
||||||
|
|
||||||
|
StateTreeGetQPS = metrics.NewRegisteredMeter("state/tree/get/qps", nil)
|
||||||
|
StateTreeGetTime = metrics.NewRegisteredTimer("state/tree/get/time", nil)
|
||||||
|
StateAccountTreeGetQPS = metrics.NewRegisteredMeter("state/tree/account/get/qps", nil)
|
||||||
|
StateAccountTreeGetTime = metrics.NewRegisteredTimer("state/tree/account/get/time", nil)
|
||||||
|
StateStorageTreeGetQPS = metrics.NewRegisteredMeter("state/tree/storage/get/qps", nil)
|
||||||
|
StateStorageTreeGetTime = metrics.NewRegisteredTimer("state/tree/storage/get/time", nil)
|
||||||
|
|
||||||
|
StateTreePutQPS = metrics.NewRegisteredMeter("state/tree/put/qps", nil)
|
||||||
|
StateTreePutTime = metrics.NewRegisteredTimer("state/tree/put/time", nil)
|
||||||
|
StateAccountTreePutQPS = metrics.NewRegisteredMeter("state/tree/account/put/qps", nil)
|
||||||
|
StateAccountTreePutTime = metrics.NewRegisteredTimer("state/tree/account/put/time", nil)
|
||||||
|
StateStorageTreePutQPS = metrics.NewRegisteredMeter("state/tree/storage/put/qps", nil)
|
||||||
|
StateStorageTreePutTime = metrics.NewRegisteredTimer("state/tree/storage/put/time", nil)
|
||||||
|
|
||||||
|
StateTreeDelQPS = metrics.NewRegisteredMeter("state/tree/del/qps", nil)
|
||||||
|
StateTreeDelTime = metrics.NewRegisteredTimer("state/tree/del/time", nil)
|
||||||
|
StateAccountTreeDelQPS = metrics.NewRegisteredMeter("state/tree/account/del/qps", nil)
|
||||||
|
StateAccountTreeDelTime = metrics.NewRegisteredTimer("state/tree/account/del/time", nil)
|
||||||
|
StateStorageTreeDelQPS = metrics.NewRegisteredMeter("state/tree/storage/del/qps", nil)
|
||||||
|
StateStorageTreeDelTime = metrics.NewRegisteredTimer("state/tree/storage/del/time", nil)
|
||||||
|
|
||||||
|
StateTreeCommitQPS = metrics.NewRegisteredMeter("state/tree/commit/qps", nil)
|
||||||
|
StateTreeCommitTime = metrics.NewRegisteredTimer("state/tree/commit/time", nil)
|
||||||
|
|
||||||
|
StateTreeCalcQPS = metrics.NewRegisteredMeter("state/tree/calc/qps", nil)
|
||||||
|
StateTreeCalcTime = metrics.NewRegisteredTimer("state/tree/calc/time", nil)
|
||||||
|
)
|
||||||
|
|
||||||
// SecureTrie is the old name of StateTrie.
|
// SecureTrie is the old name of StateTrie.
|
||||||
// Deprecated: use StateTrie.
|
// Deprecated: use StateTrie.
|
||||||
type SecureTrie = StateTrie
|
type SecureTrie = StateTrie
|
||||||
@@ -63,6 +98,11 @@ type StateTrie struct {
|
|||||||
// trie is initially empty. Otherwise, New will panic if db is nil
|
// trie is initially empty. Otherwise, New will panic if db is nil
|
||||||
// and returns MissingNodeError if the root node cannot be found.
|
// and returns MissingNodeError if the root node cannot be found.
|
||||||
func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) {
|
func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreeOpenQPS.Mark(1)
|
||||||
|
StateTreeOpenTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
|
|
||||||
if db == nil {
|
if db == nil {
|
||||||
panic("trie.NewStateTrie called without a database")
|
panic("trie.NewStateTrie called without a database")
|
||||||
}
|
}
|
||||||
@@ -87,6 +127,12 @@ func (t *StateTrie) MustGet(key []byte) []byte {
|
|||||||
// If the specified storage slot is not in the trie, nil will be returned.
|
// If the specified storage slot is not in the trie, nil will be returned.
|
||||||
// If a trie node is not found in the database, a MissingNodeError is returned.
|
// If a trie node is not found in the database, a MissingNodeError is returned.
|
||||||
func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
|
func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreeGetQPS.Mark(1)
|
||||||
|
StateTreeGetTime.UpdateSince(start)
|
||||||
|
StateStorageTreeGetQPS.Mark(1)
|
||||||
|
StateStorageTreeGetTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
enc, err := t.trie.Get(t.hashKey(key))
|
enc, err := t.trie.Get(t.hashKey(key))
|
||||||
if err != nil || len(enc) == 0 {
|
if err != nil || len(enc) == 0 {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -99,6 +145,12 @@ func (t *StateTrie) GetStorage(_ common.Address, key []byte) ([]byte, error) {
|
|||||||
// If the specified account is not in the trie, nil will be returned.
|
// If the specified account is not in the trie, nil will be returned.
|
||||||
// If a trie node is not found in the database, a MissingNodeError is returned.
|
// If a trie node is not found in the database, a MissingNodeError is returned.
|
||||||
func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
|
func (t *StateTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreeGetQPS.Mark(1)
|
||||||
|
StateTreeGetTime.UpdateSince(start)
|
||||||
|
StateAccountTreeGetQPS.Mark(1)
|
||||||
|
StateAccountTreeGetTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
res, err := t.trie.Get(t.hashKey(address.Bytes()))
|
res, err := t.trie.Get(t.hashKey(address.Bytes()))
|
||||||
if res == nil || err != nil {
|
if res == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -153,6 +205,12 @@ func (t *StateTrie) MustUpdate(key, value []byte) {
|
|||||||
//
|
//
|
||||||
// If a node is not found in the database, a MissingNodeError is returned.
|
// If a node is not found in the database, a MissingNodeError is returned.
|
||||||
func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
|
func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreePutQPS.Mark(1)
|
||||||
|
StateTreePutTime.UpdateSince(start)
|
||||||
|
StateStorageTreePutQPS.Mark(1)
|
||||||
|
StateStorageTreePutTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
hk := t.hashKey(key)
|
hk := t.hashKey(key)
|
||||||
v, _ := rlp.EncodeToBytes(value)
|
v, _ := rlp.EncodeToBytes(value)
|
||||||
err := t.trie.Update(hk, v)
|
err := t.trie.Update(hk, v)
|
||||||
@@ -165,6 +223,12 @@ func (t *StateTrie) UpdateStorage(_ common.Address, key, value []byte) error {
|
|||||||
|
|
||||||
// UpdateAccount will abstract the write of an account to the secure trie.
|
// UpdateAccount will abstract the write of an account to the secure trie.
|
||||||
func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error {
|
func (t *StateTrie) UpdateAccount(address common.Address, acc *types.StateAccount) error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreePutQPS.Mark(1)
|
||||||
|
StateTreePutTime.UpdateSince(start)
|
||||||
|
StateAccountTreePutQPS.Mark(1)
|
||||||
|
StateAccountTreePutTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
hk := t.hashKey(address.Bytes())
|
hk := t.hashKey(address.Bytes())
|
||||||
data, err := rlp.EncodeToBytes(acc)
|
data, err := rlp.EncodeToBytes(acc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -193,6 +257,12 @@ func (t *StateTrie) MustDelete(key []byte) {
|
|||||||
// If the specified trie node is not in the trie, nothing will be changed.
|
// If the specified trie node is not in the trie, nothing will be changed.
|
||||||
// If a node is not found in the database, a MissingNodeError is returned.
|
// If a node is not found in the database, a MissingNodeError is returned.
|
||||||
func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
|
func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreeDelQPS.Mark(1)
|
||||||
|
StateTreeDelTime.UpdateSince(start)
|
||||||
|
StateStorageTreeDelQPS.Mark(1)
|
||||||
|
StateStorageTreeDelTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
hk := t.hashKey(key)
|
hk := t.hashKey(key)
|
||||||
delete(t.getSecKeyCache(), string(hk))
|
delete(t.getSecKeyCache(), string(hk))
|
||||||
return t.trie.Delete(hk)
|
return t.trie.Delete(hk)
|
||||||
@@ -200,6 +270,12 @@ func (t *StateTrie) DeleteStorage(_ common.Address, key []byte) error {
|
|||||||
|
|
||||||
// DeleteAccount abstracts an account deletion from the trie.
|
// DeleteAccount abstracts an account deletion from the trie.
|
||||||
func (t *StateTrie) DeleteAccount(address common.Address) error {
|
func (t *StateTrie) DeleteAccount(address common.Address) error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreeDelQPS.Mark(1)
|
||||||
|
StateTreeDelTime.UpdateSince(start)
|
||||||
|
StateAccountTreeDelQPS.Mark(1)
|
||||||
|
StateAccountTreeDelTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
hk := t.hashKey(address.Bytes())
|
hk := t.hashKey(address.Bytes())
|
||||||
delete(t.getSecKeyCache(), string(hk))
|
delete(t.getSecKeyCache(), string(hk))
|
||||||
return t.trie.Delete(hk)
|
return t.trie.Delete(hk)
|
||||||
@@ -222,6 +298,10 @@ func (t *StateTrie) GetKey(shaKey []byte) []byte {
|
|||||||
// Once the trie is committed, it's not usable anymore. A new trie must
|
// Once the trie is committed, it's not usable anymore. A new trie must
|
||||||
// be created with new root and updated trie database for following usage
|
// be created with new root and updated trie database for following usage
|
||||||
func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
|
func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreeCommitQPS.Mark(1)
|
||||||
|
StateTreeCommitTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
// Write all the pre-images to the actual disk database
|
// Write all the pre-images to the actual disk database
|
||||||
if len(t.getSecKeyCache()) > 0 {
|
if len(t.getSecKeyCache()) > 0 {
|
||||||
preimages := make(map[common.Hash][]byte)
|
preimages := make(map[common.Hash][]byte)
|
||||||
@@ -238,6 +318,10 @@ func (t *StateTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, er
|
|||||||
// Hash returns the root hash of StateTrie. It does not write to the
|
// Hash returns the root hash of StateTrie. It does not write to the
|
||||||
// database and can be used even if the trie doesn't have one.
|
// database and can be used even if the trie doesn't have one.
|
||||||
func (t *StateTrie) Hash() common.Hash {
|
func (t *StateTrie) Hash() common.Hash {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
StateTreeCalcQPS.Mark(1)
|
||||||
|
StateTreeCalcTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
return t.trie.Hash()
|
return t.trie.Hash()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
34
trie/sync.go
34
trie/sync.go
@@ -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.KeyValueReader // Persistent database to check for existing entries
|
database ethdb.Database // 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.KeyValueReader, callback LeafCallback, scheme string) *Sync {
|
func NewSync(root common.Hash, database ethdb.Database, 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) error {
|
func (s *Sync) Commit(dbw ethdb.Batch, stateBatch 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,9 +430,17 @@ func (s *Sync) Commit(dbw 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{}) {
|
||||||
rawdb.DeleteAccountTrieNode(dbw, op.path)
|
if stateBatch != nil {
|
||||||
|
rawdb.DeleteAccountTrieNode(stateBatch, op.path)
|
||||||
|
} else {
|
||||||
|
rawdb.DeleteAccountTrieNode(dbw, op.path)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rawdb.DeleteStorageTrieNode(dbw, op.owner, op.path)
|
if stateBatch != nil {
|
||||||
|
rawdb.DeleteStorageTrieNode(stateBatch, op.owner, op.path)
|
||||||
|
} else {
|
||||||
|
rawdb.DeleteStorageTrieNode(dbw, op.owner, op.path)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
deletionGauge.Inc(1)
|
deletionGauge.Inc(1)
|
||||||
} else {
|
} else {
|
||||||
@@ -441,7 +449,11 @@ func (s *Sync) Commit(dbw ethdb.Batch) error {
|
|||||||
} else {
|
} else {
|
||||||
storage += 1
|
storage += 1
|
||||||
}
|
}
|
||||||
rawdb.WriteTrieNode(dbw, op.owner, op.path, op.hash, op.blob, s.scheme)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
accountNodeSyncedGauge.Inc(int64(account))
|
accountNodeSyncedGauge.Inc(int64(account))
|
||||||
@@ -546,9 +558,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, append(inner, key[:i]...))
|
exists = rawdb.ExistsAccountTrieNode(s.database.StateStoreReader(), append(inner, key[:i]...))
|
||||||
} else {
|
} else {
|
||||||
exists = rawdb.ExistsStorageTrieNode(s.database, owner, append(inner, key[:i]...))
|
exists = rawdb.ExistsStorageTrieNode(s.database.StateStoreReader(), 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]...))
|
||||||
@@ -687,15 +699,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, hash), false
|
return rawdb.HasLegacyTrieNode(s.database.StateStoreReader(), 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, path)
|
blob, dbHash = rawdb.ReadAccountTrieNode(s.database.StateStoreReader(), path)
|
||||||
} else {
|
} else {
|
||||||
blob, dbHash = rawdb.ReadStorageTrieNode(s.database, owner, path)
|
blob, dbHash = rawdb.ReadStorageTrieNode(s.database.StateStoreReader(), owner, path)
|
||||||
}
|
}
|
||||||
exists = hash == dbHash
|
exists = hash == dbHash
|
||||||
inconsistent = !exists && len(blob) != 0
|
inconsistent = !exists && len(blob) != 0
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ 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"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -143,7 +142,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(), memorydb.New(), nil, []*testDb{dbA, dbB, dbC, dbD}[i].Scheme())
|
sync := NewSync(trie.Hash(), rawdb.NewMemoryDatabase(), 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)
|
||||||
}
|
}
|
||||||
@@ -212,7 +211,7 @@ func testIterativeSync(t *testing.T, count int, bypath bool, scheme string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := diskdb.NewBatch()
|
batch := diskdb.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
@@ -278,7 +277,7 @@ func testIterativeDelayedSync(t *testing.T, scheme string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := diskdb.NewBatch()
|
batch := diskdb.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
@@ -348,7 +347,7 @@ func testIterativeRandomSync(t *testing.T, count int, scheme string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := diskdb.NewBatch()
|
batch := diskdb.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
@@ -419,7 +418,7 @@ func testIterativeRandomDelayedSync(t *testing.T, scheme string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := diskdb.NewBatch()
|
batch := diskdb.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
@@ -491,7 +490,7 @@ func testDuplicateAvoidanceSync(t *testing.T, scheme string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := diskdb.NewBatch()
|
batch := diskdb.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
@@ -563,7 +562,7 @@ func testIncompleteSync(t *testing.T, scheme string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := diskdb.NewBatch()
|
batch := diskdb.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
@@ -653,7 +652,7 @@ func testSyncOrdering(t *testing.T, scheme string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := diskdb.NewBatch()
|
batch := diskdb.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
batch.Write()
|
batch.Write()
|
||||||
@@ -723,7 +722,7 @@ func syncWithHookWriter(t *testing.T, root common.Hash, db ethdb.Database, srcDb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
batch := db.NewBatch()
|
batch := db.NewBatch()
|
||||||
if err := sched.Commit(batch); err != nil {
|
if err := sched.Commit(batch, nil); err != nil {
|
||||||
t.Fatalf("failed to commit data: %v", err)
|
t.Fatalf("failed to commit data: %v", err)
|
||||||
}
|
}
|
||||||
if hookWriter != nil {
|
if hookWriter != nil {
|
||||||
|
|||||||
@@ -246,6 +246,10 @@ func (db *Database) Reader(root common.Hash) (layer, error) {
|
|||||||
// The passed in maps(nodes, states) will be retained to avoid copying everything.
|
// The passed in maps(nodes, states) will be retained to avoid copying everything.
|
||||||
// Therefore, these maps must not be changed afterwards.
|
// Therefore, these maps must not be changed afterwards.
|
||||||
func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
|
func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
|
||||||
|
defer func(start time.Time) {
|
||||||
|
PbssUpdateDiffQPS.Mark(1)
|
||||||
|
PbssUpdateDiffTime.UpdateSince(start)
|
||||||
|
}(time.Now())
|
||||||
// Hold the lock to prevent concurrent mutations.
|
// Hold the lock to prevent concurrent mutations.
|
||||||
db.lock.Lock()
|
db.lock.Lock()
|
||||||
defer db.lock.Unlock()
|
defer db.lock.Unlock()
|
||||||
|
|||||||
@@ -26,6 +26,106 @@ 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.
|
||||||
//
|
//
|
||||||
@@ -39,7 +139,10 @@ 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
|
||||||
}
|
}
|
||||||
@@ -58,6 +161,20 @@ 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))
|
||||||
@@ -75,6 +192,12 @@ 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 {
|
||||||
@@ -133,6 +256,32 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/VictoriaMetrics/fastcache"
|
"github.com/VictoriaMetrics/fastcache"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@@ -197,11 +198,15 @@ func (dl *diskLayer) Node(owner common.Hash, path []byte, hash common.Hash) ([]b
|
|||||||
nBlob []byte
|
nBlob []byte
|
||||||
nHash common.Hash
|
nHash common.Hash
|
||||||
)
|
)
|
||||||
|
// TODO:
|
||||||
|
trieNodeQPS.Mark(1)
|
||||||
|
startLoadTrieNode := time.Now()
|
||||||
if owner == (common.Hash{}) {
|
if owner == (common.Hash{}) {
|
||||||
nBlob, nHash = rawdb.ReadAccountTrieNode(dl.db.diskdb, path)
|
nBlob, nHash = rawdb.ReadAccountTrieNode(dl.db.diskdb, path)
|
||||||
} else {
|
} else {
|
||||||
nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path)
|
nBlob, nHash = rawdb.ReadStorageTrieNode(dl.db.diskdb, owner, path)
|
||||||
}
|
}
|
||||||
|
trieNodeTime.Mark(time.Since(startLoadTrieNode).Nanoseconds())
|
||||||
if nHash != hash {
|
if nHash != hash {
|
||||||
diskFalseMeter.Mark(1)
|
diskFalseMeter.Mark(1)
|
||||||
log.Error("Unexpected trie node in disk", "owner", owner, "path", path, "expect", hash, "got", nHash)
|
log.Error("Unexpected trie node in disk", "owner", owner, "path", path, "expect", hash, "got", nHash)
|
||||||
@@ -286,6 +291,9 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,9 +51,20 @@ 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
|
||||||
@@ -98,12 +109,19 @@ 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()
|
||||||
@@ -132,8 +150,15 @@ 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
|
||||||
@@ -146,6 +171,7 @@ 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) {
|
||||||
@@ -166,6 +192,7 @@ 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))
|
||||||
@@ -180,6 +207,13 @@ 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)
|
||||||
@@ -189,8 +223,25 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,4 +47,16 @@ 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)
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user