forked from forks/go-ethereum
core: initialize history pruning in BlockChain (#31636)
I added the history mode configuration in eth/ethconfig initially, since it seemed like the logical place. But it turns out we need access to the intended pruning setting at a deeper level, and it actually needs to be integrated with the blockchain startup procedure. With this change applied, if a node previously had its history pruned, and is subsequently restarted **without** the `--history.chain postmerge` flag, the `BlockChain` initialization code will now verify the freezer tail against the known pruning point of the predefined network and will restore pruning status. Note that this logic is quite restrictive, we allow non-zero tail only for known networks, and only for the specific pruning point that is defined.
This commit is contained in:
parent
c5c75977ab
commit
48ec86abbb
14 changed files with 188 additions and 90 deletions
|
|
@ -31,11 +31,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/internal/debug"
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
"github.com/ethereum/go-ethereum/internal/era"
|
"github.com/ethereum/go-ethereum/internal/era"
|
||||||
|
|
@ -625,7 +625,7 @@ func pruneHistory(ctx *cli.Context) error {
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
// Determine the prune point. This will be the first PoS block.
|
// Determine the prune point. This will be the first PoS block.
|
||||||
prunePoint, ok := ethconfig.HistoryPrunePoints[chain.Genesis().Hash()]
|
prunePoint, ok := history.PrunePoints[chain.Genesis().Hash()]
|
||||||
if !ok || prunePoint == nil {
|
if !ok || prunePoint == nil {
|
||||||
return errors.New("prune point not found")
|
return errors.New("prune point not found")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/internal/utesting"
|
"github.com/ethereum/go-ethereum/internal/utesting"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -124,13 +124,13 @@ func testConfigFromCLI(ctx *cli.Context) (cfg testConfig) {
|
||||||
cfg.filterQueryFile = "queries/filter_queries_mainnet.json"
|
cfg.filterQueryFile = "queries/filter_queries_mainnet.json"
|
||||||
cfg.historyTestFile = "queries/history_mainnet.json"
|
cfg.historyTestFile = "queries/history_mainnet.json"
|
||||||
cfg.historyPruneBlock = new(uint64)
|
cfg.historyPruneBlock = new(uint64)
|
||||||
*cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.MainnetGenesisHash].BlockNumber
|
*cfg.historyPruneBlock = history.PrunePoints[params.MainnetGenesisHash].BlockNumber
|
||||||
case ctx.Bool(testSepoliaFlag.Name):
|
case ctx.Bool(testSepoliaFlag.Name):
|
||||||
cfg.fsys = builtinTestFiles
|
cfg.fsys = builtinTestFiles
|
||||||
cfg.filterQueryFile = "queries/filter_queries_sepolia.json"
|
cfg.filterQueryFile = "queries/filter_queries_sepolia.json"
|
||||||
cfg.historyTestFile = "queries/history_sepolia.json"
|
cfg.historyTestFile = "queries/history_sepolia.json"
|
||||||
cfg.historyPruneBlock = new(uint64)
|
cfg.historyPruneBlock = new(uint64)
|
||||||
*cfg.historyPruneBlock = ethconfig.HistoryPrunePoints[params.SepoliaGenesisHash].BlockNumber
|
*cfg.historyPruneBlock = history.PrunePoints[params.SepoliaGenesisHash].BlockNumber
|
||||||
default:
|
default:
|
||||||
cfg.fsys = os.DirFS(".")
|
cfg.fsys = os.DirFS(".")
|
||||||
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
cfg.filterQueryFile = ctx.String(filterQueryFileFlag.Name)
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,11 @@ func testHeaderVerification(t *testing.T, scheme string) {
|
||||||
headers[i] = block.Header()
|
headers[i] = block.Header()
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
for i := 0; i < len(blocks); i++ {
|
for i := 0; i < len(blocks); i++ {
|
||||||
for j, valid := range []bool{true, false} {
|
for j, valid := range []bool{true, false} {
|
||||||
|
|
@ -163,8 +166,11 @@ func testHeaderVerificationForMerging(t *testing.T, isClique bool) {
|
||||||
postHeaders[i] = block.Header()
|
postHeaders[i] = block.Header()
|
||||||
}
|
}
|
||||||
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
// Run the header checker for blocks one-by-one, checking for both valid and invalid nonces
|
||||||
chain, _ := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{}, nil)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Verify the blocks before the merging
|
// Verify the blocks before the merging
|
||||||
for i := 0; i < len(preBlocks); i++ {
|
for i := 0; i < len(preBlocks); i++ {
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
|
|
@ -158,8 +159,7 @@ type CacheConfig struct {
|
||||||
|
|
||||||
// This defines the cutoff block for history expiry.
|
// This defines the cutoff block for history expiry.
|
||||||
// Blocks before this number may be unavailable in the chain database.
|
// Blocks before this number may be unavailable in the chain database.
|
||||||
HistoryPruningCutoffNumber uint64
|
ChainHistoryMode history.HistoryMode
|
||||||
HistoryPruningCutoffHash common.Hash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// triedbConfig derives the configures for trie database.
|
// triedbConfig derives the configures for trie database.
|
||||||
|
|
@ -255,6 +255,7 @@ type BlockChain struct {
|
||||||
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
|
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
|
||||||
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
|
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
|
||||||
currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block
|
currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block
|
||||||
|
historyPrunePoint atomic.Pointer[history.PrunePoint]
|
||||||
|
|
||||||
bodyCache *lru.Cache[common.Hash, *types.Body]
|
bodyCache *lru.Cache[common.Hash, *types.Body]
|
||||||
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue]
|
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue]
|
||||||
|
|
@ -533,6 +534,12 @@ func (bc *BlockChain) loadLastState() error {
|
||||||
}
|
}
|
||||||
bc.hc.SetCurrentHeader(headHeader)
|
bc.hc.SetCurrentHeader(headHeader)
|
||||||
|
|
||||||
|
// Initialize history pruning.
|
||||||
|
latest := max(headBlock.NumberU64(), headHeader.Number.Uint64())
|
||||||
|
if err := bc.initializeHistoryPruning(latest); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Restore the last known head snap block
|
// Restore the last known head snap block
|
||||||
bc.currentSnapBlock.Store(headBlock.Header())
|
bc.currentSnapBlock.Store(headBlock.Header())
|
||||||
headFastBlockGauge.Update(int64(headBlock.NumberU64()))
|
headFastBlockGauge.Update(int64(headBlock.NumberU64()))
|
||||||
|
|
@ -555,6 +562,7 @@ func (bc *BlockChain) loadLastState() error {
|
||||||
headSafeBlockGauge.Update(int64(block.NumberU64()))
|
headSafeBlockGauge.Update(int64(block.NumberU64()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Issue a status log for the user
|
// Issue a status log for the user
|
||||||
var (
|
var (
|
||||||
currentSnapBlock = bc.CurrentSnapBlock()
|
currentSnapBlock = bc.CurrentSnapBlock()
|
||||||
|
|
@ -573,9 +581,57 @@ func (bc *BlockChain) loadLastState() error {
|
||||||
if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil {
|
if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil {
|
||||||
log.Info("Loaded last snap-sync pivot marker", "number", *pivot)
|
log.Info("Loaded last snap-sync pivot marker", "number", *pivot)
|
||||||
}
|
}
|
||||||
|
if pruning := bc.historyPrunePoint.Load(); pruning != nil {
|
||||||
|
log.Info("Chain history is pruned", "earliest", pruning.BlockNumber, "hash", pruning.BlockHash)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// initializeHistoryPruning sets bc.historyPrunePoint.
|
||||||
|
func (bc *BlockChain) initializeHistoryPruning(latest uint64) error {
|
||||||
|
freezerTail, _ := bc.db.Tail()
|
||||||
|
|
||||||
|
switch bc.cacheConfig.ChainHistoryMode {
|
||||||
|
case history.KeepAll:
|
||||||
|
if freezerTail == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// The database was pruned somehow, so we need to figure out if it's a known
|
||||||
|
// configuration or an error.
|
||||||
|
predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()]
|
||||||
|
if predefinedPoint == nil || freezerTail != predefinedPoint.BlockNumber {
|
||||||
|
log.Error("Chain history database is pruned with unknown configuration", "tail", freezerTail)
|
||||||
|
return fmt.Errorf("unexpected database tail")
|
||||||
|
}
|
||||||
|
bc.historyPrunePoint.Store(predefinedPoint)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
case history.KeepPostMerge:
|
||||||
|
if freezerTail == 0 && latest != 0 {
|
||||||
|
// This is the case where a user is trying to run with --history.chain
|
||||||
|
// postmerge directly on an existing DB. We could just trigger the pruning
|
||||||
|
// here, but it'd be a bit dangerous since they may not have intended this
|
||||||
|
// action to happen. So just tell them how to do it.
|
||||||
|
log.Error(fmt.Sprintf("Chain history mode is configured as %q, but database is not pruned.", bc.cacheConfig.ChainHistoryMode.String()))
|
||||||
|
log.Error(fmt.Sprintf("Run 'geth prune-history' to prune pre-merge history."))
|
||||||
|
return fmt.Errorf("history pruning requested via configuration")
|
||||||
|
}
|
||||||
|
predefinedPoint := history.PrunePoints[bc.genesisBlock.Hash()]
|
||||||
|
if predefinedPoint == nil {
|
||||||
|
log.Error("Chain history pruning is not supported for this network", "genesis", bc.genesisBlock.Hash())
|
||||||
|
return fmt.Errorf("history pruning requested for unknown network")
|
||||||
|
} else if freezerTail != predefinedPoint.BlockNumber {
|
||||||
|
log.Error("Chain history database is pruned to unknown block", "tail", freezerTail)
|
||||||
|
return fmt.Errorf("unexpected database tail")
|
||||||
|
}
|
||||||
|
bc.historyPrunePoint.Store(predefinedPoint)
|
||||||
|
return nil
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid history mode: %d", bc.cacheConfig.ChainHistoryMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetHead rewinds the local chain to a new head. Depending on whether the node
|
// SetHead rewinds the local chain to a new head. Depending on whether the node
|
||||||
// was snap synced or full synced and in which state, the method will try to
|
// was snap synced or full synced and in which state, the method will try to
|
||||||
// delete minimal data from disk whilst retaining chain consistency.
|
// delete minimal data from disk whilst retaining chain consistency.
|
||||||
|
|
@ -1014,7 +1070,9 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
|
||||||
bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
|
bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
|
||||||
bc.currentSnapBlock.Store(bc.genesisBlock.Header())
|
bc.currentSnapBlock.Store(bc.genesisBlock.Header())
|
||||||
headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
|
headFastBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
|
||||||
return nil
|
|
||||||
|
// Reset history pruning status.
|
||||||
|
return bc.initializeHistoryPruning(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Export writes the active chain to the given writer.
|
// Export writes the active chain to the given writer.
|
||||||
|
|
|
||||||
|
|
@ -410,7 +410,11 @@ func (bc *BlockChain) TxIndexProgress() (TxIndexProgress, error) {
|
||||||
// HistoryPruningCutoff returns the configured history pruning point.
|
// HistoryPruningCutoff returns the configured history pruning point.
|
||||||
// Blocks before this might not be available in the database.
|
// Blocks before this might not be available in the database.
|
||||||
func (bc *BlockChain) HistoryPruningCutoff() (uint64, common.Hash) {
|
func (bc *BlockChain) HistoryPruningCutoff() (uint64, common.Hash) {
|
||||||
return bc.cacheConfig.HistoryPruningCutoffNumber, bc.cacheConfig.HistoryPruningCutoffHash
|
pt := bc.historyPrunePoint.Load()
|
||||||
|
if pt == nil {
|
||||||
|
return 0, bc.genesisBlock.Hash()
|
||||||
|
}
|
||||||
|
return pt.BlockNumber, pt.BlockHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrieDB retrieves the low level trie database used for data storage.
|
// TrieDB retrieves the low level trie database used for data storage.
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/consensus/beacon"
|
"github.com/ethereum/go-ethereum/consensus/beacon"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
@ -4257,13 +4258,7 @@ func testChainReorgSnapSync(t *testing.T, ancientLimit uint64) {
|
||||||
// be persisted without the receipts and bodies; chain after should be persisted
|
// be persisted without the receipts and bodies; chain after should be persisted
|
||||||
// normally.
|
// normally.
|
||||||
func TestInsertChainWithCutoff(t *testing.T) {
|
func TestInsertChainWithCutoff(t *testing.T) {
|
||||||
testInsertChainWithCutoff(t, 32, 32) // cutoff = 32, ancientLimit = 32
|
const chainLength = 64
|
||||||
testInsertChainWithCutoff(t, 32, 64) // cutoff = 32, ancientLimit = 64 (entire chain in ancient)
|
|
||||||
testInsertChainWithCutoff(t, 32, 65) // cutoff = 32, ancientLimit = 65 (64 blocks in ancient, 1 block in live)
|
|
||||||
}
|
|
||||||
|
|
||||||
func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64) {
|
|
||||||
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true)))
|
|
||||||
|
|
||||||
// Configure and generate a sample block chain
|
// Configure and generate a sample block chain
|
||||||
var (
|
var (
|
||||||
|
|
@ -4278,24 +4273,51 @@ func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64)
|
||||||
signer = types.LatestSigner(gspec.Config)
|
signer = types.LatestSigner(gspec.Config)
|
||||||
engine = beacon.New(ethash.NewFaker())
|
engine = beacon.New(ethash.NewFaker())
|
||||||
)
|
)
|
||||||
_, blocks, receipts := GenerateChainWithGenesis(gspec, engine, int(2*cutoff), func(i int, block *BlockGen) {
|
_, blocks, receipts := GenerateChainWithGenesis(gspec, engine, chainLength, func(i int, block *BlockGen) {
|
||||||
block.SetCoinbase(common.Address{0x00})
|
block.SetCoinbase(common.Address{0x00})
|
||||||
|
|
||||||
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key)
|
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, block.header.BaseFee, nil), signer, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Run the actual tests.
|
||||||
|
t.Run("cutoff-32/ancientLimit-32", func(t *testing.T) {
|
||||||
|
// cutoff = 32, ancientLimit = 32
|
||||||
|
testInsertChainWithCutoff(t, 32, 32, gspec, blocks, receipts)
|
||||||
|
})
|
||||||
|
t.Run("cutoff-32/ancientLimit-64", func(t *testing.T) {
|
||||||
|
// cutoff = 32, ancientLimit = 64 (entire chain in ancient)
|
||||||
|
testInsertChainWithCutoff(t, 32, 64, gspec, blocks, receipts)
|
||||||
|
})
|
||||||
|
t.Run("cutoff-32/ancientLimit-64", func(t *testing.T) {
|
||||||
|
// cutoff = 32, ancientLimit = 65 (64 blocks in ancient, 1 block in live)
|
||||||
|
testInsertChainWithCutoff(t, 32, 65, gspec, blocks, receipts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64, genesis *Genesis, blocks []*types.Block, receipts []types.Receipts) {
|
||||||
|
// log.SetDefault(log.NewLogger(log.NewTerminalHandlerWithLevel(os.Stderr, log.LevelDebug, true)))
|
||||||
|
|
||||||
|
// Add a known pruning point for the duration of the test.
|
||||||
|
ghash := genesis.ToBlock().Hash()
|
||||||
|
cutoffBlock := blocks[cutoff-1]
|
||||||
|
history.PrunePoints[ghash] = &history.PrunePoint{
|
||||||
|
BlockNumber: cutoffBlock.NumberU64(),
|
||||||
|
BlockHash: cutoffBlock.Hash(),
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
delete(history.PrunePoints, ghash)
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Enable pruning in cache config.
|
||||||
|
config := DefaultCacheConfigWithScheme(rawdb.PathScheme)
|
||||||
|
config.ChainHistoryMode = history.KeepPostMerge
|
||||||
|
|
||||||
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
|
||||||
cutoffBlock := blocks[cutoff-1]
|
|
||||||
config := DefaultCacheConfigWithScheme(rawdb.PathScheme)
|
|
||||||
config.HistoryPruningCutoffNumber = cutoffBlock.NumberU64()
|
|
||||||
config.HistoryPruningCutoffHash = cutoffBlock.Hash()
|
|
||||||
|
|
||||||
chain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.PathScheme), gspec, nil, beacon.New(ethash.NewFaker()), vm.Config{}, nil)
|
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -4326,8 +4348,8 @@ func testInsertChainWithCutoff(t *testing.T, cutoff uint64, ancientLimit uint64)
|
||||||
t.Errorf("head header #%d: header mismatch: want: %v, got: %v", headHeader.Number, blocks[len(blocks)-1].Hash(), headHeader.Hash())
|
t.Errorf("head header #%d: header mismatch: want: %v, got: %v", headHeader.Number, blocks[len(blocks)-1].Hash(), headHeader.Hash())
|
||||||
}
|
}
|
||||||
headBlock := chain.CurrentBlock()
|
headBlock := chain.CurrentBlock()
|
||||||
if headBlock.Hash() != gspec.ToBlock().Hash() {
|
if headBlock.Hash() != ghash {
|
||||||
t.Errorf("head block #%d: header mismatch: want: %v, got: %v", headBlock.Number, gspec.ToBlock().Hash(), headBlock.Hash())
|
t.Errorf("head block #%d: header mismatch: want: %v, got: %v", headBlock.Number, ghash, headBlock.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all chain data components, and cross reference
|
// Iterate over all chain data components, and cross reference
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package ethconfig
|
package history
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -27,22 +27,22 @@ import (
|
||||||
type HistoryMode uint32
|
type HistoryMode uint32
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// AllHistory (default) means that all chain history down to genesis block will be kept.
|
// KeepAll (default) means that all chain history down to genesis block will be kept.
|
||||||
AllHistory HistoryMode = iota
|
KeepAll HistoryMode = iota
|
||||||
|
|
||||||
// PostMergeHistory sets the history pruning point to the merge activation block.
|
// KeepPostMerge sets the history pruning point to the merge activation block.
|
||||||
PostMergeHistory
|
KeepPostMerge
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m HistoryMode) IsValid() bool {
|
func (m HistoryMode) IsValid() bool {
|
||||||
return m <= PostMergeHistory
|
return m <= KeepPostMerge
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m HistoryMode) String() string {
|
func (m HistoryMode) String() string {
|
||||||
switch m {
|
switch m {
|
||||||
case AllHistory:
|
case KeepAll:
|
||||||
return "all"
|
return "all"
|
||||||
case PostMergeHistory:
|
case KeepPostMerge:
|
||||||
return "postmerge"
|
return "postmerge"
|
||||||
default:
|
default:
|
||||||
return fmt.Sprintf("invalid HistoryMode(%d)", m)
|
return fmt.Sprintf("invalid HistoryMode(%d)", m)
|
||||||
|
|
@ -61,24 +61,24 @@ func (m HistoryMode) MarshalText() ([]byte, error) {
|
||||||
func (m *HistoryMode) UnmarshalText(text []byte) error {
|
func (m *HistoryMode) UnmarshalText(text []byte) error {
|
||||||
switch string(text) {
|
switch string(text) {
|
||||||
case "all":
|
case "all":
|
||||||
*m = AllHistory
|
*m = KeepAll
|
||||||
case "postmerge":
|
case "postmerge":
|
||||||
*m = PostMergeHistory
|
*m = KeepPostMerge
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf(`unknown sync mode %q, want "all" or "postmerge"`, text)
|
return fmt.Errorf(`unknown sync mode %q, want "all" or "postmerge"`, text)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type HistoryPrunePoint struct {
|
type PrunePoint struct {
|
||||||
BlockNumber uint64
|
BlockNumber uint64
|
||||||
BlockHash common.Hash
|
BlockHash common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// HistoryPrunePoints contains the pre-defined history pruning cutoff blocks for known networks.
|
// PrunePoints the pre-defined history pruning cutoff blocks for known networks.
|
||||||
// They point to the first post-merge block. Any pruning should truncate *up to* but excluding
|
// They point to the first post-merge block. Any pruning should truncate *up to* but excluding
|
||||||
// given block.
|
// given block.
|
||||||
var HistoryPrunePoints = map[common.Hash]*HistoryPrunePoint{
|
var PrunePoints = map[common.Hash]*PrunePoint{
|
||||||
// mainnet
|
// mainnet
|
||||||
params.MainnetGenesisHash: {
|
params.MainnetGenesisHash: {
|
||||||
BlockNumber: 15537393,
|
BlockNumber: 15537393,
|
||||||
|
|
@ -91,7 +91,7 @@ var HistoryPrunePoints = map[common.Hash]*HistoryPrunePoint{
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrunedHistoryError is returned when the requested history is pruned.
|
// PrunedHistoryError is returned by APIs when the requested history is pruned.
|
||||||
type PrunedHistoryError struct{}
|
type PrunedHistoryError struct{}
|
||||||
|
|
||||||
func (e *PrunedHistoryError) Error() string { return "pruned history unavailable" }
|
func (e *PrunedHistoryError) Error() string { return "pruned history unavailable" }
|
||||||
|
|
@ -29,12 +29,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/filtermaps"
|
"github.com/ethereum/go-ethereum/core/filtermaps"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool"
|
"github.com/ethereum/go-ethereum/core/txpool"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
|
@ -156,7 +156,7 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
|
||||||
}
|
}
|
||||||
block := b.eth.blockchain.GetBlockByNumber(bn)
|
block := b.eth.blockchain.GetBlockByNumber(bn)
|
||||||
if block == nil && bn < b.HistoryPruningCutoff() {
|
if block == nil && bn < b.HistoryPruningCutoff() {
|
||||||
return nil, ðconfig.PrunedHistoryError{}
|
return nil, &history.PrunedHistoryError{}
|
||||||
}
|
}
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
@ -168,7 +168,7 @@ func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*typ
|
||||||
}
|
}
|
||||||
block := b.eth.blockchain.GetBlock(hash, *number)
|
block := b.eth.blockchain.GetBlock(hash, *number)
|
||||||
if block == nil && *number < b.HistoryPruningCutoff() {
|
if block == nil && *number < b.HistoryPruningCutoff() {
|
||||||
return nil, ðconfig.PrunedHistoryError{}
|
return nil, &history.PrunedHistoryError{}
|
||||||
}
|
}
|
||||||
return block, nil
|
return block, nil
|
||||||
}
|
}
|
||||||
|
|
@ -181,7 +181,7 @@ func (b *EthAPIBackend) GetBody(ctx context.Context, hash common.Hash, number rp
|
||||||
body := b.eth.blockchain.GetBody(hash)
|
body := b.eth.blockchain.GetBody(hash)
|
||||||
if body == nil {
|
if body == nil {
|
||||||
if uint64(number) < b.HistoryPruningCutoff() {
|
if uint64(number) < b.HistoryPruningCutoff() {
|
||||||
return nil, ðconfig.PrunedHistoryError{}
|
return nil, &history.PrunedHistoryError{}
|
||||||
}
|
}
|
||||||
return nil, errors.New("block body not found")
|
return nil, errors.New("block body not found")
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +203,7 @@ func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r
|
||||||
block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64())
|
block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64())
|
||||||
if block == nil {
|
if block == nil {
|
||||||
if header.Number.Uint64() < b.HistoryPruningCutoff() {
|
if header.Number.Uint64() < b.HistoryPruningCutoff() {
|
||||||
return nil, ðconfig.PrunedHistoryError{}
|
return nil, &history.PrunedHistoryError{}
|
||||||
}
|
}
|
||||||
return nil, errors.New("header found, but block body is missing")
|
return nil, errors.New("header found, but block body is missing")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
|
|
||||||
// Here we determine genesis hash and active ChainConfig.
|
// Here we determine genesis hash and active ChainConfig.
|
||||||
// We need these to figure out the consensus parameters and to set up history pruning.
|
// We need these to figure out the consensus parameters and to set up history pruning.
|
||||||
chainConfig, genesisHash, err := core.LoadChainConfig(chainDb, config.Genesis)
|
chainConfig, _, err := core.LoadChainConfig(chainDb, config.Genesis)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -153,22 +153,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate history pruning configuration.
|
|
||||||
var (
|
|
||||||
cutoffNumber uint64
|
|
||||||
cutoffHash common.Hash
|
|
||||||
)
|
|
||||||
if config.HistoryMode == ethconfig.PostMergeHistory {
|
|
||||||
prunecfg, ok := ethconfig.HistoryPrunePoints[genesisHash]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("no history pruning point is defined for genesis %x", genesisHash)
|
|
||||||
}
|
|
||||||
cutoffNumber = prunecfg.BlockNumber
|
|
||||||
cutoffHash = prunecfg.BlockHash
|
|
||||||
log.Info("Chain cutoff configured", "number", cutoffNumber, "hash", cutoffHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set networkID to chainID by default.
|
// Set networkID to chainID by default.
|
||||||
networkID := config.NetworkId
|
networkID := config.NetworkId
|
||||||
if networkID == 0 {
|
if networkID == 0 {
|
||||||
|
|
@ -195,6 +179,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
}
|
}
|
||||||
log.Info("Initialising Ethereum protocol", "network", networkID, "dbversion", dbVer)
|
log.Info("Initialising Ethereum protocol", "network", networkID, "dbversion", dbVer)
|
||||||
|
|
||||||
|
// Create BlockChain object.
|
||||||
if !config.SkipBcVersionCheck {
|
if !config.SkipBcVersionCheck {
|
||||||
if bcVersion != nil && *bcVersion > core.BlockChainVersion {
|
if bcVersion != nil && *bcVersion > core.BlockChainVersion {
|
||||||
return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, version.WithMeta, core.BlockChainVersion)
|
return nil, fmt.Errorf("database version is v%d, Geth %s only supports v%d", *bcVersion, version.WithMeta, core.BlockChainVersion)
|
||||||
|
|
@ -210,17 +195,16 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
EnablePreimageRecording: config.EnablePreimageRecording,
|
EnablePreimageRecording: config.EnablePreimageRecording,
|
||||||
}
|
}
|
||||||
cacheConfig = &core.CacheConfig{
|
cacheConfig = &core.CacheConfig{
|
||||||
TrieCleanLimit: config.TrieCleanCache,
|
TrieCleanLimit: config.TrieCleanCache,
|
||||||
TrieCleanNoPrefetch: config.NoPrefetch,
|
TrieCleanNoPrefetch: config.NoPrefetch,
|
||||||
TrieDirtyLimit: config.TrieDirtyCache,
|
TrieDirtyLimit: config.TrieDirtyCache,
|
||||||
TrieDirtyDisabled: config.NoPruning,
|
TrieDirtyDisabled: config.NoPruning,
|
||||||
TrieTimeLimit: config.TrieTimeout,
|
TrieTimeLimit: config.TrieTimeout,
|
||||||
SnapshotLimit: config.SnapshotCache,
|
SnapshotLimit: config.SnapshotCache,
|
||||||
Preimages: config.Preimages,
|
Preimages: config.Preimages,
|
||||||
StateHistory: config.StateHistory,
|
StateHistory: config.StateHistory,
|
||||||
StateScheme: scheme,
|
StateScheme: scheme,
|
||||||
HistoryPruningCutoffNumber: cutoffNumber,
|
ChainHistoryMode: config.HistoryMode,
|
||||||
HistoryPruningCutoffHash: cutoffHash,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
if config.VMTrace != "" {
|
if config.VMTrace != "" {
|
||||||
|
|
@ -246,6 +230,8 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize filtermaps log index.
|
||||||
fmConfig := filtermaps.Config{
|
fmConfig := filtermaps.Config{
|
||||||
History: config.LogHistory,
|
History: config.LogHistory,
|
||||||
Disabled: config.LogNoHistory,
|
Disabled: config.LogNoHistory,
|
||||||
|
|
@ -261,6 +247,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, historyCutoff, finalBlock, filtermaps.DefaultParams, fmConfig)
|
eth.filterMaps = filtermaps.NewFilterMaps(chainDb, chainView, historyCutoff, finalBlock, filtermaps.DefaultParams, fmConfig)
|
||||||
eth.closeFilterMaps = make(chan chan struct{})
|
eth.closeFilterMaps = make(chan chan struct{})
|
||||||
|
|
||||||
|
// TxPool
|
||||||
if config.TxPool.Journal != "" {
|
if config.TxPool.Journal != "" {
|
||||||
config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal)
|
config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal)
|
||||||
}
|
}
|
||||||
|
|
@ -285,6 +272,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
eth.localTxTracker = locals.New(config.TxPool.Journal, rejournal, eth.blockchain.Config(), eth.txPool)
|
eth.localTxTracker = locals.New(config.TxPool.Journal, rejournal, eth.blockchain.Config(), eth.txPool)
|
||||||
stack.RegisterLifecycle(eth.localTxTracker)
|
stack.RegisterLifecycle(eth.localTxTracker)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Permit the downloader to use the trie cache allowance during fast sync
|
// Permit the downloader to use the trie cache allowance during fast sync
|
||||||
cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit
|
cacheLimit := cacheConfig.TrieCleanLimit + cacheConfig.TrieDirtyLimit + cacheConfig.SnapshotLimit
|
||||||
if eth.handler, err = newHandler(&handlerConfig{
|
if eth.handler, err = newHandler(&handlerConfig{
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/clique"
|
"github.com/ethereum/go-ethereum/consensus/clique"
|
||||||
"github.com/ethereum/go-ethereum/consensus/ethash"
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
|
|
@ -48,7 +49,7 @@ var FullNodeGPO = gasprice.Config{
|
||||||
|
|
||||||
// Defaults contains default settings for use on the Ethereum main net.
|
// Defaults contains default settings for use on the Ethereum main net.
|
||||||
var Defaults = Config{
|
var Defaults = Config{
|
||||||
HistoryMode: AllHistory,
|
HistoryMode: history.KeepAll,
|
||||||
SyncMode: SnapSync,
|
SyncMode: SnapSync,
|
||||||
NetworkId: 0, // enable auto configuration of networkID == chainID
|
NetworkId: 0, // enable auto configuration of networkID == chainID
|
||||||
TxLookupLimit: 2350000,
|
TxLookupLimit: 2350000,
|
||||||
|
|
@ -84,7 +85,7 @@ type Config struct {
|
||||||
SyncMode SyncMode
|
SyncMode SyncMode
|
||||||
|
|
||||||
// HistoryMode configures chain history retention.
|
// HistoryMode configures chain history retention.
|
||||||
HistoryMode HistoryMode
|
HistoryMode history.HistoryMode
|
||||||
|
|
||||||
// This can be set to list of enrtree:// URLs which will be queried for
|
// This can be set to list of enrtree:// URLs which will be queried for
|
||||||
// nodes to connect to.
|
// nodes to connect to.
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
|
|
@ -19,13 +20,16 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||||
Genesis *core.Genesis `toml:",omitempty"`
|
Genesis *core.Genesis `toml:",omitempty"`
|
||||||
NetworkId uint64
|
NetworkId uint64
|
||||||
SyncMode SyncMode
|
SyncMode SyncMode
|
||||||
HistoryMode HistoryMode
|
HistoryMode history.HistoryMode
|
||||||
EthDiscoveryURLs []string
|
EthDiscoveryURLs []string
|
||||||
SnapDiscoveryURLs []string
|
SnapDiscoveryURLs []string
|
||||||
NoPruning bool
|
NoPruning bool
|
||||||
NoPrefetch bool
|
NoPrefetch bool
|
||||||
TxLookupLimit uint64 `toml:",omitempty"`
|
TxLookupLimit uint64 `toml:",omitempty"`
|
||||||
TransactionHistory uint64 `toml:",omitempty"`
|
TransactionHistory uint64 `toml:",omitempty"`
|
||||||
|
LogHistory uint64 `toml:",omitempty"`
|
||||||
|
LogNoHistory bool `toml:",omitempty"`
|
||||||
|
LogExportCheckpoints string
|
||||||
StateHistory uint64 `toml:",omitempty"`
|
StateHistory uint64 `toml:",omitempty"`
|
||||||
StateScheme string `toml:",omitempty"`
|
StateScheme string `toml:",omitempty"`
|
||||||
RequiredBlocks map[uint64]common.Hash `toml:"-"`
|
RequiredBlocks map[uint64]common.Hash `toml:"-"`
|
||||||
|
|
@ -63,6 +67,9 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||||
enc.NoPrefetch = c.NoPrefetch
|
enc.NoPrefetch = c.NoPrefetch
|
||||||
enc.TxLookupLimit = c.TxLookupLimit
|
enc.TxLookupLimit = c.TxLookupLimit
|
||||||
enc.TransactionHistory = c.TransactionHistory
|
enc.TransactionHistory = c.TransactionHistory
|
||||||
|
enc.LogHistory = c.LogHistory
|
||||||
|
enc.LogNoHistory = c.LogNoHistory
|
||||||
|
enc.LogExportCheckpoints = c.LogExportCheckpoints
|
||||||
enc.StateHistory = c.StateHistory
|
enc.StateHistory = c.StateHistory
|
||||||
enc.StateScheme = c.StateScheme
|
enc.StateScheme = c.StateScheme
|
||||||
enc.RequiredBlocks = c.RequiredBlocks
|
enc.RequiredBlocks = c.RequiredBlocks
|
||||||
|
|
@ -97,13 +104,16 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
Genesis *core.Genesis `toml:",omitempty"`
|
Genesis *core.Genesis `toml:",omitempty"`
|
||||||
NetworkId *uint64
|
NetworkId *uint64
|
||||||
SyncMode *SyncMode
|
SyncMode *SyncMode
|
||||||
HistoryMode *HistoryMode
|
HistoryMode *history.HistoryMode
|
||||||
EthDiscoveryURLs []string
|
EthDiscoveryURLs []string
|
||||||
SnapDiscoveryURLs []string
|
SnapDiscoveryURLs []string
|
||||||
NoPruning *bool
|
NoPruning *bool
|
||||||
NoPrefetch *bool
|
NoPrefetch *bool
|
||||||
TxLookupLimit *uint64 `toml:",omitempty"`
|
TxLookupLimit *uint64 `toml:",omitempty"`
|
||||||
TransactionHistory *uint64 `toml:",omitempty"`
|
TransactionHistory *uint64 `toml:",omitempty"`
|
||||||
|
LogHistory *uint64 `toml:",omitempty"`
|
||||||
|
LogNoHistory *bool `toml:",omitempty"`
|
||||||
|
LogExportCheckpoints *string
|
||||||
StateHistory *uint64 `toml:",omitempty"`
|
StateHistory *uint64 `toml:",omitempty"`
|
||||||
StateScheme *string `toml:",omitempty"`
|
StateScheme *string `toml:",omitempty"`
|
||||||
RequiredBlocks map[uint64]common.Hash `toml:"-"`
|
RequiredBlocks map[uint64]common.Hash `toml:"-"`
|
||||||
|
|
@ -164,6 +174,15 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
if dec.TransactionHistory != nil {
|
if dec.TransactionHistory != nil {
|
||||||
c.TransactionHistory = *dec.TransactionHistory
|
c.TransactionHistory = *dec.TransactionHistory
|
||||||
}
|
}
|
||||||
|
if dec.LogHistory != nil {
|
||||||
|
c.LogHistory = *dec.LogHistory
|
||||||
|
}
|
||||||
|
if dec.LogNoHistory != nil {
|
||||||
|
c.LogNoHistory = *dec.LogNoHistory
|
||||||
|
}
|
||||||
|
if dec.LogExportCheckpoints != nil {
|
||||||
|
c.LogExportCheckpoints = *dec.LogExportCheckpoints
|
||||||
|
}
|
||||||
if dec.StateHistory != nil {
|
if dec.StateHistory != nil {
|
||||||
c.StateHistory = *dec.StateHistory
|
c.StateHistory = *dec.StateHistory
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum"
|
"github.com/ethereum/go-ethereum"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
@ -360,7 +360,7 @@ func (api *FilterAPI) GetLogs(ctx context.Context, crit FilterCriteria) ([]*type
|
||||||
return nil, errInvalidBlockRange
|
return nil, errInvalidBlockRange
|
||||||
}
|
}
|
||||||
if begin > 0 && begin < int64(api.events.backend.HistoryPruningCutoff()) {
|
if begin > 0 && begin < int64(api.events.backend.HistoryPruningCutoff()) {
|
||||||
return nil, ðconfig.PrunedHistoryError{}
|
return nil, &history.PrunedHistoryError{}
|
||||||
}
|
}
|
||||||
// Construct the range filter
|
// Construct the range filter
|
||||||
filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics)
|
filter = api.sys.NewRangeFilter(begin, end, crit.Addresses, crit.Topics)
|
||||||
|
|
|
||||||
|
|
@ -26,8 +26,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/filtermaps"
|
"github.com/ethereum/go-ethereum/core/filtermaps"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
@ -88,7 +88,7 @@ func (f *Filter) Logs(ctx context.Context) ([]*types.Log, error) {
|
||||||
return nil, errors.New("unknown block")
|
return nil, errors.New("unknown block")
|
||||||
}
|
}
|
||||||
if header.Number.Uint64() < f.sys.backend.HistoryPruningCutoff() {
|
if header.Number.Uint64() < f.sys.backend.HistoryPruningCutoff() {
|
||||||
return nil, ðconfig.PrunedHistoryError{}
|
return nil, &history.PrunedHistoryError{}
|
||||||
}
|
}
|
||||||
return f.blockLogs(ctx, header)
|
return f.blockLogs(ctx, header)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/lru"
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/filtermaps"
|
"github.com/ethereum/go-ethereum/core/filtermaps"
|
||||||
|
"github.com/ethereum/go-ethereum/core/history"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -311,7 +311,7 @@ func (es *EventSystem) SubscribeLogs(crit ethereum.FilterQuery, logs chan []*typ
|
||||||
}
|
}
|
||||||
// Queries beyond the pruning cutoff are not supported.
|
// Queries beyond the pruning cutoff are not supported.
|
||||||
if uint64(from) < es.backend.HistoryPruningCutoff() {
|
if uint64(from) < es.backend.HistoryPruningCutoff() {
|
||||||
return nil, ðconfig.PrunedHistoryError{}
|
return nil, &history.PrunedHistoryError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// only interested in new mined logs
|
// only interested in new mined logs
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue