Compare commits
35 Commits
v1.4.10
...
versa_comp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba71e76c55 | ||
|
|
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 |
@@ -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
|
||||||
|
|||||||
37
CHANGELOG.md
37
CHANGELOG.md
@@ -1,4 +1,41 @@
|
|||||||
# 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
|
## v1.4.10
|
||||||
### FEATURE
|
### FEATURE
|
||||||
NA
|
NA
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -349,6 +349,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||||||
}
|
}
|
||||||
// Re-create statedb instance with new root upon the updated database
|
// Re-create statedb instance with new root upon the updated database
|
||||||
// for accessing latest states.
|
// for accessing latest states.
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err = state.New(root, statedb.Database(), nil)
|
statedb, err = state.New(root, statedb.Database(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not reopen state: %v", err))
|
||||||
@@ -358,7 +359,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB {
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
sdb := state.NewDatabaseWithConfig(db, &triedb.Config{Preimages: true})
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
|
statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
|
||||||
for addr, a := range accounts {
|
for addr, a := range accounts {
|
||||||
statedb.SetCode(addr, a.Code)
|
statedb.SetCode(addr, a.Code)
|
||||||
@@ -372,6 +375,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
|
|||||||
statedb.Finalise(false)
|
statedb.Finalise(false)
|
||||||
statedb.AccountsIntermediateRoot()
|
statedb.AccountsIntermediateRoot()
|
||||||
root, _, _ := statedb.Commit(0, nil)
|
root, _, _ := statedb.Commit(0, nil)
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, _ = state.New(root, sdb, nil)
|
statedb, _ = state.New(root, sdb, nil)
|
||||||
return statedb
|
return statedb
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,12 +148,14 @@ func runCmd(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
db := rawdb.NewMemoryDatabase()
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
// TODO:: ignore cmd, if use versa if should be nil, if triedb is not used later in this func
|
||||||
triedb := triedb.NewDatabase(db, &triedb.Config{
|
triedb := triedb.NewDatabase(db, &triedb.Config{
|
||||||
Preimages: preimages,
|
Preimages: preimages,
|
||||||
HashDB: hashdb.Defaults,
|
HashDB: hashdb.Defaults,
|
||||||
})
|
})
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
genesis := genesisConfig.MustCommit(db, triedb)
|
genesis := genesisConfig.MustCommit(db, triedb)
|
||||||
|
// TODO:: ignore cmd, internally compatible with versa is sufficient.
|
||||||
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
sdb := state.NewDatabaseWithNodeDB(db, triedb)
|
||||||
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
statedb, _ = state.New(genesis.Root(), sdb, nil)
|
||||||
chainConfig = genesisConfig.Config
|
chainConfig = genesisConfig.Config
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ func runStateTest(fname string, cfg vm.Config, jsonOut, dump bool) error {
|
|||||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||||
}
|
}
|
||||||
if dump { // Dump any state to aid debugging
|
if dump { // Dump any state to aid debugging
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
|
cpy, _ := state.New(root, tstate.StateDB.Database(), nil)
|
||||||
dump := cpy.RawDump(nil)
|
dump := cpy.RawDump(nil)
|
||||||
result.State = &dump
|
result.State = &dump
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -787,6 +778,7 @@ func parseDumpConfig(ctx *cli.Context, stack *node.Node) (*state.DumpConfig, eth
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Use latest
|
// Use latest
|
||||||
|
// TODO:: if versa, scheme = VersaScheme
|
||||||
if scheme == rawdb.PathScheme {
|
if scheme == rawdb.PathScheme {
|
||||||
triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly)})
|
triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly)})
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
@@ -842,6 +834,7 @@ func dump(ctx *cli.Context) error {
|
|||||||
triedb := utils.MakeTrieDatabase(ctx, stack, db, true, true, false) // always enable preimage lookup
|
triedb := utils.MakeTrieDatabase(ctx, stack, db, true, true, false) // always enable preimage lookup
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -859,6 +852,7 @@ func dumpAllRootHashInPath(ctx *cli.Context) error {
|
|||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
db := utils.MakeChainDatabase(ctx, stack, true, false)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
// TODO:: ignore cmd
|
||||||
triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly)})
|
triedb := triedb.NewDatabase(db, &triedb.Config{PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly)})
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -457,6 +457,7 @@ func inspectTrie(ctx *cli.Context) error {
|
|||||||
config = triedb.HashDefaults
|
config = triedb.HashDefaults
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:: ignore cmd
|
||||||
triedb := triedb.NewDatabase(db, config)
|
triedb := triedb.NewDatabase(db, config)
|
||||||
theTrie, err := trie.New(trie.TrieID(trieRootHash), triedb)
|
theTrie, err := trie.New(trie.TrieID(trieRootHash), triedb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -1212,7 +1213,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 +1256,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()
|
||||||
|
|
||||||
@@ -1268,13 +1269,14 @@ func hbss2pbss(ctx *cli.Context) error {
|
|||||||
}
|
}
|
||||||
if lastStateID == 0 || force {
|
if lastStateID == 0 || force {
|
||||||
config := triedb.HashDefaults
|
config := triedb.HashDefaults
|
||||||
|
// TODO:: ignore cmd
|
||||||
triedb := triedb.NewDatabase(db, config)
|
triedb := triedb.NewDatabase(db, config)
|
||||||
triedb.Cap(0)
|
triedb.Cap(0)
|
||||||
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)
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ func accessDb(ctx *cli.Context, stack *node.Node) (ethdb.Database, error) {
|
|||||||
} else if dbScheme == rawdb.HashScheme {
|
} else if dbScheme == rawdb.HashScheme {
|
||||||
config = triedb.HashDefaults
|
config = triedb.HashDefaults
|
||||||
}
|
}
|
||||||
|
// TODO:: ignore snapshot
|
||||||
snaptree, err := snapshot.New(snapconfig, chaindb, triedb.NewDatabase(chaindb, config), headBlock.Root(), TriesInMemory, false)
|
snaptree, err := snapshot.New(snapconfig, chaindb, triedb.NewDatabase(chaindb, config), headBlock.Root(), TriesInMemory, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("snaptree error", "err", err)
|
log.Error("snaptree error", "err", err)
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -2600,6 +2589,7 @@ func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, p
|
|||||||
// ignore the parameter silently. TODO(rjl493456442)
|
// ignore the parameter silently. TODO(rjl493456442)
|
||||||
// please config it if read mode is implemented.
|
// please config it if read mode is implemented.
|
||||||
config.HashDB = hashdb.Defaults
|
config.HashDB = hashdb.Defaults
|
||||||
|
// TODO::skip MakeTrieDatabase
|
||||||
return triedb.NewDatabase(disk, config)
|
return triedb.NewDatabase(disk, config)
|
||||||
}
|
}
|
||||||
if readOnly {
|
if readOnly {
|
||||||
@@ -2608,6 +2598,7 @@ func MakeTrieDatabase(ctx *cli.Context, stack *node.Node, disk ethdb.Database, p
|
|||||||
config.PathDB = pathdb.Defaults
|
config.PathDB = pathdb.Defaults
|
||||||
}
|
}
|
||||||
config.PathDB.JournalFilePath = fmt.Sprintf("%s/%s", stack.ResolvePath("chaindata"), eth.JournalFileName)
|
config.PathDB.JournalFilePath = fmt.Sprintf("%s/%s", stack.ResolvePath("chaindata"), eth.JournalFileName)
|
||||||
|
// TODO::skip MakeTrieDatabase
|
||||||
return triedb.NewDatabase(disk, config)
|
return triedb.NewDatabase(disk, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -336,6 +336,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
diffLayerChanCache, _ := exlru.New(diffLayerCacheLimit)
|
diffLayerChanCache, _ := exlru.New(diffLayerCacheLimit)
|
||||||
|
|
||||||
// Open trie database with provided config
|
// Open trie database with provided config
|
||||||
|
// TODO:: if versa , have its owen init genesis logic
|
||||||
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig())
|
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig())
|
||||||
|
|
||||||
// Setup the genesis block, commit the provided genesis specification
|
// Setup the genesis block, commit the provided genesis specification
|
||||||
@@ -384,6 +385,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
}
|
}
|
||||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
bc.forker = NewForkChoice(bc, shouldPreserve)
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
||||||
bc.prefetcher = NewStatePrefetcher(chainConfig, bc, engine)
|
bc.prefetcher = NewStatePrefetcher(chainConfig, bc, engine)
|
||||||
@@ -462,8 +464,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
|
||||||
}
|
}
|
||||||
@@ -657,20 +659,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.BlockStore())} {
|
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
|
||||||
}
|
}
|
||||||
@@ -706,7 +701,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")
|
||||||
@@ -728,7 +723,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
|
||||||
}
|
}
|
||||||
@@ -739,7 +734,7 @@ func (bc *BlockChain) loadLastState() error {
|
|||||||
bc.currentSnapBlock.Store(headBlock.Header())
|
bc.currentSnapBlock.Store(headBlock.Header())
|
||||||
headFastBlockGauge.Update(int64(headBlock.NumberU64()))
|
headFastBlockGauge.Update(int64(headBlock.NumberU64()))
|
||||||
|
|
||||||
if head := rawdb.ReadHeadFastBlockHash(bc.db.BlockStore()); head != (common.Hash{}) {
|
if head := rawdb.ReadHeadFastBlockHash(bc.db); head != (common.Hash{}) {
|
||||||
if block := bc.GetBlockByHash(head); block != nil {
|
if block := bc.GetBlockByHash(head); block != nil {
|
||||||
bc.currentSnapBlock.Store(block.Header())
|
bc.currentSnapBlock.Store(block.Header())
|
||||||
headFastBlockGauge.Update(int64(block.NumberU64()))
|
headFastBlockGauge.Update(int64(block.NumberU64()))
|
||||||
@@ -1107,7 +1102,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
|
||||||
}
|
}
|
||||||
@@ -1116,11 +1111,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.
|
||||||
@@ -1563,9 +1558,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
|
||||||
@@ -1583,7 +1578,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
|
||||||
@@ -1591,7 +1586,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.
|
||||||
@@ -1599,7 +1594,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
|
||||||
@@ -1619,7 +1614,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)
|
||||||
}
|
}
|
||||||
@@ -1805,6 +1800,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
|||||||
if err := blockBatch.Write(); err != nil {
|
if err := blockBatch.Write(); err != nil {
|
||||||
log.Crit("Failed to write block into disk", "err", err)
|
log.Crit("Failed to write block into disk", "err", err)
|
||||||
}
|
}
|
||||||
|
bc.hc.tdCache.Add(block.Hash(), externTd)
|
||||||
|
bc.blockCache.Add(block.Hash(), block)
|
||||||
|
bc.receiptsCache.Add(block.Hash(), receipts)
|
||||||
|
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
|
||||||
|
bc.sidecarsCache.Add(block.Hash(), block.Sidecars())
|
||||||
|
}
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -2233,6 +2234,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||||||
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
|
statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return it.index, err
|
return it.index, err
|
||||||
@@ -2282,8 +2284,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||||||
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)
|
||||||
@@ -2396,26 +2396,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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
@@ -396,6 +396,7 @@ func (bc *BlockChain) State() (*state.StateDB, error) {
|
|||||||
|
|
||||||
// StateAt returns a new mutable state based on a particular point in time.
|
// StateAt returns a new mutable state based on a particular point in time.
|
||||||
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
stateDb, err := state.New(root, bc.stateCache, bc.snaps)
|
stateDb, err := state.New(root, bc.stateCache, bc.snaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -514,7 +515,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -397,10 +397,12 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Forcibly use hash-based state scheme for retaining all nodes in disk.
|
// Forcibly use hash-based state scheme for retaining all nodes in disk.
|
||||||
|
// TODO:: ignore, only use to UT
|
||||||
triedb := triedb.NewDatabase(db, triedb.HashDefaults)
|
triedb := triedb.NewDatabase(db, triedb.HashDefaults)
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
|
// @TODO:: ignore, it used to UT, state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
|
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -126,7 +126,9 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
|
|||||||
}
|
}
|
||||||
// Create an ephemeral in-memory database for computing hash,
|
// Create an ephemeral in-memory database for computing hash,
|
||||||
// all the derived states will be discarded to not pollute disk.
|
// all the derived states will be discarded to not pollute disk.
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
|
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err := state.New(types.EmptyRootHash, db, nil)
|
statedb, err := state.New(types.EmptyRootHash, db, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
@@ -154,6 +156,7 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
|
|||||||
if triedbConfig != nil {
|
if triedbConfig != nil {
|
||||||
triedbConfig.NoTries = false
|
triedbConfig.NoTries = false
|
||||||
}
|
}
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -216,8 +219,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 +246,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -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()
|
||||||
@@ -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
|
||||||
@@ -403,6 +419,7 @@ func (db *emptyfreezedb) Sync() error {
|
|||||||
func (db *emptyfreezedb) DiffStore() ethdb.KeyValueStore { return db }
|
func (db *emptyfreezedb) DiffStore() ethdb.KeyValueStore { return db }
|
||||||
func (db *emptyfreezedb) SetDiffStore(diff ethdb.KeyValueStore) {}
|
func (db *emptyfreezedb) SetDiffStore(diff ethdb.KeyValueStore) {}
|
||||||
func (db *emptyfreezedb) StateStore() ethdb.Database { return db }
|
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) SetStateStore(state ethdb.Database) {}
|
||||||
func (db *emptyfreezedb) StateStoreReader() ethdb.Reader { return db }
|
func (db *emptyfreezedb) StateStoreReader() ethdb.Reader { return db }
|
||||||
func (db *emptyfreezedb) BlockStore() ethdb.Database { return db }
|
func (db *emptyfreezedb) BlockStore() ethdb.Database { return db }
|
||||||
@@ -518,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
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,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
|
||||||
@@ -566,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
|
||||||
@@ -576,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)
|
||||||
}
|
}
|
||||||
@@ -591,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
|
||||||
@@ -617,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
|
||||||
@@ -1238,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, ": "))
|
||||||
@@ -1249,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>"
|
||||||
@@ -1271,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.BlockStore()))},
|
|
||||||
{"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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ func pruneAll(maindb ethdb.Database, g *core.Genesis) error {
|
|||||||
}
|
}
|
||||||
log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart)))
|
log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart)))
|
||||||
}
|
}
|
||||||
|
// TODO:: ignore, versa has its own prunner
|
||||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(maindb), nil)
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(maindb), nil)
|
||||||
for addr, account := range g.Alloc {
|
for addr, account := range g.Alloc {
|
||||||
statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
|
statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
|
||||||
|
|||||||
@@ -205,6 +205,8 @@ type Tree struct {
|
|||||||
// state trie.
|
// state trie.
|
||||||
// - otherwise, the entire snapshot is considered invalid and will be recreated on
|
// - otherwise, the entire snapshot is considered invalid and will be recreated on
|
||||||
// a background thread.
|
// a background thread.
|
||||||
|
//
|
||||||
|
// TODO:: if use versa, set SnapshotLimit == 0, will forbidden to use
|
||||||
func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, root common.Hash, cap int, withoutTrie bool) (*Tree, error) {
|
func New(config Config, diskdb ethdb.KeyValueStore, triedb *triedb.Database, root common.Hash, cap int, withoutTrie bool) (*Tree, error) {
|
||||||
snap := &Tree{
|
snap := &Tree{
|
||||||
config: config,
|
config: config,
|
||||||
|
|||||||
@@ -933,8 +933,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 {
|
||||||
|
|||||||
@@ -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()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
|||||||
setDefaults(cfg)
|
setDefaults(cfg)
|
||||||
|
|
||||||
if cfg.State == nil {
|
if cfg.State == nil {
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
@@ -149,6 +150,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
|||||||
setDefaults(cfg)
|
setDefaults(cfg)
|
||||||
|
|
||||||
if cfg.State == nil {
|
if cfg.State == nil {
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
|
||||||
}
|
}
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -185,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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -71,7 +71,9 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
// the internal junks created by tracing will be persisted into the disk.
|
// the internal junks created by tracing will be persisted into the disk.
|
||||||
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
||||||
// please re-enable it for better performance.
|
// please re-enable it for better performance.
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults)
|
database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults)
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
if statedb, err = state.New(block.Root(), database, nil); err == nil {
|
if statedb, err = state.New(block.Root(), database, nil); err == nil {
|
||||||
log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number())
|
log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number())
|
||||||
return statedb, noopReleaser, nil
|
return statedb, noopReleaser, nil
|
||||||
@@ -91,13 +93,16 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
// the internal junks created by tracing will be persisted into the disk.
|
// the internal junks created by tracing will be persisted into the disk.
|
||||||
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
||||||
// please re-enable it for better performance.
|
// please re-enable it for better performance.
|
||||||
|
// TODO:: if use versa, tdb == nil
|
||||||
tdb = triedb.NewDatabase(eth.chainDb, triedb.HashDefaults)
|
tdb = triedb.NewDatabase(eth.chainDb, triedb.HashDefaults)
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb)
|
database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb)
|
||||||
|
|
||||||
// If we didn't check the live database, do check state over ephemeral database,
|
// If we didn't check the live database, do check state over ephemeral database,
|
||||||
// otherwise we would rewind past a persisted block (specific corner case is
|
// otherwise we would rewind past a persisted block (specific corner case is
|
||||||
// chain tracing from the genesis).
|
// chain tracing from the genesis).
|
||||||
if !readOnly {
|
if !readOnly {
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err = state.New(current.Root(), database, nil)
|
statedb, err = state.New(current.Root(), database, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return statedb, noopReleaser, nil
|
return statedb, noopReleaser, nil
|
||||||
@@ -116,7 +121,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
return nil, nil, fmt.Errorf("missing block %v %d", current.ParentHash(), current.NumberU64()-1)
|
return nil, nil, fmt.Errorf("missing block %v %d", current.ParentHash(), current.NumberU64()-1)
|
||||||
}
|
}
|
||||||
current = parent
|
current = parent
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err = state.New(current.Root(), database, nil)
|
statedb, err = state.New(current.Root(), database, nil)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
break
|
break
|
||||||
@@ -164,6 +169,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w",
|
return nil, nil, fmt.Errorf("stateAtBlock commit failed, number %d root %v: %w",
|
||||||
current.NumberU64(), current.Root().Hex(), err)
|
current.NumberU64(), current.Root().Hex(), err)
|
||||||
}
|
}
|
||||||
|
// TODO:: state.NewDatabase internally compatible with versa is sufficient.
|
||||||
statedb, err = state.New(root, database, nil) // nolint:staticcheck
|
statedb, err = state.New(root, database, nil) // nolint:staticcheck
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err)
|
return nil, nil, fmt.Errorf("state reset after block %d failed: %v", current.NumberU64(), err)
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -151,8 +151,6 @@ func testChainSyncWithBlobs(t *testing.T, mode downloader.SyncMode, preCancunBlk
|
|||||||
go full.handler.runEthPeer(fullPeerEth, func(peer *eth.Peer) error {
|
go full.handler.runEthPeer(fullPeerEth, func(peer *eth.Peer) error {
|
||||||
return eth.Handle((*ethHandler)(full.handler), peer)
|
return eth.Handle((*ethHandler)(full.handler), peer)
|
||||||
})
|
})
|
||||||
// Wait a bit for the above handlers to start
|
|
||||||
time.Sleep(250 * time.Millisecond)
|
|
||||||
|
|
||||||
emptyPipeSnap, fullPipeSnap := p2p.MsgPipe()
|
emptyPipeSnap, fullPipeSnap := p2p.MsgPipe()
|
||||||
defer emptyPipeSnap.Close()
|
defer emptyPipeSnap.Close()
|
||||||
@@ -167,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")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,8 +236,16 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// @TODO:: add VersaDB() method
|
||||||
// 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
|
||||||
// only access the key-value data store but also the chain freezer.
|
// only access the key-value data store but also the chain freezer.
|
||||||
type Database interface {
|
type Database interface {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"math/big"
|
"math/big"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
@@ -68,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 {
|
||||||
@@ -95,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{}
|
||||||
@@ -128,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),
|
||||||
@@ -327,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:
|
||||||
@@ -334,60 +345,47 @@ 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),
|
|
||||||
finished: make(chan struct{}),
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
@@ -419,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()
|
||||||
@@ -446,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
|
||||||
}
|
}
|
||||||
@@ -495,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
|
||||||
@@ -546,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
|
||||||
@@ -637,7 +642,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
|
|||||||
if b.config.GreedyMergeTx {
|
if b.config.GreedyMergeTx {
|
||||||
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
|
delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)
|
||||||
if delay != nil && *delay > 0 {
|
if delay != nil && *delay > 0 {
|
||||||
bidTxsSet := mapset.NewSet[common.Hash]()
|
bidTxsSet := mapset.NewThreadUnsafeSetWithSize[common.Hash](len(bidRuntime.bid.Txs))
|
||||||
for _, tx := range bidRuntime.bid.Txs {
|
for _, tx := range bidRuntime.bid.Txs {
|
||||||
bidTxsSet.Add(tx.Hash())
|
bidTxsSet.Add(tx.Hash())
|
||||||
}
|
}
|
||||||
@@ -662,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)
|
||||||
@@ -682,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:
|
||||||
}
|
}
|
||||||
@@ -702,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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -722,11 +744,42 @@ type BidRuntime 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()
|
||||||
@@ -782,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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1371,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 = 10 // 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)
|
||||||
|
|||||||
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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user