Compare commits
24 Commits
v1.4.6
...
faucet-bal
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e149161d54 | ||
|
|
cb0b34b7c2 | ||
|
|
5b7a71e38e | ||
|
|
6b8cbbe172 | ||
|
|
5ea2ada0ee | ||
|
|
b230a02006 | ||
|
|
86e3a02490 | ||
|
|
0c0958ff87 | ||
|
|
d436f9e2e8 | ||
|
|
97c3b9b267 | ||
|
|
0560685460 | ||
|
|
bf16a39876 | ||
|
|
2c8720016d | ||
|
|
23f6194fad | ||
|
|
691d195526 | ||
|
|
b57c779759 | ||
|
|
a7d5b02919 | ||
|
|
1ce9bb044d | ||
|
|
7948950f7a | ||
|
|
0c101e618a | ||
|
|
571ea2c4b9 | ||
|
|
7bc5a3353d | ||
|
|
901ea2e0d2 | ||
|
|
1d81f3316f |
1
.nancy-ignore
Normal file
1
.nancy-ignore
Normal file
@@ -0,0 +1 @@
|
||||
CVE-2024-34478 # "CWE-754: Improper Check for Unusual or Exceptional Conditions." This vulnerability is BTC only, BSC does not have the issue.
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,4 +1,18 @@
|
||||
# Changelog
|
||||
## v1.4.7
|
||||
### FEATURE
|
||||
* [\#2439](https://github.com/bnb-chain/bsc/pull/2439) config: setup Mainnet Tycho(Cancun) hardfork date
|
||||
|
||||
### IMPROVEMENT
|
||||
* [\#2396](https://github.com/bnb-chain/bsc/pull/2396) metrics: add blockInsertMgaspsGauge to trace mgasps
|
||||
* [\#2411](https://github.com/bnb-chain/bsc/pull/2411) build(deps): bump golang.org/x/net from 0.19.0 to 0.23.0
|
||||
* [\#2435](https://github.com/bnb-chain/bsc/pull/2435) txpool: limit max gas when mining is enabled
|
||||
* [\#2438](https://github.com/bnb-chain/bsc/pull/2438) fix: performance issue when load journal
|
||||
* [\#2440](https://github.com/bnb-chain/bsc/pull/2440) nancy: add files .nancy-ignore
|
||||
|
||||
### BUGFIX
|
||||
NA
|
||||
|
||||
## v1.4.6
|
||||
### FEATURE
|
||||
* [\#2227](https://github.com/bnb-chain/bsc/pull/2227) core: separated databases for block data
|
||||
|
||||
@@ -193,14 +193,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||
cfg.Eth.OverrideVerkle = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideFeynman.Name) {
|
||||
v := ctx.Uint64(utils.OverrideFeynman.Name)
|
||||
cfg.Eth.OverrideFeynman = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideFeynmanFix.Name) {
|
||||
v := ctx.Uint64(utils.OverrideFeynmanFix.Name)
|
||||
cfg.Eth.OverrideFeynmanFix = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideFullImmutabilityThreshold.Name) {
|
||||
params.FullImmutabilityThreshold = ctx.Uint64(utils.OverrideFullImmutabilityThreshold.Name)
|
||||
downloader.FullMaxForkAncestry = ctx.Uint64(utils.OverrideFullImmutabilityThreshold.Name)
|
||||
@@ -211,6 +203,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
||||
if ctx.IsSet(utils.OverrideDefaultExtraReserveForBlobRequests.Name) {
|
||||
params.DefaultExtraReserveForBlobRequests = ctx.Uint64(utils.OverrideDefaultExtraReserveForBlobRequests.Name)
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideBreatheBlockInterval.Name) {
|
||||
params.BreatheBlockInterval = ctx.Uint64(utils.OverrideBreatheBlockInterval.Name)
|
||||
}
|
||||
|
||||
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
|
||||
|
||||
|
||||
@@ -106,12 +106,12 @@ Remove blockchain and state databases`,
|
||||
dbInspectTrieCmd = &cli.Command{
|
||||
Action: inspectTrie,
|
||||
Name: "inspect-trie",
|
||||
ArgsUsage: "<blocknum> <jobnum>",
|
||||
ArgsUsage: "<blocknum> <jobnum> <topn>",
|
||||
Flags: []cli.Flag{
|
||||
utils.DataDirFlag,
|
||||
utils.SyncModeFlag,
|
||||
},
|
||||
Usage: "Inspect the MPT tree of the account and contract.",
|
||||
Usage: "Inspect the MPT tree of the account and contract. 'blocknum' can be latest/snapshot/number. 'topn' means output the top N storage tries info ranked by the total number of TrieNodes",
|
||||
Description: `This commands iterates the entrie WorldState.`,
|
||||
}
|
||||
dbCheckStateContentCmd = &cli.Command{
|
||||
@@ -386,6 +386,7 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
blockNumber uint64
|
||||
trieRootHash common.Hash
|
||||
jobnum uint64
|
||||
topN uint64
|
||||
)
|
||||
|
||||
stack, _ := makeConfigNode(ctx)
|
||||
@@ -411,12 +412,25 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
|
||||
if ctx.NArg() == 1 {
|
||||
jobnum = 1000
|
||||
topN = 10
|
||||
} else if ctx.NArg() == 2 {
|
||||
var err error
|
||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
topN = 10
|
||||
} else {
|
||||
var err error
|
||||
jobnum, err = strconv.ParseUint(ctx.Args().Get(1), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to Parse jobnum, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
|
||||
topN, err = strconv.ParseUint(ctx.Args().Get(2), 10, 64)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to Parse topn, Args[1]: %v, err: %v", ctx.Args().Get(1), err)
|
||||
}
|
||||
}
|
||||
|
||||
if blockNumber != math.MaxUint64 {
|
||||
@@ -437,6 +451,7 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
if dbScheme == rawdb.PathScheme {
|
||||
config = &triedb.Config{
|
||||
PathDB: utils.PathDBConfigAddJournalFilePath(stack, pathdb.ReadOnly),
|
||||
Cache: 0,
|
||||
}
|
||||
} else if dbScheme == rawdb.HashScheme {
|
||||
config = triedb.HashDefaults
|
||||
@@ -448,7 +463,7 @@ func inspectTrie(ctx *cli.Context) error {
|
||||
fmt.Printf("fail to new trie tree, err: %v, rootHash: %v\n", err, trieRootHash.String())
|
||||
return err
|
||||
}
|
||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum)
|
||||
theInspect, err := trie.NewInspector(theTrie, triedb, trieRootHash, blockNumber, jobnum, int(topN))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||
@@ -72,11 +74,10 @@ var (
|
||||
utils.RialtoHash,
|
||||
utils.OverrideCancun,
|
||||
utils.OverrideVerkle,
|
||||
utils.OverrideFeynman,
|
||||
utils.OverrideFeynmanFix,
|
||||
utils.OverrideFullImmutabilityThreshold,
|
||||
utils.OverrideMinBlocksForBlobRequests,
|
||||
utils.OverrideDefaultExtraReserveForBlobRequests,
|
||||
utils.OverrideBreatheBlockInterval,
|
||||
utils.EnablePersonal,
|
||||
utils.TxPoolLocalsFlag,
|
||||
utils.TxPoolNoLocalsFlag,
|
||||
@@ -456,6 +457,10 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend, isCon
|
||||
// Set the gas price to the limits from the CLI and start mining
|
||||
gasprice := flags.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
|
||||
ethBackend.TxPool().SetGasTip(gasprice)
|
||||
gasCeil := ethBackend.Miner().GasCeil()
|
||||
if gasCeil > params.SystemTxsGas {
|
||||
ethBackend.TxPool().SetMaxGas(gasCeil - params.SystemTxsGas)
|
||||
}
|
||||
if err := ethBackend.StartMining(); err != nil {
|
||||
utils.Fatalf("Failed to start mining: %v", err)
|
||||
}
|
||||
|
||||
@@ -409,7 +409,7 @@ func pruneBlock(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
if _, err := os.Stat(newAncientPath); err == nil {
|
||||
// No file lock found for old ancientDB but new ancientDB exsisted, indicating the geth was interrupted
|
||||
// No file lock found for old ancientDB but new ancientDB existed, indicating the geth was interrupted
|
||||
// after old ancientDB removal, this happened after backup successfully, so just rename the new ancientDB
|
||||
if err := blockpruner.AncientDbReplacer(); err != nil {
|
||||
log.Error("Failed to rename new ancient directory")
|
||||
|
||||
51
cmd/jsutils/check_blobtx.js
Normal file
51
cmd/jsutils/check_blobtx.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { ethers } from "ethers";
|
||||
import program from "commander";
|
||||
|
||||
// depends on ethjs v6.11.0+ for 4844, https://github.com/ethers-io/ethers.js/releases/tag/v6.11.0
|
||||
// BSC testnet enabled 4844 on block: 39539137
|
||||
// Usage:
|
||||
// nvm use 20
|
||||
// node check_blobtx.js --rpc https://data-seed-prebsc-1-s1.binance.org:8545 --startNum 39539137
|
||||
// node check_blobtx.js --rpc https://data-seed-prebsc-1-s1.binance.org:8545 --startNum 39539137 --endNum 40345994
|
||||
program.option("--rpc <Rpc>", "Rpc Server URL");
|
||||
program.option("--startNum <Num>", "start block", 0);
|
||||
program.option("--endNum <Num>", "end block", 0);
|
||||
program.parse(process.argv);
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(program.rpc);
|
||||
const main = async () => {
|
||||
var startBlock = parseInt(program.startNum)
|
||||
var endBlock = parseInt(program.endNum)
|
||||
if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) {
|
||||
console.error("invalid input, --startNum", program.startNum, "--end", program.endNum)
|
||||
return
|
||||
}
|
||||
// if --endNum is not specified, set it to the latest block number.
|
||||
if (endBlock == 0) {
|
||||
endBlock = await provider.getBlockNumber();
|
||||
}
|
||||
if (startBlock > endBlock) {
|
||||
console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock);
|
||||
return
|
||||
}
|
||||
|
||||
for (let i = startBlock; i <= endBlock; i++) {
|
||||
let blockData = await provider.getBlock(i);
|
||||
console.log("startBlock:",startBlock, "endBlock:", endBlock, "curBlock", i, "blobGasUsed", blockData.blobGasUsed);
|
||||
if (blockData.blobGasUsed == 0) {
|
||||
continue
|
||||
}
|
||||
for (let txIndex = 0; txIndex<= blockData.transactions.length - 1; txIndex++) {
|
||||
let txHash = blockData.transactions[txIndex]
|
||||
let txData = await provider.getTransaction(txHash);
|
||||
if (txData.type == 3) {
|
||||
console.log("BlobTx in block:",i, " txIndex:", txIndex, " txHash:", txHash);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
main().then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
49
cmd/jsutils/faucet_request.js
Normal file
49
cmd/jsutils/faucet_request.js
Normal file
@@ -0,0 +1,49 @@
|
||||
import { ethers } from "ethers";
|
||||
import program from "commander";
|
||||
|
||||
// Usage:
|
||||
// node faucet_request.js --rpc localhost:8545 --startNum 39539137
|
||||
// node faucet_request.js --rpc localhost:8545 --startNum 39539137 --endNum 40345994
|
||||
|
||||
// node faucet_request.js --rpc https://data-seed-prebsc-1-s1.bnbchain.org:8545 --startNum 39539137 --endNum 40345994
|
||||
program.option("--rpc <Rpc>", "Rpc Server URL");
|
||||
program.option("--startNum <Num>", "start block", 0);
|
||||
program.option("--endNum <Num>", "end block", 0);
|
||||
program.parse(process.argv);
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(program.rpc);
|
||||
const main = async () => {
|
||||
var startBlock = parseInt(program.startNum)
|
||||
var endBlock = parseInt(program.endNum)
|
||||
if (isNaN(endBlock) || isNaN(startBlock) || startBlock == 0) {
|
||||
console.error("invalid input, --startNum", program.startNum, "--end", program.endNum)
|
||||
return
|
||||
}
|
||||
// if --endNum is not specified, set it to the latest block number.
|
||||
if (endBlock == 0) {
|
||||
endBlock = await provider.getBlockNumber();
|
||||
}
|
||||
if (startBlock > endBlock) {
|
||||
console.error("invalid input, startBlock:",startBlock, " endBlock:", endBlock);
|
||||
return
|
||||
}
|
||||
|
||||
let startBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", startBlock)
|
||||
let endBalance = await provider.getBalance("0xaa25Aa7a19f9c426E07dee59b12f944f4d9f1DD3", endBlock)
|
||||
const faucetAmount = BigInt(0.3 * 10**18); // Convert 0.3 ether to wei as a BigInt
|
||||
const numFaucetRequest = (startBalance - endBalance) / faucetAmount;
|
||||
|
||||
// Convert BigInt to ether
|
||||
const startBalanceEth = Number(startBalance) / 10**18;
|
||||
const endBalanceEth = Number(endBalance) / 10**18;
|
||||
|
||||
console.log(`Start Balance: ${startBalanceEth} ETH`);
|
||||
console.log(`End Balance: ${endBalanceEth} ETH`);
|
||||
|
||||
console.log("successful faucet request: ",numFaucetRequest);
|
||||
};
|
||||
main().then(() => process.exit(0))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -315,15 +315,6 @@ var (
|
||||
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverrideFeynman = &cli.Uint64Flag{
|
||||
Name: "override.feynman",
|
||||
Usage: "Manually specify the Feynman fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverrideFeynmanFix = &cli.Uint64Flag{
|
||||
Name: "override.feynmanfix",
|
||||
Usage: "Manually specify the FeynmanFix fork timestamp, overriding the bundled setting",
|
||||
}
|
||||
OverrideFullImmutabilityThreshold = &cli.Uint64Flag{
|
||||
Name: "override.immutabilitythreshold",
|
||||
Usage: "It is the number of blocks after which a chain segment is considered immutable, only for testing purpose",
|
||||
@@ -342,6 +333,12 @@ var (
|
||||
Value: params.DefaultExtraReserveForBlobRequests,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverrideBreatheBlockInterval = &cli.Uint64Flag{
|
||||
Name: "override.breatheblockinterval",
|
||||
Usage: "It changes the interval between breathe blocks, only for testing purpose",
|
||||
Value: params.BreatheBlockInterval,
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
SyncModeFlag = &flags.TextMarshalerFlag{
|
||||
Name: "syncmode",
|
||||
Usage: `Blockchain sync mode ("snap" or "full")`,
|
||||
|
||||
@@ -15,14 +15,13 @@ import (
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
)
|
||||
|
||||
const SecondsPerDay uint64 = 86400
|
||||
|
||||
// the params should be two blocks' time(timestamp)
|
||||
func sameDayInUTC(first, second uint64) bool {
|
||||
return first/SecondsPerDay == second/SecondsPerDay
|
||||
return first/params.BreatheBlockInterval == second/params.BreatheBlockInterval
|
||||
}
|
||||
|
||||
func isBreatheBlock(lastBlockTime, blockTime uint64) bool {
|
||||
|
||||
@@ -66,6 +66,31 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, engin
|
||||
return validator
|
||||
}
|
||||
|
||||
// ValidateListsInBody validates that UncleHash, WithdrawalsHash, and WithdrawalsHash correspond to the lists in the block body, respectively.
|
||||
func ValidateListsInBody(block *types.Block) error {
|
||||
header := block.Header()
|
||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
||||
}
|
||||
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
|
||||
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
|
||||
}
|
||||
// Withdrawals are present after the Shanghai fork.
|
||||
if header.WithdrawalsHash != nil {
|
||||
// Withdrawals list must be present in body after Shanghai.
|
||||
if block.Withdrawals() == nil {
|
||||
return errors.New("missing withdrawals in block body")
|
||||
}
|
||||
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
|
||||
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
||||
}
|
||||
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
|
||||
// Withdrawals are not allowed prior to shanghai fork
|
||||
return errors.New("withdrawals present in block body")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateBody validates the given block's uncles and verifies the block
|
||||
// header's transaction and uncle roots. The headers are assumed to be already
|
||||
// validated at this point.
|
||||
@@ -83,31 +108,12 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||
if err := v.engine.VerifyUncles(v.bc, block); err != nil {
|
||||
return err
|
||||
}
|
||||
if hash := types.CalcUncleHash(block.Uncles()); hash != header.UncleHash {
|
||||
return fmt.Errorf("uncle root hash mismatch (header value %x, calculated %x)", header.UncleHash, hash)
|
||||
}
|
||||
|
||||
validateFuns := []func() error{
|
||||
func() error {
|
||||
if hash := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); hash != header.TxHash {
|
||||
return fmt.Errorf("transaction root hash mismatch: have %x, want %x", hash, header.TxHash)
|
||||
}
|
||||
return nil
|
||||
return ValidateListsInBody(block)
|
||||
},
|
||||
func() error {
|
||||
// Withdrawals are present after the Shanghai fork.
|
||||
if header.WithdrawalsHash != nil {
|
||||
// Withdrawals list must be present in body after Shanghai.
|
||||
if block.Withdrawals() == nil {
|
||||
return errors.New("missing withdrawals in block body")
|
||||
}
|
||||
if hash := types.DeriveSha(block.Withdrawals(), trie.NewStackTrie(nil)); hash != *header.WithdrawalsHash {
|
||||
return fmt.Errorf("withdrawals root hash mismatch (header value %x, calculated %x)", *header.WithdrawalsHash, hash)
|
||||
}
|
||||
} else if block.Withdrawals() != nil { // Withdrawals turn into empty from nil when BlockBody has Sidecars
|
||||
// Withdrawals are not allowed prior to shanghai fork
|
||||
return errors.New("withdrawals present in block body")
|
||||
}
|
||||
// Blob transactions may be present after the Cancun fork.
|
||||
var blobs int
|
||||
for i, tx := range block.Transactions() {
|
||||
|
||||
@@ -71,6 +71,8 @@ var (
|
||||
justifiedBlockGauge = metrics.NewRegisteredGauge("chain/head/justified", nil)
|
||||
finalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
|
||||
|
||||
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
|
||||
|
||||
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
||||
|
||||
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
||||
|
||||
@@ -58,11 +58,13 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
|
||||
end := chain[index]
|
||||
|
||||
// Assemble the log context and send it to the logger
|
||||
mgasps := float64(st.usedGas) * 1000 / float64(elapsed)
|
||||
context := []interface{}{
|
||||
"number", end.Number(), "hash", end.Hash(), "miner", end.Coinbase(),
|
||||
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
|
||||
"elapsed", common.PrettyDuration(elapsed), "mgasps", float64(st.usedGas) * 1000 / float64(elapsed),
|
||||
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
|
||||
}
|
||||
blockInsertMgaspsGauge.Update(int64(mgasps))
|
||||
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
||||
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
||||
}
|
||||
|
||||
@@ -511,3 +511,12 @@ func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscr
|
||||
func (bc *BlockChain) SubscribeFinalizedHeaderEvent(ch chan<- FinalizedHeaderEvent) event.Subscription {
|
||||
return bc.scope.Track(bc.finalizedHeaderFeed.Subscribe(ch))
|
||||
}
|
||||
|
||||
// AncientTail retrieves the tail the ancients blocks
|
||||
func (bc *BlockChain) AncientTail() (uint64, error) {
|
||||
tail, err := bc.db.Tail()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return tail, nil
|
||||
}
|
||||
|
||||
@@ -216,10 +216,8 @@ func (e *GenesisMismatchError) Error() string {
|
||||
// ChainOverrides contains the changes to chain config
|
||||
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
||||
type ChainOverrides struct {
|
||||
OverrideCancun *uint64
|
||||
OverrideVerkle *uint64
|
||||
OverrideFeynman *uint64
|
||||
OverrideFeynmanFix *uint64
|
||||
OverrideCancun *uint64
|
||||
OverrideVerkle *uint64
|
||||
}
|
||||
|
||||
// SetupGenesisBlock writes or updates the genesis block in db.
|
||||
@@ -251,12 +249,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
||||
if overrides != nil && overrides.OverrideVerkle != nil {
|
||||
config.VerkleTime = overrides.OverrideVerkle
|
||||
}
|
||||
if overrides != nil && overrides.OverrideFeynman != nil {
|
||||
config.FeynmanTime = overrides.OverrideFeynman
|
||||
}
|
||||
if overrides != nil && overrides.OverrideFeynmanFix != nil {
|
||||
config.FeynmanFixTime = overrides.OverrideFeynmanFix
|
||||
}
|
||||
}
|
||||
}
|
||||
// Just commit the new block if there is no stored genesis block.
|
||||
|
||||
@@ -316,8 +316,8 @@ func ReadHeaderRange(db ethdb.Reader, number uint64, count uint64) []rlp.RawValu
|
||||
if count == 0 {
|
||||
return rlpHeaders
|
||||
}
|
||||
// read remaining from ancients
|
||||
data, err := db.AncientRange(ChainFreezerHeaderTable, i+1-count, count, 0)
|
||||
// read remaining from ancients, cap at 2M
|
||||
data, err := db.AncientRange(ChainFreezerHeaderTable, i+1-count, count, 2*1024*1024)
|
||||
if err != nil {
|
||||
log.Error("Failed to read headers from freezer", "err", err)
|
||||
return rlpHeaders
|
||||
|
||||
@@ -239,7 +239,7 @@ func (f *Freezer) Ancient(kind string, number uint64) ([]byte, error) {
|
||||
// - if maxBytes is not specified, 'count' items will be returned if they are present.
|
||||
func (f *Freezer) AncientRange(kind string, start, count, maxBytes uint64) ([][]byte, error) {
|
||||
if table := f.tables[kind]; table != nil {
|
||||
return table.RetrieveItems(start, count, maxBytes)
|
||||
return table.RetrieveItems(start-f.offset, count, maxBytes)
|
||||
}
|
||||
return nil, errUnknownTable
|
||||
}
|
||||
@@ -252,7 +252,7 @@ func (f *Freezer) Ancients() (uint64, error) {
|
||||
func (f *Freezer) TableAncients(kind string) (uint64, error) {
|
||||
f.writeLock.RLock()
|
||||
defer f.writeLock.RUnlock()
|
||||
return f.tables[kind].items.Load(), nil
|
||||
return f.tables[kind].items.Load() + f.offset, nil
|
||||
}
|
||||
|
||||
// ItemAmountInAncient returns the actual length of current ancientDB.
|
||||
|
||||
@@ -402,7 +402,7 @@ func (p *BlockPruner) backUpOldDb(name string, cache, handles int, namespace str
|
||||
|
||||
var oldOffSet uint64
|
||||
if interrupt {
|
||||
// The interrupt scecario within this function is specific for old and new ancientDB exsisted concurrently,
|
||||
// The interrupt scecario within this function is specific for old and new ancientDB existed concurrently,
|
||||
// should use last version of offset for oldAncientDB, because current offset is
|
||||
// actually of the new ancientDB_Backup, but what we want is the offset of ancientDB being backup.
|
||||
oldOffSet = rawdb.ReadOffSetOfLastAncientFreezer(chainDb)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -57,31 +57,3 @@ var (
|
||||
//go:embed chapel/TokenRecoverPortalContract
|
||||
ChapelTokenRecoverPortalContract string
|
||||
)
|
||||
|
||||
// contract codes for Rialto upgrade
|
||||
var (
|
||||
//go:embed rialto/ValidatorContract
|
||||
RialtoValidatorContract string
|
||||
//go:embed rialto/SlashContract
|
||||
RialtoSlashContract string
|
||||
//go:embed rialto/TokenHubContract
|
||||
RialtoTokenHubContract string
|
||||
//go:embed rialto/GovHubContract
|
||||
RialtoGovHubContract string
|
||||
//go:embed rialto/CrossChainContract
|
||||
RialtoCrossChainContract string
|
||||
//go:embed rialto/StakingContract
|
||||
RialtoStakingContract string
|
||||
//go:embed rialto/StakeHubContract
|
||||
RialtoStakeHubContract string
|
||||
//go:embed rialto/StakeCreditContract
|
||||
RialtoStakeCreditContract string
|
||||
//go:embed rialto/GovernorContract
|
||||
RialtoGovernorContract string
|
||||
//go:embed rialto/GovTokenContract
|
||||
RialtoGovTokenContract string
|
||||
//go:embed rialto/TimelockContract
|
||||
RialtoTimelockContract string
|
||||
//go:embed rialto/TokenRecoverPortalContract
|
||||
RialtoTokenRecoverPortalContract string
|
||||
)
|
||||
|
||||
@@ -680,72 +680,6 @@ func init() {
|
||||
},
|
||||
}
|
||||
|
||||
feynmanUpgrade[rialtoNet] = &Upgrade{
|
||||
UpgradeName: "feynman",
|
||||
Configs: []*UpgradeConfig{
|
||||
{
|
||||
ContractAddr: common.HexToAddress(ValidatorContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoValidatorContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(SlashContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoSlashContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(TokenHubContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoTokenHubContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(GovHubContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoGovHubContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(CrossChainContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoCrossChainContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(StakingContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoStakingContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(StakeHubContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoStakeHubContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(StakeCreditContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.MainnetStakeCreditContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(GovernorContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoGovernorContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(GovTokenContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.MainnetGovTokenContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(TimelockContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoTimelockContract,
|
||||
},
|
||||
{
|
||||
ContractAddr: common.HexToAddress(TokenRecoverPortalContract),
|
||||
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/2d6372ddba77902ef01e45887a425938376d5a5c",
|
||||
Code: feynman.RialtoTokenRecoverPortalContract,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// This upgrade is to fix an error on testnet only. So the upgrade config of mainnet is empty.
|
||||
feynmanFixUpgrade[mainNet] = &Upgrade{
|
||||
UpgradeName: "feynmanFix",
|
||||
@@ -767,11 +701,6 @@ func init() {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
feynmanFixUpgrade[rialtoNet] = &Upgrade{
|
||||
UpgradeName: "feynmanFix",
|
||||
Configs: []*UpgradeConfig{},
|
||||
}
|
||||
}
|
||||
|
||||
func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb *state.StateDB) {
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestAllCodesHash(t *testing.T) {
|
||||
|
||||
allCodes := make([]byte, 0, 10_000_000)
|
||||
for _, hardfork := range upgradesList {
|
||||
for _, network := range []string{mainNet, chapelNet, rialtoNet} {
|
||||
for _, network := range []string{mainNet, chapelNet} {
|
||||
allCodes = append(allCodes, []byte(network)...)
|
||||
if hardfork[network] != nil {
|
||||
for _, addressConfig := range hardfork[network].Configs {
|
||||
@@ -37,6 +37,5 @@ func TestAllCodesHash(t *testing.T) {
|
||||
}
|
||||
}
|
||||
allCodeHash := sha256.Sum256(allCodes)
|
||||
|
||||
require.Equal(t, allCodeHash[:], common.Hex2Bytes("3d68c07faa6b9385e981a45bd539f15d4cbb712426c604b9cab22591af446fc8"))
|
||||
require.Equal(t, allCodeHash[:], common.Hex2Bytes("833cc0fc87c46ad8a223e44ccfdc16a51a7e7383525136441bd0c730f06023df"))
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -305,6 +306,7 @@ type BlobPool struct {
|
||||
head *types.Header // Current head of the chain
|
||||
state *state.StateDB // Current state at the head of the chain
|
||||
gasTip *uint256.Int // Currently accepted minimum gas tip
|
||||
maxGas atomic.Uint64 // Currently accepted max gas, it will be modified by MinerAPI
|
||||
|
||||
lookup map[common.Hash]uint64 // Lookup table mapping hashes to tx billy entries
|
||||
index map[common.Address][]*blobTxMeta // Blob transactions grouped by accounts, sorted by nonce
|
||||
@@ -1098,6 +1100,7 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
|
||||
Accept: 1 << types.BlobTxType,
|
||||
MaxSize: txMaxSize,
|
||||
MinTip: p.gasTip.ToBig(),
|
||||
MaxGas: p.GetMaxGas(),
|
||||
}
|
||||
if err := txpool.ValidateTransaction(tx, p.head, p.signer, baseOpts); err != nil {
|
||||
return err
|
||||
@@ -1671,3 +1674,11 @@ func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus {
|
||||
}
|
||||
return txpool.TxStatusUnknown
|
||||
}
|
||||
|
||||
func (p *BlobPool) SetMaxGas(maxGas uint64) {
|
||||
p.maxGas.Store(maxGas)
|
||||
}
|
||||
|
||||
func (p *BlobPool) GetMaxGas() uint64 {
|
||||
return p.maxGas.Load()
|
||||
}
|
||||
|
||||
@@ -219,6 +219,7 @@ type LegacyPool struct {
|
||||
scope event.SubscriptionScope
|
||||
signer types.Signer
|
||||
mu sync.RWMutex
|
||||
maxGas atomic.Uint64 // Currently accepted max gas, it will be modified by MinerAPI
|
||||
|
||||
currentHead atomic.Pointer[types.Header] // Current head of the blockchain
|
||||
currentState *state.StateDB // Current state in the blockchain head
|
||||
@@ -670,6 +671,7 @@ func (pool *LegacyPool) validateTxBasics(tx *types.Transaction, local bool) erro
|
||||
1<<types.DynamicFeeTxType,
|
||||
MaxSize: txMaxSize,
|
||||
MinTip: pool.gasTip.Load().ToBig(),
|
||||
MaxGas: pool.GetMaxGas(),
|
||||
}
|
||||
if local {
|
||||
opts.MinTip = new(big.Int)
|
||||
@@ -1769,6 +1771,14 @@ func (pool *LegacyPool) demoteUnexecutables() {
|
||||
}
|
||||
}
|
||||
|
||||
func (pool *LegacyPool) GetMaxGas() uint64 {
|
||||
return pool.maxGas.Load()
|
||||
}
|
||||
|
||||
func (pool *LegacyPool) SetMaxGas(maxGas uint64) {
|
||||
pool.maxGas.Store(maxGas)
|
||||
}
|
||||
|
||||
// addressByHeartbeat is an account address tagged with its last activity timestamp.
|
||||
type addressByHeartbeat struct {
|
||||
address common.Address
|
||||
|
||||
@@ -166,4 +166,7 @@ type SubPool interface {
|
||||
// Status returns the known status (unknown/pending/queued) of a transaction
|
||||
// identified by their hashes.
|
||||
Status(hash common.Hash) TxStatus
|
||||
|
||||
// SetMaxGas limit max acceptable tx gas when mine is enabled
|
||||
SetMaxGas(maxGas uint64)
|
||||
}
|
||||
|
||||
@@ -284,6 +284,12 @@ func (p *TxPool) SetGasTip(tip *big.Int) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *TxPool) SetMaxGas(gas uint64) {
|
||||
for _, subpool := range p.subpools {
|
||||
subpool.SetMaxGas(gas)
|
||||
}
|
||||
}
|
||||
|
||||
// Has returns an indicator whether the pool has a transaction cached with the
|
||||
// given hash.
|
||||
func (p *TxPool) Has(hash common.Hash) bool {
|
||||
|
||||
@@ -45,6 +45,7 @@ type ValidationOptions struct {
|
||||
Accept uint8 // Bitmap of transaction types that should be accepted for the calling pool
|
||||
MaxSize uint64 // Maximum size of a transaction that the caller can meaningfully handle
|
||||
MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool
|
||||
MaxGas uint64 // Max acceptable transaction gas in the txpool
|
||||
}
|
||||
|
||||
// ValidateTransaction is a helper method to check whether a transaction is valid
|
||||
@@ -86,6 +87,12 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types
|
||||
if head.GasLimit < tx.Gas() {
|
||||
return ErrGasLimit
|
||||
}
|
||||
|
||||
// Ensure the transaction doesn't exceed the current miner max acceptable limit gas
|
||||
if opts.MaxGas > 0 && opts.MaxGas < tx.Gas() {
|
||||
return ErrGasLimit
|
||||
}
|
||||
|
||||
// Sanity check for extremely large numbers (supported by RLP or RPC)
|
||||
if tx.GasFeeCap().BitLen() > 256 {
|
||||
return core.ErrFeeCapVeryHigh
|
||||
|
||||
@@ -20,6 +20,8 @@ import (
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
@@ -71,6 +73,9 @@ func (api *MinerAPI) SetGasPrice(gasPrice hexutil.Big) bool {
|
||||
// SetGasLimit sets the gaslimit to target towards during mining.
|
||||
func (api *MinerAPI) SetGasLimit(gasLimit hexutil.Uint64) bool {
|
||||
api.e.Miner().SetGasCeil(uint64(gasLimit))
|
||||
if api.e.Miner().Mining() && uint64(gasLimit) > params.SystemTxsGas {
|
||||
api.e.TxPool().SetMaxGas(uint64(gasLimit) - params.SystemTxsGas)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -187,14 +187,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||
chainConfig.VerkleTime = config.OverrideVerkle
|
||||
overrides.OverrideVerkle = config.OverrideVerkle
|
||||
}
|
||||
if config.OverrideFeynman != nil {
|
||||
chainConfig.FeynmanTime = config.OverrideFeynman
|
||||
overrides.OverrideFeynman = config.OverrideFeynman
|
||||
}
|
||||
if config.OverrideFeynmanFix != nil {
|
||||
chainConfig.FeynmanFixTime = config.OverrideFeynmanFix
|
||||
overrides.OverrideFeynmanFix = config.OverrideFeynmanFix
|
||||
}
|
||||
|
||||
// startup ancient freeze
|
||||
if err = chainDb.SetupFreezerEnv(ðdb.FreezerEnv{
|
||||
|
||||
@@ -209,6 +209,9 @@ type BlockChain interface {
|
||||
|
||||
// UpdateChasingHead update remote best chain head, used by DA check now.
|
||||
UpdateChasingHead(head *types.Header)
|
||||
|
||||
// AncientTail retrieves the tail the ancients blocks
|
||||
AncientTail() (uint64, error)
|
||||
}
|
||||
|
||||
type DownloadOption func(downloader *Downloader) *Downloader
|
||||
@@ -797,6 +800,11 @@ func (d *Downloader) findAncestor(p *peerConnection, localHeight uint64, remoteH
|
||||
// We're above the max reorg threshold, find the earliest fork point
|
||||
floor = int64(localHeight - maxForkAncestry)
|
||||
}
|
||||
// if we have pruned too much history, reset the floor
|
||||
if tail, err := d.blockchain.AncientTail(); err == nil && tail > uint64(floor) {
|
||||
floor = int64(tail)
|
||||
}
|
||||
|
||||
// If we're doing a light sync, ensure the floor doesn't go below the CHT, as
|
||||
// all headers before that point will be missing.
|
||||
if mode == LightSync {
|
||||
|
||||
@@ -194,12 +194,6 @@ type Config struct {
|
||||
// OverrideVerkle (TODO: remove after the fork)
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
|
||||
// OverrideFeynman (TODO: remove after the fork)
|
||||
OverrideFeynman *uint64 `toml:",omitempty"`
|
||||
|
||||
// OverrideFeynmanFix (TODO: remove after the fork)
|
||||
OverrideFeynmanFix *uint64 `toml:",omitempty"`
|
||||
|
||||
// blob setting
|
||||
BlobExtraReserve uint64
|
||||
}
|
||||
|
||||
@@ -32,11 +32,12 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
EnableTrustProtocol bool
|
||||
PipeCommit bool
|
||||
RangeLimit bool
|
||||
TxLookupLimit uint64 `toml:",omitempty"`
|
||||
TransactionHistory uint64 `toml:",omitempty"`
|
||||
StateHistory uint64 `toml:",omitempty"`
|
||||
StateScheme string `toml:",omitempty"`
|
||||
PathSyncFlush bool `toml:",omitempty"`
|
||||
TxLookupLimit uint64 `toml:",omitempty"`
|
||||
TransactionHistory uint64 `toml:",omitempty"`
|
||||
StateHistory uint64 `toml:",omitempty"`
|
||||
StateScheme string `toml:",omitempty"`
|
||||
PathSyncFlush bool `toml:",omitempty"`
|
||||
JournalFileEnabled bool
|
||||
RequiredBlocks map[uint64]common.Hash `toml:"-"`
|
||||
LightServ int `toml:",omitempty"`
|
||||
LightIngress int `toml:",omitempty"`
|
||||
@@ -71,8 +72,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
RPCTxFeeCap float64
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
OverrideFeynman *uint64 `toml:",omitempty"`
|
||||
OverrideFeynmanFix *uint64 `toml:",omitempty"`
|
||||
BlobExtraReserve uint64
|
||||
}
|
||||
var enc Config
|
||||
enc.Genesis = c.Genesis
|
||||
@@ -95,6 +95,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.StateHistory = c.StateHistory
|
||||
enc.StateScheme = c.StateScheme
|
||||
enc.PathSyncFlush = c.PathSyncFlush
|
||||
enc.JournalFileEnabled = c.JournalFileEnabled
|
||||
enc.RequiredBlocks = c.RequiredBlocks
|
||||
enc.LightServ = c.LightServ
|
||||
enc.LightIngress = c.LightIngress
|
||||
@@ -129,8 +130,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
||||
enc.OverrideCancun = c.OverrideCancun
|
||||
enc.OverrideVerkle = c.OverrideVerkle
|
||||
enc.OverrideFeynman = c.OverrideFeynman
|
||||
enc.OverrideFeynmanFix = c.OverrideFeynmanFix
|
||||
enc.BlobExtraReserve = c.BlobExtraReserve
|
||||
return &enc, nil
|
||||
}
|
||||
|
||||
@@ -152,11 +152,12 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
EnableTrustProtocol *bool
|
||||
PipeCommit *bool
|
||||
RangeLimit *bool
|
||||
TxLookupLimit *uint64 `toml:",omitempty"`
|
||||
TransactionHistory *uint64 `toml:",omitempty"`
|
||||
StateHistory *uint64 `toml:",omitempty"`
|
||||
StateScheme *string `toml:",omitempty"`
|
||||
PathSyncFlush *bool `toml:",omitempty"`
|
||||
TxLookupLimit *uint64 `toml:",omitempty"`
|
||||
TransactionHistory *uint64 `toml:",omitempty"`
|
||||
StateHistory *uint64 `toml:",omitempty"`
|
||||
StateScheme *string `toml:",omitempty"`
|
||||
PathSyncFlush *bool `toml:",omitempty"`
|
||||
JournalFileEnabled *bool
|
||||
RequiredBlocks map[uint64]common.Hash `toml:"-"`
|
||||
LightServ *int `toml:",omitempty"`
|
||||
LightIngress *int `toml:",omitempty"`
|
||||
@@ -191,8 +192,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
RPCTxFeeCap *float64
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
OverrideFeynman *uint64 `toml:",omitempty"`
|
||||
OverrideFeynmanFix *uint64 `toml:",omitempty"`
|
||||
BlobExtraReserve *uint64
|
||||
}
|
||||
var dec Config
|
||||
if err := unmarshal(&dec); err != nil {
|
||||
@@ -258,6 +258,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.PathSyncFlush != nil {
|
||||
c.PathSyncFlush = *dec.PathSyncFlush
|
||||
}
|
||||
if dec.JournalFileEnabled != nil {
|
||||
c.JournalFileEnabled = *dec.JournalFileEnabled
|
||||
}
|
||||
if dec.RequiredBlocks != nil {
|
||||
c.RequiredBlocks = dec.RequiredBlocks
|
||||
}
|
||||
@@ -360,11 +363,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||
if dec.OverrideVerkle != nil {
|
||||
c.OverrideVerkle = dec.OverrideVerkle
|
||||
}
|
||||
if dec.OverrideFeynman != nil {
|
||||
c.OverrideFeynman = dec.OverrideFeynman
|
||||
}
|
||||
if dec.OverrideFeynmanFix != nil {
|
||||
c.OverrideFeynmanFix = dec.OverrideFeynmanFix
|
||||
if dec.BlobExtraReserve != nil {
|
||||
c.BlobExtraReserve = *dec.BlobExtraReserve
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
mapset "github.com/deckarep/golang-set/v2"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/prque"
|
||||
"github.com/ethereum/go-ethereum/consensus"
|
||||
@@ -66,6 +67,10 @@ var (
|
||||
headerFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/headers/out", nil)
|
||||
bodyFilterInMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/bodies/in", nil)
|
||||
bodyFilterOutMeter = metrics.NewRegisteredMeter("eth/fetcher/block/filter/bodies/out", nil)
|
||||
|
||||
blockInsertFailRecords = mapset.NewSet[common.Hash]()
|
||||
blockInsertFailRecordslimit = 1000
|
||||
blockInsertFailGauge = metrics.NewRegisteredGauge("chain/insert/failed", nil)
|
||||
)
|
||||
|
||||
var errTerminated = errors.New("terminated")
|
||||
@@ -934,6 +939,10 @@ func (f *BlockFetcher) importBlocks(op *blockOrHeaderInject) {
|
||||
}
|
||||
// Run the actual import and log any issues
|
||||
if _, err := f.insertChain(types.Blocks{block}); err != nil {
|
||||
if blockInsertFailRecords.Cardinality() < blockInsertFailRecordslimit {
|
||||
blockInsertFailRecords.Add(block.Hash())
|
||||
blockInsertFailGauge.Update(int64(blockInsertFailRecords.Cardinality()))
|
||||
}
|
||||
log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -44,6 +44,9 @@ var (
|
||||
// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
|
||||
const maxTopics = 4
|
||||
|
||||
// The maximum number of allowed topics within a topic criteria
|
||||
const maxSubTopics = 1000
|
||||
|
||||
// filter is a helper struct that holds meta information over the filter type
|
||||
// and associated subscription in the event system.
|
||||
type filter struct {
|
||||
@@ -671,6 +674,9 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
||||
return errors.New("invalid addresses in query")
|
||||
}
|
||||
}
|
||||
if len(raw.Topics) > maxTopics {
|
||||
return errExceedMaxTopics
|
||||
}
|
||||
|
||||
// topics is an array consisting of strings and/or arrays of strings.
|
||||
// JSON null values are converted to common.Hash{} and ignored by the filter manager.
|
||||
@@ -691,6 +697,9 @@ func (args *FilterCriteria) UnmarshalJSON(data []byte) error {
|
||||
|
||||
case []interface{}:
|
||||
// or case e.g. [null, "topic0", "topic1"]
|
||||
if len(topic) > maxSubTopics {
|
||||
return errExceedMaxTopics
|
||||
}
|
||||
for _, rawTopic := range topic {
|
||||
if rawTopic == nil {
|
||||
// null component, match all
|
||||
|
||||
@@ -318,7 +318,30 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||
}
|
||||
return h.chain.InsertChain(blocks)
|
||||
}
|
||||
h.blockFetcher = fetcher.NewBlockFetcher(false, nil, h.chain.GetBlockByHash, validator, h.BroadcastBlock,
|
||||
|
||||
broadcastBlockWithCheck := func(block *types.Block, propagate bool) {
|
||||
if propagate {
|
||||
checkErrs := make(chan error, 2)
|
||||
|
||||
go func() {
|
||||
checkErrs <- core.ValidateListsInBody(block)
|
||||
}()
|
||||
go func() {
|
||||
checkErrs <- core.IsDataAvailable(h.chain, block)
|
||||
}()
|
||||
|
||||
for i := 0; i < cap(checkErrs); i++ {
|
||||
err := <-checkErrs
|
||||
if err != nil {
|
||||
log.Error("Propagating invalid block", "number", block.Number(), "hash", block.Hash(), "err", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
h.BroadcastBlock(block, propagate)
|
||||
}
|
||||
|
||||
h.blockFetcher = fetcher.NewBlockFetcher(false, nil, h.chain.GetBlockByHash, validator, broadcastBlockWithCheck,
|
||||
heighter, finalizeHeighter, nil, inserter, h.removePeer)
|
||||
|
||||
fetchTx := func(peer string, hashes []common.Hash) error {
|
||||
|
||||
@@ -131,9 +131,9 @@ func (ec *Client) BlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumb
|
||||
}
|
||||
|
||||
// BlobSidecars return the Sidecars of a given block number or hash.
|
||||
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]*types.BlobTxSidecar, error) {
|
||||
func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, fullBlob bool) ([]*types.BlobTxSidecar, error) {
|
||||
var r []*types.BlobTxSidecar
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String())
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlobSidecars", blockNrOrHash.String(), fullBlob)
|
||||
if err == nil && r == nil {
|
||||
return nil, ethereum.NotFound
|
||||
}
|
||||
@@ -141,9 +141,9 @@ func (ec *Client) BlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumbe
|
||||
}
|
||||
|
||||
// BlobSidecarByTxHash return a sidecar of a given blob transaction
|
||||
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash) (*types.BlobTxSidecar, error) {
|
||||
func (ec *Client) BlobSidecarByTxHash(ctx context.Context, hash common.Hash, fullBlob bool) (*types.BlobTxSidecar, error) {
|
||||
var r *types.BlobTxSidecar
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlockSidecarByTxHash", hash)
|
||||
err := ec.c.CallContext(ctx, &r, "eth_getBlockSidecarByTxHash", hash, fullBlob)
|
||||
if err == nil && r == nil {
|
||||
return nil, ethereum.NotFound
|
||||
}
|
||||
|
||||
@@ -48,6 +48,9 @@ const (
|
||||
|
||||
// numLevels is the level number of pebble sst files
|
||||
numLevels = 7
|
||||
// degradationWarnInterval specifies how often warning should be printed if the
|
||||
// leveldb database cannot keep up with requested writes.
|
||||
degradationWarnInterval = time.Minute
|
||||
)
|
||||
|
||||
// Database is a persistent key-value store based on the pebble storage engine.
|
||||
@@ -79,14 +82,16 @@ type Database struct {
|
||||
|
||||
log log.Logger // Contextual logger tracking the database path
|
||||
|
||||
activeComp int // Current number of active compactions
|
||||
compStartTime time.Time // The start time of the earliest currently-active compaction
|
||||
compTime atomic.Int64 // Total time spent in compaction in ns
|
||||
level0Comp atomic.Uint32 // Total number of level-zero compactions
|
||||
nonLevel0Comp atomic.Uint32 // Total number of non level-zero compactions
|
||||
writeDelayStartTime time.Time // The start time of the latest write stall
|
||||
writeDelayCount atomic.Int64 // Total number of write stall counts
|
||||
writeDelayTime atomic.Int64 // Total time spent in write stalls
|
||||
activeComp int // Current number of active compactions
|
||||
compStartTime time.Time // The start time of the earliest currently-active compaction
|
||||
compTime atomic.Int64 // Total time spent in compaction in ns
|
||||
level0Comp atomic.Uint32 // Total number of level-zero compactions
|
||||
nonLevel0Comp atomic.Uint32 // Total number of non level-zero compactions
|
||||
|
||||
writeStalled atomic.Bool // Flag whether the write is stalled
|
||||
writeDelayStartTime time.Time // The start time of the latest write stall
|
||||
writeDelayCount atomic.Int64 // Total number of write stall counts
|
||||
writeDelayTime atomic.Int64 // Total time spent in write stalls
|
||||
|
||||
writeOptions *pebble.WriteOptions
|
||||
}
|
||||
@@ -115,10 +120,13 @@ func (d *Database) onCompactionEnd(info pebble.CompactionInfo) {
|
||||
|
||||
func (d *Database) onWriteStallBegin(b pebble.WriteStallBeginInfo) {
|
||||
d.writeDelayStartTime = time.Now()
|
||||
d.writeDelayCount.Add(1)
|
||||
d.writeStalled.Store(true)
|
||||
}
|
||||
|
||||
func (d *Database) onWriteStallEnd() {
|
||||
d.writeDelayTime.Add(int64(time.Since(d.writeDelayStartTime)))
|
||||
d.writeStalled.Store(false)
|
||||
}
|
||||
|
||||
// panicLogger is just a noop logger to disable Pebble's internal logger.
|
||||
@@ -461,13 +469,15 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
|
||||
|
||||
// Create storage and warning log tracer for write delay.
|
||||
var (
|
||||
compTimes [2]int64
|
||||
writeDelayTimes [2]int64
|
||||
writeDelayCounts [2]int64
|
||||
compWrites [2]int64
|
||||
compReads [2]int64
|
||||
compTimes [2]int64
|
||||
compWrites [2]int64
|
||||
compReads [2]int64
|
||||
|
||||
nWrites [2]int64
|
||||
|
||||
writeDelayTimes [2]int64
|
||||
writeDelayCounts [2]int64
|
||||
lastWriteStallReport time.Time
|
||||
)
|
||||
|
||||
// Iterate ad infinitum and collect the stats
|
||||
@@ -507,6 +517,13 @@ func (d *Database) meter(refresh time.Duration, namespace string) {
|
||||
if d.writeDelayMeter != nil {
|
||||
d.writeDelayMeter.Mark(writeDelayTimes[i%2] - writeDelayTimes[(i-1)%2])
|
||||
}
|
||||
// Print a warning log if writing has been stalled for a while. The log will
|
||||
// be printed per minute to avoid overwhelming users.
|
||||
if d.writeStalled.Load() && writeDelayCounts[i%2] == writeDelayCounts[(i-1)%2] &&
|
||||
time.Now().After(lastWriteStallReport.Add(degradationWarnInterval)) {
|
||||
d.log.Warn("Database compacting, degraded performance")
|
||||
lastWriteStallReport = time.Now()
|
||||
}
|
||||
if d.compTimeMeter != nil {
|
||||
d.compTimeMeter.Mark(compTimes[i%2] - compTimes[(i-1)%2])
|
||||
}
|
||||
@@ -600,8 +617,8 @@ func (b *batch) Reset() {
|
||||
func (b *batch) Replay(w ethdb.KeyValueWriter) error {
|
||||
reader := b.b.Reader()
|
||||
for {
|
||||
kind, k, v, ok := reader.Next()
|
||||
if !ok {
|
||||
kind, k, v, ok, err := reader.Next()
|
||||
if !ok || err != nil {
|
||||
break
|
||||
}
|
||||
// The (k,v) slices might be overwritten if the batch is reset/reused,
|
||||
|
||||
10
go.mod
10
go.mod
@@ -17,8 +17,8 @@ require (
|
||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2
|
||||
github.com/cespare/cp v1.1.1
|
||||
github.com/cloudflare/cloudflare-go v0.79.0
|
||||
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593
|
||||
github.com/cometbft/cometbft v0.37.0
|
||||
github.com/cockroachdb/pebble v1.1.0
|
||||
github.com/consensys/gnark-crypto v0.12.1
|
||||
github.com/crate-crypto/go-ipa v0.0.0-20231025140028-3c0104f4b233
|
||||
github.com/crate-crypto/go-kzg-4844 v0.7.0
|
||||
@@ -81,10 +81,10 @@ require (
|
||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3
|
||||
github.com/willf/bitset v1.1.3
|
||||
go.uber.org/automaxprocs v1.5.2
|
||||
golang.org/x/crypto v0.19.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/sys v0.17.0
|
||||
golang.org/x/sys v0.18.0
|
||||
golang.org/x/text v0.14.0
|
||||
golang.org/x/time v0.5.0
|
||||
golang.org/x/tools v0.18.0
|
||||
@@ -274,9 +274,9 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/mod v0.15.0 // indirect
|
||||
golang.org/x/net v0.21.0 // indirect
|
||||
golang.org/x/net v0.23.0 // indirect
|
||||
golang.org/x/oauth2 v0.16.0 // indirect
|
||||
golang.org/x/term v0.17.0 // indirect
|
||||
golang.org/x/term v0.18.0 // indirect
|
||||
google.golang.org/api v0.44.0 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 // indirect
|
||||
|
||||
20
go.sum
20
go.sum
@@ -275,8 +275,8 @@ github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZ
|
||||
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
|
||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
|
||||
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593 h1:aPEJyR4rPBvDmeyi+l/FS/VtA00IWvjeFvjen1m1l1A=
|
||||
github.com/cockroachdb/pebble v0.0.0-20230928194634-aa077af62593/go.mod h1:6hk1eMY/u5t+Cf18q5lFMUA1Rc+Sm5I6Ra1QuPyxXCo=
|
||||
github.com/cockroachdb/pebble v1.1.0 h1:pcFh8CdCIt2kmEpK0OIatq67Ln9uGDYY3d5XnE0LJG4=
|
||||
github.com/cockroachdb/pebble v1.1.0/go.mod h1:sEHm5NOXxyiAoKWhoFxT8xMgd/f3RA6qUqQ1BXKrh2E=
|
||||
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
|
||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||
@@ -1743,8 +1743,8 @@ golang.org/x/crypto v0.0.0-20210813211128-0a44fdfbc16e/go.mod h1:GvvjBRRGRdwPK5y
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
@@ -1857,8 +1857,8 @@ golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
golang.org/x/oauth2 v0.0.0-20170912212905-13449ad91cb2/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
@@ -2007,13 +2007,13 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -1010,7 +1010,7 @@ func (s *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *BlockChainAPI) GetBlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) {
|
||||
func (s *BlockChainAPI) GetBlobSidecars(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, fullBlob bool) ([]map[string]interface{}, error) {
|
||||
header, err := s.b.HeaderByNumberOrHash(ctx, blockNrOrHash)
|
||||
if header == nil || err != nil {
|
||||
// When the block doesn't exist, the RPC method should return JSON null
|
||||
@@ -1023,12 +1023,12 @@ func (s *BlockChainAPI) GetBlobSidecars(ctx context.Context, blockNrOrHash rpc.B
|
||||
}
|
||||
result := make([]map[string]interface{}, len(blobSidecars))
|
||||
for i, sidecar := range blobSidecars {
|
||||
result[i] = marshalBlobSidecar(sidecar)
|
||||
result[i] = marshalBlobSidecar(sidecar, fullBlob)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *BlockChainAPI) GetBlobSidecarByTxHash(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
||||
func (s *BlockChainAPI) GetBlobSidecarByTxHash(ctx context.Context, hash common.Hash, fullBlob bool) (map[string]interface{}, error) {
|
||||
txTarget, blockHash, _, Index := rawdb.ReadTransaction(s.b.ChainDb(), hash)
|
||||
if txTarget == nil {
|
||||
return nil, nil
|
||||
@@ -1045,7 +1045,7 @@ func (s *BlockChainAPI) GetBlobSidecarByTxHash(ctx context.Context, hash common.
|
||||
}
|
||||
for _, sidecar := range blobSidecars {
|
||||
if sidecar.TxIndex == Index {
|
||||
return marshalBlobSidecar(sidecar), nil
|
||||
return marshalBlobSidecar(sidecar, fullBlob), nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2142,13 +2142,31 @@ func marshalReceipt(receipt *types.Receipt, blockHash common.Hash, blockNumber u
|
||||
return fields
|
||||
}
|
||||
|
||||
func marshalBlobSidecar(sidecar *types.BlobSidecar) map[string]interface{} {
|
||||
func marshalBlobSidecar(sidecar *types.BlobSidecar, fullBlob bool) map[string]interface{} {
|
||||
fields := map[string]interface{}{
|
||||
"blockHash": sidecar.BlockHash,
|
||||
"blockNumber": hexutil.EncodeUint64(sidecar.BlockNumber.Uint64()),
|
||||
"txHash": sidecar.TxHash,
|
||||
"txIndex": hexutil.EncodeUint64(sidecar.TxIndex),
|
||||
"blobSidecar": sidecar.BlobTxSidecar,
|
||||
}
|
||||
fields["blobSidecar"] = marshalBlob(sidecar.BlobTxSidecar, fullBlob)
|
||||
return fields
|
||||
}
|
||||
|
||||
func marshalBlob(blobTxSidecar types.BlobTxSidecar, fullBlob bool) map[string]interface{} {
|
||||
fields := map[string]interface{}{
|
||||
"blobs": blobTxSidecar.Blobs,
|
||||
"commitments": blobTxSidecar.Commitments,
|
||||
"proofs": blobTxSidecar.Proofs,
|
||||
}
|
||||
if !fullBlob {
|
||||
var blobs []common.Hash
|
||||
for _, blob := range blobTxSidecar.Blobs {
|
||||
var value common.Hash
|
||||
copy(value[:], blob[:32])
|
||||
blobs = append(blobs, value)
|
||||
}
|
||||
fields["blobs"] = blobs
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -2139,48 +2139,63 @@ func TestRPCGetBlobSidecars(t *testing.T) {
|
||||
}
|
||||
|
||||
var testSuite = []struct {
|
||||
test rpc.BlockNumberOrHash
|
||||
file string
|
||||
test rpc.BlockNumberOrHash
|
||||
fullBlob bool
|
||||
file string
|
||||
}{
|
||||
// 1. block without any txs(number)
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithNumber(0),
|
||||
file: "number-1",
|
||||
test: rpc.BlockNumberOrHashWithNumber(0),
|
||||
fullBlob: true,
|
||||
file: "number-1",
|
||||
},
|
||||
// 2. earliest tag
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.EarliestBlockNumber),
|
||||
file: "tag-earliest",
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.EarliestBlockNumber),
|
||||
fullBlob: true,
|
||||
file: "tag-earliest",
|
||||
},
|
||||
// 3. latest tag
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber),
|
||||
file: "tag-latest",
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber),
|
||||
fullBlob: true,
|
||||
file: "tag-latest",
|
||||
},
|
||||
// 4. block is empty
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithHash(common.Hash{}, false),
|
||||
file: "hash-empty",
|
||||
test: rpc.BlockNumberOrHashWithHash(common.Hash{}, false),
|
||||
fullBlob: true,
|
||||
file: "hash-empty",
|
||||
},
|
||||
// 5. block is not found
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithHash(common.HexToHash("deadbeef"), false),
|
||||
file: "hash-notfound",
|
||||
test: rpc.BlockNumberOrHashWithHash(common.HexToHash("deadbeef"), false),
|
||||
fullBlob: true,
|
||||
file: "hash-notfound",
|
||||
},
|
||||
// 6. block is not found
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(genBlocks + 1)),
|
||||
file: "block-notfound",
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(genBlocks + 1)),
|
||||
fullBlob: true,
|
||||
file: "block-notfound",
|
||||
},
|
||||
// 7. block with blob tx
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(6)),
|
||||
file: "block-with-blob-tx",
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(6)),
|
||||
fullBlob: true,
|
||||
file: "block-with-blob-tx",
|
||||
},
|
||||
// 8. block with sidecar
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(7)),
|
||||
file: "block-with-blobSidecars",
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(7)),
|
||||
fullBlob: true,
|
||||
file: "block-with-blobSidecars",
|
||||
},
|
||||
// 9. block with sidecar but show little
|
||||
{
|
||||
test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(7)),
|
||||
fullBlob: false,
|
||||
file: "block-with-blobSidecars-show-little",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2189,7 +2204,7 @@ func TestRPCGetBlobSidecars(t *testing.T) {
|
||||
result interface{}
|
||||
err error
|
||||
)
|
||||
result, err = api.GetBlobSidecars(context.Background(), tt.test)
|
||||
result, err = api.GetBlobSidecars(context.Background(), tt.test, tt.fullBlob)
|
||||
if err != nil {
|
||||
t.Errorf("test %d: want no error, have %v", i, err)
|
||||
continue
|
||||
@@ -2205,33 +2220,45 @@ func TestGetBlobSidecarByTxHash(t *testing.T) {
|
||||
api = NewBlockChainAPI(backend)
|
||||
)
|
||||
var testSuite = []struct {
|
||||
test common.Hash
|
||||
file string
|
||||
test common.Hash
|
||||
fullBlob bool
|
||||
file string
|
||||
}{
|
||||
// 0. txHash is empty
|
||||
{
|
||||
test: common.Hash{},
|
||||
file: "hash-empty",
|
||||
test: common.Hash{},
|
||||
fullBlob: true,
|
||||
file: "hash-empty",
|
||||
},
|
||||
// 1. txHash is not found
|
||||
{
|
||||
test: common.HexToHash("deadbeef"),
|
||||
file: "hash-notfound",
|
||||
test: common.HexToHash("deadbeef"),
|
||||
fullBlob: true,
|
||||
file: "hash-notfound",
|
||||
},
|
||||
// 2. txHash is not blob tx
|
||||
{
|
||||
test: common.HexToHash("deadbeef"),
|
||||
file: "not-blob-tx",
|
||||
test: common.HexToHash("deadbeef"),
|
||||
fullBlob: true,
|
||||
file: "not-blob-tx",
|
||||
},
|
||||
// 3. block with blob tx without sidecar
|
||||
{
|
||||
test: txHashs[5],
|
||||
file: "block-with-blob-tx",
|
||||
test: txHashs[5],
|
||||
fullBlob: true,
|
||||
file: "block-with-blob-tx",
|
||||
},
|
||||
// 4. block with sidecar
|
||||
{
|
||||
test: txHashs[6],
|
||||
file: "block-with-blobSidecars",
|
||||
test: txHashs[6],
|
||||
fullBlob: true,
|
||||
file: "block-with-blobSidecars",
|
||||
},
|
||||
// 4. block show part blobs
|
||||
{
|
||||
test: txHashs[6],
|
||||
fullBlob: false,
|
||||
file: "block-with-blobSidecars-show-little",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2240,7 +2267,7 @@ func TestGetBlobSidecarByTxHash(t *testing.T) {
|
||||
result interface{}
|
||||
err error
|
||||
)
|
||||
result, err = api.GetBlobSidecarByTxHash(context.Background(), tt.test)
|
||||
result, err = api.GetBlobSidecarByTxHash(context.Background(), tt.test, tt.fullBlob)
|
||||
if err != nil {
|
||||
t.Errorf("test %d: want no error, have %v", i, err)
|
||||
continue
|
||||
|
||||
17
internal/ethapi/testdata/eth_getBlobSidecarByTxHash-block-with-blobSidecars-show-little.json
vendored
Normal file
17
internal/ethapi/testdata/eth_getBlobSidecarByTxHash-block-with-blobSidecars-show-little.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"blobSidecar": {
|
||||
"blobs": [
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"commitments": [
|
||||
"0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"proofs": [
|
||||
"0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
]
|
||||
},
|
||||
"blockHash": "0x6fe5e7eea22c44f700c95da066d6e0740894b6c1e993825cc63f634ad4f74250",
|
||||
"blockNumber": "0x7",
|
||||
"txHash": "0xc520427e696154779f6b21ab03a0735769e1c029035a484f5876f60383a0a7ce",
|
||||
"txIndex": "0x0"
|
||||
}
|
||||
19
internal/ethapi/testdata/eth_getBlobSidecars-block-with-blobSidecars-show-little.json
vendored
Normal file
19
internal/ethapi/testdata/eth_getBlobSidecars-block-with-blobSidecars-show-little.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
[
|
||||
{
|
||||
"blobSidecar": {
|
||||
"blobs": [
|
||||
"0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"commitments": [
|
||||
"0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
],
|
||||
"proofs": [
|
||||
"0xc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||
]
|
||||
},
|
||||
"blockHash": "0x6fe5e7eea22c44f700c95da066d6e0740894b6c1e993825cc63f634ad4f74250",
|
||||
"blockNumber": "0x7",
|
||||
"txHash": "0xc520427e696154779f6b21ab03a0735769e1c029035a484f5876f60383a0a7ce",
|
||||
"txIndex": "0x0"
|
||||
}
|
||||
]
|
||||
@@ -617,12 +617,12 @@ web3._extend({
|
||||
new web3._extend.Method({
|
||||
name: 'getBlobSidecars',
|
||||
call: 'eth_getBlobSidecars',
|
||||
params: 1,
|
||||
params: 2,
|
||||
}),
|
||||
new web3._extend.Method({
|
||||
name: 'getBlobSidecarByTxHash',
|
||||
call: 'eth_getBlobSidecarByTxHash',
|
||||
params: 1,
|
||||
params: 2,
|
||||
}),
|
||||
],
|
||||
properties: [
|
||||
|
||||
@@ -295,3 +295,7 @@ func (miner *Miner) SubscribePendingLogs(ch chan<- []*types.Log) event.Subscript
|
||||
func (miner *Miner) BuildPayload(args *BuildPayloadArgs) (*Payload, error) {
|
||||
return miner.worker.buildPayload(args)
|
||||
}
|
||||
|
||||
func (miner *Miner) GasCeil() uint64 {
|
||||
return miner.worker.getGasCeil()
|
||||
}
|
||||
|
||||
@@ -329,6 +329,12 @@ func (w *worker) setGasCeil(ceil uint64) {
|
||||
w.config.GasCeil = ceil
|
||||
}
|
||||
|
||||
func (w *worker) getGasCeil() uint64 {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
return w.config.GasCeil
|
||||
}
|
||||
|
||||
// setExtra sets the content used to initialize the block extra field.
|
||||
func (w *worker) setExtra(extra []byte) {
|
||||
w.mu.Lock()
|
||||
|
||||
@@ -147,13 +147,11 @@ var (
|
||||
LondonBlock: big.NewInt(31302048),
|
||||
HertzBlock: big.NewInt(31302048),
|
||||
HertzfixBlock: big.NewInt(34140700),
|
||||
// UnixTime: 1705996800 is January 23, 2024 8:00:00 AM UTC
|
||||
ShanghaiTime: newUint64(1705996800),
|
||||
KeplerTime: newUint64(1705996800),
|
||||
FeynmanTime: newUint64(1713419340),
|
||||
FeynmanFixTime: newUint64(1713419340),
|
||||
// TODO(GalaIO): enable cancun fork time later
|
||||
//CancunTime: newUint64(),
|
||||
ShanghaiTime: newUint64(1705996800), // 2024-01-23 08:00:00 AM UTC
|
||||
KeplerTime: newUint64(1705996800), // 2024-01-23 08:00:00 AM UTC
|
||||
FeynmanTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
|
||||
FeynmanFixTime: newUint64(1713419340), // 2024-04-18 05:49:00 AM UTC
|
||||
CancunTime: newUint64(1718863500), // 2024-06-20 06:05:00 AM UTC
|
||||
|
||||
Parlia: &ParliaConfig{
|
||||
Period: 3,
|
||||
|
||||
@@ -189,6 +189,7 @@ const (
|
||||
var (
|
||||
MinBlocksForBlobRequests uint64 = 524288 // it keeps blob data available for ~18.2 days in local, ref: https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-336.md#51-parameters.
|
||||
DefaultExtraReserveForBlobRequests uint64 = 1 * (24 * 3600) / 3 // it adds more time for expired blobs for some request cases, like expiry blob when remote peer is syncing, default 1 day.
|
||||
BreatheBlockInterval uint64 = 86400 // Controls the interval for updateValidatorSetV2
|
||||
)
|
||||
|
||||
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
const (
|
||||
VersionMajor = 1 // Major version component of the current release
|
||||
VersionMinor = 4 // Minor version component of the current release
|
||||
VersionPatch = 6 // Patch version component of the current release
|
||||
VersionPatch = 7 // Patch version component of the current release
|
||||
VersionMeta = "" // Version metadata to append to the version string
|
||||
)
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ func (h2p *Hbss2Pbss) ConcurrentTraversal(theTrie *Trie, theNode node, path []by
|
||||
}
|
||||
}
|
||||
|
||||
// copy from trie/Commiter (*committer).commit
|
||||
// copy from trie/Committer (*committer).commit
|
||||
func (h2p *Hbss2Pbss) commitChildren(path []byte, n *fullNode) [17]node {
|
||||
var children [17]node
|
||||
for i := 0; i < 16; i++ {
|
||||
|
||||
@@ -4,17 +4,15 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/mclock"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
@@ -26,63 +24,113 @@ import (
|
||||
"golang.org/x/sync/semaphore"
|
||||
)
|
||||
|
||||
type Account struct {
|
||||
Nonce uint64
|
||||
Balance *big.Int
|
||||
Root common.Hash // merkle root of the storage trie
|
||||
CodeHash []byte
|
||||
}
|
||||
|
||||
type Database interface {
|
||||
database.Database
|
||||
Scheme() string
|
||||
Cap(limit common.StorageSize) error
|
||||
DiskDB() ethdb.Database
|
||||
}
|
||||
|
||||
const TopN = 3
|
||||
|
||||
type Inspector struct {
|
||||
trie *Trie // traverse trie
|
||||
db Database
|
||||
stateRootHash common.Hash
|
||||
blocknum uint64
|
||||
blockNum uint64
|
||||
root node // root of triedb
|
||||
totalNum uint64
|
||||
wg sync.WaitGroup
|
||||
statLock sync.RWMutex
|
||||
result map[string]*TrieTreeStat
|
||||
sem *semaphore.Weighted
|
||||
eoaAccountNums uint64
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
results stat
|
||||
topN int
|
||||
|
||||
totalAccountNum atomic.Uint64
|
||||
totalStorageNum atomic.Uint64
|
||||
lastTime mclock.AbsTime
|
||||
}
|
||||
|
||||
type TrieTreeStat struct {
|
||||
is_account_trie bool
|
||||
theNodeStatByLevel [15]NodeStat
|
||||
totalNodeStat NodeStat
|
||||
type stat struct {
|
||||
lock sync.RWMutex
|
||||
account *trieStat
|
||||
storageTopN []*trieStat
|
||||
storageTopNTotal []uint64
|
||||
storageTotal nodeStat
|
||||
storageTrieNum uint64
|
||||
}
|
||||
|
||||
type NodeStat struct {
|
||||
ShortNodeCnt uint64
|
||||
FullNodeCnt uint64
|
||||
ValueNodeCnt uint64
|
||||
type trieStat struct {
|
||||
owner common.Hash
|
||||
totalNodeStat nodeStat
|
||||
nodeStatByLevel [16]nodeStat
|
||||
}
|
||||
|
||||
func (trieStat *TrieTreeStat) AtomicAdd(theNode node, height uint32) {
|
||||
type nodeStat struct {
|
||||
ShortNodeCnt atomic.Uint64
|
||||
FullNodeCnt atomic.Uint64
|
||||
ValueNodeCnt atomic.Uint64
|
||||
}
|
||||
|
||||
func (ns *nodeStat) IsEmpty() bool {
|
||||
if ns.FullNodeCnt.Load() == 0 && ns.ShortNodeCnt.Load() == 0 && ns.ValueNodeCnt.Load() == 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *stat) add(ts *trieStat, topN int) {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
if ts.owner == (common.Hash{}) {
|
||||
s.account = ts
|
||||
return
|
||||
}
|
||||
|
||||
total := ts.totalNodeStat.ValueNodeCnt.Load() + ts.totalNodeStat.FullNodeCnt.Load() + ts.totalNodeStat.ShortNodeCnt.Load()
|
||||
if len(s.storageTopNTotal) == 0 || total > s.storageTopNTotal[len(s.storageTopNTotal)-1] {
|
||||
var (
|
||||
i int
|
||||
t uint64
|
||||
)
|
||||
for i, t = range s.storageTopNTotal {
|
||||
if total < t {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
s.storageTopNTotal = append(s.storageTopNTotal[:i], append([]uint64{total}, s.storageTopNTotal[i:]...)...)
|
||||
s.storageTopN = append(s.storageTopN[:i], append([]*trieStat{ts}, s.storageTopN[i:]...)...)
|
||||
if len(s.storageTopN) > topN {
|
||||
s.storageTopNTotal = s.storageTopNTotal[:topN]
|
||||
s.storageTopN = s.storageTopN[:topN]
|
||||
}
|
||||
}
|
||||
|
||||
s.storageTotal.ShortNodeCnt.Add(ts.totalNodeStat.ShortNodeCnt.Load())
|
||||
s.storageTotal.ValueNodeCnt.Add(ts.totalNodeStat.ValueNodeCnt.Load())
|
||||
s.storageTotal.FullNodeCnt.Add(ts.totalNodeStat.FullNodeCnt.Load())
|
||||
s.storageTrieNum++
|
||||
}
|
||||
|
||||
func (trieStat *trieStat) add(theNode node, height int) {
|
||||
switch (theNode).(type) {
|
||||
case *shortNode:
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.ShortNodeCnt, 1)
|
||||
atomic.AddUint64(&(trieStat.theNodeStatByLevel[height].ShortNodeCnt), 1)
|
||||
trieStat.totalNodeStat.ShortNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].ShortNodeCnt.Add(1)
|
||||
case *fullNode:
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.FullNodeCnt, 1)
|
||||
atomic.AddUint64(&trieStat.theNodeStatByLevel[height].FullNodeCnt, 1)
|
||||
trieStat.totalNodeStat.FullNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].FullNodeCnt.Add(1)
|
||||
case valueNode:
|
||||
atomic.AddUint64(&trieStat.totalNodeStat.ValueNodeCnt, 1)
|
||||
atomic.AddUint64(&((trieStat.theNodeStatByLevel[height]).ValueNodeCnt), 1)
|
||||
default:
|
||||
panic(errors.New("Invalid node type to statistics"))
|
||||
trieStat.totalNodeStat.ValueNodeCnt.Add(1)
|
||||
trieStat.nodeStatByLevel[height].ValueNodeCnt.Add(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) {
|
||||
table := tablewriter.NewWriter(os.Stdout)
|
||||
func (trieStat *trieStat) Display(ownerAddress string, treeType string) string {
|
||||
sw := new(strings.Builder)
|
||||
table := tablewriter.NewWriter(sw)
|
||||
table.SetHeader([]string{"-", "Level", "ShortNodeCnt", "FullNodeCnt", "ValueNodeCnt"})
|
||||
if ownerAddress == "" {
|
||||
table.SetCaption(true, fmt.Sprintf("%v", treeType))
|
||||
@@ -90,38 +138,27 @@ func (trieStat *TrieTreeStat) Display(ownerAddress string, treeType string) {
|
||||
table.SetCaption(true, fmt.Sprintf("%v-%v", treeType, ownerAddress))
|
||||
}
|
||||
table.SetAlignment(1)
|
||||
for i := 0; i < len(trieStat.theNodeStatByLevel); i++ {
|
||||
nodeStat := trieStat.theNodeStatByLevel[i]
|
||||
if nodeStat.FullNodeCnt == 0 && nodeStat.ShortNodeCnt == 0 && nodeStat.ValueNodeCnt == 0 {
|
||||
break
|
||||
|
||||
for i := range trieStat.nodeStatByLevel {
|
||||
if trieStat.nodeStatByLevel[i].IsEmpty() {
|
||||
continue
|
||||
}
|
||||
table.AppendBulk([][]string{
|
||||
{"-", strconv.Itoa(i), nodeStat.ShortNodeCount(), nodeStat.FullNodeCount(), nodeStat.ValueNodeCount()},
|
||||
{"-", fmt.Sprintf("%d", i),
|
||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ShortNodeCnt.Load()),
|
||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].FullNodeCnt.Load()),
|
||||
fmt.Sprintf("%d", trieStat.nodeStatByLevel[i].ValueNodeCnt.Load())},
|
||||
})
|
||||
}
|
||||
table.AppendBulk([][]string{
|
||||
{"Total", "-", trieStat.totalNodeStat.ShortNodeCount(), trieStat.totalNodeStat.FullNodeCount(), trieStat.totalNodeStat.ValueNodeCount()},
|
||||
{"Total", "-", fmt.Sprintf("%d", trieStat.totalNodeStat.ShortNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.FullNodeCnt.Load()), fmt.Sprintf("%d", trieStat.totalNodeStat.ValueNodeCnt.Load())},
|
||||
})
|
||||
table.Render()
|
||||
}
|
||||
|
||||
func Uint64ToString(cnt uint64) string {
|
||||
return fmt.Sprintf("%v", cnt)
|
||||
}
|
||||
|
||||
func (nodeStat *NodeStat) ShortNodeCount() string {
|
||||
return Uint64ToString(nodeStat.ShortNodeCnt)
|
||||
}
|
||||
|
||||
func (nodeStat *NodeStat) FullNodeCount() string {
|
||||
return Uint64ToString(nodeStat.FullNodeCnt)
|
||||
}
|
||||
func (nodeStat *NodeStat) ValueNodeCount() string {
|
||||
return Uint64ToString(nodeStat.ValueNodeCnt)
|
||||
return sw.String()
|
||||
}
|
||||
|
||||
// NewInspector return a inspector obj
|
||||
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uint64, jobnum uint64) (*Inspector, error) {
|
||||
func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blockNum uint64, jobNum uint64, topN int) (*Inspector, error) {
|
||||
if tr == nil {
|
||||
return nil, errors.New("trie is nil")
|
||||
}
|
||||
@@ -131,15 +168,20 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uin
|
||||
}
|
||||
|
||||
ins := &Inspector{
|
||||
trie: tr,
|
||||
db: db,
|
||||
stateRootHash: stateRootHash,
|
||||
blocknum: blocknum,
|
||||
root: tr.root,
|
||||
result: make(map[string]*TrieTreeStat),
|
||||
totalNum: (uint64)(0),
|
||||
wg: sync.WaitGroup{},
|
||||
sem: semaphore.NewWeighted(int64(jobnum)),
|
||||
trie: tr,
|
||||
db: db,
|
||||
stateRootHash: stateRootHash,
|
||||
blockNum: blockNum,
|
||||
root: tr.root,
|
||||
results: stat{},
|
||||
topN: topN,
|
||||
totalAccountNum: atomic.Uint64{},
|
||||
totalStorageNum: atomic.Uint64{},
|
||||
lastTime: mclock.Now(),
|
||||
sem: semaphore.NewWeighted(int64(jobNum)),
|
||||
|
||||
wg: sync.WaitGroup{},
|
||||
|
||||
eoaAccountNums: 0,
|
||||
}
|
||||
|
||||
@@ -147,155 +189,123 @@ func NewInspector(tr *Trie, db Database, stateRootHash common.Hash, blocknum uin
|
||||
}
|
||||
|
||||
// Run statistics, external call
|
||||
func (inspect *Inspector) Run() {
|
||||
accountTrieStat := &TrieTreeStat{
|
||||
is_account_trie: true,
|
||||
}
|
||||
if inspect.db.Scheme() == rawdb.HashScheme {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
inspect.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
|
||||
func (s *Inspector) Run() {
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
go func() {
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
if s.db.Scheme() == rawdb.HashScheme {
|
||||
s.db.Cap(DEFAULT_TRIEDBCACHE_SIZE)
|
||||
}
|
||||
}()
|
||||
}
|
||||
runtime.GC()
|
||||
}
|
||||
}()
|
||||
|
||||
if _, ok := inspect.result[""]; !ok {
|
||||
inspect.result[""] = accountTrieStat
|
||||
}
|
||||
log.Info("Find Account Trie Tree", "rootHash: ", inspect.trie.Hash().String(), "BlockNum: ", inspect.blocknum)
|
||||
log.Info("Find Account Trie Tree", "rootHash: ", s.trie.Hash().String(), "BlockNum: ", s.blockNum)
|
||||
|
||||
inspect.ConcurrentTraversal(inspect.trie, accountTrieStat, inspect.root, 0, []byte{})
|
||||
inspect.wg.Wait()
|
||||
ts := &trieStat{
|
||||
owner: common.Hash{},
|
||||
}
|
||||
s.traversal(s.trie, ts, s.root, 0, []byte{})
|
||||
s.results.add(ts, s.topN)
|
||||
s.wg.Wait()
|
||||
}
|
||||
|
||||
func (inspect *Inspector) SubConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) {
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, theNode, height, path)
|
||||
inspect.wg.Done()
|
||||
}
|
||||
|
||||
func (inspect *Inspector) ConcurrentTraversal(theTrie *Trie, theTrieTreeStat *TrieTreeStat, theNode node, height uint32, path []byte) {
|
||||
// print process progress
|
||||
total_num := atomic.AddUint64(&inspect.totalNum, 1)
|
||||
if total_num%100000 == 0 {
|
||||
fmt.Printf("Complete progress: %v, go routines Num: %v\n", total_num, runtime.NumGoroutine())
|
||||
}
|
||||
|
||||
func (s *Inspector) traversal(trie *Trie, ts *trieStat, n node, height int, path []byte) {
|
||||
// nil node
|
||||
if theNode == nil {
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
|
||||
switch current := (theNode).(type) {
|
||||
ts.add(n, height)
|
||||
|
||||
switch current := (n).(type) {
|
||||
case *shortNode:
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, current.Val, height, append(path, current.Key...))
|
||||
s.traversal(trie, ts, current.Val, height, append(path, current.Key...))
|
||||
case *fullNode:
|
||||
for idx, child := range current.Children {
|
||||
if child == nil {
|
||||
continue
|
||||
}
|
||||
childPath := append(path, byte(idx))
|
||||
if inspect.sem.TryAcquire(1) {
|
||||
inspect.wg.Add(1)
|
||||
dst := make([]byte, len(childPath))
|
||||
copy(dst, childPath)
|
||||
go inspect.SubConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, dst)
|
||||
} else {
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, child, height+1, childPath)
|
||||
}
|
||||
p := common.CopyBytes(append(path, byte(idx)))
|
||||
s.traversal(trie, ts, child, height+1, p)
|
||||
}
|
||||
case hashNode:
|
||||
n, err := theTrie.resloveWithoutTrack(current, path)
|
||||
tn, err := trie.resloveWithoutTrack(current, path)
|
||||
if err != nil {
|
||||
fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, theTrie.Hash().String(), height+1, path)
|
||||
fmt.Printf("Resolve HashNode error: %v, TrieRoot: %v, Height: %v, Path: %v\n", err, trie.Hash().String(), height+1, path)
|
||||
return
|
||||
}
|
||||
inspect.ConcurrentTraversal(theTrie, theTrieTreeStat, n, height, path)
|
||||
return
|
||||
s.PrintProgress(trie)
|
||||
s.traversal(trie, ts, tn, height, path)
|
||||
case valueNode:
|
||||
if !hasTerm(path) {
|
||||
break
|
||||
}
|
||||
var account Account
|
||||
var account types.StateAccount
|
||||
if err := rlp.Decode(bytes.NewReader(current), &account); err != nil {
|
||||
break
|
||||
}
|
||||
if common.BytesToHash(account.CodeHash) == types.EmptyCodeHash {
|
||||
inspect.eoaAccountNums++
|
||||
s.eoaAccountNums++
|
||||
}
|
||||
if account.Root == (common.Hash{}) || account.Root == types.EmptyRootHash {
|
||||
break
|
||||
}
|
||||
ownerAddress := common.BytesToHash(hexToCompact(path))
|
||||
contractTrie, err := New(StorageTrieID(inspect.stateRootHash, ownerAddress, account.Root), inspect.db)
|
||||
contractTrie, err := New(StorageTrieID(s.stateRootHash, ownerAddress, account.Root), s.db)
|
||||
if err != nil {
|
||||
fmt.Printf("New contract trie node: %v, error: %v, Height: %v, Path: %v\n", theNode, err, height, path)
|
||||
break
|
||||
panic(err)
|
||||
}
|
||||
contractTrie.tracer.reset()
|
||||
trieStat := &TrieTreeStat{
|
||||
is_account_trie: false,
|
||||
}
|
||||
|
||||
inspect.statLock.Lock()
|
||||
if _, ok := inspect.result[ownerAddress.String()]; !ok {
|
||||
inspect.result[ownerAddress.String()] = trieStat
|
||||
if s.sem.TryAcquire(1) {
|
||||
s.wg.Add(1)
|
||||
go func() {
|
||||
t := &trieStat{
|
||||
owner: ownerAddress,
|
||||
}
|
||||
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
|
||||
s.results.add(t, s.topN)
|
||||
s.sem.Release(1)
|
||||
s.wg.Done()
|
||||
}()
|
||||
} else {
|
||||
t := &trieStat{
|
||||
owner: ownerAddress,
|
||||
}
|
||||
s.traversal(contractTrie, t, contractTrie.root, 0, []byte{})
|
||||
s.results.add(t, s.topN)
|
||||
}
|
||||
inspect.statLock.Unlock()
|
||||
|
||||
// log.Info("Find Contract Trie Tree, rootHash: ", contractTrie.Hash().String(), "")
|
||||
inspect.wg.Add(1)
|
||||
go inspect.SubConcurrentTraversal(contractTrie, trieStat, contractTrie.root, 0, []byte{})
|
||||
default:
|
||||
panic(errors.New("Invalid node type to traverse."))
|
||||
panic(errors.New("invalid node type to traverse"))
|
||||
}
|
||||
theTrieTreeStat.AtomicAdd(theNode, height)
|
||||
}
|
||||
|
||||
func (inspect *Inspector) DisplayResult() {
|
||||
func (s *Inspector) PrintProgress(t *Trie) {
|
||||
var (
|
||||
elapsed = mclock.Now().Sub(s.lastTime)
|
||||
)
|
||||
if t.owner == (common.Hash{}) {
|
||||
s.totalAccountNum.Add(1)
|
||||
} else {
|
||||
s.totalStorageNum.Add(1)
|
||||
}
|
||||
if elapsed > 4*time.Second {
|
||||
log.Info("traversal progress", "TotalAccountNum", s.totalAccountNum.Load(), "TotalStorageNum", s.totalStorageNum.Load(), "Goroutine", runtime.NumGoroutine())
|
||||
s.lastTime = mclock.Now()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Inspector) DisplayResult() {
|
||||
// display root hash
|
||||
if _, ok := inspect.result[""]; !ok {
|
||||
log.Info("Display result error", "missing account trie")
|
||||
return
|
||||
}
|
||||
inspect.result[""].Display("", "AccountTrie")
|
||||
fmt.Println(s.results.account.Display("", "AccountTrie"))
|
||||
fmt.Println("EOA accounts num: ", s.eoaAccountNums)
|
||||
|
||||
type SortedTrie struct {
|
||||
totalNum uint64
|
||||
ownerAddress string
|
||||
}
|
||||
// display contract trie
|
||||
var sortedTriesByNums []SortedTrie
|
||||
var totalContactsNodeStat NodeStat
|
||||
var contractTrieCnt uint64 = 0
|
||||
|
||||
for ownerAddress, stat := range inspect.result {
|
||||
if ownerAddress == "" {
|
||||
continue
|
||||
}
|
||||
contractTrieCnt++
|
||||
totalContactsNodeStat.ShortNodeCnt += stat.totalNodeStat.ShortNodeCnt
|
||||
totalContactsNodeStat.FullNodeCnt += stat.totalNodeStat.FullNodeCnt
|
||||
totalContactsNodeStat.ValueNodeCnt += stat.totalNodeStat.ValueNodeCnt
|
||||
totalNodeCnt := stat.totalNodeStat.ShortNodeCnt + stat.totalNodeStat.ValueNodeCnt + stat.totalNodeStat.FullNodeCnt
|
||||
sortedTriesByNums = append(sortedTriesByNums, SortedTrie{totalNum: totalNodeCnt, ownerAddress: ownerAddress})
|
||||
}
|
||||
sort.Slice(sortedTriesByNums, func(i, j int) bool {
|
||||
return sortedTriesByNums[i].totalNum > sortedTriesByNums[j].totalNum
|
||||
})
|
||||
fmt.Println("EOA accounts num: ", inspect.eoaAccountNums)
|
||||
// only display top 5
|
||||
for i, t := range sortedTriesByNums {
|
||||
if i > 5 {
|
||||
break
|
||||
}
|
||||
if stat, ok := inspect.result[t.ownerAddress]; !ok {
|
||||
log.Error("Storage trie stat not found", "ownerAddress", t.ownerAddress)
|
||||
} else {
|
||||
stat.Display(t.ownerAddress, "ContractTrie")
|
||||
}
|
||||
for _, st := range s.results.storageTopN {
|
||||
fmt.Println(st.Display(st.owner.String(), "StorageTrie"))
|
||||
}
|
||||
fmt.Printf("Contract Trie, total trie num: %v, ShortNodeCnt: %v, FullNodeCnt: %v, ValueNodeCnt: %v\n",
|
||||
contractTrieCnt, totalContactsNodeStat.ShortNodeCnt, totalContactsNodeStat.FullNodeCnt, totalContactsNodeStat.ValueNodeCnt)
|
||||
s.results.storageTrieNum, s.results.storageTotal.ShortNodeCnt.Load(), s.results.storageTotal.FullNodeCnt.Load(), s.results.storageTotal.ValueNodeCnt.Load())
|
||||
}
|
||||
|
||||
@@ -195,7 +195,8 @@ func newJournalReader(file string, db ethdb.Database, journalType JournalType) (
|
||||
// loadJournal tries to parse the layer journal from the disk.
|
||||
func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
|
||||
start := time.Now()
|
||||
reader, err := newJournalReader(db.config.JournalFilePath, db.diskdb, db.DetermineJournalTypeForReader())
|
||||
journalTypeForReader := db.DetermineJournalTypeForReader()
|
||||
reader, err := newJournalReader(db.config.JournalFilePath, db.diskdb, journalTypeForReader)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -226,12 +227,12 @@ func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
|
||||
return nil, fmt.Errorf("%w want %x got %x", errUnmatchedJournal, root, diskRoot)
|
||||
}
|
||||
// Load the disk layer from the journal
|
||||
base, err := db.loadDiskLayer(r)
|
||||
base, err := db.loadDiskLayer(r, journalTypeForReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Load all the diff layers from the journal
|
||||
head, err := db.loadDiffLayer(base, r)
|
||||
head, err := db.loadDiffLayer(base, r, journalTypeForReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -262,14 +263,14 @@ func (db *Database) loadLayers() layer {
|
||||
|
||||
// loadDiskLayer reads the binary blob from the layer journal, reconstructing
|
||||
// a new disk layer on it.
|
||||
func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) {
|
||||
func (db *Database) loadDiskLayer(r *rlp.Stream, journalTypeForReader JournalType) (layer, error) {
|
||||
// Resolve disk layer root
|
||||
var (
|
||||
root common.Hash
|
||||
journalBuf *rlp.Stream
|
||||
journalEncodedBuff []byte
|
||||
)
|
||||
if db.DetermineJournalTypeForReader() == JournalFileType {
|
||||
if journalTypeForReader == JournalFileType {
|
||||
if err := r.Decode(&journalEncodedBuff); err != nil {
|
||||
return nil, fmt.Errorf("load disk journal: %v", err)
|
||||
}
|
||||
@@ -310,7 +311,7 @@ func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) {
|
||||
nodes[entry.Owner] = subset
|
||||
}
|
||||
|
||||
if db.DetermineJournalTypeForReader() == JournalFileType {
|
||||
if journalTypeForReader == JournalFileType {
|
||||
var shaSum [32]byte
|
||||
if err := r.Decode(&shaSum); err != nil {
|
||||
return nil, fmt.Errorf("load shasum: %v", err)
|
||||
@@ -329,14 +330,14 @@ func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) {
|
||||
|
||||
// loadDiffLayer reads the next sections of a layer journal, reconstructing a new
|
||||
// diff and verifying that it can be linked to the requested parent.
|
||||
func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
|
||||
func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream, journalTypeForReader JournalType) (layer, error) {
|
||||
// Read the next diff journal entry
|
||||
var (
|
||||
root common.Hash
|
||||
journalBuf *rlp.Stream
|
||||
journalEncodedBuff []byte
|
||||
)
|
||||
if db.DetermineJournalTypeForReader() == JournalFileType {
|
||||
if journalTypeForReader == JournalFileType {
|
||||
if err := r.Decode(&journalEncodedBuff); err != nil {
|
||||
// The first read may fail with EOF, marking the end of the journal
|
||||
if err == io.EOF {
|
||||
@@ -409,7 +410,7 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
|
||||
storages[entry.Account] = set
|
||||
}
|
||||
|
||||
if db.DetermineJournalTypeForReader() == JournalFileType {
|
||||
if journalTypeForReader == JournalFileType {
|
||||
var shaSum [32]byte
|
||||
if err := r.Decode(&shaSum); err != nil {
|
||||
return nil, fmt.Errorf("load shasum: %v", err)
|
||||
@@ -423,7 +424,7 @@ func (db *Database) loadDiffLayer(parent layer, r *rlp.Stream) (layer, error) {
|
||||
|
||||
log.Debug("Loaded diff layer journal", "root", root, "parent", parent.rootHash(), "id", parent.stateID()+1, "block", block)
|
||||
|
||||
return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages, incomplete)), r)
|
||||
return db.loadDiffLayer(newDiffLayer(parent, root, parent.stateID()+1, block, nodes, triestate.New(accounts, storages, incomplete)), r, journalTypeForReader)
|
||||
}
|
||||
|
||||
// journal implements the layer interface, marshaling the un-flushed trie nodes
|
||||
|
||||
Reference in New Issue
Block a user