mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
cmd, core, eth: version 2
This commit is contained in:
parent
4f0cc2d7e2
commit
2c7b166b25
30 changed files with 649 additions and 266 deletions
|
|
@ -70,7 +70,7 @@ type SimulatedBackend struct {
|
||||||
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.GenesisAlloc, gasLimit uint64) *SimulatedBackend {
|
||||||
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc}
|
||||||
genesis.MustCommit(database)
|
genesis.MustCommit(database)
|
||||||
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
|
|
||||||
backend := &SimulatedBackend{
|
backend := &SimulatedBackend{
|
||||||
database: database,
|
database: database,
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,7 @@ var (
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
utils.ExitWhenSyncedFlag,
|
utils.ExitWhenSyncedFlag,
|
||||||
utils.GCModeFlag,
|
utils.GCModeFlag,
|
||||||
|
utils.TxLookupLimitFlag,
|
||||||
utils.LightServeFlag,
|
utils.LightServeFlag,
|
||||||
utils.LightLegacyServFlag,
|
utils.LightLegacyServFlag,
|
||||||
utils.LightIngressFlag,
|
utils.LightIngressFlag,
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,7 @@ func (api *RetestethAPI) SetChainParams(ctx context.Context, chainParams ChainPa
|
||||||
}
|
}
|
||||||
engine := &NoRewardEngine{inner: inner, rewardsOn: chainParams.SealEngine != "NoReward"}
|
engine := &NoRewardEngine{inner: inner, rewardsOn: chainParams.SealEngine != "NoReward"}
|
||||||
|
|
||||||
blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil)
|
blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,7 @@ var AppHelpFlagGroups = []flagGroup{
|
||||||
utils.SyncModeFlag,
|
utils.SyncModeFlag,
|
||||||
utils.ExitWhenSyncedFlag,
|
utils.ExitWhenSyncedFlag,
|
||||||
utils.GCModeFlag,
|
utils.GCModeFlag,
|
||||||
|
utils.TxLookupLimitFlag,
|
||||||
utils.EthStatsURLFlag,
|
utils.EthStatsURLFlag,
|
||||||
utils.IdentityFlag,
|
utils.IdentityFlag,
|
||||||
utils.LightKDFFlag,
|
utils.LightKDFFlag,
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,11 @@ var (
|
||||||
Usage: `Blockchain garbage collection mode ("full", "archive")`,
|
Usage: `Blockchain garbage collection mode ("full", "archive")`,
|
||||||
Value: "full",
|
Value: "full",
|
||||||
}
|
}
|
||||||
|
TxLookupLimitFlag = cli.Int64Flag{
|
||||||
|
Name: "txlookuplimit",
|
||||||
|
Usage: "The maximum number of blocks from head whose tx indices are reserved(0 means reserve all indices)",
|
||||||
|
Value: 0,
|
||||||
|
}
|
||||||
LightKDFFlag = cli.BoolFlag{
|
LightKDFFlag = cli.BoolFlag{
|
||||||
Name: "lightkdf",
|
Name: "lightkdf",
|
||||||
Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
|
Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
|
||||||
|
|
@ -1450,7 +1455,9 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
|
||||||
}
|
}
|
||||||
cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
|
cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
|
||||||
cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name)
|
cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name)
|
||||||
|
if ctx.GlobalIsSet(TxLookupLimitFlag.Name) {
|
||||||
|
cfg.TxLookupLimit = ctx.GlobalUint64(TxLookupLimitFlag.Name)
|
||||||
|
}
|
||||||
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
|
if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
|
||||||
cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
|
cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
|
||||||
}
|
}
|
||||||
|
|
@ -1716,7 +1723,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
|
||||||
cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
|
cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
|
||||||
}
|
}
|
||||||
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
|
vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
|
||||||
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil)
|
chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Fatalf("Can't create BlockChain: %v", err)
|
Fatalf("Can't create BlockChain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
genesis := genspec.MustCommit(db)
|
genesis := genspec.MustCommit(db)
|
||||||
|
|
||||||
// Generate a batch of blocks, each properly signed
|
// Generate a batch of blocks, each properly signed
|
||||||
chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil)
|
chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, 0)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(params.AllCliqueProtocolChanges, genesis, engine, db, 3, func(i int, block *core.BlockGen) {
|
||||||
|
|
@ -88,7 +88,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
genspec.MustCommit(db)
|
genspec.MustCommit(db)
|
||||||
|
|
||||||
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil)
|
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, 0)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
if _, err := chain.InsertChain(blocks[:2]); err != nil {
|
||||||
|
|
@ -101,7 +101,7 @@ func TestReimportMirroredState(t *testing.T) {
|
||||||
// Simulate a crash by creating a new chain on top of the database, without
|
// Simulate a crash by creating a new chain on top of the database, without
|
||||||
// flushing the dirty states out. Insert the last block, trigerring a sidechain
|
// flushing the dirty states out. Insert the last block, trigerring a sidechain
|
||||||
// reimport.
|
// reimport.
|
||||||
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil)
|
chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, 0)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
if _, err := chain.InsertChain(blocks[2:]); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -448,7 +448,7 @@ func TestClique(t *testing.T) {
|
||||||
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
batches[len(batches)-1] = append(batches[len(batches)-1], block)
|
||||||
}
|
}
|
||||||
// Pass all the headers through clique and ensure tallying succeeds
|
// Pass all the headers through clique and ensure tallying succeeds
|
||||||
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil)
|
chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
t.Errorf("test %d: failed to create test chain: %v", i, err)
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -175,7 +175,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||||
|
|
||||||
// Time the insertion of the new chain.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// State and blocks are stored in the same DB.
|
||||||
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer chainman.Stop()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
@ -287,7 +287,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error opening database at %v: %v", dir, err)
|
b.Fatalf("error opening database at %v: %v", dir, err)
|
||||||
}
|
}
|
||||||
chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("error creating chain: %v", err)
|
b.Fatalf("error creating chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ func TestHeaderVerification(t *testing.T) {
|
||||||
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(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
for i := 0; i < len(blocks); i++ {
|
for i := 0; i < len(blocks); i++ {
|
||||||
|
|
@ -106,11 +106,11 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) {
|
||||||
var results <-chan error
|
var results <-chan error
|
||||||
|
|
||||||
if valid {
|
if valid {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
} else {
|
} else {
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, 0)
|
||||||
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
_, results = chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
chain.Stop()
|
chain.Stop()
|
||||||
}
|
}
|
||||||
|
|
@ -173,7 +173,7 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) {
|
||||||
defer runtime.GOMAXPROCS(old)
|
defer runtime.GOMAXPROCS(old)
|
||||||
|
|
||||||
// Start the verifications and immediately abort
|
// Start the verifications and immediately abort
|
||||||
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil)
|
chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, 0)
|
||||||
defer chain.Stop()
|
defer chain.Stop()
|
||||||
|
|
||||||
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
abort, results := chain.engine.VerifyHeaders(chain, headers, seals)
|
||||||
|
|
|
||||||
|
|
@ -134,9 +134,10 @@ type BlockChain struct {
|
||||||
chainConfig *params.ChainConfig // Chain & network configuration
|
chainConfig *params.ChainConfig // Chain & network configuration
|
||||||
cacheConfig *CacheConfig // Cache configuration for pruning
|
cacheConfig *CacheConfig // Cache configuration for pruning
|
||||||
|
|
||||||
db ethdb.Database // Low level persistent database to store final content in
|
db ethdb.Database // Low level persistent database to store final content in
|
||||||
triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
|
triegc *prque.Prque // Priority queue mapping block numbers to tries to gc
|
||||||
gcproc time.Duration // Accumulates canonical block processing for trie dumping
|
gcproc time.Duration // Accumulates canonical block processing for trie dumping
|
||||||
|
txLookupLimit uint64 // The maximum number of blocks from head whose tx indices are reserved
|
||||||
|
|
||||||
hc *HeaderChain
|
hc *HeaderChain
|
||||||
rmLogsFeed event.Feed
|
rmLogsFeed event.Feed
|
||||||
|
|
@ -181,7 +182,7 @@ type BlockChain struct {
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
// available in the database. It initialises the default Ethereum Validator and
|
// available in the database. It initialises the default Ethereum Validator and
|
||||||
// Processor.
|
// Processor.
|
||||||
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool) (*BlockChain, error) {
|
func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool, txLookupLimit uint64) (*BlockChain, error) {
|
||||||
if cacheConfig == nil {
|
if cacheConfig == nil {
|
||||||
cacheConfig = &CacheConfig{
|
cacheConfig = &CacheConfig{
|
||||||
TrieCleanLimit: 256,
|
TrieCleanLimit: 256,
|
||||||
|
|
@ -200,6 +201,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
bc := &BlockChain{
|
bc := &BlockChain{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
cacheConfig: cacheConfig,
|
cacheConfig: cacheConfig,
|
||||||
|
txLookupLimit: txLookupLimit,
|
||||||
db: db,
|
db: db,
|
||||||
triegc: prque.New(nil),
|
triegc: prque.New(nil),
|
||||||
stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit),
|
stateCache: state.NewDatabaseWithCache(db, cacheConfig.TrieCleanLimit),
|
||||||
|
|
@ -231,12 +233,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
// Initialize the chain with ancient data if it isn't empty.
|
// Initialize the chain with ancient data if it isn't empty.
|
||||||
if bc.empty() {
|
if bc.empty() {
|
||||||
rawdb.InitBlockIndexFromFreezer(bc.db)
|
rawdb.InitBlockIndexFromFreezer(bc.db)
|
||||||
rawdb.WriteAncientTxLookupProgress(bc.db, 0) // Explicitly mark the missing of txlookup.
|
|
||||||
}
|
|
||||||
// Re-initialise all ancient txlookup indexes in the background.
|
|
||||||
if number := rawdb.ReadAncientTxLookupProgress(bc.db); number != nil {
|
|
||||||
// Genesis block doesn't have transaction, just ignore it.
|
|
||||||
go rawdb.InitTxsLookupFromFreezer(bc.db, *number+1)
|
|
||||||
}
|
}
|
||||||
if err := bc.loadLastState(); err != nil {
|
if err := bc.loadLastState(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -294,6 +290,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
||||||
}
|
}
|
||||||
// Take ownership of this particular state
|
// Take ownership of this particular state
|
||||||
go bc.update()
|
go bc.update()
|
||||||
|
go bc.updateTxIndices()
|
||||||
return bc, nil
|
return bc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2041,6 +2038,101 @@ func (bc *BlockChain) update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updateTxIndices is responsible for the construction and deletion of the
|
||||||
|
// transaction index.
|
||||||
|
//
|
||||||
|
// User can use flag `txlookuplimit` to specify a "recentness" block, below
|
||||||
|
// which ancient tx indices get deleted. If `txlookuplimit` is 0, it means
|
||||||
|
// all tx indices will be reserved.
|
||||||
|
//
|
||||||
|
// The user can adjust the txlookuplimit value for each launch, Geth will
|
||||||
|
// automatically construct the missing indices and delete the extra indices.
|
||||||
|
func (bc *BlockChain) updateTxIndices() {
|
||||||
|
var (
|
||||||
|
done chan struct{} // Non-nil if background unindexing or reindexing routine is active.
|
||||||
|
headCh = make(chan ChainHeadEvent)
|
||||||
|
)
|
||||||
|
sub := bc.SubscribeChainHeadEvent(headCh)
|
||||||
|
defer func() {
|
||||||
|
if sub != nil {
|
||||||
|
sub.Unsubscribe()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
// initialiseIndices inits txlookup indices into the database.
|
||||||
|
// If there already exists some indices, this function will find
|
||||||
|
// the oldest block which has been indexed and start indexing from
|
||||||
|
// this point.
|
||||||
|
initialiseIndices := func(head uint64) {
|
||||||
|
defer func() { done <- struct{}{} }()
|
||||||
|
|
||||||
|
from, to := uint64(0), head
|
||||||
|
if bc.txLookupLimit != 0 && head > bc.txLookupLimit {
|
||||||
|
from = head - bc.txLookupLimit
|
||||||
|
}
|
||||||
|
// Find oldest indexed block via binary search when we don't
|
||||||
|
// have this flag in database.
|
||||||
|
start := time.Now()
|
||||||
|
oldest := rawdb.FindOldestIndexedBlock(bc.db, from, to)
|
||||||
|
log.Debug("Find oldest indexed block", "oldest", oldest, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
|
||||||
|
// Re-construct missing tx indices.
|
||||||
|
if oldest == nil {
|
||||||
|
rawdb.IndexTxLookup(bc.db, from, to) // No block has been indexed.
|
||||||
|
} else {
|
||||||
|
rawdb.IndexTxLookup(bc.db, from, *oldest)
|
||||||
|
}
|
||||||
|
// Delete useless tx indices if user requires.
|
||||||
|
if from > 0 {
|
||||||
|
rawdb.RemoveTxsLookup(bc.db, 0, from)
|
||||||
|
}
|
||||||
|
log.Debug("Initialised transaction indices", "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
}
|
||||||
|
// indexBlocks reindex or unindex transaction indices depends
|
||||||
|
// on user's requirement.
|
||||||
|
indexBlocks := func(oldest uint64, head uint64) {
|
||||||
|
defer func() { done <- struct{}{} }()
|
||||||
|
|
||||||
|
// All indices should be reserved.
|
||||||
|
if bc.txLookupLimit == 0 || head <= bc.txLookupLimit {
|
||||||
|
if oldest == 0 {
|
||||||
|
// Short circuit if nothing to delete.
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
// Reindex all indices if necessary
|
||||||
|
rawdb.IndexTxLookup(bc.db, 0, oldest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if head-bc.txLookupLimit < oldest {
|
||||||
|
// Reindex a part of missing indices and rewind oldest indexed
|
||||||
|
// point to HEAD-limit
|
||||||
|
rawdb.IndexTxLookup(bc.db, head-bc.txLookupLimit, oldest)
|
||||||
|
} else {
|
||||||
|
// Unindex a part of stale indices and forward oldest indexed
|
||||||
|
// point to HEAD-limit
|
||||||
|
rawdb.RemoveTxsLookup(bc.db, oldest, head-bc.txLookupLimit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case head := <-headCh:
|
||||||
|
if done == nil {
|
||||||
|
done = make(chan struct{})
|
||||||
|
if number := rawdb.ReadOldestIndexedBlock(bc.db); number == nil {
|
||||||
|
go initialiseIndices(head.Block.NumberU64())
|
||||||
|
} else {
|
||||||
|
go indexBlocks(*number, head.Block.NumberU64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case <-done:
|
||||||
|
done = nil
|
||||||
|
case <-bc.quit:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
|
// BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
|
||||||
func (bc *BlockChain) BadBlocks() []*types.Block {
|
func (bc *BlockChain) BadBlocks() []*types.Block {
|
||||||
blocks := make([]*types.Block, 0, bc.badBlocks.Len())
|
blocks := make([]*types.Block, 0, bc.badBlocks.Len())
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *B
|
||||||
)
|
)
|
||||||
|
|
||||||
// Initialize a fresh chain with only a genesis block
|
// Initialize a fresh chain with only a genesis block
|
||||||
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, 0)
|
||||||
// Create and inject the requested chain
|
// Create and inject the requested chain
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return db, blockchain, nil
|
return db, blockchain, nil
|
||||||
|
|
@ -509,7 +509,7 @@ func testReorgBadHashes(t *testing.T, full bool) {
|
||||||
blockchain.Stop()
|
blockchain.Stop()
|
||||||
|
|
||||||
// Create a new BlockChain and check that it rolled back the state.
|
// Create a new BlockChain and check that it rolled back the state.
|
||||||
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil)
|
ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new chain manager: %v", err)
|
t.Fatalf("failed to create new chain manager: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -621,7 +621,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Import the chain as an archive node for the comparison baseline
|
// Import the chain as an archive node for the comparison baseline
|
||||||
archiveDb := rawdb.NewMemoryDatabase()
|
archiveDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(archiveDb)
|
gspec.MustCommit(archiveDb)
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer archive.Stop()
|
defer archive.Stop()
|
||||||
|
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
|
|
@ -630,7 +630,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
// Fast import the chain as a non-archive node to test
|
// Fast import the chain as a non-archive node to test
|
||||||
fastDb := rawdb.NewMemoryDatabase()
|
fastDb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(fastDb)
|
gspec.MustCommit(fastDb)
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -654,7 +654,7 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
||||||
|
|
@ -750,7 +750,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as an archive node and ensure all pointers are updated
|
// Import the chain as an archive node and ensure all pointers are updated
|
||||||
archiveDb, delfn := makeDb()
|
archiveDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
if n, err := archive.InsertChain(blocks); err != nil {
|
if n, err := archive.InsertChain(blocks); err != nil {
|
||||||
t.Fatalf("failed to process block %d: %v", n, err)
|
t.Fatalf("failed to process block %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -763,7 +763,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a non-archive node and ensure all pointers are updated
|
// Import the chain as a non-archive node and ensure all pointers are updated
|
||||||
fastDb, delfn := makeDb()
|
fastDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer fast.Stop()
|
defer fast.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -783,7 +783,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a ancient-first node and ensure all pointers are updated
|
// Import the chain as a ancient-first node and ensure all pointers are updated
|
||||||
ancientDb, delfn := makeDb()
|
ancientDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
|
|
||||||
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := ancient.InsertHeaderChain(headers, 1); err != nil {
|
||||||
|
|
@ -802,7 +802,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
// Import the chain as a light node and ensure all pointers are updated
|
// Import the chain as a light node and ensure all pointers are updated
|
||||||
lightDb, delfn := makeDb()
|
lightDb, delfn := makeDb()
|
||||||
defer delfn()
|
defer delfn()
|
||||||
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
if n, err := light.InsertHeaderChain(headers, 1); err != nil {
|
||||||
t.Fatalf("failed to insert header %d: %v", n, err)
|
t.Fatalf("failed to insert header %d: %v", n, err)
|
||||||
}
|
}
|
||||||
|
|
@ -871,7 +871,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
t.Fatalf("failed to insert original chain[%d]: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
@ -941,7 +941,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
rmLogsCh := make(chan RemovedLogsEvent)
|
rmLogsCh := make(chan RemovedLogsEvent)
|
||||||
|
|
@ -1018,7 +1018,7 @@ func TestLogRebirth(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
logsCh := make(chan []*types.Log)
|
logsCh := make(chan []*types.Log)
|
||||||
|
|
@ -1140,7 +1140,7 @@ func TestSideLogRebirth(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
logsCh := make(chan []*types.Log)
|
logsCh := make(chan []*types.Log)
|
||||||
|
|
@ -1195,7 +1195,7 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) {})
|
||||||
|
|
@ -1324,7 +1324,7 @@ func TestEIP155Transition(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
|
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1431,7 +1431,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) {
|
||||||
|
|
@ -1506,7 +1506,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1550,7 +1550,7 @@ func TestTrieForkGC(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1589,7 +1589,7 @@ func TestLargeReorgTrieGC(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1649,7 +1649,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -1668,7 +1668,7 @@ func TestBlockchainRecovery(t *testing.T) {
|
||||||
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash())
|
||||||
|
|
||||||
// Reopen broken blockchain again
|
// Reopen broken blockchain again
|
||||||
ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
if num := ancient.CurrentBlock().NumberU64(); num != 0 {
|
if num := ancient.CurrentBlock().NumberU64(); num != 0 {
|
||||||
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
t.Errorf("head block mismatch: have #%v, want #%v", num, 0)
|
||||||
|
|
@ -1705,7 +1705,7 @@ func TestIncompleteAncientReceiptChainInsertion(t *testing.T) {
|
||||||
t.Fatalf("failed to create temp freezer db: %v", err)
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
}
|
}
|
||||||
gspec.MustCommit(ancientDb)
|
gspec.MustCommit(ancientDb)
|
||||||
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer ancient.Stop()
|
defer ancient.Stop()
|
||||||
|
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -1762,7 +1762,7 @@ func TestLowDiffLongChain(t *testing.T) {
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1809,7 +1809,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
|
||||||
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
|
blocks, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, 2*TriesInMemory, nil)
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1906,7 +1906,7 @@ func testInsertKnownChainData(t *testing.T, typ string) {
|
||||||
new(Genesis).MustCommit(chaindb)
|
new(Genesis).MustCommit(chaindb)
|
||||||
defer os.RemoveAll(dir)
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tester chain: %v", err)
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2029,7 +2029,7 @@ func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, error
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
new(Genesis).MustCommit(diskdb)
|
new(Genesis).MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -2133,6 +2133,140 @@ func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTransactionIndices(t *testing.T) {
|
||||||
|
// Configure and generate a sample block chain
|
||||||
|
var (
|
||||||
|
gendb = rawdb.NewMemoryDatabase()
|
||||||
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
funds = big.NewInt(1000000000)
|
||||||
|
gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}
|
||||||
|
genesis = gspec.MustCommit(gendb)
|
||||||
|
signer = types.NewEIP155Signer(gspec.Config.ChainID)
|
||||||
|
)
|
||||||
|
height := uint64(128)
|
||||||
|
blocks, receipts := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, int(height), func(i int, block *BlockGen) {
|
||||||
|
tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
block.AddTx(tx)
|
||||||
|
})
|
||||||
|
blocks2, _ := GenerateChain(gspec.Config, blocks[len(blocks)-1], ethash.NewFaker(), gendb, 10, nil)
|
||||||
|
|
||||||
|
check := func(oldest *uint64, chain *BlockChain) {
|
||||||
|
indexed := rawdb.ReadOldestIndexedBlock(chain.db)
|
||||||
|
if oldest == nil && indexed != nil {
|
||||||
|
t.Fatalf("Oldest indexded block mismatch, want nil, have %d", *indexed)
|
||||||
|
}
|
||||||
|
if oldest != nil && *indexed != *oldest {
|
||||||
|
t.Fatalf("Oldest indexded block mismatch, want %d, have %d", *oldest, *indexed)
|
||||||
|
}
|
||||||
|
if oldest != nil {
|
||||||
|
for i := *oldest; i <= chain.CurrentBlock().NumberU64(); i++ {
|
||||||
|
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
|
||||||
|
if block.Transactions().Len() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index == nil {
|
||||||
|
t.Fatalf("Miss transaction indice, number %d hash %s", i, tx.Hash().Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for i := uint64(0); i < *oldest; i++ {
|
||||||
|
block := rawdb.ReadBlock(chain.db, rawdb.ReadCanonicalHash(chain.db, i), i)
|
||||||
|
if block.Transactions().Len() == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
if index := rawdb.ReadTxLookupEntry(chain.db, tx.Hash()); index != nil {
|
||||||
|
t.Fatalf("Transaction indice should be deleted, number %d hash %s", i, tx.Hash().Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Freezer style fast import the chain.
|
||||||
|
frdir, err := ioutil.TempDir("", "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create temp freezer dir: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Remove(frdir)
|
||||||
|
ancientDb, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
|
}
|
||||||
|
gspec.MustCommit(ancientDb)
|
||||||
|
|
||||||
|
// Import all blocks into ancient db
|
||||||
|
chain, err := NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
for i, block := range blocks {
|
||||||
|
headers[i] = block.Header()
|
||||||
|
}
|
||||||
|
if n, err := chain.InsertHeaderChain(headers, 0); err != nil {
|
||||||
|
t.Fatalf("failed to insert header %d: %v", n, err)
|
||||||
|
}
|
||||||
|
if n, err := chain.InsertReceiptChain(blocks, receipts, 128); err != nil {
|
||||||
|
t.Fatalf("block %d: failed to insert into chain: %v", n, err)
|
||||||
|
}
|
||||||
|
chain.Stop()
|
||||||
|
ancientDb.Close()
|
||||||
|
|
||||||
|
// Reconstruct an ancient db with inserted ancient blocks.
|
||||||
|
ancientDb, err = rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), frdir, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create temp freezer db: %v", err)
|
||||||
|
}
|
||||||
|
gspec.MustCommit(ancientDb)
|
||||||
|
|
||||||
|
var oldest uint64
|
||||||
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
chain.InsertChain(blocks2[:1]) // Feed chain a higher block to trigger indices updater.
|
||||||
|
time.Sleep(50 * time.Millisecond) // Wait for indices initialisation
|
||||||
|
check(&oldest, chain)
|
||||||
|
chain.Stop()
|
||||||
|
|
||||||
|
// Reconstruct a blockchain which only reserves HEAD-64 tx indices
|
||||||
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 64)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
chain.InsertChain(blocks2[1:2]) // Feed chain a higher block to trigger indices updater.
|
||||||
|
time.Sleep(50 * time.Millisecond) // Wait for indices initialisation
|
||||||
|
oldest = chain.CurrentBlock().NumberU64() - 64
|
||||||
|
check(&oldest, chain)
|
||||||
|
chain.Stop()
|
||||||
|
|
||||||
|
// Reconstruct a block which only reserves HEAD-32 tx indices, shorten the indices history.
|
||||||
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 32)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
chain.InsertChain(blocks2[2:3]) // Feed chain a higher block to trigger indices updater.
|
||||||
|
time.Sleep(50 * time.Millisecond) // Wait for indices initialisation
|
||||||
|
oldest = chain.CurrentBlock().NumberU64() - 32
|
||||||
|
check(&oldest, chain)
|
||||||
|
chain.Stop()
|
||||||
|
|
||||||
|
// Reconstruct a block which only reserves all tx indices, extends the indices history
|
||||||
|
chain, err = NewBlockChain(ancientDb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create tester chain: %v", err)
|
||||||
|
}
|
||||||
|
chain.InsertChain(blocks2[3:4]) // Feed chain a higher block to trigger indices updater.
|
||||||
|
time.Sleep(50 * time.Millisecond) // Wait for indices initialisation
|
||||||
|
oldest = 0
|
||||||
|
check(&oldest, chain)
|
||||||
|
}
|
||||||
|
|
||||||
// Benchmarks large blocks with value transfers to non-existing accounts
|
// Benchmarks large blocks with value transfers to non-existing accounts
|
||||||
func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) {
|
func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) {
|
||||||
var (
|
var (
|
||||||
|
|
@ -2178,7 +2312,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in
|
||||||
diskdb := rawdb.NewMemoryDatabase()
|
diskdb := rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(diskdb)
|
gspec.MustCommit(diskdb)
|
||||||
|
|
||||||
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil)
|
chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to create tester chain: %v", err)
|
b.Fatalf("failed to create tester chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func ExampleGenerateChain() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer blockchain.Stop()
|
defer blockchain.Stop()
|
||||||
|
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
proConf.DAOForkBlock = forkBlock
|
proConf.DAOForkBlock = forkBlock
|
||||||
proConf.DAOForkSupport = true
|
proConf.DAOForkSupport = true
|
||||||
|
|
||||||
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer proBc.Stop()
|
defer proBc.Stop()
|
||||||
|
|
||||||
conDb := rawdb.NewMemoryDatabase()
|
conDb := rawdb.NewMemoryDatabase()
|
||||||
|
|
@ -55,7 +55,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
conConf.DAOForkBlock = forkBlock
|
conConf.DAOForkBlock = forkBlock
|
||||||
conConf.DAOForkSupport = false
|
conConf.DAOForkSupport = false
|
||||||
|
|
||||||
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer conBc.Stop()
|
defer conBc.Stop()
|
||||||
|
|
||||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
if _, err := proBc.InsertChain(prefix); err != nil {
|
||||||
|
|
@ -69,7 +69,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a pro-fork block, and try to feed into the no-fork chain
|
// Create a pro-fork block, and try to feed into the no-fork chain
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -94,7 +94,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Create a no-fork block, and try to feed into the pro-fork chain
|
// Create a no-fork block, and try to feed into the pro-fork chain
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -120,7 +120,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
// Verify that contra-forkers accept pro-fork extra-datas after forking finishes
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().NumberU64()))
|
||||||
|
|
@ -140,7 +140,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
gspec.MustCommit(db)
|
gspec.MustCommit(db)
|
||||||
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil)
|
bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().NumberU64()))
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ func TestSetupGenesis(t *testing.T) {
|
||||||
// Advance to block #4, past the homestead transition block of customg.
|
// Advance to block #4, past the homestead transition block of customg.
|
||||||
genesis := oldcustomg.MustCommit(db)
|
genesis := oldcustomg.MustCommit(db)
|
||||||
|
|
||||||
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil)
|
bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, 0)
|
||||||
defer bc.Stop()
|
defer bc.Stop()
|
||||||
|
|
||||||
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil)
|
||||||
|
|
|
||||||
|
|
@ -171,10 +171,11 @@ func WriteFastTrieProgress(db ethdb.KeyValueWriter, count uint64) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAncientTxLookupProgress retrieves the number of ancient blocks which
|
// ReadOldestIndexedBlock retrieves the number of oldest indexed block
|
||||||
// txlookup has been inserted to allow reporting correct numbers across restarts.
|
// whose transaction indices has been indexed. If the corresponding entry
|
||||||
func ReadAncientTxLookupProgress(db ethdb.KeyValueReader) *uint64 {
|
// is non-existent in database it means the indexing has been finished.
|
||||||
data, _ := db.Get(ancientTxLookupProgressKey)
|
func ReadOldestIndexedBlock(db ethdb.KeyValueReader) *uint64 {
|
||||||
|
data, _ := db.Get(oldestIndexedBlockKey)
|
||||||
if len(data) != 8 {
|
if len(data) != 8 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -182,18 +183,11 @@ func ReadAncientTxLookupProgress(db ethdb.KeyValueReader) *uint64 {
|
||||||
return &number
|
return &number
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteAncientTxLookupProgress stores the ancient txlookup process counter to support
|
// WriteOldestIndexedBlock stores the number of oldest indexed block
|
||||||
// retrieving it across restarts.
|
// into database.
|
||||||
func WriteAncientTxLookupProgress(db ethdb.KeyValueWriter, number uint64) {
|
func WriteOldestIndexedBlock(db ethdb.KeyValueWriter, number uint64) {
|
||||||
if err := db.Put(ancientTxLookupProgressKey, encodeBlockNumber(number)); err != nil {
|
if err := db.Put(oldestIndexedBlockKey, encodeBlockNumber(number)); err != nil {
|
||||||
log.Crit("Failed to store head number of txlookup", "err", err)
|
log.Crit("Failed to store the number of oldest indexed block", "err", err)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteAncientTxLookupProgress deletes the ancient txlookup progress.
|
|
||||||
func DeleteAncientTxLookupProgress(db ethdb.KeyValueWriter) {
|
|
||||||
if err := db.Delete(ancientTxLookupProgressKey); err != nil {
|
|
||||||
log.Crit("Failed to delete ancient txlookup progress entry", "err", err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -584,3 +578,40 @@ func FindCommonAncestor(db ethdb.Reader, a, b *types.Header) *types.Header {
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FindOldestIndexedBlock binary searches the oldest block which has been indexed.
|
||||||
|
// We will always ensures that if Bi is indexed, then Bi+1 must has been indexed.
|
||||||
|
//
|
||||||
|
// If no block has been indexed, then the returned value is to+1.
|
||||||
|
//
|
||||||
|
// The block doesn't contain any transaction will be regarded as unindexed. It can
|
||||||
|
// cause the blocks before this block can be reindexed.
|
||||||
|
func FindOldestIndexedBlock(db ethdb.Reader, from uint64, to uint64) *uint64 {
|
||||||
|
low, high := from, to+1
|
||||||
|
|
||||||
|
check := func(number uint64) bool {
|
||||||
|
block := ReadBlock(db, ReadCanonicalHash(db, number), number)
|
||||||
|
if block == nil {
|
||||||
|
log.Crit("Failed to retrieve block from database", "number", number)
|
||||||
|
}
|
||||||
|
if block.Transactions().Len() == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if ReadTxLookupEntry(db, block.Transactions()[0].Hash()) == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for low != high {
|
||||||
|
mid := (low + high) / 2
|
||||||
|
if !check(mid) {
|
||||||
|
low = mid + 1
|
||||||
|
} else {
|
||||||
|
high = mid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if low == to+1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &low
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -358,3 +358,52 @@ func checkReceiptsRLP(have, want types.Receipts) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindOldestIndexedBlock(t *testing.T) {
|
||||||
|
var cases = []struct {
|
||||||
|
empty bool
|
||||||
|
oldest uint64
|
||||||
|
height uint64
|
||||||
|
nilBlocks map[uint64]bool
|
||||||
|
expect uint64
|
||||||
|
}{
|
||||||
|
{true, 0, 10, nil, 0}, // No block has been indexed
|
||||||
|
{false, 0, 10, nil, 1}, // Genesis block doesn't have indices
|
||||||
|
{false, 1, 10, nil, 1},
|
||||||
|
{false, 4, 10, nil, 4},
|
||||||
|
{false, 5, 10, nil, 5},
|
||||||
|
{false, 6, 10, nil, 6},
|
||||||
|
{false, 10, 10, nil, 10},
|
||||||
|
{false, 3, 10, map[uint64]bool{4: true, 6: true, 8: true}, 5},
|
||||||
|
}
|
||||||
|
for cid, c := range cases {
|
||||||
|
var (
|
||||||
|
db = NewMemoryDatabase()
|
||||||
|
block *types.Block
|
||||||
|
)
|
||||||
|
for i := uint64(0); i <= c.height; i++ {
|
||||||
|
if i == 0 {
|
||||||
|
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, nil, nil, nil) // Empty genesis block
|
||||||
|
} else {
|
||||||
|
tx := types.NewTransaction(i, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
|
||||||
|
txset := []*types.Transaction{tx}
|
||||||
|
if c.nilBlocks != nil && c.nilBlocks[i] {
|
||||||
|
txset = nil
|
||||||
|
}
|
||||||
|
block = types.NewBlock(&types.Header{Number: big.NewInt(int64(i))}, txset, nil, nil)
|
||||||
|
}
|
||||||
|
WriteBlock(db, block)
|
||||||
|
WriteCanonicalHash(db, block.Hash(), block.NumberU64())
|
||||||
|
if !c.empty && block.NumberU64() >= c.oldest {
|
||||||
|
WriteTxLookupEntries(db, block)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res := FindOldestIndexedBlock(db, 0, c.height)
|
||||||
|
if c.empty && res != nil {
|
||||||
|
t.Fatalf("Case %d failed, oldest block mismatch, want nil, have %d", cid, *res)
|
||||||
|
}
|
||||||
|
if !c.empty && *res != c.expect {
|
||||||
|
t.Fatalf("Case %d failed, oldest block mismatch, want %d, have %d", cid, c.expect, *res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,16 @@ func WriteTxLookupEntries(db ethdb.KeyValueWriter, block *types.Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteTxLookupEntries removes all transaction lookup indices contained in
|
||||||
|
// given block.
|
||||||
|
func DeleteTxLookupEntries(db ethdb.KeyValueWriter, block *types.Block) {
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
if err := db.Delete(txLookupKey(tx.Hash())); err != nil {
|
||||||
|
log.Crit("Failed to delete transaction lookup entry", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
||||||
func DeleteTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) {
|
func DeleteTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) {
|
||||||
db.Delete(txLookupKey(hash))
|
db.Delete(txLookupKey(hash))
|
||||||
|
|
|
||||||
230
core/rawdb/chain_iterator.go
Normal file
230
core/rawdb/chain_iterator.go
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
// Copyright 2019 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// 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/>.
|
||||||
|
|
||||||
|
package rawdb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
"runtime"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
prepareCallback func(*types.Block) // The callback for customized prepare operation.
|
||||||
|
actionCallback func(ethdb.Batch, *types.Block) // The callback for customized action.
|
||||||
|
)
|
||||||
|
|
||||||
|
// iterateCanonicalChain iterates the specified range canonical chain and then apply
|
||||||
|
// the given action callback.
|
||||||
|
// Note for forward iteration, the range is [from, to), otherwise the range is (from, to].
|
||||||
|
func iterateCanonicalChain(db ethdb.Database, from uint64, to uint64, typ string, prepare prepareCallback, action actionCallback, reverse bool, report bool) error {
|
||||||
|
// Short circuit if the action is nil.
|
||||||
|
if action == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Short circuit if the iteration range is invalid.
|
||||||
|
if from >= to {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Spawn multi-routines, iterate over the specified blocks and invoke prepare
|
||||||
|
// callback concurrently.
|
||||||
|
var (
|
||||||
|
number int64
|
||||||
|
results = make(chan *types.Block, 4*runtime.NumCPU())
|
||||||
|
)
|
||||||
|
if !reverse {
|
||||||
|
number = int64(from - 1)
|
||||||
|
} else {
|
||||||
|
number = int64(to + 1)
|
||||||
|
}
|
||||||
|
abort := make(chan struct{})
|
||||||
|
defer close(abort)
|
||||||
|
|
||||||
|
for i := 0; i < runtime.NumCPU(); i++ {
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
// Fetch the next task number, terminating if everything's done
|
||||||
|
var n int64
|
||||||
|
if !reverse {
|
||||||
|
n = atomic.AddInt64(&number, 1)
|
||||||
|
if n >= int64(to) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
n = atomic.AddInt64(&number, -1)
|
||||||
|
if n <= int64(from) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block := ReadBlock(db, ReadCanonicalHash(db, uint64(n)), uint64(n))
|
||||||
|
if prepare != nil && block != nil {
|
||||||
|
prepare(block)
|
||||||
|
}
|
||||||
|
// Feed the block to the aggregator, or abort on interrupt
|
||||||
|
select {
|
||||||
|
case results <- block:
|
||||||
|
case <-abort:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
// Reassemble the blocks into a contiguous stream and apply the action callback.
|
||||||
|
var (
|
||||||
|
next, first, last int64
|
||||||
|
queue = prque.New(nil)
|
||||||
|
|
||||||
|
batch = db.NewBatch()
|
||||||
|
start = time.Now()
|
||||||
|
logged time.Time
|
||||||
|
)
|
||||||
|
if !reverse {
|
||||||
|
next, first, last = int64(from), int64(from), int64(to)
|
||||||
|
} else {
|
||||||
|
next, first, last = int64(to), int64(to), int64(from)
|
||||||
|
}
|
||||||
|
logFn := log.Debug
|
||||||
|
if report {
|
||||||
|
logFn = log.Info
|
||||||
|
}
|
||||||
|
for i := from; i < to; i++ {
|
||||||
|
// Retrieve the next result and bail if it's nil
|
||||||
|
block := <-results
|
||||||
|
if block == nil {
|
||||||
|
return errors.New("broken database")
|
||||||
|
}
|
||||||
|
// Push the block into the import queue and process contiguous ranges
|
||||||
|
priority := -int64(block.NumberU64())
|
||||||
|
if reverse {
|
||||||
|
priority = int64(block.NumberU64())
|
||||||
|
}
|
||||||
|
queue.Push(block, priority)
|
||||||
|
for !queue.Empty() {
|
||||||
|
// If the next available item is gapped, return
|
||||||
|
if _, priority := queue.Peek(); !reverse && -priority != next || reverse && priority != next {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Next block available, pop it off and index it
|
||||||
|
block = queue.PopItem().(*types.Block)
|
||||||
|
|
||||||
|
if !reverse {
|
||||||
|
next++
|
||||||
|
} else {
|
||||||
|
next--
|
||||||
|
}
|
||||||
|
// Invoke action to inject specified data into key-value database.
|
||||||
|
action(batch, block)
|
||||||
|
|
||||||
|
// If enough data was accumulated in memory or we're at the last block, dump to disk
|
||||||
|
if batch.ValueSize() > ethdb.IdealBatchSize || next == last {
|
||||||
|
if err := batch.Write(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
batch.Reset()
|
||||||
|
}
|
||||||
|
// If we've spent too much time already, notify the user of what we're doing
|
||||||
|
if time.Since(logged) > 8*time.Second {
|
||||||
|
logFn("Iterating canonical chain", "type", typ, "reserve", reverse, "number", block.Number(), "hash", block.Hash(), "total", int64(math.Abs(float64(next-first))), "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
logged = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logFn("Iterated canonical chain", "type", typ, "reverse", reverse, "total", to-from, "elapsed", common.PrettyDuration(time.Since(start)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitBlockIndexFromFreezer reinitializes an empty database from a previous batch
|
||||||
|
// of frozen ancient blocks. The method iterates over all the frozen blocks and
|
||||||
|
// injects into the database the block hash->number mappings and the transaction
|
||||||
|
// lookup entries.
|
||||||
|
func InitBlockIndexFromFreezer(db ethdb.Database) {
|
||||||
|
// If we can't access the freezer or it's empty, abort
|
||||||
|
frozen, err := db.Ancients()
|
||||||
|
if err != nil || frozen == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// hashBlock calculates block hash in advance using the multi-routine's concurrent
|
||||||
|
// computing power.
|
||||||
|
hashBlock := func(block *types.Block) { block.Hash() }
|
||||||
|
|
||||||
|
// writeIndex injects hash <-> number mapping into the database.
|
||||||
|
writeIndex := func(batch ethdb.Batch, block *types.Block) { WriteHeaderNumber(batch, block.Hash(), block.NumberU64()) }
|
||||||
|
|
||||||
|
if err := iterateCanonicalChain(db, 0, frozen, "blocks", hashBlock, writeIndex, false, true); err != nil {
|
||||||
|
log.Crit("Failed to iterate canonical chain", "err", err)
|
||||||
|
}
|
||||||
|
hash := ReadCanonicalHash(db, frozen-1)
|
||||||
|
WriteHeadHeaderHash(db, hash)
|
||||||
|
WriteHeadFastBlockHash(db, hash)
|
||||||
|
log.Info("Initialized chain from ancient data", "number", frozen-1, "hash", hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexTxLookup initializes txlookup indices of the specified range blocks into the database.
|
||||||
|
//
|
||||||
|
// This function iterates canonical chain in reverse order, it has two advantages:
|
||||||
|
// * If Geth crashes during the indexing without writing the oldest flag, we can
|
||||||
|
// binary search to quickly locate the oldest indexed block
|
||||||
|
// * We can write oldest indexed block flag periodically even without the whole
|
||||||
|
// indexing procedure is finished. So that we can resume indexing procedure next
|
||||||
|
// time quickly.
|
||||||
|
func IndexTxLookup(db ethdb.Database, from uint64, to uint64) {
|
||||||
|
// hashTxs calculates transaction hash in advance using the multi-routine's
|
||||||
|
// concurrent computing power.
|
||||||
|
hashTxs := func(block *types.Block) {
|
||||||
|
for _, tx := range block.Transactions() {
|
||||||
|
tx.Hash()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// writeIndices injects txlookup indices into the database.
|
||||||
|
writeIndices := func(batch ethdb.Batch, block *types.Block) {
|
||||||
|
WriteTxLookupEntries(batch, block)
|
||||||
|
if block.NumberU64()%1000000 == 0 {
|
||||||
|
WriteOldestIndexedBlock(batch, block.NumberU64())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := iterateCanonicalChain(db, from, to, "txlookup", hashTxs, writeIndices, true, true); err != nil {
|
||||||
|
log.Crit("Failed to iterate canonical chain", "err", err)
|
||||||
|
}
|
||||||
|
WriteOldestIndexedBlock(db, from)
|
||||||
|
log.Info("Constructed transaction indices", "from", from, "to", to, "count", to-from)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveTxsLookup removes txlookup indices of the specified range blocks.
|
||||||
|
func RemoveTxsLookup(db ethdb.Database, from uint64, to uint64) {
|
||||||
|
// Write flag first and then unindex the transaction indices. Some indices
|
||||||
|
// will be left in the database if crash happens but it's fine.
|
||||||
|
WriteOldestIndexedBlock(db, to)
|
||||||
|
|
||||||
|
if from+1 == to {
|
||||||
|
hash := ReadCanonicalHash(db, from)
|
||||||
|
DeleteTxLookupEntries(db, ReadBlock(db, hash, from))
|
||||||
|
log.Debug("Removed transaction indices", "number", from, "hash", hash)
|
||||||
|
} else {
|
||||||
|
deleteIndices := func(batch ethdb.Batch, block *types.Block) { DeleteTxLookupEntries(batch, block) }
|
||||||
|
if err := iterateCanonicalChain(db, from, to, "txlookup", nil, deleteIndices, false, false); err != nil {
|
||||||
|
log.Crit("Failed to iterate canonical chain", "err", err)
|
||||||
|
}
|
||||||
|
log.Debug("Removed transaction indices", "from", from, "to", to, "count", to-from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
// Copyright 2019 The go-ethereum Authors
|
|
||||||
// This file is part of the go-ethereum library.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU Lesser General Public License for more details.
|
|
||||||
//
|
|
||||||
// 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/>.
|
|
||||||
|
|
||||||
package rawdb
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"runtime"
|
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
initPrepare func(*types.Block) // The callback for customized prepare operation.
|
|
||||||
initAction func(ethdb.Batch, *types.Block) // The callback for customized initialisation action.
|
|
||||||
)
|
|
||||||
|
|
||||||
// iterateAncient iterates the specified range blocks from ancient database
|
|
||||||
// and then apply initialisation action.
|
|
||||||
func iterateAncient(db ethdb.Database, from uint64, typ string, prepare initPrepare, action initAction) error {
|
|
||||||
// Short circuit if the init action is nil.
|
|
||||||
if action == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// If we can't access the freezer or it's empty, abort
|
|
||||||
frozen, err := db.Ancients()
|
|
||||||
if err != nil || frozen == 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// Spawn multi-routines, iterate over the specified blocks and invoke prepare
|
|
||||||
// callback concurrently.
|
|
||||||
var (
|
|
||||||
number uint64
|
|
||||||
results = make(chan *types.Block, 4*runtime.NumCPU())
|
|
||||||
)
|
|
||||||
if from == 0 {
|
|
||||||
number = ^uint64(0) // -1
|
|
||||||
} else {
|
|
||||||
number = from - 1
|
|
||||||
}
|
|
||||||
abort := make(chan struct{})
|
|
||||||
defer close(abort)
|
|
||||||
|
|
||||||
for i := 0; i < runtime.NumCPU(); i++ {
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
// Fetch the next task number, terminating if everything's done
|
|
||||||
n := atomic.AddUint64(&number, 1)
|
|
||||||
if n >= frozen {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Retrieve the block from the freezer (no need for the hash, we pull by
|
|
||||||
// number from the freezer).
|
|
||||||
block := ReadBlock(db, common.Hash{}, n)
|
|
||||||
if prepare != nil && block != nil {
|
|
||||||
prepare(block)
|
|
||||||
}
|
|
||||||
// Feed the block to the aggregator, or abort on interrupt
|
|
||||||
select {
|
|
||||||
case results <- block:
|
|
||||||
case <-abort:
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
// Reassemble the blocks into a contiguous stream and apply the action callback.
|
|
||||||
var (
|
|
||||||
queue = prque.New(nil)
|
|
||||||
next = int64(from)
|
|
||||||
|
|
||||||
batch = db.NewBatch()
|
|
||||||
start = time.Now()
|
|
||||||
logged time.Time
|
|
||||||
)
|
|
||||||
for i := from; i < frozen; i++ {
|
|
||||||
// Retrieve the next result and bail if it's nil
|
|
||||||
block := <-results
|
|
||||||
if block == nil {
|
|
||||||
return errors.New("broken database")
|
|
||||||
}
|
|
||||||
// Push the block into the import queue and process contiguous ranges
|
|
||||||
queue.Push(block, -int64(block.NumberU64()))
|
|
||||||
for !queue.Empty() {
|
|
||||||
// If the next available item is gapped, return
|
|
||||||
if _, priority := queue.Peek(); -priority != next {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// Next block available, pop it off and index it
|
|
||||||
block = queue.PopItem().(*types.Block)
|
|
||||||
next++
|
|
||||||
|
|
||||||
// Invoke action to inject specified data into key-value database.
|
|
||||||
action(batch, block)
|
|
||||||
|
|
||||||
// If enough data was accumulated in memory or we're at the last block, dump to disk
|
|
||||||
if batch.ValueSize() > ethdb.IdealBatchSize || uint64(next) == frozen {
|
|
||||||
if err := batch.Write(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
batch.Reset()
|
|
||||||
}
|
|
||||||
// If we've spent too much time already, notify the user of what we're doing
|
|
||||||
if time.Since(logged) > 8*time.Second {
|
|
||||||
log.Info("Initializing chain from ancient data", "type", typ, "number", block.Number(), "hash", block.Hash(), "total", uint64(next)-from, "elapsed", common.PrettyDuration(time.Since(start)))
|
|
||||||
logged = time.Now()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
log.Info("Initialized chain from ancient data", "type", typ, "number", frozen-from, "elapsed", common.PrettyDuration(time.Since(start)))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitBlockIndexFromFreezer reinitializes an empty database from a previous batch
|
|
||||||
// of frozen ancient blocks. The method iterates over all the frozen blocks and
|
|
||||||
// injects into the database the block hash->number mappings and the transaction
|
|
||||||
// lookup entries.
|
|
||||||
func InitBlockIndexFromFreezer(db ethdb.Database) error {
|
|
||||||
// If we can't access the freezer or it's empty, abort
|
|
||||||
frozen, err := db.Ancients()
|
|
||||||
if err != nil || frozen == 0 {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// hashBlock calculates block hash in advance using the multi-routine's concurrent
|
|
||||||
// computing power.
|
|
||||||
hashBlock := func(block *types.Block) { block.Hash() }
|
|
||||||
|
|
||||||
// writeIndex injects hash <-> number mapping into the database.
|
|
||||||
writeIndex := func(batch ethdb.Batch, block *types.Block) { WriteHeaderNumber(batch, block.Hash(), block.NumberU64()) }
|
|
||||||
|
|
||||||
if err := iterateAncient(db, 0, "blocks", hashBlock, writeIndex); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hash := ReadCanonicalHash(db, frozen-1)
|
|
||||||
WriteHeadHeaderHash(db, hash)
|
|
||||||
WriteHeadFastBlockHash(db, hash)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitTxsLookupFromFreezer initializes txlookup indexes in the database.
|
|
||||||
func InitTxsLookupFromFreezer(db ethdb.Database, from uint64) error {
|
|
||||||
// hashTxs calculates transaction hash in advance using the multi-routine's
|
|
||||||
// concurrent computing power.
|
|
||||||
hashTxs := func(block *types.Block) {
|
|
||||||
for _, tx := range block.Transactions() {
|
|
||||||
tx.Hash()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// writeIndex injects txlookup indexes into the database.
|
|
||||||
writeIndex := func(batch ethdb.Batch, block *types.Block) {
|
|
||||||
WriteTxLookupEntries(batch, block)
|
|
||||||
if block.NumberU64()%10000 == 0 {
|
|
||||||
WriteAncientTxLookupProgress(batch, block.NumberU64())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err := iterateAncient(db, from, "txlookup", hashTxs, writeIndex); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
DeleteAncientTxLookupProgress(db) // Mark all txlookup indexes of ancient blocks have been inserted.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -41,8 +41,8 @@ var (
|
||||||
// fastTrieProgressKey tracks the number of trie entries imported during fast sync.
|
// fastTrieProgressKey tracks the number of trie entries imported during fast sync.
|
||||||
fastTrieProgressKey = []byte("TrieSync")
|
fastTrieProgressKey = []byte("TrieSync")
|
||||||
|
|
||||||
// ancientTxLookupProgressKey tracks the progress of ancient txs lookup insertion.
|
// oldestIndexedBlockKey tracks the oldest block whose transaction indices(txlookup) has been indexed.
|
||||||
ancientTxLookupProgressKey = []byte("AncientTxsLookup")
|
oldestIndexedBlockKey = []byte("OldestIndexedBlock")
|
||||||
|
|
||||||
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
|
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
|
||||||
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
|
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
TrieTimeLimit: config.TrieTimeout,
|
TrieTimeLimit: config.TrieTimeout,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve)
|
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, config.TxLookupLimit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ type Config struct {
|
||||||
NoPruning bool // Whether to disable pruning and flush everything to disk
|
NoPruning bool // Whether to disable pruning and flush everything to disk
|
||||||
NoPrefetch bool // Whether to disable prefetching and only load state on demand
|
NoPrefetch bool // Whether to disable prefetching and only load state on demand
|
||||||
|
|
||||||
|
TxLookupLimit uint64 `toml:",omitempty"` // The maximum number of blocks from head whose tx indices are reserved.
|
||||||
|
|
||||||
// Whitelist of required block number -> hash values to accept
|
// Whitelist of required block number -> hash values to accept
|
||||||
Whitelist map[uint64]common.Hash `toml:"-"`
|
Whitelist map[uint64]common.Hash `toml:"-"`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||||
SyncMode downloader.SyncMode
|
SyncMode downloader.SyncMode
|
||||||
NoPruning bool
|
NoPruning bool
|
||||||
NoPrefetch bool
|
NoPrefetch bool
|
||||||
|
TxLookupLimit uint64 `toml:",omitempty"`
|
||||||
Whitelist map[uint64]common.Hash `toml:"-"`
|
Whitelist map[uint64]common.Hash `toml:"-"`
|
||||||
LightServ int `toml:",omitempty"`
|
LightServ int `toml:",omitempty"`
|
||||||
LightIngress int `toml:",omitempty"`
|
LightIngress int `toml:",omitempty"`
|
||||||
|
|
@ -56,6 +57,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||||
enc.SyncMode = c.SyncMode
|
enc.SyncMode = c.SyncMode
|
||||||
enc.NoPruning = c.NoPruning
|
enc.NoPruning = c.NoPruning
|
||||||
enc.NoPrefetch = c.NoPrefetch
|
enc.NoPrefetch = c.NoPrefetch
|
||||||
|
enc.TxLookupLimit = c.TxLookupLimit
|
||||||
enc.Whitelist = c.Whitelist
|
enc.Whitelist = c.Whitelist
|
||||||
enc.LightServ = c.LightServ
|
enc.LightServ = c.LightServ
|
||||||
enc.LightIngress = c.LightIngress
|
enc.LightIngress = c.LightIngress
|
||||||
|
|
@ -93,6 +95,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
SyncMode *downloader.SyncMode
|
SyncMode *downloader.SyncMode
|
||||||
NoPruning *bool
|
NoPruning *bool
|
||||||
NoPrefetch *bool
|
NoPrefetch *bool
|
||||||
|
TxLookupLimit *uint64 `toml:",omitempty"`
|
||||||
Whitelist map[uint64]common.Hash `toml:"-"`
|
Whitelist map[uint64]common.Hash `toml:"-"`
|
||||||
LightServ *int `toml:",omitempty"`
|
LightServ *int `toml:",omitempty"`
|
||||||
LightIngress *int `toml:",omitempty"`
|
LightIngress *int `toml:",omitempty"`
|
||||||
|
|
@ -139,6 +142,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
if dec.NoPrefetch != nil {
|
if dec.NoPrefetch != nil {
|
||||||
c.NoPrefetch = *dec.NoPrefetch
|
c.NoPrefetch = *dec.NoPrefetch
|
||||||
}
|
}
|
||||||
|
if dec.TxLookupLimit != nil {
|
||||||
|
c.TxLookupLimit = *dec.TxLookupLimit
|
||||||
|
}
|
||||||
if dec.Whitelist != nil {
|
if dec.Whitelist != nil {
|
||||||
c.Whitelist = dec.Whitelist
|
c.Whitelist = dec.Whitelist
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -489,7 +489,7 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Create a checkpoint aware protocol manager
|
// Create a checkpoint aware protocol manager
|
||||||
blockchain, err := core.NewBlockChain(db, nil, config, ethash.NewFaker(), vm.Config{}, nil)
|
blockchain, err := core.NewBlockChain(db, nil, config, ethash.NewFaker(), vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new blockchain: %v", err)
|
t.Fatalf("failed to create new blockchain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -576,7 +576,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) {
|
||||||
gspec = &core.Genesis{Config: config}
|
gspec = &core.Genesis{Config: config}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
)
|
)
|
||||||
blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil)
|
blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create new blockchain: %v", err)
|
t.Fatalf("failed to create new blockchain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func
|
||||||
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
|
Alloc: core.GenesisAlloc{testBank: {Balance: big.NewInt(1000000)}},
|
||||||
}
|
}
|
||||||
genesis = gspec.MustCommit(db)
|
genesis = gspec.MustCommit(db)
|
||||||
blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
|
blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, 0)
|
||||||
)
|
)
|
||||||
chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator)
|
chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator)
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ func testChainOdr(t *testing.T, protocol int, fn odrTestFn) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil)
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, 0)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ func TestNodeIterator(t *testing.T) {
|
||||||
genesis = gspec.MustCommit(fulldb)
|
genesis = gspec.MustCommit(fulldb)
|
||||||
)
|
)
|
||||||
gspec.MustCommit(lightdb)
|
gspec.MustCommit(lightdb)
|
||||||
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil)
|
blockchain, _ := core.NewBlockChain(fulldb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, 0)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), fulldb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ func TestTxPool(t *testing.T) {
|
||||||
)
|
)
|
||||||
gspec.MustCommit(ldb)
|
gspec.MustCommit(ldb)
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil)
|
blockchain, _ := core.NewBlockChain(sdb, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, 0)
|
||||||
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
gchain, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), sdb, poolTestBlocks, txPoolTestChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
|
||||||
}
|
}
|
||||||
genesis := gspec.MustCommit(db)
|
genesis := gspec.MustCommit(db)
|
||||||
|
|
||||||
chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil)
|
chain, _ := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, 0)
|
||||||
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
txpool := core.NewTxPool(testTxPoolConfig, chainConfig, chain)
|
||||||
|
|
||||||
// Generate a small n-block chain and an uncle block for it
|
// Generate a small n-block chain and an uncle block for it
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ func (t *BlockTest) Run() error {
|
||||||
} else {
|
} else {
|
||||||
engine = ethash.NewShared()
|
engine = ethash.NewShared()
|
||||||
}
|
}
|
||||||
chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil)
|
chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, engine, vm.Config{}, nil, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue