diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index c6caf86bb54046d15529d2d8dd41729ef7c6492d..22917c86c10506d498138ff11778e4d9d04e18e1 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -70,18 +70,22 @@ type SimulatedBackend struct {
 	engine     consensus.Engine
 	blockchain *core.BlockChain // Ethereum blockchain to handle the consensus
 
-	mu            sync.Mutex
-	prependBlock  *types.Block
-	pendingHeader *types.Header
-	gasPool       *core.GasPool
-	pendingBlock  *types.Block // Currently pending block that will be imported on request
-	pendingTds    *state.TrieDbState
-	pendingState  *state.IntraBlockState // Currently pending state that will be the active on request
+	mu              sync.Mutex
+	prependBlock    *types.Block
+	pendingReceipts types.Receipts
+	pendingHeader   *types.Header
+	gasPool         *core.GasPool
+	pendingBlock    *types.Block // Currently pending block that will be imported on request
+	pendingReader   *state.PlainStateReader
+	pendingState    *state.IntraBlockState // Currently pending state that will be the active on request
 
 	events *filters.EventSystem // Event system for filtering log events live
 
-	config   *params.ChainConfig
-	txCacher *core.TxSenderCacher
+	config     *params.ChainConfig
+	txCacher   *core.TxSenderCacher
+	rmLogsFeed event.Feed
+	chainFeed  event.Feed
+	logsFeed   event.Feed
 }
 
 // NewSimulatedBackendWithDatabase creates a new binding backend based on the given database
@@ -104,9 +108,9 @@ func NewSimulatedBackendWithDatabase(database *ethdb.ObjectDatabase, alloc core.
 		engine:       engine,
 		blockchain:   blockchain,
 		config:       genesis.Config,
-		events:       filters.NewEventSystem(&filterBackend{database, blockchain}, false),
 		txCacher:     txCacher,
 	}
+	backend.events = filters.NewEventSystem(&filterBackend{database, backend}, false)
 	backend.emptyPendingBlock()
 	return backend
 }
@@ -119,7 +123,7 @@ func NewSimulatedBackendWithConfig(alloc core.GenesisAlloc, config *params.Chain
 	genesisBlock := genesis.MustCommit(database)
 	engine := ethash.NewFaker()
 
-	txCacher := core.NewTxSenderCacher(runtime.NumCPU())
+	txCacher := core.NewTxSenderCacher(1)
 	blockchain, err := core.NewBlockChain(database, nil, genesis.Config, engine, vm.Config{}, nil, txCacher)
 	if err != nil {
 		panic(err)
@@ -132,9 +136,9 @@ func NewSimulatedBackendWithConfig(alloc core.GenesisAlloc, config *params.Chain
 		engine:       engine,
 		blockchain:   blockchain,
 		config:       genesis.Config,
-		events:       filters.NewEventSystem(&filterBackend{database, blockchain}, false),
 		txCacher:     txCacher,
 	}
+	backend.events = filters.NewEventSystem(&filterBackend{database, backend}, false)
 	backend.emptyPendingBlock()
 	return backend
 }
@@ -162,9 +166,21 @@ func (b *SimulatedBackend) Commit() {
 	//fmt.Printf("---- Start committing block %d\n", b.pendingBlock.NumberU64())
 	b.mu.Lock()
 	defer b.mu.Unlock()
-	if _, err := b.blockchain.InsertChain(context.Background(), []*types.Block{b.pendingBlock}); err != nil {
-		panic(err)
-	}
+	stateWriter := state.NewPlainStateWriter(b.database, b.pendingBlock.NumberU64())
+	ctx := b.config.WithEIPsFlags(context.Background(), b.pendingHeader.Number)
+	rawdb.WriteBlock(ctx, b.database, b.pendingBlock)
+	rawdb.WriteCanonicalHash(b.database, b.pendingBlock.Hash(), b.pendingBlock.NumberU64())
+	rawdb.WriteTxLookupEntries(b.database, b.pendingBlock)
+	rawdb.WriteReceipts(b.database, b.pendingBlock.Hash(), b.pendingBlock.NumberU64(), b.pendingReceipts)
+	if err := b.pendingState.CommitBlock(ctx, stateWriter); err != nil {
+		panic(fmt.Errorf("committing block %d failed: %v", b.pendingBlock.NumberU64(), err))
+	}
+	//nolint:prealloc
+	var allLogs []*types.Log
+	for _, r := range b.pendingReceipts {
+		allLogs = append(allLogs, r.Logs...)
+	}
+	b.logsFeed.Send(allLogs)
 	//fmt.Printf("---- End committing block %d\n", b.pendingBlock.NumberU64())
 	b.prependBlock = b.pendingBlock
 	b.emptyPendingBlock()
@@ -179,26 +195,26 @@ func (b *SimulatedBackend) Rollback() {
 }
 
 func (b *SimulatedBackend) emptyPendingBlock() {
-	blocks, _, _ := core.GenerateChain(b.config, b.prependBlock, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}, false /* intermediateHashes */)
+	blocks, receipts, _ := core.GenerateChain(b.config, b.prependBlock, ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {}, false /* intermediateHashes */)
 	b.pendingBlock = blocks[0]
+	b.pendingReceipts = receipts[0]
 	b.pendingHeader = b.pendingBlock.Header()
 	b.gasPool = new(core.GasPool).AddGas(b.pendingHeader.GasLimit)
-	b.pendingTds = state.NewTrieDbState(b.prependBlock.Root(), b.database.NewBatch(), b.prependBlock.NumberU64())
-	b.pendingState = state.New(b.pendingTds)
-	b.pendingTds.StartNewBuffer()
+	b.pendingReader = state.NewPlainStateReader(b.database)
+	b.pendingState = state.New(b.pendingReader)
 }
 
 func (b *SimulatedBackend) prependingState() *state.IntraBlockState {
-	tds := state.NewTrieDbState(b.prependBlock.Root(), b.database.NewBatch(), b.prependBlock.NumberU64())
-	return state.New(tds)
+	dbs := state.NewPlainDBState(b.kv, b.prependBlock.NumberU64())
+	return state.New(dbs)
 }
 
 // stateByBlockNumber retrieves a state by a given blocknumber.
 func (b *SimulatedBackend) stateByBlockNumber(ctx context.Context, blockNumber *big.Int) (*state.IntraBlockState, error) {
-	if blockNumber == nil || blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) == 0 {
-		return state.New(state.NewDbState(b.kv, b.blockchain.CurrentBlock().NumberU64())), nil
+	if blockNumber == nil || blockNumber.Cmp(b.pendingBlock.Number()) == 0 {
+		return state.New(state.NewPlainDBState(b.kv, b.pendingBlock.NumberU64())), nil
 	}
-	return state.New(state.NewDbState(b.kv, uint64(blockNumber.Int64()))), nil
+	return state.New(state.NewPlainDBState(b.kv, uint64(blockNumber.Int64()))), nil
 }
 
 // CodeAt returns the code associated with a certain account in the blockchain.
@@ -288,7 +304,7 @@ func (b *SimulatedBackend) BlockByHash(ctx context.Context, hash common.Hash) (*
 		return b.pendingBlock, nil
 	}
 
-	block := b.blockchain.GetBlockByHash(hash)
+	block := rawdb.ReadBlockByHash(b.database, hash)
 	if block != nil {
 		return block, nil
 	}
@@ -308,11 +324,12 @@ func (b *SimulatedBackend) BlockByNumber(ctx context.Context, number *big.Int) (
 // blockByNumberNoLock retrieves a block from the database by number, caching it
 // (associated with its hash) if found without Lock.
 func (b *SimulatedBackend) blockByNumberNoLock(_ context.Context, number *big.Int) (*types.Block, error) {
-	if number == nil || number.Cmp(b.pendingBlock.Number()) == 0 {
-		return b.blockchain.CurrentBlock(), nil
+	if number == nil || number.Cmp(b.prependBlock.Number()) == 0 {
+		return b.prependBlock, nil
 	}
 
-	block := b.blockchain.GetBlockByNumber(uint64(number.Int64()))
+	hash := rawdb.ReadCanonicalHash(b.database, number.Uint64())
+	block := rawdb.ReadBlock(b.database, hash, number.Uint64())
 	if block == nil {
 		return nil, errBlockDoesNotExist
 	}
@@ -329,7 +346,11 @@ func (b *SimulatedBackend) HeaderByHash(ctx context.Context, hash common.Hash) (
 		return b.pendingBlock.Header(), nil
 	}
 
-	header := b.blockchain.GetHeaderByHash(hash)
+	number := rawdb.ReadHeaderNumber(b.database, hash)
+	if number == nil {
+		return nil, errBlockDoesNotExist
+	}
+	header := rawdb.ReadHeader(b.database, hash, *number)
 	if header == nil {
 		return nil, errBlockDoesNotExist
 	}
@@ -339,15 +360,16 @@ func (b *SimulatedBackend) HeaderByHash(ctx context.Context, hash common.Hash) (
 
 // HeaderByNumber returns a block header from the current canonical chain. If number is
 // nil, the latest known header is returned.
-func (b *SimulatedBackend) HeaderByNumber(ctx context.Context, block *big.Int) (*types.Header, error) {
+func (b *SimulatedBackend) HeaderByNumber(ctx context.Context, number *big.Int) (*types.Header, error) {
 	b.mu.Lock()
 	defer b.mu.Unlock()
 
-	if block == nil || block.Cmp(b.pendingBlock.Number()) == 0 {
-		return b.blockchain.CurrentHeader(), nil
+	if number == nil || number.Cmp(b.prependBlock.Number()) == 0 {
+		return b.prependBlock.Header(), nil
 	}
-
-	return b.blockchain.GetHeaderByNumber(uint64(block.Int64())), nil
+	hash := rawdb.ReadCanonicalHash(b.database, number.Uint64())
+	header := rawdb.ReadHeader(b.database, hash, number.Uint64())
+	return header, nil
 }
 
 // TransactionCount returns the number of transactions in a given block
@@ -359,7 +381,7 @@ func (b *SimulatedBackend) TransactionCount(ctx context.Context, blockHash commo
 		return uint(b.pendingBlock.Transactions().Len()), nil
 	}
 
-	block := b.blockchain.GetBlockByHash(blockHash)
+	block := rawdb.ReadBlockByHash(b.database, blockHash)
 	if block == nil {
 		return uint(0), errBlockDoesNotExist
 	}
@@ -381,7 +403,7 @@ func (b *SimulatedBackend) TransactionInBlock(ctx context.Context, blockHash com
 		return transactions[index], nil
 	}
 
-	block := b.blockchain.GetBlockByHash(blockHash)
+	block := rawdb.ReadBlockByHash(b.database, blockHash)
 	if block == nil {
 		return nil, errBlockDoesNotExist
 	}
@@ -437,11 +459,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
 	b.mu.Lock()
 	defer b.mu.Unlock()
 
-	if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
+	if blockNumber != nil && blockNumber.Cmp(b.pendingBlock.Number()) != 0 {
 		return nil, errBlockNumberUnsupported
 	}
-	s := state.New(state.NewDbState(b.kv, b.blockchain.CurrentBlock().NumberU64()))
-	res, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), s)
+	s := state.New(state.NewPlainStateReader(b.database))
+	res, err := b.callContract(ctx, call, b.pendingBlock, s)
 	if err != nil {
 		return nil, err
 	}
@@ -621,16 +643,17 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
 	}
 
 	b.pendingState.Prepare(tx.Hash(), common.Hash{}, len(b.pendingBlock.Transactions()))
+	//fmt.Printf("==== Start producing block %d, header: %d\n", b.pendingBlock.NumberU64(), b.pendingHeader.Number.Uint64())
 	if _, err := core.ApplyTransaction(
 		b.config, b.blockchain,
 		&b.pendingHeader.Coinbase, b.gasPool,
-		b.pendingState, b.pendingTds.TrieStateWriter(),
+		b.pendingState, state.NewNoopWriter(),
 		b.pendingHeader, tx,
 		&b.pendingHeader.GasUsed, vm.Config{}); err != nil {
 		return err
 	}
 	//fmt.Printf("==== Start producing block %d\n", (b.prependBlock.NumberU64() + 1))
-	blocks, _, err := core.GenerateChain(b.config, b.prependBlock, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
+	blocks, receipts, err := core.GenerateChain(b.config, b.prependBlock, ethash.NewFaker(), b.database, 1, func(number int, block *core.BlockGen) {
 		for _, tx := range b.pendingBlock.Transactions() {
 			block.AddTxWithChain(b.blockchain, tx)
 		}
@@ -639,8 +662,9 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
 	if err != nil {
 		return err
 	}
-	//fmt.Printf("==== End producing block %d\n", (b.prependBlock.NumberU64() + 1))
+	//fmt.Printf("==== End producing block %d\n", b.pendingBlock.NumberU64())
 	b.pendingBlock = blocks[0]
+	b.pendingReceipts = receipts[0]
 	b.pendingHeader = b.pendingBlock.Header()
 	return nil
 }
@@ -653,7 +677,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter
 	var filter *filters.Filter
 	if query.BlockHash != nil {
 		// Block filter requested, construct a single-shot filter
-		filter = filters.NewBlockFilter(&filterBackend{b.database, b.blockchain}, *query.BlockHash, query.Addresses, query.Topics)
+		filter = filters.NewBlockFilter(&filterBackend{b.database, b}, *query.BlockHash, query.Addresses, query.Topics)
 	} else {
 		// Initialize unset filter boundaried to run from genesis to chain head
 		from := int64(0)
@@ -665,7 +689,7 @@ func (b *SimulatedBackend) FilterLogs(ctx context.Context, query ethereum.Filter
 			to = query.ToBlock.Int64()
 		}
 		// Construct the range filter
-		filter = filters.NewRangeFilter(&filterBackend{b.database, b.blockchain}, from, to, query.Addresses, query.Topics)
+		filter = filters.NewRangeFilter(&filterBackend{b.database, b}, from, to, query.Addresses, query.Topics)
 	}
 	// Run the filter and return all the logs
 	logs, err := filter.Logs(ctx)
@@ -783,7 +807,7 @@ func (m callmsg) Data() []byte           { return m.CallMsg.Data }
 // taking bloom-bits acceleration structures into account.
 type filterBackend struct {
 	db ethdb.Database
-	bc *core.BlockChain
+	b  *SimulatedBackend
 }
 
 func (fb *filterBackend) ChainDb() ethdb.Database  { return fb.db }
@@ -791,13 +815,13 @@ func (fb *filterBackend) EventMux() *event.TypeMux { panic("not supported") }
 
 func (fb *filterBackend) HeaderByNumber(ctx context.Context, block rpc.BlockNumber) (*types.Header, error) {
 	if block == rpc.LatestBlockNumber {
-		return fb.bc.CurrentHeader(), nil
+		return fb.b.HeaderByNumber(ctx, nil)
 	}
-	return fb.bc.GetHeaderByNumber(uint64(block.Int64())), nil
+	return fb.b.HeaderByNumber(ctx, big.NewInt(block.Int64()))
 }
 
 func (fb *filterBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
-	return fb.bc.GetHeaderByHash(hash), nil
+	return fb.b.HeaderByHash(ctx, hash)
 }
 
 func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
@@ -805,7 +829,7 @@ func (fb *filterBackend) GetReceipts(ctx context.Context, hash common.Hash) (typ
 	if number == nil {
 		return nil, nil
 	}
-	return rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config()), nil
+	return rawdb.ReadReceipts(fb.db, hash, *number, fb.b.config), nil
 }
 
 func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*types.Log, error) {
@@ -813,7 +837,7 @@ func (fb *filterBackend) GetLogs(ctx context.Context, hash common.Hash) ([][]*ty
 	if number == nil {
 		return nil, nil
 	}
-	receipts := rawdb.ReadReceipts(fb.db, hash, *number, fb.bc.Config())
+	receipts := rawdb.ReadReceipts(fb.db, hash, *number, fb.b.config)
 	if receipts == nil {
 		return nil, nil
 	}
@@ -829,15 +853,15 @@ func (fb *filterBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.
 }
 
 func (fb *filterBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
-	return fb.bc.SubscribeChainEvent(ch)
+	return fb.b.chainFeed.Subscribe(ch)
 }
 
 func (fb *filterBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
-	return fb.bc.SubscribeRemovedLogsEvent(ch)
+	return fb.b.rmLogsFeed.Subscribe(ch)
 }
 
 func (fb *filterBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
-	return fb.bc.SubscribeLogsEvent(ch)
+	return fb.b.logsFeed.Subscribe(ch)
 }
 
 func (fb *filterBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
diff --git a/accounts/abi/bind/backends/simulated_test.go b/accounts/abi/bind/backends/simulated_test.go
index d0918e80f0a48707ac0d5ece75f383290f269445..e2cb8e3d58f000ac2cee3e5f8ff38cefce29ac13 100644
--- a/accounts/abi/bind/backends/simulated_test.go
+++ b/accounts/abi/bind/backends/simulated_test.go
@@ -69,7 +69,7 @@ func TestSimulatedBackend(t *testing.T) {
 
 	err = sim.SendTransaction(context.Background(), tx)
 	if err != nil {
-		t.Fatal("error sending transaction")
+		t.Fatalf("error sending transaction: %v", err)
 	}
 
 	txHash = tx.Hash()
@@ -134,7 +134,7 @@ func TestNewSimulatedBackend(t *testing.T) {
 		t.Errorf("expected sim blockchain config to equal params.AllEthashProtocolChanges, got %v", sim.config)
 	}
 
-	statedb := state.New(state.NewDbState(sim.KV(), sim.blockchain.CurrentBlock().NumberU64()))
+	statedb := state.New(state.NewPlainDBState(sim.KV(), sim.blockchain.CurrentBlock().NumberU64()))
 	bal := statedb.GetBalance(testAddr)
 	if !bal.Eq(expectedBal) {
 		t.Errorf("expected balance for test address not received. expected: %v actual: %v", expectedBal, bal)
diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go
index 2e1e3c2539cb8f8aebc96a69bd7f64acec6faa8d..b06b448091833f5191203dbdb62214f11299cd83 100644
--- a/accounts/abi/bind/bind_test.go
+++ b/accounts/abi/bind/bind_test.go
@@ -763,219 +763,219 @@ var bindTests = []struct {
 	{
 		`Eventer`,
 		`
-			contract Eventer {
-				event SimpleEvent (
-					address indexed Addr,
-					bytes32 indexed Id,
-					bool    indexed Flag,
-					uint    Value
-				);
-				function raiseSimpleEvent(address addr, bytes32 id, bool flag, uint value) {
-					SimpleEvent(addr, id, flag, value);
-				}
+				contract Eventer {
+					event SimpleEvent (
+						address indexed Addr,
+						bytes32 indexed Id,
+						bool    indexed Flag,
+						uint    Value
+					);
+					function raiseSimpleEvent(address addr, bytes32 id, bool flag, uint value) {
+						SimpleEvent(addr, id, flag, value);
+					}
 
-				event NodataEvent (
-					uint   indexed Number,
-					int16  indexed Short,
-					uint32 indexed Long
-				);
-				function raiseNodataEvent(uint number, int16 short, uint32 long) {
-					NodataEvent(number, short, long);
-				}
+					event NodataEvent (
+						uint   indexed Number,
+						int16  indexed Short,
+						uint32 indexed Long
+					);
+					function raiseNodataEvent(uint number, int16 short, uint32 long) {
+						NodataEvent(number, short, long);
+					}
 
-				event DynamicEvent (
-					string indexed IndexedString,
-					bytes  indexed IndexedBytes,
-					string NonIndexedString,
-					bytes  NonIndexedBytes
-				);
-				function raiseDynamicEvent(string str, bytes blob) {
-					DynamicEvent(str, blob, str, blob);
-				}
+					event DynamicEvent (
+						string indexed IndexedString,
+						bytes  indexed IndexedBytes,
+						string NonIndexedString,
+						bytes  NonIndexedBytes
+					);
+					function raiseDynamicEvent(string str, bytes blob) {
+						DynamicEvent(str, blob, str, blob);
+					}
 
-				event FixedBytesEvent (
-					bytes24 indexed IndexedBytes,
-					bytes24 NonIndexedBytes
-				);
-				function raiseFixedBytesEvent(bytes24 blob) {
-					FixedBytesEvent(blob, blob);
+					event FixedBytesEvent (
+						bytes24 indexed IndexedBytes,
+						bytes24 NonIndexedBytes
+					);
+					function raiseFixedBytesEvent(bytes24 blob) {
+						FixedBytesEvent(blob, blob);
+					}
 				}
-			}
-		`,
+			`,
 		[]string{`608060405234801561001057600080fd5b5061043f806100206000396000f3006080604052600436106100615763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663528300ff8114610066578063630c31e2146100ff5780636cc6b94014610138578063c7d116dd1461015b575b600080fd5b34801561007257600080fd5b506040805160206004803580820135601f81018490048402850184019095528484526100fd94369492936024939284019190819084018382808284375050604080516020601f89358b018035918201839004830284018301909452808352979a9998810197919650918201945092508291508401838280828437509497506101829650505050505050565b005b34801561010b57600080fd5b506100fd73ffffffffffffffffffffffffffffffffffffffff60043516602435604435151560643561033c565b34801561014457600080fd5b506100fd67ffffffffffffffff1960043516610394565b34801561016757600080fd5b506100fd60043560243560010b63ffffffff604435166103d6565b806040518082805190602001908083835b602083106101b25780518252601f199092019160209182019101610193565b51815160209384036101000a6000190180199092169116179052604051919093018190038120875190955087945090928392508401908083835b6020831061020b5780518252601f1990920191602091820191016101ec565b6001836020036101000a03801982511681845116808217855250505050505090500191505060405180910390207f3281fd4f5e152dd3385df49104a3f633706e21c9e80672e88d3bcddf33101f008484604051808060200180602001838103835285818151815260200191508051906020019080838360005b8381101561029c578181015183820152602001610284565b50505050905090810190601f1680156102c95780820380516001836020036101000a031916815260200191505b50838103825284518152845160209182019186019080838360005b838110156102fc5781810151838201526020016102e4565b50505050905090810190601f1680156103295780820380516001836020036101000a031916815260200191505b5094505050505060405180910390a35050565b60408051828152905183151591859173ffffffffffffffffffffffffffffffffffffffff8816917f1f097de4289df643bd9c11011cc61367aa12983405c021056e706eb5ba1250c8919081900360200190a450505050565b6040805167ffffffffffffffff19831680825291517fcdc4c1b1aed5524ffb4198d7a5839a34712baef5fa06884fac7559f4a5854e0a9181900360200190a250565b8063ffffffff168260010b847f3ca7f3a77e5e6e15e781850bc82e32adfa378a2a609370db24b4d0fae10da2c960405160405180910390a45050505600a165627a7a72305820468b5843bf653145bd924b323c64ef035d3dd922c170644b44d61aa666ea6eee0029`},
 		[]string{`[{"constant":false,"inputs":[{"name":"str","type":"string"},{"name":"blob","type":"bytes"}],"name":"raiseDynamicEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"},{"name":"id","type":"bytes32"},{"name":"flag","type":"bool"},{"name":"value","type":"uint256"}],"name":"raiseSimpleEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"blob","type":"bytes24"}],"name":"raiseFixedBytesEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"number","type":"uint256"},{"name":"short","type":"int16"},{"name":"long","type":"uint32"}],"name":"raiseNodataEvent","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Addr","type":"address"},{"indexed":true,"name":"Id","type":"bytes32"},{"indexed":true,"name":"Flag","type":"bool"},{"indexed":false,"name":"Value","type":"uint256"}],"name":"SimpleEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"Number","type":"uint256"},{"indexed":true,"name":"Short","type":"int16"},{"indexed":true,"name":"Long","type":"uint32"}],"name":"NodataEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexedString","type":"string"},{"indexed":true,"name":"IndexedBytes","type":"bytes"},{"indexed":false,"name":"NonIndexedString","type":"string"},{"indexed":false,"name":"NonIndexedBytes","type":"bytes"}],"name":"DynamicEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"IndexedBytes","type":"bytes24"},{"indexed":false,"name":"NonIndexedBytes","type":"bytes24"}],"name":"FixedBytesEvent","type":"event"}]`},
 		`
-			"math/big"
-			"time"
-
-			"github.com/ledgerwatch/turbo-geth/accounts/abi/bind"
-			"github.com/ledgerwatch/turbo-geth/accounts/abi/bind/backends"
-			"github.com/ledgerwatch/turbo-geth/common"
-			"github.com/ledgerwatch/turbo-geth/core"
-			"github.com/ledgerwatch/turbo-geth/crypto"
-		`,
+				"math/big"
+				"time"
+
+				"github.com/ledgerwatch/turbo-geth/accounts/abi/bind"
+				"github.com/ledgerwatch/turbo-geth/accounts/abi/bind/backends"
+				"github.com/ledgerwatch/turbo-geth/common"
+				"github.com/ledgerwatch/turbo-geth/core"
+				"github.com/ledgerwatch/turbo-geth/crypto"
+			`,
 		`
-			// Generate a new random account and a funded simulator
-			key, _ := crypto.GenerateKey()
-			auth := bind.NewKeyedTransactor(key)
+				// Generate a new random account and a funded simulator
+				key, _ := crypto.GenerateKey()
+				auth := bind.NewKeyedTransactor(key)
 
-			sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
-			defer sim.Close()
+				sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}, 10000000)
+				defer sim.Close()
 
-			// Deploy an eventer contract
-			_, _, eventer, err := DeployEventer(auth, sim)
-			if err != nil {
-				t.Fatalf("Failed to deploy eventer contract: %v", err)
-			}
-			sim.Commit()
+				// Deploy an eventer contract
+				_, _, eventer, err := DeployEventer(auth, sim)
+				if err != nil {
+					t.Fatalf("Failed to deploy eventer contract: %v", err)
+				}
+				sim.Commit()
 
-			// Inject a few events into the contract, gradually more in each block
-			for i := 1; i <= 3; i++ {
-				for j := 1; j <= i; j++ {
-					if _, err := eventer.RaiseSimpleEvent(auth, common.Address{byte(j)}, [32]byte{byte(j)}, true, big.NewInt(int64(10*i+j))); err != nil {
-						t.Fatalf("block %d, event %d: raise failed: %v", i, j, err)
+				// Inject a few events into the contract, gradually more in each block
+				for i := 1; i <= 3; i++ {
+					for j := 1; j <= i; j++ {
+						if _, err := eventer.RaiseSimpleEvent(auth, common.Address{byte(j)}, [32]byte{byte(j)}, true, big.NewInt(int64(10*i+j))); err != nil {
+							t.Fatalf("block %d, event %d: raise failed: %v", i, j, err)
+						}
 					}
+					sim.Commit()
 				}
-				sim.Commit()
-			}
-			// Test filtering for certain events and ensure they can be found
-			sit, err := eventer.FilterSimpleEvent(nil, []common.Address{common.Address{1}, common.Address{3}}, [][32]byte{{byte(1)}, {byte(2)}, {byte(3)}}, []bool{true})
-			if err != nil {
-				t.Fatalf("failed to filter for simple events: %v", err)
-			}
-			defer sit.Close()
+				// Test filtering for certain events and ensure they can be found
+				sit, err := eventer.FilterSimpleEvent(nil, []common.Address{common.Address{1}, common.Address{3}}, [][32]byte{{byte(1)}, {byte(2)}, {byte(3)}}, []bool{true})
+				if err != nil {
+					t.Fatalf("failed to filter for simple events: %v", err)
+				}
+				defer sit.Close()
 
-			sit.Next()
-			if sit.Event.Value.Uint64() != 11 || !sit.Event.Flag {
-				t.Errorf("simple log content mismatch: have %v, want {11, true}", sit.Event)
-			}
-			sit.Next()
-			if sit.Event.Value.Uint64() != 21 || !sit.Event.Flag {
-				t.Errorf("simple log content mismatch: have %v, want {21, true}", sit.Event)
-			}
-			sit.Next()
-			if sit.Event.Value.Uint64() != 31 || !sit.Event.Flag {
-				t.Errorf("simple log content mismatch: have %v, want {31, true}", sit.Event)
-			}
-			sit.Next()
-			if sit.Event.Value.Uint64() != 33 || !sit.Event.Flag {
-				t.Errorf("simple log content mismatch: have %v, want {33, true}", sit.Event)
-			}
+				sit.Next()
+				if sit.Event.Value.Uint64() != 11 || !sit.Event.Flag {
+					t.Errorf("simple log content mismatch: have %v, want {11, true}", sit.Event)
+				}
+				sit.Next()
+				if sit.Event.Value.Uint64() != 21 || !sit.Event.Flag {
+					t.Errorf("simple log content mismatch: have %v, want {21, true}", sit.Event)
+				}
+				sit.Next()
+				if sit.Event.Value.Uint64() != 31 || !sit.Event.Flag {
+					t.Errorf("simple log content mismatch: have %v, want {31, true}", sit.Event)
+				}
+				sit.Next()
+				if sit.Event.Value.Uint64() != 33 || !sit.Event.Flag {
+					t.Errorf("simple log content mismatch: have %v, want {33, true}", sit.Event)
+				}
 
-			if sit.Next() {
-				t.Errorf("unexpected simple event found: %+v", sit.Event)
-			}
-			if err = sit.Error(); err != nil {
-				t.Fatalf("simple event iteration failed: %v", err)
-			}
-			// Test raising and filtering for an event with no data component
-			if _, err := eventer.RaiseNodataEvent(auth, big.NewInt(314), 141, 271); err != nil {
-				t.Fatalf("failed to raise nodata event: %v", err)
-			}
-			sim.Commit()
+				if sit.Next() {
+					t.Errorf("unexpected simple event found: %+v", sit.Event)
+				}
+				if err = sit.Error(); err != nil {
+					t.Fatalf("simple event iteration failed: %v", err)
+				}
+				// Test raising and filtering for an event with no data component
+				if _, err := eventer.RaiseNodataEvent(auth, big.NewInt(314), 141, 271); err != nil {
+					t.Fatalf("failed to raise nodata event: %v", err)
+				}
+				sim.Commit()
 
-			nit, err := eventer.FilterNodataEvent(nil, []*big.Int{big.NewInt(314)}, []int16{140, 141, 142}, []uint32{271})
-			if err != nil {
-				t.Fatalf("failed to filter for nodata events: %v", err)
-			}
-			defer nit.Close()
+				nit, err := eventer.FilterNodataEvent(nil, []*big.Int{big.NewInt(314)}, []int16{140, 141, 142}, []uint32{271})
+				if err != nil {
+					t.Fatalf("failed to filter for nodata events: %v", err)
+				}
+				defer nit.Close()
 
-			if !nit.Next() {
-				t.Fatalf("nodata log not found: %v", nit.Error())
-			}
-			if nit.Event.Number.Uint64() != 314 {
-				t.Errorf("nodata log content mismatch: have %v, want 314", nit.Event.Number)
-			}
-			if nit.Next() {
-				t.Errorf("unexpected nodata event found: %+v", nit.Event)
-			}
-			if err = nit.Error(); err != nil {
-				t.Fatalf("nodata event iteration failed: %v", err)
-			}
-			// Test raising and filtering for events with dynamic indexed components
-			if _, err := eventer.RaiseDynamicEvent(auth, "Hello", []byte("World")); err != nil {
-				t.Fatalf("failed to raise dynamic event: %v", err)
-			}
-			sim.Commit()
+				if !nit.Next() {
+					t.Fatalf("nodata log not found: %v", nit.Error())
+				}
+				if nit.Event.Number.Uint64() != 314 {
+					t.Errorf("nodata log content mismatch: have %v, want 314", nit.Event.Number)
+				}
+				if nit.Next() {
+					t.Errorf("unexpected nodata event found: %+v", nit.Event)
+				}
+				if err = nit.Error(); err != nil {
+					t.Fatalf("nodata event iteration failed: %v", err)
+				}
+				// Test raising and filtering for events with dynamic indexed components
+				if _, err := eventer.RaiseDynamicEvent(auth, "Hello", []byte("World")); err != nil {
+					t.Fatalf("failed to raise dynamic event: %v", err)
+				}
+				sim.Commit()
 
-			dit, err := eventer.FilterDynamicEvent(nil, []string{"Hi", "Hello", "Bye"}, [][]byte{[]byte("World")})
-			if err != nil {
-				t.Fatalf("failed to filter for dynamic events: %v", err)
-			}
-			defer dit.Close()
+				dit, err := eventer.FilterDynamicEvent(nil, []string{"Hi", "Hello", "Bye"}, [][]byte{[]byte("World")})
+				if err != nil {
+					t.Fatalf("failed to filter for dynamic events: %v", err)
+				}
+				defer dit.Close()
 
-			if !dit.Next() {
-				t.Fatalf("dynamic log not found: %v", dit.Error())
-			}
-			if dit.Event.NonIndexedString != "Hello" || string(dit.Event.NonIndexedBytes) != "World" ||	dit.Event.IndexedString != common.HexToHash("0x06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2") || dit.Event.IndexedBytes != common.HexToHash("0xf2208c967df089f60420785795c0a9ba8896b0f6f1867fa7f1f12ad6f79c1a18") {
-				t.Errorf("dynamic log content mismatch: have %v, want {'0x06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2, '0xf2208c967df089f60420785795c0a9ba8896b0f6f1867fa7f1f12ad6f79c1a18', 'Hello', 'World'}", dit.Event)
-			}
-			if dit.Next() {
-				t.Errorf("unexpected dynamic event found: %+v", dit.Event)
-			}
-			if err = dit.Error(); err != nil {
-				t.Fatalf("dynamic event iteration failed: %v", err)
-			}
-			// Test raising and filtering for events with fixed bytes components
-			var fblob [24]byte
-			copy(fblob[:], []byte("Fixed Bytes"))
+				if !dit.Next() {
+					t.Fatalf("dynamic log not found: %v", dit.Error())
+				}
+				if dit.Event.NonIndexedString != "Hello" || string(dit.Event.NonIndexedBytes) != "World" ||	dit.Event.IndexedString != common.HexToHash("0x06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2") || dit.Event.IndexedBytes != common.HexToHash("0xf2208c967df089f60420785795c0a9ba8896b0f6f1867fa7f1f12ad6f79c1a18") {
+					t.Errorf("dynamic log content mismatch: have %v, want {'0x06b3dfaec148fb1bb2b066f10ec285e7c9bf402ab32aa78a5d38e34566810cd2, '0xf2208c967df089f60420785795c0a9ba8896b0f6f1867fa7f1f12ad6f79c1a18', 'Hello', 'World'}", dit.Event)
+				}
+				if dit.Next() {
+					t.Errorf("unexpected dynamic event found: %+v", dit.Event)
+				}
+				if err = dit.Error(); err != nil {
+					t.Fatalf("dynamic event iteration failed: %v", err)
+				}
+				// Test raising and filtering for events with fixed bytes components
+				var fblob [24]byte
+				copy(fblob[:], []byte("Fixed Bytes"))
 
-			if _, err := eventer.RaiseFixedBytesEvent(auth, fblob); err != nil {
-				t.Fatalf("failed to raise fixed bytes event: %v", err)
-			}
-			sim.Commit()
+				if _, err := eventer.RaiseFixedBytesEvent(auth, fblob); err != nil {
+					t.Fatalf("failed to raise fixed bytes event: %v", err)
+				}
+				sim.Commit()
 
-			fit, err := eventer.FilterFixedBytesEvent(nil, [][24]byte{fblob})
-			if err != nil {
-				t.Fatalf("failed to filter for fixed bytes events: %v", err)
-			}
-			defer fit.Close()
+				fit, err := eventer.FilterFixedBytesEvent(nil, [][24]byte{fblob})
+				if err != nil {
+					t.Fatalf("failed to filter for fixed bytes events: %v", err)
+				}
+				defer fit.Close()
 
-			if !fit.Next() {
-				t.Fatalf("fixed bytes log not found: %v", fit.Error())
-			}
-			if fit.Event.NonIndexedBytes != fblob || fit.Event.IndexedBytes != fblob {
-				t.Errorf("fixed bytes log content mismatch: have %v, want {'%x', '%x'}", fit.Event, fblob, fblob)
-			}
-			if fit.Next() {
-				t.Errorf("unexpected fixed bytes event found: %+v", fit.Event)
-			}
-			if err = fit.Error(); err != nil {
-				t.Fatalf("fixed bytes event iteration failed: %v", err)
-			}
-			// Test subscribing to an event and raising it afterwards
-			ch := make(chan *EventerSimpleEvent, 16)
-			sub, err := eventer.WatchSimpleEvent(nil, ch, nil, nil, nil)
-			if err != nil {
-				t.Fatalf("failed to subscribe to simple events: %v", err)
-			}
-			if _, err := eventer.RaiseSimpleEvent(auth, common.Address{255}, [32]byte{255}, true, big.NewInt(255)); err != nil {
-				t.Fatalf("failed to raise subscribed simple event: %v", err)
-			}
-			sim.Commit()
+				if !fit.Next() {
+					t.Fatalf("fixed bytes log not found: %v", fit.Error())
+				}
+				if fit.Event.NonIndexedBytes != fblob || fit.Event.IndexedBytes != fblob {
+					t.Errorf("fixed bytes log content mismatch: have %v, want {'%x', '%x'}", fit.Event, fblob, fblob)
+				}
+				if fit.Next() {
+					t.Errorf("unexpected fixed bytes event found: %+v", fit.Event)
+				}
+				if err = fit.Error(); err != nil {
+					t.Fatalf("fixed bytes event iteration failed: %v", err)
+				}
+				// Test subscribing to an event and raising it afterwards
+				ch := make(chan *EventerSimpleEvent, 16)
+				sub, err := eventer.WatchSimpleEvent(nil, ch, nil, nil, nil)
+				if err != nil {
+					t.Fatalf("failed to subscribe to simple events: %v", err)
+				}
+				if _, err := eventer.RaiseSimpleEvent(auth, common.Address{255}, [32]byte{255}, true, big.NewInt(255)); err != nil {
+					t.Fatalf("failed to raise subscribed simple event: %v", err)
+				}
+				sim.Commit()
 
-			select {
-			case event := <-ch:
-				if event.Value.Uint64() != 255 {
-					t.Errorf("simple log content mismatch: have %v, want 255", event)
+				select {
+				case event := <-ch:
+					if event.Value.Uint64() != 255 {
+						t.Errorf("simple log content mismatch: have %v, want 255", event)
+					}
+				case <-time.After(250 * time.Millisecond):
+					t.Fatalf("subscribed simple event didn't arrive")
 				}
-			case <-time.After(250 * time.Millisecond):
-				t.Fatalf("subscribed simple event didn't arrive")
-			}
-			// Unsubscribe from the event and make sure we're not delivered more
-			sub.Unsubscribe()
+				// Unsubscribe from the event and make sure we're not delivered more
+				sub.Unsubscribe()
 
-			if _, err := eventer.RaiseSimpleEvent(auth, common.Address{254}, [32]byte{254}, true, big.NewInt(254)); err != nil {
-				t.Fatalf("failed to raise subscribed simple event: %v", err)
-			}
-			sim.Commit()
+				if _, err := eventer.RaiseSimpleEvent(auth, common.Address{254}, [32]byte{254}, true, big.NewInt(254)); err != nil {
+					t.Fatalf("failed to raise subscribed simple event: %v", err)
+				}
+				sim.Commit()
 
-			select {
-			case event := <-ch:
-				t.Fatalf("unsubscribed simple event arrived: %v", event)
-			case <-time.After(250 * time.Millisecond):
-			}
-		`,
+				select {
+				case event := <-ch:
+					t.Fatalf("unsubscribed simple event arrived: %v", event)
+				case <-time.After(250 * time.Millisecond):
+				}
+			`,
 		nil,
 		nil,
 		nil,
@@ -1583,7 +1583,7 @@ var bindTests = []struct {
 			}
 			if num, err := pav.ViewFunc(nil); err != nil {
 				t.Fatalf("Failed to call anonymous field retriever: %v", err)
-			} else if num.Cmp(big.NewInt(1)) != 0 {
+			} else if num.Cmp(big.NewInt(2)) != 0 {
 				t.Fatalf("Retrieved value mismatch: have %v, want %v", num, 1)
 			}
 		`,
diff --git a/cmd/hack/hack.go b/cmd/hack/hack.go
index 596efa889f7d2218fefd7d5975de8affa9c63085..3b2892b30b268906c416226311d188a3f5e3d51f 100644
--- a/cmd/hack/hack.go
+++ b/cmd/hack/hack.go
@@ -30,7 +30,6 @@ import (
 	"github.com/ledgerwatch/turbo-geth/core"
 	"github.com/ledgerwatch/turbo-geth/core/rawdb"
 	"github.com/ledgerwatch/turbo-geth/core/state"
-	"github.com/ledgerwatch/turbo-geth/core/types"
 	"github.com/ledgerwatch/turbo-geth/core/types/accounts"
 	"github.com/ledgerwatch/turbo-geth/core/vm"
 	"github.com/ledgerwatch/turbo-geth/crypto"
@@ -589,77 +588,6 @@ func trieChart() {
 	check(err)
 }
 
-func execToBlock(chaindata string, block uint64, fromScratch bool) {
-	state.MaxTrieCacheSize = 100 * 1024
-	blockDb := ethdb.MustOpen(chaindata)
-	defer blockDb.Close()
-	txCacher := core.NewTxSenderCacher(runtime.NumCPU())
-	bcb, err := core.NewBlockChain(blockDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, txCacher)
-	check(err)
-	defer bcb.Stop()
-	if fromScratch {
-		os.Remove("statedb")
-	}
-	stateDB := ethdb.MustOpen("statedb")
-	defer stateDB.Close()
-
-	//_, _, _, err = core.SetupGenesisBlock(stateDB, core.DefaultGenesisBlock())
-	_, _, _, err = core.SetupGenesisBlock(stateDB, nil, false /* history */, true /* overwrite */)
-	check(err)
-	bcTxCacher := core.NewTxSenderCacher(runtime.NumCPU())
-	bc, err := core.NewBlockChain(stateDB, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, bcTxCacher)
-	check(err)
-	defer bc.Stop()
-	tds, err := bc.GetTrieDbState()
-	check(err)
-
-	importedBn := tds.GetBlockNr()
-	if importedBn == 0 {
-		importedBn = 1
-	}
-
-	//bc.SetNoHistory(true)
-	blocks := types.Blocks{}
-	var lastBlock *types.Block
-
-	now := time.Now()
-
-Loop:
-	for i := importedBn; i <= block; i++ {
-		lastBlock = bcb.GetBlockByNumber(i)
-		blocks = append(blocks, lastBlock)
-		if len(blocks) >= 1000 || i == block {
-			_, err = bc.InsertChain(context.Background(), blocks)
-			if err != nil {
-				log.Error("Could not insert blocks (group)", "number", len(blocks), "error", err)
-				// Try to insert blocks one by one to keep the latest state
-				for j := 0; j < len(blocks); j++ {
-					if _, err1 := bc.InsertChain(context.Background(), blocks[j:j+1]); err1 != nil {
-						log.Error("Could not insert block", "error", err1)
-						break Loop
-					}
-				}
-				break
-			}
-			blocks = types.Blocks{}
-		}
-		if i%10000 == 0 {
-			fmt.Printf("Inserted %dK, %s \n", i/1000, time.Since(now))
-		}
-	}
-
-	root := tds.LastRoot()
-	fmt.Printf("Root hash: %x\n", root)
-	fmt.Printf("Last block root hash: %x\n", lastBlock.Root())
-	filename := fmt.Sprintf("right_%d.txt", lastBlock.NumberU64())
-	fmt.Printf("Generating deep snapshot of the right tries... %s\n", filename)
-	f, err := os.Create(filename)
-	if err == nil {
-		defer f.Close()
-		tds.PrintTrie(f)
-	}
-}
-
 func extractTrie(block int) {
 	stateDb := ethdb.MustOpen("statedb")
 	defer stateDb.Close()
@@ -1737,9 +1665,6 @@ func main() {
 	//invTree("iw", "ir", "id", *block, true)
 	//loadAccount()
 	//printBranches(uint64(*block))
-	if *action == "execToBlock" {
-		execToBlock(*chaindata, uint64(*block), false)
-	}
 	//extractTrie(*block)
 	//repair()
 	if *action == "readAccount" {
diff --git a/cmd/pics/state.go b/cmd/pics/state.go
index 3d2a39a649987b3786907b4acadf6319abe01de3..fa3952e79a496c7461b7d38f1b8530e41bcdf268 100644
--- a/cmd/pics/state.go
+++ b/cmd/pics/state.go
@@ -10,7 +10,6 @@ import (
 	"os/exec"
 	"runtime"
 	"sort"
-	"time"
 
 	"github.com/holiman/uint256"
 	"github.com/ledgerwatch/turbo-geth/accounts/abi/bind"
@@ -18,7 +17,6 @@ import (
 	"github.com/ledgerwatch/turbo-geth/cmd/pics/contracts"
 	"github.com/ledgerwatch/turbo-geth/common"
 	"github.com/ledgerwatch/turbo-geth/common/dbutils"
-	"github.com/ledgerwatch/turbo-geth/consensus"
 	"github.com/ledgerwatch/turbo-geth/consensus/ethash"
 	"github.com/ledgerwatch/turbo-geth/core"
 	"github.com/ledgerwatch/turbo-geth/core/rawdb"
@@ -27,7 +25,6 @@ import (
 	"github.com/ledgerwatch/turbo-geth/core/vm"
 	"github.com/ledgerwatch/turbo-geth/crypto"
 	"github.com/ledgerwatch/turbo-geth/eth/stagedsync"
-	"github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages"
 	"github.com/ledgerwatch/turbo-geth/ethdb"
 	"github.com/ledgerwatch/turbo-geth/params"
 	"github.com/ledgerwatch/turbo-geth/trie"
@@ -164,126 +161,6 @@ func hexPalette() error {
 	return nil
 }
 
-func insertBlocksInStages(db ethdb.Database, config *params.ChainConfig, engine consensus.Engine, block *types.Block, bc *core.BlockChain) error {
-
-	num := block.Number().Uint64()
-	// Stage 1
-	if _, _, err := stagedsync.InsertHeaderChain(db, []*types.Header{block.Header()}, config, engine, 1); err != nil {
-		return err
-	}
-	if err := stages.SaveStageProgress(db, stages.Headers, num, nil); err != nil {
-		return err
-	}
-	// Stage 2
-	if err := stagedsync.SpawnBlockHashStage(&stagedsync.StageState{
-		BlockNumber: num - 1,
-	}, db, nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.BlockHashes, num, nil); err != nil {
-		return err
-	}
-
-	// Stage 3
-	if _, err := bc.InsertBodyChain(context.TODO(), []*types.Block{block}); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.Bodies, num, nil); err != nil {
-		return err
-	}
-	// Stage 4
-	const batchSize = 10000
-	const blockSize = 4096
-	n := runtime.NumCPU()
-
-	cfg := stagedsync.Stage3Config{
-		BatchSize:       batchSize,
-		BlockSize:       blockSize,
-		BufferSize:      (blockSize * 10 / 20) * 10000, // 20*4096
-		StartTrace:      false,
-		Prof:            false,
-		NumOfGoroutines: n,
-		ReadChLen:       4,
-		Now:             time.Now(),
-	}
-	if err := stagedsync.SpawnRecoverSendersStage(cfg, &stagedsync.StageState{
-		BlockNumber: num - 1,
-	}, db, config, 0, "", nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.Senders, num, nil); err != nil {
-		return err
-	}
-	// Stage 5
-	if err := stagedsync.SpawnExecuteBlocksStage(&stagedsync.StageState{
-		BlockNumber: num - 1,
-	}, db, config, bc, bc.GetVMConfig(), 0, nil, true, nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.Execution, num, nil); err != nil {
-		return err
-	}
-
-	// Stage 6
-	if err := stagedsync.SpawnIntermediateHashesStage(&stagedsync.StageState{
-		BlockNumber: num - 1,
-	}, db, "", nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.IntermediateHashes, num, nil); err != nil {
-		return err
-	}
-
-	// Stage 7
-	if err := stagedsync.SpawnHashStateStage(&stagedsync.StageState{
-		BlockNumber: num - 1,
-	}, db, "", nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.HashState, num, nil); err != nil {
-		return err
-	}
-
-	// Stage 8
-	if err := stagedsync.SpawnAccountHistoryIndex(&stagedsync.StageState{
-		BlockNumber: num - 1,
-	}, db, "", nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.AccountHistoryIndex, num, nil); err != nil {
-		return err
-	}
-
-	// Stage 9
-	if err := stagedsync.SpawnStorageHistoryIndex(&stagedsync.StageState{
-		BlockNumber: num - 1,
-	}, db, "", nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.StorageHistoryIndex, num, nil); err != nil {
-		return err
-	}
-
-	// Stage 10
-	if err := stagedsync.SpawnTxLookup(&stagedsync.StageState{}, db, "", nil); err != nil {
-		return err
-	}
-
-	if err := stages.SaveStageProgress(db, stages.TxLookup, num, nil); err != nil {
-		return err
-	}
-
-	return nil
-}
-
 func stateDatabaseComparison(first ethdb.KV, second ethdb.KV, number int) error {
 	filename := fmt.Sprintf("changes_%d.dot", number)
 	f, err := os.Create(filename)
@@ -612,7 +489,7 @@ func initialState1() error {
 	// BLOCK 1
 	snapshotDB = db.MemCopy()
 
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[0], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[0], blockchain); err != nil {
 		return err
 	}
 
@@ -626,7 +503,7 @@ func initialState1() error {
 
 	// BLOCK 2
 	snapshotDB = db.MemCopy()
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[1], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[1], blockchain); err != nil {
 		return err
 	}
 
@@ -640,7 +517,7 @@ func initialState1() error {
 	// BLOCK 3
 	snapshotDB = db.MemCopy()
 
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[2], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[2], blockchain); err != nil {
 		return err
 	}
 
@@ -662,7 +539,7 @@ func initialState1() error {
 	// BLOCK 4
 	snapshotDB = db.MemCopy()
 
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[3], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[3], blockchain); err != nil {
 		return err
 	}
 
@@ -677,7 +554,7 @@ func initialState1() error {
 	// BLOCK 5
 	snapshotDB = db.MemCopy()
 
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[4], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[4], blockchain); err != nil {
 		return err
 	}
 
@@ -694,7 +571,7 @@ func initialState1() error {
 	// BLOCK 6
 	snapshotDB = db.MemCopy()
 
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[5], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[5], blockchain); err != nil {
 		return err
 	}
 
@@ -715,7 +592,7 @@ func initialState1() error {
 	// BLOCK 7
 	snapshotDB = db.MemCopy()
 
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[6], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[6], blockchain); err != nil {
 		return err
 	}
 
@@ -732,7 +609,7 @@ func initialState1() error {
 	// BLOCK 8
 	snapshotDB = db.MemCopy()
 
-	if err = insertBlocksInStages(db, gspec.Config, engine, blocks[7], blockchain); err != nil {
+	if err = stagedsync.InsertBlockInStages(db, gspec.Config, engine, blocks[7], blockchain); err != nil {
 		return err
 	}
 
diff --git a/cmd/restapi/apis/remote_reader.go b/cmd/restapi/apis/remote_reader.go
index d11ace20d9003a8c959406058c4c804aec7e318c..cd3213bb1f7ff7dd55656d9c1103e7c2d81835a1 100644
--- a/cmd/restapi/apis/remote_reader.go
+++ b/cmd/restapi/apis/remote_reader.go
@@ -121,7 +121,7 @@ func (r *RemoteReader) ReadAccountData(address common.Address) (*accounts.Accoun
 	if err != nil {
 		return nil, err
 	}
-	enc, err := state.GetAsOf(r.db, false /* plain */, false /* storage */, addrHash[:], r.blockNr+1)
+	enc, err := state.GetAsOf(r.db, false /* storage */, addrHash[:], r.blockNr+1)
 	if err != nil || enc == nil || len(enc) == 0 {
 		return nil, nil
 	}
@@ -150,7 +150,7 @@ func (r *RemoteReader) ReadAccountStorage(address common.Address, incarnation ui
 	}
 
 	compositeKey := dbutils.GenerateCompositeStorageKey(addrHash, incarnation, keyHash)
-	enc, err := state.GetAsOf(r.db, false /* plain */, true /* storage */, compositeKey, r.blockNr+1)
+	enc, err := state.GetAsOf(r.db, true /* storage */, compositeKey, r.blockNr+1)
 	if err != nil || enc == nil {
 		return nil, nil
 	}
diff --git a/cmd/state/stateless/deps.go b/cmd/state/stateless/deps.go
index acf41b9fc145103386709c505763bf657202e402..77639a94d4e263ec182c089582533378cfc8279d 100644
--- a/cmd/state/stateless/deps.go
+++ b/cmd/state/stateless/deps.go
@@ -143,7 +143,7 @@ func dataDependencies(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 		statedb := state.New(dbstate)
 		statedb.SetTracer(dt)
 		signer := types.MakeSigner(chainConfig, block.Number())
diff --git a/cmd/state/stateless/naked_accouts.go b/cmd/state/stateless/naked_accouts.go
index 0bd1a1a6b21bdd9cd27642b1a6d70a9c00d3b2d0..529f059fb59b679af19f51b6b2ffa63ff67856d8 100644
--- a/cmd/state/stateless/naked_accouts.go
+++ b/cmd/state/stateless/naked_accouts.go
@@ -108,7 +108,7 @@ func accountsReadWrites(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 		statedb := state.New(dbstate)
 		statedb.SetTracer(at)
 		signer := types.MakeSigner(chainConfig, block.Number())
diff --git a/cmd/state/stateless/naked_storage.go b/cmd/state/stateless/naked_storage.go
index ecc6860f9b6f65d9f1813f5f8e8f07e1411c8197..0e7b16584cc011ec5ebfda4a552504c5be2ca143 100644
--- a/cmd/state/stateless/naked_storage.go
+++ b/cmd/state/stateless/naked_storage.go
@@ -136,7 +136,7 @@ func storageReadWrites(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 		statedb := state.New(dbstate)
 		signer := types.MakeSigner(chainConfig, block.Number())
 		st.loaded = make(map[common.Address]map[common.Hash]struct{})
diff --git a/cmd/state/stateless/spec_exec.go b/cmd/state/stateless/spec_exec.go
index faca1c5167f912bb15483e55fb57da8acb0dcbfe..30330f801166532714f1daae033ec6c05f9e91b1 100644
--- a/cmd/state/stateless/spec_exec.go
+++ b/cmd/state/stateless/spec_exec.go
@@ -183,7 +183,7 @@ func speculativeExecution(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 
 		// First pass - execute transactions in sequence
 		statedb1 := state.New(dbstate)
diff --git a/cmd/state/stateless/state.go b/cmd/state/stateless/state.go
index 86393c1462e6fa6457aaf25cb1c692a8c72939e7..57351adbda8558ae8f8ddc9f30578fb056efb9c6 100644
--- a/cmd/state/stateless/state.go
+++ b/cmd/state/stateless/state.go
@@ -1165,7 +1165,7 @@ func makeCreators(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 		statedb := state.New(dbstate)
 		signer := types.MakeSigner(chainConfig, block.Number())
 		for _, tx := range block.Transactions() {
@@ -1751,7 +1751,7 @@ func makeSha3Preimages(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 		statedb := state.New(dbstate)
 		signer := types.MakeSigner(chainConfig, block.Number())
 		for _, tx := range block.Transactions() {
diff --git a/cmd/state/stateless/tokens.go b/cmd/state/stateless/tokens.go
index 7122931334e60c2ee7aabfc6ee8fb855cd35c4bc..5d26ee438e7e9871ffdfd26fab55facd3edb3d71 100644
--- a/cmd/state/stateless/tokens.go
+++ b/cmd/state/stateless/tokens.go
@@ -155,7 +155,7 @@ func makeTokens(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 		statedb := state.New(dbstate)
 		signer := types.MakeSigner(chainConfig, block.Number())
 		for _, tx := range block.Transactions() {
@@ -239,7 +239,7 @@ func makeTokenBalances() {
 		fmt.Printf("Analysing token %x...", token)
 		count := 0
 		addrCount := 0
-		dbstate := state.NewDbState(ethDb.KV(), currentBlockNr)
+		dbstate := state.NewPlainDBState(ethDb.KV(), currentBlockNr)
 		statedb := state.New(dbstate)
 		msg := types.NewMessage(
 			caller,
@@ -460,7 +460,7 @@ func makeTokenAllowances() {
 		fmt.Printf("Analysing token %x...", token)
 		count := 0
 		addrCount := 0
-		dbstate := state.NewDbState(ethDb.KV(), currentBlockNr)
+		dbstate := state.NewPlainDBState(ethDb.KV(), currentBlockNr)
 		statedb := state.New(dbstate)
 		msg := types.NewMessage(
 			caller,
diff --git a/cmd/state/stateless/transaction_stats.go b/cmd/state/stateless/transaction_stats.go
index 39eb001985dc0752ea9c3c3dc65e273a1ea343c0..9bab443e0f128cb86a144d3944a92c890c1bd3a5 100644
--- a/cmd/state/stateless/transaction_stats.go
+++ b/cmd/state/stateless/transaction_stats.go
@@ -205,7 +205,7 @@ func transactionStats(blockNum uint64) {
 		if block == nil {
 			break
 		}
-		dbstate := state.NewDbState(ethDb.KV(), block.NumberU64()-1)
+		dbstate := state.NewPlainDBState(ethDb.KV(), block.NumberU64()-1)
 		statedb := state.New(dbstate)
 		signer := types.MakeSigner(chainConfig, block.Number())
 		for txIdx, tx := range block.Transactions() {
diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go
index 815c7bd84fdb896299a56e465c5b90618860e4a8..45ee81482f4f61c90b73487b0628cdb131a5d131 100644
--- a/cmd/utils/cmd.go
+++ b/cmd/utils/cmd.go
@@ -21,8 +21,6 @@ import (
 	"compress/gzip"
 	"context"
 	"fmt"
-	"github.com/spf13/cobra"
-	"github.com/urfave/cli"
 	"io"
 	"os"
 	"os/signal"
@@ -30,12 +28,16 @@ import (
 	"strings"
 	"syscall"
 
+	"github.com/spf13/cobra"
+	"github.com/urfave/cli"
+
 	"github.com/ledgerwatch/turbo-geth/common"
 	"github.com/ledgerwatch/turbo-geth/common/dbutils"
 	"github.com/ledgerwatch/turbo-geth/core"
 	"github.com/ledgerwatch/turbo-geth/core/rawdb"
 	"github.com/ledgerwatch/turbo-geth/core/types"
 	"github.com/ledgerwatch/turbo-geth/crypto"
+	"github.com/ledgerwatch/turbo-geth/eth/stagedsync"
 	"github.com/ledgerwatch/turbo-geth/ethdb"
 	"github.com/ledgerwatch/turbo-geth/internal/debug"
 	"github.com/ledgerwatch/turbo-geth/log"
@@ -165,7 +167,7 @@ func ImportChain(chain *core.BlockChain, fn string) error {
 			log.Info("Skipping batch as all blocks present", "batch", batch, "first", blocks[0].Hash(), "last", blocks[i-1].Hash())
 			continue
 		}
-		if _, err := chain.InsertChain(context.Background(), missing); err != nil {
+		if _, err := stagedsync.InsertBlocksInStages(chain.ChainDb(), chain.Config(), chain.Engine(), missing, chain); err != nil {
 			return fmt.Errorf("invalid block %d: %v", n, err)
 		}
 	}
diff --git a/common/dbutils/helper.go b/common/dbutils/helper.go
index 09a613543c4f6b28d4d139757c61e2681230b4cb..b0b4d49119eecc6f7a1e5ff7215fc2bdddc0ca60 100644
--- a/common/dbutils/helper.go
+++ b/common/dbutils/helper.go
@@ -30,16 +30,11 @@ func DecodeTimestamp(suffix []byte) (uint64, []byte) {
 	return timestamp, suffix[bytecount:]
 }
 
-func ChangeSetByIndexBucket(plain, storage bool) string {
-	if plain {
-		if storage {
-			return PlainStorageChangeSetBucket
-		}
-		return PlainAccountChangeSetBucket
-	} else if storage {
-		return StorageChangeSetBucket
+func ChangeSetByIndexBucket(storage bool) string {
+	if storage {
+		return PlainStorageChangeSetBucket
 	}
-	return AccountChangeSetBucket
+	return PlainAccountChangeSetBucket
 }
 
 // NextSubtree does []byte++. Returns false if overflow.
diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go
index ba933cc3e936c75d46a729d89cf7edcdfadd2cef..9bead06eb4024afd28784c34ee419001014ab094 100644
--- a/consensus/clique/clique_test.go
+++ b/consensus/clique/clique_test.go
@@ -17,7 +17,6 @@
 package clique
 
 import (
-	"context"
 	"math/big"
 	"runtime"
 	"testing"
@@ -29,6 +28,7 @@ import (
 	"github.com/ledgerwatch/turbo-geth/core/types"
 	"github.com/ledgerwatch/turbo-geth/core/vm"
 	"github.com/ledgerwatch/turbo-geth/crypto"
+	"github.com/ledgerwatch/turbo-geth/eth/stagedsync"
 	"github.com/ledgerwatch/turbo-geth/ethdb"
 	"github.com/ledgerwatch/turbo-geth/params"
 )
@@ -100,7 +100,7 @@ func TestReimportMirroredState(t *testing.T) {
 	chain1, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, txCacher1)
 	defer chain1.Stop()
 
-	if _, err := chain1.InsertChain(context.Background(), blocks[:2]); err != nil {
+	if _, err := stagedsync.InsertBlocksInStages(db, params.AllCliqueProtocolChanges, engine, blocks[:2], chain1); err != nil {
 		t.Fatalf("failed to insert initial blocks: %v", err)
 	}
 	if head := chain1.CurrentBlock().NumberU64(); head != 2 {
@@ -114,7 +114,7 @@ func TestReimportMirroredState(t *testing.T) {
 	chain2, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, txCacher2)
 	defer chain2.Stop()
 
-	if _, err := chain2.InsertChain(context.Background(), blocks[2:]); err != nil {
+	if _, err := stagedsync.InsertBlocksInStages(db, params.AllCliqueProtocolChanges, chain2.Engine(), blocks[2:], chain2); err != nil {
 		t.Fatalf("failed to insert final block: %v", err)
 	}
 	if head := chain2.CurrentBlock().NumberU64(); head != 3 {
diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go
index f70c4976e12e1e68f8ff4c6893cfa721664ace1b..7fe2ced0c80a998efda62f1ec35f58a6c16fa30c 100644
--- a/consensus/clique/snapshot_test.go
+++ b/consensus/clique/snapshot_test.go
@@ -18,8 +18,8 @@ package clique
 
 import (
 	"bytes"
-	"context"
 	"crypto/ecdsa"
+	"errors"
 	"runtime"
 	"sort"
 	"testing"
@@ -29,6 +29,7 @@ import (
 	"github.com/ledgerwatch/turbo-geth/core/types"
 	"github.com/ledgerwatch/turbo-geth/core/vm"
 	"github.com/ledgerwatch/turbo-geth/crypto"
+	"github.com/ledgerwatch/turbo-geth/eth/stagedsync"
 	"github.com/ledgerwatch/turbo-geth/ethdb"
 	"github.com/ledgerwatch/turbo-geth/params"
 )
@@ -466,7 +467,7 @@ func TestClique(t *testing.T) {
 		failed := false
 		var k int
 		for j := 0; j < len(batches)-1; j++ {
-			if k, err = chain.InsertChain(context.Background(), batches[j]); err != nil {
+			if k, err = stagedsync.InsertBlocksInStages(db, &config, engine, batches[j], chain); err != nil {
 				t.Errorf("test %d: failed to import batch %d, block %d: %v", i, j, k, err)
 				failed = true
 				break
@@ -475,7 +476,7 @@ func TestClique(t *testing.T) {
 		if failed {
 			continue
 		}
-		if _, err = chain.InsertChain(context.Background(), batches[len(batches)-1]); err != tt.failure {
+		if _, err = stagedsync.InsertBlocksInStages(db, &config, engine, batches[len(batches)-1], chain); !errors.Is(err, tt.failure) {
 			t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure)
 		}
 		if tt.failure != nil {
diff --git a/contracts/checkpointoracle/oracle_test.go b/contracts/checkpointoracle/oracle_test.go
index 6d1cfe7b413bf074007dfc50a0852f6bb1c01a1c..0dbabc56b40731d14d5e628fc0f95fdc7fc79404 100644
--- a/contracts/checkpointoracle/oracle_test.go
+++ b/contracts/checkpointoracle/oracle_test.go
@@ -18,6 +18,7 @@ package checkpointoracle
 
 import (
 	"bytes"
+	"context"
 	"crypto/ecdsa"
 	"encoding/binary"
 	"errors"
@@ -189,8 +190,9 @@ func TestCheckpointRegister(t *testing.T) {
 
 	// getRecent returns block height and hash of the head parent.
 	getRecent := func() (*big.Int, common.Hash) {
-		parentNumber := new(big.Int).Sub(contractBackend.Blockchain().CurrentHeader().Number, big.NewInt(1))
-		parentHash := contractBackend.Blockchain().CurrentHeader().ParentHash
+		h, _ := contractBackend.HeaderByNumber(context.Background(), nil)
+		parentNumber := new(big.Int).Sub(h.Number, big.NewInt(1))
+		parentHash := h.ParentHash
 		return parentNumber, parentHash
 	}
 	// collectSig generates specified number signatures.
diff --git a/core/blockchain.go b/core/blockchain.go
index 8390e0a7caa953d4188e8ae2b85964cc04e6b1d9..1f608de107157cb216c8139da81d118af6b5d396 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -23,7 +23,6 @@ import (
 	"fmt"
 	"io"
 	"math/big"
-	"sort"
 	"sync"
 	"sync/atomic"
 	"time"
@@ -766,24 +765,6 @@ func (bc *BlockChain) insertStopped() bool {
 	return atomic.LoadInt32(&bc.procInterrupt) == 1
 }
 
-func (bc *BlockChain) procFutureBlocks() {
-	blocks := make([]*types.Block, 0, bc.futureBlocks.Len())
-	for _, hash := range bc.futureBlocks.Keys() {
-		if block, exist := bc.futureBlocks.Peek(hash); exist {
-			blocks = append(blocks, block.(*types.Block))
-		}
-	}
-	if len(blocks) > 0 {
-		sort.Slice(blocks, func(i, j int) bool {
-			return blocks[i].NumberU64() < blocks[j].NumberU64()
-		})
-		// Insert one by one as chain insertion needs contiguous ancestry between blocks
-		for i := range blocks {
-			_, _ = bc.InsertChain(context.Background(), blocks[i:i+1])
-		}
-	}
-}
-
 // WriteStatus status of write
 type WriteStatus byte
 
@@ -1150,6 +1131,10 @@ func (bc *BlockChain) writeBlockWithState(ctx context.Context, block *types.Bloc
 		if err := stateDb.CommitBlock(ctx, blockWriter); err != nil {
 			return NonStatTy, err
 		}
+		plainBlockWriter := state.NewPlainStateWriter(bc.db, block.NumberU64())
+		if err := stateDb.CommitBlock(ctx, plainBlockWriter); err != nil {
+			return NonStatTy, err
+		}
 		// Always write changesets
 		if err := blockWriter.WriteChangeSets(); err != nil {
 			return NonStatTy, err
@@ -1877,19 +1862,6 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
 	return nil
 }
 
-func (bc *BlockChain) update() {
-	futureTimer := time.NewTicker(5 * time.Second)
-	defer futureTimer.Stop()
-	for {
-		select {
-		case <-futureTimer.C:
-			bc.procFutureBlocks()
-		case <-bc.quit:
-			return
-		}
-	}
-}
-
 // BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
 func (bc *BlockChain) BadBlocks() []*types.Block {
 	blocks := make([]*types.Block, 0, bc.badBlocks.Len())
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 0920c4c742353ced9ce6b0de1568f4b1d3c87bf4..90f0bdfe63b776644dd4e1abd0a1f3939fef4679 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -82,7 +82,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (*ethdb.ObjectDatab
 	if full {
 		// Full block-chain requested
 		blocks := makeBlockChain(genesis, n, engine, db, canonicalSeed)
-		_, err := blockchain.InsertChain(context.Background(), blocks)
+		_, err = blockchain.InsertChain(context.Background(), blocks)
 		return db, blockchain, err
 	}
 	// Header-only chain requested
@@ -676,7 +676,7 @@ func TestFastVsFullChains(t *testing.T) {
 		genesis = gspec.MustCommit(gendb)
 		signer  = types.NewEIP155Signer(gspec.Config.ChainID)
 	)
-	blocks, receipts, err := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) {
+	blocks, receipts, err1 := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), gendb, 1024, func(i int, block *BlockGen) {
 		block.SetCoinbase(common.Address{0x00})
 
 		// If the block number is multiple of 3, send a few bonus transactions to the miner
@@ -694,8 +694,8 @@ func TestFastVsFullChains(t *testing.T) {
 			block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))})
 		}
 	}, false /* intemediateHashes */)
-	if err != nil {
-		t.Fatalf("generate chain: %v", err)
+	if err1 != nil {
+		t.Fatalf("generate chain: %v", err1)
 	}
 	// Import the chain as an archive node for the comparison baseline
 	archiveDb := ethdb.NewMemDatabase()
@@ -996,8 +996,8 @@ func TestChainTxReorgs(t *testing.T) {
 		t.Fatalf("generate chain: %v", err)
 	}
 	// Import the chain. This runs all block validation rules.
-	if i, err := blockchain.InsertChain(context.Background(), chain); err != nil {
-		t.Fatalf("failed to insert original chain[%d]: %v", i, err)
+	if i, err1 := blockchain.InsertChain(context.Background(), chain); err1 != nil {
+		t.Fatalf("failed to insert original chain[%d]: %v", i, err1)
 	}
 	defer blockchain.Stop()
 
@@ -1098,8 +1098,8 @@ func TestLogReorgs(t *testing.T) {
 		t.Fatalf("generate chain: %v", err)
 	}
 
-	if _, err := blockchain.InsertChain(context.Background(), chain); err != nil {
-		t.Fatalf("failed to insert chain: %v", err)
+	if _, err1 := blockchain.InsertChain(context.Background(), chain); err1 != nil {
+		t.Fatalf("failed to insert chain: %v", err1)
 	}
 
 	chain, _, err = GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), genesisDB, 3, func(i int, gen *BlockGen) {}, false /* intemediateHashes */)
@@ -1152,11 +1152,9 @@ func TestLogRebirth(t *testing.T) {
 	rmLogsCh := make(chan RemovedLogsEvent, 10)
 	blockchain.SubscribeLogsEvent(newLogCh)
 	blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
-	dbCopy := db.MemCopy()
-	defer dbCopy.Close()
 
 	// This chain contains a single log.
-	chain, _, err := GenerateChain(params.TestChainConfig, genesis, engine, dbCopy, 2, func(i int, gen *BlockGen) {
+	chain, _, err := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) {
 		if i == 1 {
 			tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(uint256.Int), 1000000, new(uint256.Int), logCode), signer, key1)
 			if err != nil {
@@ -1168,14 +1166,9 @@ func TestLogRebirth(t *testing.T) {
 	if err != nil {
 		t.Fatalf("generate chain: %v", err)
 	}
-	if _, err := blockchain.InsertChain(context.Background(), chain); err != nil {
-		t.Fatalf("failed to insert chain: %v", err)
-	}
-	checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
-
 	// Generate long reorg chain containing another log. Inserting the
 	// chain removes one log and adds one.
-	forkChain, _, err := GenerateChain(params.TestChainConfig, genesis, engine, dbCopy, 2, func(i int, gen *BlockGen) {
+	forkChain, _, err := GenerateChain(params.TestChainConfig, genesis, engine, db, 2, func(i int, gen *BlockGen) {
 		if i == 1 {
 			tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(uint256.Int), 1000000, new(uint256.Int), logCode), signer, key1)
 			if err != nil {
@@ -1188,20 +1181,33 @@ func TestLogRebirth(t *testing.T) {
 	if err != nil {
 		t.Fatalf("generate fork chain: %v", err)
 	}
-	if _, err := blockchain.InsertChain(context.Background(), forkChain); err != nil {
-		t.Fatalf("failed to insert forked chain: %v", err)
-	}
-	checkLogEvents(t, newLogCh, rmLogsCh, 1, 1)
-
 	// This chain segment is rooted in the original chain, but doesn't contain any logs.
 	// When inserting it, the canonical chain switches away from forkChain and re-emits
 	// the log event for the old chain, as well as a RemovedLogsEvent for forkChain.
-	newBlocks, _, err := GenerateChain(params.TestChainConfig, chain[len(chain)-1], engine, db, 1, func(i int, gen *BlockGen) {}, false /* intemediateHashes */)
+	newBlocks, _, err := GenerateChain(params.TestChainConfig, genesis, engine, db, 3, func(i int, gen *BlockGen) {
+		if i == 1 {
+			tx, err1 := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(uint256.Int), 1000000, new(uint256.Int), logCode), signer, key1)
+			if err1 != nil {
+				t.Fatalf("failed to create tx: %v", err1)
+			}
+			gen.AddTx(tx)
+		}
+	}, false /* intemediateHashes */)
 	if err != nil {
 		t.Fatalf("generate new blocks: %v", err)
 	}
 
-	if _, err := blockchain.InsertChain(context.Background(), newBlocks); err != nil {
+	if _, err := blockchain.InsertChain(context.Background(), chain); err != nil {
+		t.Fatalf("failed to insert chain: %v", err)
+	}
+	checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
+
+	if _, err := blockchain.InsertChain(context.Background(), forkChain); err != nil {
+		t.Fatalf("failed to insert forked chain: %v", err)
+	}
+	checkLogEvents(t, newLogCh, rmLogsCh, 1, 1)
+
+	if _, err := blockchain.InsertChain(context.Background(), newBlocks[2:]); err != nil {
 		t.Fatalf("failed to insert forked chain: %v", err)
 	}
 	checkLogEvents(t, newLogCh, rmLogsCh, 1, 1)
@@ -1311,7 +1317,7 @@ func TestReorgSideEvent(t *testing.T) {
 	if err != nil {
 		t.Fatalf("generate chain: %v", err)
 	}
-	if _, err := blockchain.InsertChain(context.Background(), chain); err != nil {
+	if _, err = blockchain.InsertChain(context.Background(), chain); err != nil {
 		t.Fatalf("failed to insert chain: %v", err)
 	}
 
@@ -1497,7 +1503,7 @@ func TestEIP155Transition(t *testing.T) {
 		t.Fatalf("generate chain: %v", err)
 	}
 
-	if _, err := blockchain.InsertChain(context.Background(), blocks); err != nil {
+	if _, err = blockchain.InsertChain(context.Background(), blocks); err != nil {
 		t.Fatal(err)
 	}
 	block := blockchain.GetBlockByNumber(1)
@@ -1512,7 +1518,7 @@ func TestEIP155Transition(t *testing.T) {
 	if !block.Transactions()[1].Protected() {
 		t.Error("Expected block[3].txs[1] to be replay protected")
 	}
-	if _, err := blockchain.InsertChain(context.Background(), blocks[4:]); err != nil {
+	if _, err = blockchain.InsertChain(context.Background(), blocks[4:]); err != nil {
 		t.Fatal(err)
 	}
 
@@ -1758,7 +1764,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
 	if _, err := blockchain.InsertChain(context.Background(), types.Blocks{blocks[0]}); err != nil {
 		t.Fatal(err)
 	}
-	if st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64())); !st.Exist(theAddr) {
+	if st := state.New(state.NewDbStateReader(db)); !st.Exist(theAddr) {
 		t.Error("expected account to exist")
 	}
 
@@ -1766,7 +1772,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
 	if _, err := blockchain.InsertChain(context.Background(), types.Blocks{blocks[1]}); err != nil {
 		t.Fatal(err)
 	}
-	if st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64())); st.Exist(theAddr) {
+	if st := state.New(state.NewDbStateReader(db)); st.Exist(theAddr) {
 		t.Error("account should not exist")
 	}
 
@@ -1774,7 +1780,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
 	if _, err := blockchain.InsertChain(context.Background(), types.Blocks{blocks[2]}); err != nil {
 		t.Fatal(err)
 	}
-	if st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64())); st.Exist(theAddr) {
+	if st := state.New(state.NewDbStateReader(db)); st.Exist(theAddr) {
 		t.Error("account should not exist")
 	}
 }
@@ -1833,21 +1839,23 @@ func TestDoubleAccountRemoval(t *testing.T) {
 	_, err = blockchain.InsertChain(context.Background(), blocks)
 	assert.NoError(t, err)
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	assert.NoError(t, err)
 	assert.False(t, st.Exist(theAddr), "Contract should've been removed")
 
-	st = state.New(state.NewDbState(db.KV(), 0))
-	assert.NoError(t, err)
-	assert.False(t, st.Exist(theAddr), "Contract should not exist at block #0")
+	/*
+		st = state.New(state.NewDbState(db.KV(), 0))
+		assert.NoError(t, err)
+		assert.False(t, st.Exist(theAddr), "Contract should not exist at block #0")
 
-	st = state.New(state.NewDbState(db.KV(), 1))
-	assert.NoError(t, err)
-	assert.True(t, st.Exist(theAddr), "Contract should exist at block #1")
+		st = state.New(state.NewDbState(db.KV(), 1))
+		assert.NoError(t, err)
+		assert.True(t, st.Exist(theAddr), "Contract should exist at block #1")
 
-	st = state.New(state.NewDbState(db.KV(), 2))
-	assert.NoError(t, err)
-	assert.True(t, st.Exist(theAddr), "Contract should exist at block #2")
+		st = state.New(state.NewDbState(db.KV(), 2))
+		assert.NoError(t, err)
+		assert.True(t, st.Exist(theAddr), "Contract should exist at block #2")
+	*/
 }
 
 // This is a regression test (i.e. as weird as it is, don't delete it ever), which
@@ -2951,11 +2959,9 @@ func TestDeleteRecreateSlots(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 	// Import the canonical chain
-	diskdb := ethdb.NewMemDatabase()
-	gspec.MustCommit(diskdb)
 
 	txCacher := NewTxSenderCacher(runtime.NumCPU())
-	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, txCacher)
+	chain, err := NewBlockChain(db, nil, params.TestChainConfig, engine, vm.Config{}, nil, txCacher)
 	if err != nil {
 		t.Fatalf("failed to create tester chain: %v", err)
 	}
@@ -2963,7 +2969,7 @@ func TestDeleteRecreateSlots(t *testing.T) {
 	if n, err := chain.InsertChain(context.Background(), blocks); err != nil {
 		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
 	}
-	statedb := state.New(state.NewDbState(diskdb.KV(), chain.CurrentBlock().NumberU64()))
+	statedb := state.New(state.NewDbStateReader(db))
 
 	// If all is correct, then slot 1 and 2 are zero
 	key1 := common.HexToHash("01")
@@ -3029,18 +3035,6 @@ func TestDeleteRecreateAccount(t *testing.T) {
 	}
 	genesis := gspec.MustCommit(db)
 
-	cacheConfig := &CacheConfig{
-		TrieCleanLimit: 256,
-		TrieDirtyLimit: 256,
-		TrieTimeLimit:  5 * time.Minute,
-		NoHistory:      false,
-		Pruning:        false,
-	}
-
-	txCacher := NewTxSenderCacher(runtime.NumCPU())
-	blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, txCacher)
-	defer blockchain.Stop()
-
 	blocks, _, err := GenerateChain(params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) {
 		b.SetCoinbase(common.Address{1})
 		// One transaction to AA, to kill it
@@ -3056,11 +3050,8 @@ func TestDeleteRecreateAccount(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 	// Import the canonical chain
-	diskdb := ethdb.NewMemDatabase()
-	defer diskdb.Close()
-	gspec.MustCommit(diskdb)
 	txCacher1 := NewTxSenderCacher(runtime.NumCPU())
-	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, txCacher1)
+	chain, err := NewBlockChain(db, nil, params.TestChainConfig, engine, vm.Config{}, nil, txCacher1)
 	if err != nil {
 		t.Fatalf("failed to create tester chain: %v", err)
 	}
@@ -3068,7 +3059,7 @@ func TestDeleteRecreateAccount(t *testing.T) {
 	if n, err := chain.InsertChain(context.Background(), blocks); err != nil {
 		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
 	}
-	statedb := state.New(state.NewDbState(diskdb.KV(), chain.CurrentBlock().NumberU64()))
+	statedb := state.New(state.NewDbStateReader(db))
 
 	// If all is correct, then both slots are zero
 	key1 := common.HexToHash("01")
@@ -3209,18 +3200,6 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) {
 		return tx
 	}
 
-	cacheConfig := &CacheConfig{
-		TrieCleanLimit: 256,
-		TrieDirtyLimit: 256,
-		TrieTimeLimit:  5 * time.Minute,
-		NoHistory:      false,
-		Pruning:        false,
-	}
-
-	txCacher := NewTxSenderCacher(runtime.NumCPU())
-	blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, txCacher)
-	defer blockchain.Stop()
-
 	blocks, _, err := GenerateChain(params.TestChainConfig, genesis, engine, db, 150, func(i int, b *BlockGen) {
 		var exp = new(expectation)
 		exp.blocknum = i + 1
@@ -3250,14 +3229,11 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 	// Import the canonical chain
-	diskdb := ethdb.NewMemDatabase()
-	defer diskdb.Close()
-	gspec.MustCommit(diskdb)
-	txCacher1 := NewTxSenderCacher(runtime.NumCPU())
-	chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{
+	txCacher := NewTxSenderCacher(runtime.NumCPU())
+	chain, err := NewBlockChain(db, nil, params.TestChainConfig, engine, vm.Config{
 		//Debug:  true,
 		//Tracer: vm.NewJSONLogger(nil, os.Stdout),
-	}, nil, txCacher1)
+	}, nil, txCacher)
 	if err != nil {
 		t.Fatalf("failed to create tester chain: %v", err)
 	}
@@ -3270,7 +3246,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) {
 		if n, err := chain.InsertChain(context.Background(), []*types.Block{block}); err != nil {
 			t.Fatalf("block %d: failed to insert into chain: %v", n, err)
 		}
-		statedb := state.New(state.NewDbState(diskdb.KV(), chain.CurrentBlock().NumberU64()))
+		statedb := state.New(state.NewDbStateReader(db))
 		// If all is correct, then slot 1 and 2 are zero
 		key1 := common.HexToHash("01")
 		var got uint256.Int
@@ -3422,7 +3398,7 @@ func TestInitThenFailCreateContract(t *testing.T) {
 	if err != nil {
 		t.Fatalf("failed to create tester chain: %v", err)
 	}
-	statedb := state.New(state.NewDbState(diskdb.KV(), chain.CurrentBlock().NumberU64()))
+	statedb := state.New(state.NewDbStateReader(db))
 	if got, exp := statedb.GetBalance(aa), uint64(100000); got.Uint64() != exp {
 		t.Fatalf("Genesis err, got %v exp %v", got, exp)
 	}
@@ -3432,7 +3408,7 @@ func TestInitThenFailCreateContract(t *testing.T) {
 		if _, err := chain.InsertChain(context.Background(), []*types.Block{blocks[0]}); err != nil {
 			t.Fatalf("block %d: failed to insert into chain: %v", block.NumberU64(), err)
 		}
-		statedb = state.New(state.NewDbState(diskdb.KV(), chain.CurrentBlock().NumberU64()))
+		statedb = state.New(state.NewDbStateReader(db))
 		if got, exp := statedb.GetBalance(aa), uint64(100000); got.Uint64() != exp {
 			t.Fatalf("block %d: got %v exp %v", block.NumberU64(), got, exp)
 		}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index ff2f07ad45bd89f19f8f8719831b8ca30c3b7621..c24ede636e8dd184817bf8ed1992a6e63843234d 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -215,7 +215,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
 	chainreader := &fakeChainReader{config: config}
 	dbCopy := db.MemCopy()
 	defer dbCopy.Close()
-	genblock := func(i int, parent *types.Block, ibs *state.IntraBlockState, stateReader state.StateReader, stateWriter *state.DbStateWriter) (*types.Block, types.Receipts, error) {
+	genblock := func(i int, parent *types.Block, ibs *state.IntraBlockState, stateReader state.StateReader,
+		stateWriter *state.DbStateWriter, plainStateWriter *state.PlainStateWriter) (*types.Block, types.Receipts, error) {
 		b := &BlockGen{i: i, chain: blocks, parent: parent, ibs: ibs, stateReader: stateReader, stateWriter: stateWriter, config: config, engine: engine}
 		b.header = makeHeader(chainreader, parent, ibs, b.engine)
 		// Mutate the state and block according to any hard-fork specs
@@ -242,7 +243,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
 			ctx := config.WithEIPsFlags(context.Background(), b.header.Number)
 			// Write state changes to db
 			if err := ibs.CommitBlock(ctx, stateWriter); err != nil {
-				return nil, nil, fmt.Errorf("call to CommitBlock:  %w", err)
+				return nil, nil, fmt.Errorf("call to CommitBlock to stateWriter:  %w", err)
+			}
+			if err := ibs.CommitBlock(ctx, plainStateWriter); err != nil {
+				return nil, nil, fmt.Errorf("call to CommitBlock to plainStateWriter:  %w", err)
 			}
 			if GenerateTrace {
 				fmt.Printf("State after %d================\n", i)
@@ -310,10 +314,11 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
 	}
 
 	for i := 0; i < n; i++ {
-		stateReader := state.NewDbStateReader(dbCopy)
+		stateReader := state.NewPlainStateReader(dbCopy)
 		stateWriter := state.NewDbStateWriter(dbCopy, parent.Number().Uint64()+uint64(i)+1)
+		plainStateWriter := state.NewPlainStateWriter(dbCopy, parent.Number().Uint64()+uint64(i)+1)
 		ibs := state.New(stateReader)
-		block, receipt, err := genblock(i, parent, ibs, stateReader, stateWriter)
+		block, receipt, err := genblock(i, parent, ibs, stateReader, stateWriter, plainStateWriter)
 		if err != nil {
 			return nil, nil, fmt.Errorf("generating block %d: %w", i, err)
 		}
diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go
index c7991c9074476a2565651f42bf8c06480c42a78d..92121f447b48c97f45f22b6783232c06f3dac69a 100644
--- a/core/chain_makers_test.go
+++ b/core/chain_makers_test.go
@@ -105,7 +105,7 @@ func ExampleGenerateChain() {
 		return
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number())
 	fmt.Println("balance of addr1:", st.GetBalance(addr1))
 	fmt.Println("balance of addr2:", st.GetBalance(addr2))
diff --git a/core/dao_test.go b/core/dao_test.go
index 83b6ab07d31f26f0bed687d62a67a45cef5575b9..7fb57cf9f041ef275319ac59f02ae030b32ad2c9 100644
--- a/core/dao_test.go
+++ b/core/dao_test.go
@@ -69,10 +69,10 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, txCacherConBc)
 	defer conBc.Stop()
 
-	if _, err := proBc.InsertChain(context.Background(), prefix); err != nil {
+	if _, err = proBc.InsertChain(context.Background(), prefix); err != nil {
 		t.Fatalf("pro-fork: failed to import chain prefix: %v", err)
 	}
-	if _, err := conBc.InsertChain(context.Background(), prefix); err != nil {
+	if _, err = conBc.InsertChain(context.Background(), prefix); err != nil {
 		t.Fatalf("con-fork: failed to import chain prefix: %v", err)
 	}
 	// Try to expand both pro-fork and non-fork chains iteratively with other camp's blocks
@@ -90,7 +90,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 			for j := 0; j < len(blocks)/2; j++ {
 				blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
 			}
-			if _, err := bc.InsertChain(context.Background(), blocks); err != nil {
+			if _, err = bc.InsertChain(context.Background(), blocks); err != nil {
 				t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
 			}
 			blocks, _, err = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), conDb, 1, func(i int, gen *BlockGen) {}, false /* intermediateHashes */)
@@ -105,7 +105,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 			if err != nil {
 				t.Fatalf("generate blocks: %v", err)
 			}
-			if _, err := conBc.InsertChain(context.Background(), blocks); err != nil {
+			if _, err = conBc.InsertChain(context.Background(), blocks); err != nil {
 				t.Fatalf("contra-fork chain didn't accepted no-fork block: %v", err)
 			}
 			db.Close()
@@ -122,14 +122,14 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 			for j := 0; j < len(blocks)/2; j++ {
 				blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
 			}
-			if _, err := bc.InsertChain(context.Background(), blocks); err != nil {
+			if _, err = bc.InsertChain(context.Background(), blocks); err != nil {
 				t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
 			}
 			blocks, _, err = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), proDb, 1, func(i int, gen *BlockGen) {}, false /* intermediateHashes */)
 			if err != nil {
 				t.Fatalf("generate blocks: %v", err)
 			}
-			if _, err := proBc.InsertChain(context.Background(), blocks); err == nil {
+			if _, err = proBc.InsertChain(context.Background(), blocks); err == nil {
 				t.Fatalf("pro-fork chain accepted contra-fork block: %v", blocks[0])
 			}
 			// Create a proper pro-fork block for the pro-forker
@@ -137,7 +137,7 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 			if err != nil {
 				t.Fatalf("generate blocks: %v", err)
 			}
-			if _, err := proBc.InsertChain(context.Background(), blocks); err != nil {
+			if _, err = proBc.InsertChain(context.Background(), blocks); err != nil {
 				t.Fatalf("pro-fork chain didn't accepted pro-fork block: %v", err)
 			}
 		})
@@ -154,14 +154,14 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	for j := 0; j < len(blocks)/2; j++ {
 		blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
 	}
-	if _, err := bc.InsertChain(context.Background(), blocks); err != nil {
+	if _, err = bc.InsertChain(context.Background(), blocks); err != nil {
 		t.Fatalf("failed to import contra-fork chain for expansion: %v", err)
 	}
 	blocks, _, err = GenerateChain(&proConf, conBc.CurrentBlock(), ethash.NewFaker(), conDb, 1, func(i int, gen *BlockGen) {}, false /* intermediateHashes */)
 	if err != nil {
 		t.Fatalf("generate blocks: %v", err)
 	}
-	if _, err := conBc.InsertChain(context.Background(), blocks); err != nil {
+	if _, err = conBc.InsertChain(context.Background(), blocks); err != nil {
 		t.Fatalf("contra-fork chain didn't accept pro-fork block post-fork: %v", err)
 	}
 	// Verify that pro-forkers accept contra-fork extra-datas after forking finishes
@@ -176,14 +176,14 @@ func TestDAOForkRangeExtradata(t *testing.T) {
 	for j := 0; j < len(blocks)/2; j++ {
 		blocks[j], blocks[len(blocks)-1-j] = blocks[len(blocks)-1-j], blocks[j]
 	}
-	if _, err := bc.InsertChain(context.Background(), blocks); err != nil {
+	if _, err = bc.InsertChain(context.Background(), blocks); err != nil {
 		t.Fatalf("failed to import pro-fork chain for expansion: %v", err)
 	}
 	blocks, _, err = GenerateChain(&conConf, proBc.CurrentBlock(), ethash.NewFaker(), proDb, 1, func(i int, gen *BlockGen) {}, false /* intermediateHashes */)
 	if err != nil {
 		t.Fatalf("generate blocks: %v", err)
 	}
-	if _, err := proBc.InsertChain(context.Background(), blocks); err != nil {
+	if _, err = proBc.InsertChain(context.Background(), blocks); err != nil {
 		t.Fatalf("pro-fork chain didn't accept contra-fork block post-fork: %v", err)
 	}
 }
diff --git a/core/genesis.go b/core/genesis.go
index f6ace2608e4c3dc7af428a87ab106a185a0a87bc..98ec18c93b74333f4ad5107a350b02fa9f3c6ef0 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -320,11 +320,7 @@ func (g *Genesis) CommitGenesisState(db ethdb.Database, history bool) (*types.Bl
 	tds.SetBlockNr(0)
 
 	var blockWriter state.WriterWithChangeSets
-	if UsePlainStateExecution {
-		blockWriter = tds.PlainStateWriter()
-	} else {
-		blockWriter = tds.DbStateWriter()
-	}
+	blockWriter = tds.PlainStateWriter()
 
 	if err := statedb.CommitBlock(context.Background(), blockWriter); err != nil {
 		return nil, statedb, fmt.Errorf("cannot write state: %v", err)
@@ -339,6 +335,12 @@ func (g *Genesis) CommitGenesisState(db ethdb.Database, history bool) (*types.Bl
 			return nil, statedb, fmt.Errorf("cannot write history: %v", err)
 		}
 	}
+	if !UsePlainStateExecution {
+		blockWriter = tds.DbStateWriter()
+		if err := statedb.CommitBlock(context.Background(), blockWriter); err != nil {
+			return nil, statedb, fmt.Errorf("cannot write state: %v", err)
+		}
+	}
 
 	if _, err := batch.Commit(); err != nil {
 		return nil, nil, err
diff --git a/core/state/database_test.go b/core/state/database_test.go
index ef4107fb6eb3321eb93304fcd196976329e7ef46..e3fbbd164f44f355d0b739d080ddc889d266ce56 100644
--- a/core/state/database_test.go
+++ b/core/state/database_test.go
@@ -137,7 +137,7 @@ func TestCreate2Revive(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -150,7 +150,7 @@ func TestCreate2Revive(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
@@ -170,7 +170,7 @@ func TestCreate2Revive(t *testing.T) {
 	if it.Event.D != create2address {
 		t.Errorf("Wrong create2address: %x, expected %x", it.Event.D, create2address)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(create2address) {
 		t.Error("expected create2address to exist at the block 2", create2address.String())
 	}
@@ -186,7 +186,7 @@ func TestCreate2Revive(t *testing.T) {
 	if _, err = blockchain.InsertChain(context.Background(), types.Blocks{blocks[2]}); err != nil {
 		t.Fatal(err)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if st.Exist(create2address) {
 		t.Error("expected create2address to be self-destructed at the block 3", create2address.String())
 	}
@@ -205,7 +205,7 @@ func TestCreate2Revive(t *testing.T) {
 	if it.Event.D != create2address {
 		t.Errorf("Wrong create2address: %x, expected %x", it.Event.D, create2address)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(create2address) {
 		t.Error("expected create2address to exist at the block 2", create2address.String())
 	}
@@ -348,7 +348,7 @@ func TestCreate2Polymorth(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -361,7 +361,7 @@ func TestCreate2Polymorth(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
@@ -381,7 +381,7 @@ func TestCreate2Polymorth(t *testing.T) {
 	if it.Event.D != create2address {
 		t.Errorf("Wrong create2address: %x, expected %x", it.Event.D, create2address)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(create2address) {
 		t.Error("expected create2address to exist at the block 2", create2address.String())
 	}
@@ -396,7 +396,7 @@ func TestCreate2Polymorth(t *testing.T) {
 	if _, err = blockchain.InsertChain(context.Background(), types.Blocks{blocks[2]}); err != nil {
 		t.Fatal(err)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if st.Exist(create2address) {
 		t.Error("expected create2address to be self-destructed at the block 3", create2address.String())
 	}
@@ -415,7 +415,7 @@ func TestCreate2Polymorth(t *testing.T) {
 	if it.Event.D != create2address {
 		t.Errorf("Wrong create2address: %x, expected %x", it.Event.D, create2address)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(create2address) {
 		t.Error("expected create2address to exist at the block 4", create2address.String())
 	}
@@ -440,7 +440,7 @@ func TestCreate2Polymorth(t *testing.T) {
 	if it.Event.D != create2address {
 		t.Errorf("Wrong create2address: %x, expected %x", it.Event.D, create2address)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(create2address) {
 		t.Error("expected create2address to exist at the block 5", create2address.String())
 	}
@@ -544,7 +544,7 @@ func TestReorgOverSelfDestruct(t *testing.T) {
 		t.Fatalf("generate long blocks")
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -557,7 +557,7 @@ func TestReorgOverSelfDestruct(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
@@ -572,7 +572,7 @@ func TestReorgOverSelfDestruct(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if st.Exist(contractAddress) {
 		t.Error("expected contractAddress to not exist at the block 3", contractAddress.String())
 	}
@@ -582,7 +582,7 @@ func TestReorgOverSelfDestruct(t *testing.T) {
 	if _, err = blockchain.InsertChain(context.Background(), types.Blocks{longerBlocks[1], longerBlocks[2], longerBlocks[3]}); err != nil {
 		t.Fatal(err)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 4", contractAddress.String())
 	}
@@ -594,7 +594,7 @@ func TestReorgOverSelfDestruct(t *testing.T) {
 		t.Fatal(err)
 	}
 	defer blockchain1.Stop()
-	st = state.New(state.NewDbState(db.KV(), blockchain1.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	var valueX uint256.Int
 	st.GetState(contractAddress, &key0, &valueX)
 	if valueX != correctValueX {
@@ -688,7 +688,7 @@ func TestReorgOverStateChange(t *testing.T) {
 		t.Fatalf("generate longer blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -701,7 +701,7 @@ func TestReorgOverStateChange(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
@@ -722,7 +722,7 @@ func TestReorgOverStateChange(t *testing.T) {
 	if _, err = blockchain.InsertChain(context.Background(), types.Blocks{longerBlocks[1], longerBlocks[2]}); err != nil {
 		t.Fatal(err)
 	}
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 4", contractAddress.String())
 	}
@@ -734,7 +734,7 @@ func TestReorgOverStateChange(t *testing.T) {
 		t.Fatal(err)
 	}
 	defer blockchain2.Stop()
-	st = state.New(state.NewDbState(db.KV(), blockchain2.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	var valueX uint256.Int
 	st.GetState(contractAddress, &key0, &valueX)
 	if valueX != correctValueX {
@@ -985,7 +985,7 @@ func TestCreateOnExistingStorage(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -998,7 +998,7 @@ func TestCreateOnExistingStorage(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
@@ -1135,7 +1135,7 @@ func TestEip2200Gas(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -1149,7 +1149,7 @@ func TestEip2200Gas(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
@@ -1223,7 +1223,7 @@ func TestWrongIncarnation(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -1250,7 +1250,7 @@ func TestWrongIncarnation(t *testing.T) {
 		t.Fatal("Incorrect incarnation", acc.Incarnation)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
@@ -1386,7 +1386,7 @@ func TestWrongIncarnation2(t *testing.T) {
 		t.Fatalf("generate longer blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -1401,7 +1401,7 @@ func TestWrongIncarnation2(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(contractAddress) {
 		t.Error("expected contractAddress to exist at the block 1", contractAddress.String())
 	}
diff --git a/core/state/history.go b/core/state/history.go
index 8f91f82c965da7cb02bd2b40f9715665c9498c7b..e9ab6773800b0c9b4d49cc6e6081f051aa463394 100644
--- a/core/state/history.go
+++ b/core/state/history.go
@@ -19,10 +19,10 @@ import (
 //MaxChangesetsSearch -
 const MaxChangesetsSearch = 256
 
-func GetAsOf(db ethdb.KV, plain, storage bool, key []byte, timestamp uint64) ([]byte, error) {
+func GetAsOf(db ethdb.KV, storage bool, key []byte, timestamp uint64) ([]byte, error) {
 	var dat []byte
 	err := db.View(context.Background(), func(tx ethdb.Tx) error {
-		v, err := FindByHistory(tx, plain, storage, key, timestamp)
+		v, err := FindByHistory(tx, storage, key, timestamp)
 		if err == nil {
 			dat = make([]byte, len(v))
 			copy(dat, v)
@@ -32,13 +32,7 @@ func GetAsOf(db ethdb.KV, plain, storage bool, key []byte, timestamp uint64) ([]
 			return err
 		}
 		{
-			var bucket string
-			if plain {
-				bucket = dbutils.PlainStateBucket
-			} else {
-				bucket = dbutils.CurrentStateBucket
-			}
-			v, err := tx.Get(bucket, key)
+			v, err := tx.Get(dbutils.PlainStateBucket, key)
 			if err != nil {
 				return err
 			}
@@ -53,7 +47,7 @@ func GetAsOf(db ethdb.KV, plain, storage bool, key []byte, timestamp uint64) ([]
 	return dat, err
 }
 
-func FindByHistory(tx ethdb.Tx, plain, storage bool, key []byte, timestamp uint64) ([]byte, error) {
+func FindByHistory(tx ethdb.Tx, storage bool, key []byte, timestamp uint64) ([]byte, error) {
 	var hBucket string
 	if storage {
 		hBucket = dbutils.StorageHistoryBucket
@@ -69,16 +63,9 @@ func FindByHistory(tx ethdb.Tx, plain, storage bool, key []byte, timestamp uint6
 		return nil, ethdb.ErrKeyNotFound
 	}
 	if storage {
-		if plain {
-			if !bytes.Equal(k[:common.AddressLength], key[:common.AddressLength]) ||
-				!bytes.Equal(k[common.AddressLength:common.AddressLength+common.HashLength], key[common.AddressLength+common.IncarnationLength:]) {
-				return nil, ethdb.ErrKeyNotFound
-			}
-		} else {
-			if !bytes.Equal(k[:common.HashLength], key[:common.HashLength]) ||
-				!bytes.Equal(k[common.HashLength:common.HashLength+common.HashLength], key[common.HashLength+common.IncarnationLength:]) {
-				return nil, ethdb.ErrKeyNotFound
-			}
+		if !bytes.Equal(k[:common.AddressLength], key[:common.AddressLength]) ||
+			!bytes.Equal(k[common.AddressLength:common.AddressLength+common.HashLength], key[common.AddressLength+common.IncarnationLength:]) {
+			return nil, ethdb.ErrKeyNotFound
 		}
 	} else {
 		if !bytes.HasPrefix(k, key) {
@@ -95,23 +82,17 @@ func FindByHistory(tx ethdb.Tx, plain, storage bool, key []byte, timestamp uint6
 		if set && !storage {
 			return []byte{}, nil
 		}
-		csBucket := dbutils.ChangeSetByIndexBucket(plain, storage)
+		csBucket := dbutils.ChangeSetByIndexBucket(storage)
 		csKey := dbutils.EncodeTimestamp(changeSetBlock)
 		changeSetData, err := tx.Get(csBucket, csKey)
 		if err != nil {
 			return nil, err
 		}
 
-		if plain {
-			if storage {
-				data, err = changeset.StorageChangeSetPlainBytes(changeSetData).FindWithIncarnation(key)
-			} else {
-				data, err = changeset.AccountChangeSetPlainBytes(changeSetData).Find(key)
-			}
-		} else if storage {
-			data, err = changeset.StorageChangeSetBytes(changeSetData).FindWithoutIncarnation(key[:common.HashLength], key[common.HashLength+common.IncarnationLength:])
+		if storage {
+			data, err = changeset.StorageChangeSetPlainBytes(changeSetData).FindWithIncarnation(key)
 		} else {
-			data, err = changeset.AccountChangeSetBytes(changeSetData).Find(key)
+			data, err = changeset.AccountChangeSetPlainBytes(changeSetData).Find(key)
 		}
 		if err != nil {
 			if !errors.Is(err, changeset.ErrNotFound) {
@@ -119,7 +100,7 @@ func FindByHistory(tx ethdb.Tx, plain, storage bool, key []byte, timestamp uint6
 			}
 			return nil, ethdb.ErrKeyNotFound
 		}
-	} else if plain {
+	} else {
 		//fmt.Printf("Not Found changeSetBlock in [%s]\n", index)
 		var lastChangesetBlock, lastIndexBlock uint64
 		v1, err1 := tx.Get(dbutils.SyncStageProgress, stages.DBKeys[stages.Execution])
@@ -143,7 +124,7 @@ func FindByHistory(tx ethdb.Tx, plain, storage bool, key []byte, timestamp uint6
 		//fmt.Printf("lastChangesetBlock=%d, lastIndexBlock=%d\n", lastChangesetBlock, lastIndexBlock)
 		if lastChangesetBlock > lastIndexBlock {
 			// iterate over changeset to compensate for lacking of the history index
-			csBucket := dbutils.ChangeSetByIndexBucket(plain, storage)
+			csBucket := dbutils.ChangeSetByIndexBucket(storage)
 			c := tx.Cursor(csBucket)
 			var startTimestamp uint64
 			if timestamp < lastIndexBlock {
@@ -172,8 +153,6 @@ func FindByHistory(tx ethdb.Tx, plain, storage bool, key []byte, timestamp uint6
 		} else {
 			return nil, ethdb.ErrKeyNotFound
 		}
-	} else {
-		return nil, ethdb.ErrKeyNotFound
 	}
 
 	//restore codehash
@@ -185,16 +164,9 @@ func FindByHistory(tx ethdb.Tx, plain, storage bool, key []byte, timestamp uint6
 		if acc.Incarnation > 0 && acc.IsEmptyCodeHash() {
 			var codeHash []byte
 			var err error
-			if plain {
-				codeHash, err = tx.Get(dbutils.PlainContractCodeBucket, dbutils.PlainGenerateStoragePrefix(key, acc.Incarnation))
-				if err != nil {
-					return nil, err
-				}
-			} else {
-				codeHash, err = tx.Get(dbutils.ContractCodeBucket, dbutils.GenerateStoragePrefix(key, acc.Incarnation))
-				if err != nil {
-					return nil, err
-				}
+			codeHash, err = tx.Get(dbutils.PlainContractCodeBucket, dbutils.PlainGenerateStoragePrefix(key, acc.Incarnation))
+			if err != nil {
+				return nil, err
 			}
 			if len(codeHash) > 0 {
 				acc.CodeHash = common.BytesToHash(codeHash)
@@ -469,7 +441,6 @@ func walkAsOfThinAccounts(db ethdb.KV, bucket string, hBucket string, startkey [
 	return err
 }
 
-
 func findInHistory(hK, hV []byte, timestamp uint64, csGetter func([]byte) ([]byte, error), adapter func(v []byte) changeset.Walker) ([]byte, bool, error) {
 	index := dbutils.WrapHistoryIndex(hV)
 	if changeSetBlock, set, ok := index.Search(timestamp); ok {
diff --git a/core/state/history_test.go b/core/state/history_test.go
index 88255030db7448a42b35f32525a36037fa5d9e6f..dbd3d63bd79ae856583d0465c119d793ce3c78b9 100644
--- a/core/state/history_test.go
+++ b/core/state/history_test.go
@@ -5,7 +5,6 @@ import (
 	"context"
 	"encoding/binary"
 	"fmt"
-	"github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages"
 	"math/big"
 	"math/rand"
 	"reflect"
@@ -13,6 +12,8 @@ import (
 	"strconv"
 	"testing"
 
+	"github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages"
+
 	"github.com/davecgh/go-spew/spew"
 	"github.com/holiman/uint256"
 	"github.com/stretchr/testify/assert"
@@ -160,7 +161,7 @@ func TestMutationCommitThinHistory(t *testing.T) {
 		}
 
 		for k, v := range accHistoryStateStorage[i] {
-			res, err := GetAsOf(db.KV(), true /* plain */, true /* storage */, dbutils.PlainGenerateCompositeStorageKey(addr, acc.Incarnation, k), 1)
+			res, err := GetAsOf(db.KV(), true /* storage */, dbutils.PlainGenerateCompositeStorageKey(addr, acc.Incarnation, k), 1)
 			if err != nil {
 				t.Fatal(err)
 			}
diff --git a/core/state/intra_block_state_test.go b/core/state/intra_block_state_test.go
index 794272f76992ae4d53fe17d7ded4fab6153ed162..54dcd2414b3cf6af12c1a9e49795e63738ccecb6 100644
--- a/core/state/intra_block_state_test.go
+++ b/core/state/intra_block_state_test.go
@@ -363,7 +363,7 @@ func (test *snapshotTest) run() bool {
 	db := ethdb.NewMemDatabase()
 	defer db.Close()
 	var (
-		ds           = NewDbState(db.KV(), 0)
+		ds           = NewDbStateReader(db)
 		state        = New(ds)
 		snapshotRevs = make([]int, len(test.snapshots))
 		sindex       = 0
@@ -378,13 +378,13 @@ func (test *snapshotTest) run() bool {
 	// Revert all snapshots in reverse order. Each revert must yield a state
 	// that is equivalent to fresh state with all actions up the snapshot applied.
 	for sindex--; sindex >= 0; sindex-- {
-		checkds := NewDbState(db.KV(), 0)
+		checkds := NewDbStateReader(db)
 		checkstate := New(checkds)
 		for _, action := range test.actions[:test.snapshots[sindex]] {
 			action.fn(action, checkstate)
 		}
 		state.RevertToSnapshot(snapshotRevs[sindex])
-		if err := test.checkEqual(state, checkstate, ds, checkds); err != nil {
+		if err := test.checkEqual(state, checkstate); err != nil {
 			test.err = fmt.Errorf("state mismatch after revert to snapshot %d\n%v", sindex, err)
 			return false
 		}
@@ -393,7 +393,7 @@ func (test *snapshotTest) run() bool {
 }
 
 // checkEqual checks that methods of state and checkstate return the same values.
-func (test *snapshotTest) checkEqual(state, checkstate *IntraBlockState, ds, checkds *DbState) error {
+func (test *snapshotTest) checkEqual(state, checkstate *IntraBlockState) error {
 	for _, addr := range test.addrs {
 		addr := addr // pin
 		var err error
@@ -412,7 +412,9 @@ func (test *snapshotTest) checkEqual(state, checkstate *IntraBlockState, ds, che
 			return true
 		}
 		// Check basic accessor methods.
-		checkeq("Exist", state.Exist(addr), checkstate.Exist(addr))
+		if !checkeq("Exist", state.Exist(addr), checkstate.Exist(addr)) {
+			return err
+		}
 		checkeq("HasSuicided", state.HasSuicided(addr), checkstate.HasSuicided(addr))
 		checkeqBigInt("GetBalance", state.GetBalance(addr).ToBig(), checkstate.GetBalance(addr).ToBig())
 		checkeq("GetNonce", state.GetNonce(addr), checkstate.GetNonce(addr))
@@ -421,26 +423,23 @@ func (test *snapshotTest) checkEqual(state, checkstate *IntraBlockState, ds, che
 		checkeq("GetCodeSize", state.GetCodeSize(addr), checkstate.GetCodeSize(addr))
 		// Check storage.
 		if obj := state.getStateObject(addr); obj != nil {
-			err = ds.ForEachStorage(addr, []byte{} /*startKey*/, func(key, seckey common.Hash, value uint256.Int) bool {
+			for key, value := range obj.dirtyStorage {
 				var out uint256.Int
 				checkstate.GetState(addr, &key, &out)
-				return checkeq("GetState("+key.Hex()+")", out, value)
-			}, 1000)
-			if err != nil {
-				return err
+				if !checkeq("GetState("+key.Hex()+")", out, value) {
+					return err
+				}
 			}
-			err = checkds.ForEachStorage(addr, []byte{} /*startKey*/, func(key, seckey common.Hash, value uint256.Int) bool {
+		}
+		if obj := checkstate.getStateObject(addr); obj != nil {
+			for key, value := range obj.dirtyStorage {
 				var out uint256.Int
 				state.GetState(addr, &key, &out)
-				return checkeq("GetState("+key.Hex()+")", out, value)
-			}, 1000)
-			if err != nil {
-				return err
+				if !checkeq("GetState("+key.Hex()+")", out, value) {
+					return err
+				}
 			}
 		}
-		if err != nil {
-			return err
-		}
 	}
 
 	if state.GetRefund() != checkstate.GetRefund() {
diff --git a/core/state/plain_readonly.go b/core/state/plain_readonly.go
index 61540daf355d8a21039b4e49fa768f8dfecce3be..054ae2dcee548f353ecb358c64a113dd2cea8ee3 100644
--- a/core/state/plain_readonly.go
+++ b/core/state/plain_readonly.go
@@ -21,9 +21,10 @@ import (
 	"context"
 	"encoding/binary"
 	"errors"
-	"github.com/ledgerwatch/turbo-geth/common/changeset"
 	"math/big"
 
+	"github.com/ledgerwatch/turbo-geth/common/changeset"
+
 	"github.com/holiman/uint256"
 	"github.com/petar/GoLLRB/llrb"
 
@@ -35,6 +36,16 @@ import (
 	"github.com/ledgerwatch/turbo-geth/trie"
 )
 
+type storageItem struct {
+	key, seckey common.Hash
+	value       uint256.Int
+}
+
+func (a *storageItem) Less(b llrb.Item) bool {
+	bi := b.(*storageItem)
+	return bytes.Compare(a.key[:], bi.key[:]) < 0
+}
+
 // Implements StateReader by wrapping database only, without trie
 type PlainDBState struct {
 	db      ethdb.KV
@@ -62,7 +73,7 @@ func (dbs *PlainDBState) ForEachStorage(addr common.Address, start []byte, cb fu
 	st := llrb.New()
 	var s [common.AddressLength + common.IncarnationLength + common.HashLength]byte
 	copy(s[:], addr[:])
-	accData, _ := GetAsOf(dbs.db, true /* plain */, false /* storage */, addr[:], dbs.blockNr+1)
+	accData, _ := GetAsOf(dbs.db, false /* storage */, addr[:], dbs.blockNr+1)
 	var acc accounts.Account
 	if err := acc.DecodeForStorage(accData); err != nil {
 		log.Error("Error decoding account", "error", err)
@@ -161,7 +172,7 @@ func (dbs *PlainDBState) ForEachAccount(start []byte, cb func(address *common.Ad
 }
 
 func (dbs *PlainDBState) ReadAccountData(address common.Address) (*accounts.Account, error) {
-	enc, err := GetAsOf(dbs.db, true /* plain */, false /* storage */, address[:], dbs.blockNr+1)
+	enc, err := GetAsOf(dbs.db, false /* storage */, address[:], dbs.blockNr+1)
 	if err != nil || enc == nil || len(enc) == 0 {
 		return nil, nil
 	}
@@ -190,7 +201,7 @@ func (dbs *PlainDBState) ReadAccountData(address common.Address) (*accounts.Acco
 
 func (dbs *PlainDBState) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) {
 	compositeKey := dbutils.PlainGenerateCompositeStorageKey(address, incarnation, *key)
-	enc, err := GetAsOf(dbs.db, true /* plain */, true /* storage */, compositeKey, dbs.blockNr+1)
+	enc, err := GetAsOf(dbs.db, true /* storage */, compositeKey, dbs.blockNr+1)
 	if err != nil && !errors.Is(err, ethdb.ErrKeyNotFound) {
 		return nil, err
 	}
diff --git a/core/state/readonly.go b/core/state/readonly.go
deleted file mode 100644
index 0e4a4a6a3ebf0aa72586a663466d11c6e482a337..0000000000000000000000000000000000000000
--- a/core/state/readonly.go
+++ /dev/null
@@ -1,355 +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 state
-
-import (
-	"bytes"
-	"context"
-	"encoding/binary"
-	"fmt"
-	"github.com/ledgerwatch/turbo-geth/common/changeset"
-	"math/big"
-
-	"github.com/holiman/uint256"
-	"github.com/petar/GoLLRB/llrb"
-
-	"github.com/ledgerwatch/turbo-geth/common"
-	"github.com/ledgerwatch/turbo-geth/common/dbutils"
-	"github.com/ledgerwatch/turbo-geth/core/types/accounts"
-	"github.com/ledgerwatch/turbo-geth/ethdb"
-	"github.com/ledgerwatch/turbo-geth/log"
-	"github.com/ledgerwatch/turbo-geth/trie"
-)
-
-var _ StateReader = (*DbState)(nil)
-var _ StateWriter = (*DbState)(nil)
-
-type storageItem struct {
-	key, seckey common.Hash
-	value       uint256.Int
-}
-
-func (a *storageItem) Less(b llrb.Item) bool {
-	bi := b.(*storageItem)
-	return bytes.Compare(a.seckey[:], bi.seckey[:]) < 0
-}
-
-// Implements StateReader by wrapping database only, without trie
-type DbState struct {
-	db      ethdb.KV
-	blockNr uint64
-	storage map[common.Address]*llrb.LLRB
-}
-
-func NewDbState(db ethdb.KV, blockNr uint64) *DbState {
-	return &DbState{
-		db:      db,
-		blockNr: blockNr,
-		storage: make(map[common.Address]*llrb.LLRB),
-	}
-}
-
-func (dbs *DbState) SetBlockNr(blockNr uint64) {
-	dbs.blockNr = blockNr
-}
-
-func (dbs *DbState) GetBlockNr() uint64 {
-	return dbs.blockNr
-}
-
-func (dbs *DbState) ForEachStorage(addr common.Address, start []byte, cb func(key, seckey common.Hash, value uint256.Int) bool, maxResults int) error {
-	addrHash, err := common.HashData(addr[:])
-	if err != nil {
-		log.Error("Error on hashing", "err", err)
-		return err
-	}
-
-	st := llrb.New()
-	var s [common.HashLength + common.IncarnationLength + common.HashLength]byte
-	copy(s[:], addrHash[:])
-	accData, _ := GetAsOf(dbs.db, false /* plain */, false /* storage */, addrHash[:], dbs.blockNr+1)
-	var acc accounts.Account
-	if err = acc.DecodeForStorage(accData); err != nil {
-		log.Error("Error decoding account", "error", err)
-		return err
-	}
-	binary.BigEndian.PutUint64(s[common.HashLength:], acc.Incarnation)
-	copy(s[common.HashLength+common.IncarnationLength:], start)
-	var lastSecKey common.Hash
-	overrideCounter := 0
-	emptyHash := common.Hash{}
-	min := &storageItem{seckey: common.BytesToHash(start)}
-	if t, ok := dbs.storage[addr]; ok {
-		t.AscendGreaterOrEqual(min, func(i llrb.Item) bool {
-			item := i.(*storageItem)
-			st.ReplaceOrInsert(item)
-			if !item.value.IsZero() {
-				copy(lastSecKey[:], item.seckey[:])
-				// Only count non-zero items
-				overrideCounter++
-			}
-			return overrideCounter < maxResults
-		})
-	}
-	numDeletes := st.Len() - overrideCounter
-	err = WalkAsOf(dbs.db, dbutils.CurrentStateBucket, dbutils.StorageHistoryBucket, s[:], 8*(common.HashLength+common.IncarnationLength), dbs.blockNr+1, func(ks, vs []byte) (bool, error) {
-		if !bytes.HasPrefix(ks, addrHash[:]) {
-			return false, nil
-		}
-		if vs == nil || len(vs) == 0 {
-			// Skip deleted entries
-			return true, nil
-		}
-		seckey := ks[common.HashLength:]
-		//fmt.Printf("seckey: %x\n", seckey)
-		si := storageItem{}
-		copy(si.seckey[:], seckey)
-		if st.Has(&si) {
-			return true, nil
-		}
-		si.value.SetBytes(vs)
-		st.InsertNoReplace(&si)
-		if bytes.Compare(seckey[:], lastSecKey[:]) > 0 {
-			// Beyond overrides
-			return st.Len() < maxResults+numDeletes, nil
-		}
-		return st.Len() < maxResults+overrideCounter+numDeletes, nil
-	})
-	if err != nil {
-		log.Error("ForEachStorage walk error", "err", err)
-		return err
-	}
-	results := 0
-	var innerErr error
-	st.AscendGreaterOrEqual(min, func(i llrb.Item) bool {
-		item := i.(*storageItem)
-		if !item.value.IsZero() {
-			// Skip if value == 0
-			if item.key == emptyHash {
-				key, err := ethdb.Get(dbs.db, dbutils.PreimagePrefix, item.seckey[:])
-				if err == nil {
-					copy(item.key[:], key)
-				} else {
-					log.Error(fmt.Sprintf("Error getting preimage for %x", item.seckey[:]), "err", err)
-					innerErr = err
-					return false
-				}
-			}
-			cb(item.key, item.seckey, item.value)
-			results++
-		}
-		return results < maxResults
-	})
-	return innerErr
-}
-
-func (dbs *DbState) ForEachAccount(start []byte, cb func(address *common.Address, addrHash common.Hash), maxResults int) {
-	results := 0
-	err := WalkAsOf(dbs.db, dbutils.CurrentStateBucket, dbutils.AccountsHistoryBucket, start[:], 0, dbs.blockNr+1, func(ks, vs []byte) (bool, error) {
-		if vs == nil || len(vs) == 0 {
-			// Skip deleted entries
-			return true, nil
-		}
-
-		if len(ks) > 32 {
-			return true, nil
-		}
-		addrHash := common.BytesToHash(ks[:common.HashLength])
-		preimage, err := ethdb.Get(dbs.db, dbutils.PreimagePrefix, addrHash[:])
-		if err == nil {
-			addr := &common.Address{}
-			addr.SetBytes(preimage)
-			cb(addr, addrHash)
-		} else {
-			cb(nil, addrHash)
-		}
-		results++
-		return results < maxResults, nil
-	})
-	if err != nil {
-		log.Error("ForEachAccount walk error", "err", err)
-	}
-}
-
-func (dbs *DbState) ReadAccountData(address common.Address) (*accounts.Account, error) {
-	addrHash, err := common.HashData(address[:])
-	if err != nil {
-		return nil, err
-	}
-	enc, err := GetAsOf(dbs.db, false /* plain */, false /* storage */, addrHash[:], dbs.blockNr+1)
-	if err != nil || enc == nil || len(enc) == 0 {
-		return nil, nil
-	}
-	var acc accounts.Account
-	if err := acc.DecodeForStorage(enc); err != nil {
-		return nil, err
-	}
-	return &acc, nil
-}
-
-func (dbs *DbState) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) {
-	keyHash, err := common.HashData(key[:])
-	if err != nil {
-		return nil, err
-	}
-
-	addrHash, err := common.HashData(address[:])
-	if err != nil {
-		return nil, err
-	}
-
-	compositeKey := dbutils.GenerateCompositeStorageKey(addrHash, incarnation, keyHash)
-	enc, err := GetAsOf(dbs.db, false /* plain */, true /* storage */, compositeKey, dbs.blockNr+1)
-	if err != nil || enc == nil {
-		return nil, nil
-	}
-	return enc, nil
-}
-
-func (dbs *DbState) ReadAccountCode(address common.Address, codeHash common.Hash) ([]byte, error) {
-	if bytes.Equal(codeHash[:], emptyCodeHash) {
-		return nil, nil
-	}
-	return ethdb.Get(dbs.db, dbutils.CodeBucket, codeHash[:])
-}
-
-func (dbs *DbState) ReadAccountCodeSize(address common.Address, codeHash common.Hash) (int, error) {
-	code, err := dbs.ReadAccountCode(address, codeHash)
-	if err != nil {
-		return 0, err
-	}
-	return len(code), nil
-}
-
-func (dbs *DbState) ReadAccountIncarnation(address common.Address) (uint64, error) {
-	// We do not need to know the accurate incarnation value when DbState is used, because correct incarnation
-	// is stored in the account record
-	return 0, nil
-}
-
-func (dbs *DbState) UpdateAccountData(_ context.Context, address common.Address, original, account *accounts.Account) error {
-	return nil
-}
-
-func (dbs *DbState) DeleteAccount(_ context.Context, address common.Address, original *accounts.Account) error {
-	return nil
-}
-
-func (dbs *DbState) UpdateAccountCode(address common.Address, incarnation uint64, codeHash common.Hash, code []byte) error {
-	return nil
-}
-
-func (dbs *DbState) WriteAccountStorage(_ context.Context, address common.Address, incarnation uint64, key *common.Hash, original, value *uint256.Int) error {
-	t, ok := dbs.storage[address]
-	if !ok {
-		t = llrb.New()
-		dbs.storage[address] = t
-	}
-	h := common.NewHasher()
-	defer common.ReturnHasherToPool(h)
-	h.Sha.Reset()
-	_, err := h.Sha.Write(key[:])
-	if err != nil {
-		return err
-	}
-	i := &storageItem{key: *key, value: *value}
-	_, err = h.Sha.Read(i.seckey[:])
-	if err != nil {
-		return err
-	}
-
-	t.ReplaceOrInsert(i)
-	return nil
-}
-
-func (dbs *DbState) CreateContract(address common.Address) error {
-	delete(dbs.storage, address)
-	return nil
-}
-
-func (dbs *DbState) GetKey(shaKey []byte) []byte {
-	key, _ := ethdb.Get(dbs.db, dbutils.PreimagePrefix, shaKey)
-	return key
-}
-
-// WalkStorageRange calls the walker for each storage item whose key starts with a given prefix,
-// for no more than maxItems.
-// Returns whether all matching storage items were traversed (provided there was no error).
-func (dbs *DbState) WalkStorageRange(addrHash common.Hash, prefix trie.Keybytes, maxItems int, walker func(common.Hash, big.Int)) (bool, error) {
-	startkey := make([]byte, common.HashLength+common.IncarnationLength+common.HashLength)
-	copy(startkey, addrHash[:])
-	// TODO: [Issue 99] Support incarnations
-	binary.BigEndian.PutUint64(startkey[common.HashLength:], changeset.DefaultIncarnation)
-	copy(startkey[common.HashLength+common.IncarnationLength:], prefix.Data)
-
-	fixedbits := (common.HashLength + common.IncarnationLength + len(prefix.Data)) * 8
-	if prefix.Odd {
-		fixedbits -= 4
-	}
-
-	i := 0
-
-	err := WalkAsOf(dbs.db, dbutils.CurrentStateBucket, dbutils.StorageHistoryBucket, startkey, fixedbits, dbs.blockNr+1,
-		func(key []byte, value []byte) (bool, error) {
-			val := new(big.Int).SetBytes(value)
-
-			if i < maxItems {
-				walker(common.BytesToHash(key), *val)
-			}
-			i++
-			return i <= maxItems, nil
-		},
-	)
-
-	return i <= maxItems, err
-}
-
-// WalkRangeOfAccounts calls the walker for each account whose key starts with a given prefix,
-// for no more than maxItems.
-// Returns whether all matching accounts were traversed (provided there was no error).
-func (dbs *DbState) WalkRangeOfAccounts(prefix trie.Keybytes, maxItems int, walker func(common.Hash, *accounts.Account)) (bool, error) {
-	startkey := make([]byte, common.HashLength)
-	copy(startkey, prefix.Data)
-
-	fixedbits := len(prefix.Data) * 8
-	if prefix.Odd {
-		fixedbits -= 4
-	}
-
-	i := 0
-
-	var acc accounts.Account
-	err := WalkAsOf(dbs.db, dbutils.CurrentStateBucket, dbutils.AccountsHistoryBucket, startkey, fixedbits, dbs.blockNr+1,
-		func(key []byte, value []byte) (bool, error) {
-			if len(key) > 32 {
-				return true, nil
-			}
-			if len(value) > 0 {
-				if err := acc.DecodeForStorage(value); err != nil {
-					return false, err
-				}
-				if i < maxItems {
-					walker(common.BytesToHash(key), &acc)
-				}
-				i++
-			}
-			return i <= maxItems, nil
-		},
-	)
-
-	return i <= maxItems, err
-}
diff --git a/eth/api_backend.go b/eth/api_backend.go
index cba7d3d2c06335047de0486c0df98db929d1a9aa..ff7cdc9ee0281c94e7d707e7251bc3b9724ad58b 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -157,7 +157,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, blockNr rpc.
 	if header == nil {
 		return nil, nil, errors.New("header not found")
 	}
-	ds := state.NewDbState(b.eth.ChainKV(), bn)
+	ds := state.NewPlainDBState(b.eth.ChainKV(), bn)
 	stateDb := state.New(ds)
 	return stateDb, header, nil
 
@@ -178,7 +178,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN
 		if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
 			return nil, nil, errors.New("hash is not currently canonical")
 		}
-		ds := state.NewDbState(b.eth.ChainKV(), header.Number.Uint64())
+		ds := state.NewPlainDBState(b.eth.ChainKV(), header.Number.Uint64())
 		stateDb := state.New(ds)
 		return stateDb, header, nil
 	}
@@ -201,7 +201,7 @@ func (b *EthAPIBackend) GetReceipts(ctx context.Context, hash common.Hash) (type
 }
 
 func (b *EthAPIBackend) getReceiptsByReApplyingTransactions(block *types.Block, number uint64) (types.Receipts, error) {
-	dbstate := state.NewDbState(b.eth.ChainKV(), number-1)
+	dbstate := state.NewPlainDBState(b.eth.ChainKV(), number-1)
 	statedb := state.New(dbstate)
 	header := block.Header()
 	var receipts types.Receipts
diff --git a/eth/downloader/downloader_stagedsync_test.go b/eth/downloader/downloader_stagedsync_test.go
index fdb93b37eecb3d58d9ddea17b0b8e5da49ce8a3a..e6ff1a671cb6eabe472095af7d54220b8115f4a1 100644
--- a/eth/downloader/downloader_stagedsync_test.go
+++ b/eth/downloader/downloader_stagedsync_test.go
@@ -302,4 +302,3 @@ func TestUnwind(t *testing.T) {
 		t.Errorf("last block expected hash %x, got %x", expectedHash, currentHeader.Hash())
 	}
 }
-
diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go
index 8d51f31f21026e5a00ea84dc11d8ae502857ead9..599b293a09f3b509d0234772760644f3acf3dc25 100644
--- a/eth/downloader/downloader_test.go
+++ b/eth/downloader/downloader_test.go
@@ -31,6 +31,7 @@ import (
 	"github.com/ledgerwatch/turbo-geth/common"
 	"github.com/ledgerwatch/turbo-geth/common/dbutils"
 	"github.com/ledgerwatch/turbo-geth/consensus"
+	"github.com/ledgerwatch/turbo-geth/consensus/ethash"
 	"github.com/ledgerwatch/turbo-geth/core/types"
 	"github.com/ledgerwatch/turbo-geth/core/vm"
 	"github.com/ledgerwatch/turbo-geth/ethdb"
@@ -61,6 +62,7 @@ type downloadTester struct {
 	stateDb *ethdb.ObjectDatabase // Database used by the tester for syncing from peers
 	peerDb  *ethdb.ObjectDatabase // Database of the peers containing all data
 	peers   map[string]*downloadTesterPeer
+	engine  consensus.Engine
 
 	ownHashes   []common.Hash                  // Hash chain belonging to the tester
 	ownHeaders  map[common.Hash]*types.Header  // Headers belonging to the tester
@@ -93,6 +95,7 @@ func newTester() *downloadTester {
 		ancientBlocks:   map[common.Hash]*types.Block{testGenesis.Hash(): testGenesis},
 		ancientReceipts: map[common.Hash]types.Receipts{testGenesis.Hash(): nil},
 		ancientChainTd:  map[common.Hash]*big.Int{testGenesis.Hash(): testGenesis.Difficulty()},
+		engine:          ethash.NewFaker(),
 	}
 	tester.stateDb = ethdb.NewMemDatabase()
 	err := tester.stateDb.Put(dbutils.BlockBodyPrefix, dbutils.BlockBodyKey(testGenesis.NumberU64(), testGenesis.Root()), []byte{0x00})
@@ -410,7 +413,7 @@ func (dl *downloadTester) GetBlockByNumber(number uint64) *types.Block {
 }
 
 func (dl *downloadTester) Engine() consensus.Engine {
-	panic("not implemented and should not be called")
+	return dl.engine
 }
 
 func (dl *downloadTester) GetHeader(common.Hash, uint64) *types.Header {
diff --git a/eth/stagedsync/all_stages.go b/eth/stagedsync/all_stages.go
new file mode 100644
index 0000000000000000000000000000000000000000..23090966d90b0f68a8a44538b2349397db58684e
--- /dev/null
+++ b/eth/stagedsync/all_stages.go
@@ -0,0 +1,142 @@
+package stagedsync
+
+import (
+	"context"
+	"runtime"
+	"time"
+
+	"github.com/ledgerwatch/turbo-geth/consensus"
+	"github.com/ledgerwatch/turbo-geth/core"
+	"github.com/ledgerwatch/turbo-geth/core/types"
+	"github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages"
+	"github.com/ledgerwatch/turbo-geth/ethdb"
+	"github.com/ledgerwatch/turbo-geth/params"
+)
+
+func InsertBlocksInStages(db ethdb.Database, config *params.ChainConfig, engine consensus.Engine, blocks []*types.Block, bc *core.BlockChain) (int, error) {
+	for i, block := range blocks {
+		if err := InsertBlockInStages(db, config, engine, block, bc); err != nil {
+			return i, err
+		}
+	}
+	return len(blocks), nil
+}
+
+func InsertBlockInStages(db ethdb.Database, config *params.ChainConfig, engine consensus.Engine, block *types.Block, bc *core.BlockChain) error {
+	num := block.Number().Uint64()
+	// Stage 1
+	if _, _, err := InsertHeaderChain(db, []*types.Header{block.Header()}, config, engine, 1); err != nil {
+		return err
+	}
+	if err := stages.SaveStageProgress(db, stages.Headers, num, nil); err != nil {
+		return err
+	}
+	// Stage 2
+	if err := SpawnBlockHashStage(&StageState{
+		BlockNumber: num - 1,
+	}, db, nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.BlockHashes, num, nil); err != nil {
+		return err
+	}
+
+	// Stage 3
+	if _, err := bc.InsertBodyChain(context.TODO(), []*types.Block{block}); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.Bodies, num, nil); err != nil {
+		return err
+	}
+	// Stage 4
+	const batchSize = 10000
+	const blockSize = 4096
+	n := runtime.NumCPU()
+
+	cfg := Stage3Config{
+		BatchSize:       batchSize,
+		BlockSize:       blockSize,
+		BufferSize:      (blockSize * 10 / 20) * 10000, // 20*4096
+		StartTrace:      false,
+		Prof:            false,
+		NumOfGoroutines: n,
+		ReadChLen:       4,
+		Now:             time.Now(),
+	}
+	if err := SpawnRecoverSendersStage(cfg, &StageState{
+		BlockNumber: num - 1,
+	}, db, config, 0, "", nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.Senders, num, nil); err != nil {
+		return err
+	}
+	// Stage 5
+	if err := SpawnExecuteBlocksStage(&StageState{
+		BlockNumber: num - 1,
+	}, db, config, bc, bc.GetVMConfig(), 0, nil, true, nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.Execution, num, nil); err != nil {
+		return err
+	}
+
+	// Stage 6
+	if err := SpawnHashStateStage(&StageState{
+		BlockNumber: num - 1,
+	}, db, "", nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.HashState, num, nil); err != nil {
+		return err
+	}
+
+	// Stage 7
+	if err := SpawnIntermediateHashesStage(&StageState{
+		BlockNumber: num - 1,
+	}, db, "", nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.IntermediateHashes, num, nil); err != nil {
+		return err
+	}
+
+	// Stage 8
+	if err := SpawnAccountHistoryIndex(&StageState{
+		BlockNumber: num - 1,
+	}, db, "", nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.AccountHistoryIndex, num, nil); err != nil {
+		return err
+	}
+
+	// Stage 9
+	if err := SpawnStorageHistoryIndex(&StageState{
+		BlockNumber: num - 1,
+	}, db, "", nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.StorageHistoryIndex, num, nil); err != nil {
+		return err
+	}
+
+	// Stage 10
+	if err := SpawnTxLookup(&StageState{}, db, "", nil); err != nil {
+		return err
+	}
+
+	if err := stages.SaveStageProgress(db, stages.TxLookup, num, nil); err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go
index 879e0ae9bcace5eb8c37da74d8574db503dedad9..c40fa77fb4cc98711bc11c4c92b2c0dc2f72d50c 100644
--- a/ethclient/ethclient_test.go
+++ b/ethclient/ethclient_test.go
@@ -195,7 +195,7 @@ func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
 	// Create Ethereum Service
 	config := &eth.Config{Genesis: genesis}
 	config.Ethash.PowMode = ethash.ModeFake
-		config.Pruning = false
+	config.Pruning = false
 	ethservice, err := eth.New(n, config)
 	if err != nil {
 		t.Fatalf("can't create new ethereum service: %v", err)
diff --git a/ethdb/object_db.go b/ethdb/object_db.go
index ebde4dacb05ada8b77b891d2722e260d52cbdb65..4e12c417d9de67ca55c28144089d3a066a5905af 100644
--- a/ethdb/object_db.go
+++ b/ethdb/object_db.go
@@ -197,7 +197,7 @@ func (db *ObjectDatabase) GetChangeSetByBlock(storage bool, timestamp uint64) ([
 
 	var dat []byte
 	err := db.kv.View(context.Background(), func(tx Tx) error {
-		v, err := tx.Get(dbutils.ChangeSetByIndexBucket(true /* plain */, storage), key)
+		v, err := tx.Get(dbutils.ChangeSetByIndexBucket(storage), key)
 		if err != nil {
 			return err
 		}
diff --git a/miner/worker.go b/miner/worker.go
index fceec3381efdc19211005960aa21029b2973c67e..0d495324f4e00a3745f7542fd33b3271fa119456 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -36,6 +36,7 @@ import (
 	"github.com/ledgerwatch/turbo-geth/core"
 	"github.com/ledgerwatch/turbo-geth/core/state"
 	"github.com/ledgerwatch/turbo-geth/core/types"
+	"github.com/ledgerwatch/turbo-geth/eth/stagedsync"
 	"github.com/ledgerwatch/turbo-geth/event"
 	"github.com/ledgerwatch/turbo-geth/log"
 	"github.com/ledgerwatch/turbo-geth/params"
@@ -653,8 +654,7 @@ func (w *worker) insertToChain(result consensus.ResultWithContext, createdAt tim
 		log.Info("Successfully sealed new block", "number", block.Number(), "sealhash", sealHash, "hash", block.Hash(),
 			"elapsed", common.PrettyDuration(time.Since(createdAt)), "difficulty", block.Difficulty())
 	} else {
-		_, err := w.chain.InsertChain(result.Cancel, types.Blocks{block})
-		if err != nil {
+		if err := stagedsync.InsertBlockInStages(w.chain.ChainDb(), w.chain.Config(), w.chain.Engine(), block, w.chain); err != nil {
 			log.Error("Failed writing block to chain", "err", err)
 			return
 		}
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index b156d92f7579563b9f6c03a59c81aeae1e07bda0..181a34394c3f9660b3a8cfcf4f15f8ebf018e3be 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.go
@@ -136,7 +136,7 @@ func (t *BlockTest) Run(_ bool) error {
 	if common.Hash(t.json.BestBlock) != cmlast {
 		return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
 	}
-	newDB := state.New(state.NewDbState(db.KV(), chain.CurrentBlock().NumberU64()))
+	newDB := state.New(state.NewPlainDBState(db.KV(), chain.CurrentBlock().NumberU64()))
 	if err = t.validatePostState(newDB); err != nil {
 		return fmt.Errorf("post state validation failed: %v", err)
 	}
@@ -184,13 +184,12 @@ func (t *BlockTest) insertBlocks(blockchain *core.BlockChain) ([]btBlock, error)
 			}
 		}
 		// RLP decoding worked, try to insert into chain:
-		blocks := types.Blocks{cb}
-		i, err := blockchain.InsertChain(context.Background(), blocks)
-		if err != nil {
+		if _, err = blockchain.InsertChain(context.Background(), []*types.Block{cb}); err != nil {
+			//if err := stagedsync.InsertBlockInStages(blockchain.ChainDb(), blockchain.Config(), blockchain.Engine(), cb, blockchain); err != nil {
 			if b.BlockHeader == nil {
 				continue // OK - block is supposed to be invalid, continue with next block
 			} else {
-				return nil, fmt.Errorf("block #%v insertion into chain failed: %v", blocks[i].Number(), err)
+				return nil, fmt.Errorf("block #%v insertion into chain failed: %v", cb.Number(), err)
 			}
 		}
 		if b.BlockHeader == nil {
diff --git a/tests/statedb_chain_test.go b/tests/statedb_chain_test.go
index b350033be66172cd7d5da7d389af24bc96790047..d4f72ddeda0a0ad37ec03539d3ad62c348a3941a 100644
--- a/tests/statedb_chain_test.go
+++ b/tests/statedb_chain_test.go
@@ -111,7 +111,7 @@ func TestSelfDestructReceive(t *testing.T) {
 		t.Fatalf("generate blocks: %v", err)
 	}
 
-	st := state.New(state.NewDbState(db.KV(), blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
@@ -142,7 +142,7 @@ func TestSelfDestructReceive(t *testing.T) {
 	// and that means that the state of the accounts written in the first block was correct.
 	// This test checks that the storage root of the account is properly set to the root of the empty tree
 
-	st = state.New(state.NewDbState(db.KV(), blockchain1.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(address) {
 		t.Error("expected account to exist")
 	}
diff --git a/tests/statedb_insert_chain_transaction_test.go b/tests/statedb_insert_chain_transaction_test.go
index d342b77936f05db951f1c030fe91a28a3711114a..20c4a8541d8582d1a3c1922ee06b16f7a30d6689 100644
--- a/tests/statedb_insert_chain_transaction_test.go
+++ b/tests/statedb_insert_chain_transaction_test.go
@@ -59,8 +59,8 @@ func TestInsertIncorrectStateRootDifferentAccounts(t *testing.T) {
 	}
 
 	// insert a correct block
-	var kv ethdb.KV
-	blockchain, kv, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
+	var db *ethdb.ObjectDatabase
+	blockchain, db, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(data.addresses[1], to, uint256.NewInt().SetUint64(5000)),
 			data.keys[1],
@@ -75,7 +75,7 @@ func TestInsertIncorrectStateRootDifferentAccounts(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(to) {
 		t.Error("expected account to exist")
 	}
@@ -126,8 +126,8 @@ func TestInsertIncorrectStateRootSameAccount(t *testing.T) {
 	}
 
 	// insert a correct block
-	var kv ethdb.KV
-	blockchain, kv, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
+	var db *ethdb.ObjectDatabase
+	blockchain, db, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(5000)),
 			fromKey,
@@ -142,7 +142,7 @@ func TestInsertIncorrectStateRootSameAccount(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(to) {
 		t.Error("expected account to exist")
 	}
@@ -187,8 +187,8 @@ func TestInsertIncorrectStateRootSameAccountSameAmount(t *testing.T) {
 	}
 
 	// insert a correct block
-	var kv ethdb.KV
-	blockchain, kv, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
+	var db *ethdb.ObjectDatabase
+	blockchain, db, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(1000)),
 			fromKey,
@@ -203,7 +203,7 @@ func TestInsertIncorrectStateRootSameAccountSameAmount(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(to) {
 		t.Error("expected account to exist")
 	}
@@ -248,8 +248,8 @@ func TestInsertIncorrectStateRootAllFundsRoot(t *testing.T) {
 	}
 
 	// insert a correct block
-	var kv ethdb.KV
-	blockchain, kv, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
+	var db *ethdb.ObjectDatabase
+	blockchain, db, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(1000)),
 			fromKey,
@@ -264,7 +264,7 @@ func TestInsertIncorrectStateRootAllFundsRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(to) {
 		t.Error("expected account to exist")
 	}
@@ -308,8 +308,8 @@ func TestInsertIncorrectStateRootAllFunds(t *testing.T) {
 	}
 
 	// insert a correct block
-	var kv ethdb.KV
-	blockchain, kv, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
+	var db *ethdb.ObjectDatabase
+	blockchain, db, blocks, _, clear, err = genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(1000)),
 			fromKey,
@@ -324,7 +324,7 @@ func TestInsertIncorrectStateRootAllFunds(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(to) {
 		t.Error("expected account to exist")
 	}
@@ -346,7 +346,7 @@ func TestAccountDeployIncorrectRoot(t *testing.T) {
 	var contractAddress common.Address
 	eipContract := new(contracts.Testcontract)
 
-	blockchain, kv, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
+	blockchain, db, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(10)),
 			fromKey,
@@ -366,7 +366,7 @@ func TestAccountDeployIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -384,7 +384,7 @@ func TestAccountDeployIncorrectRoot(t *testing.T) {
 		t.Fatal("should fail")
 	}
 
-	st = state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -398,7 +398,7 @@ func TestAccountDeployIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -417,7 +417,7 @@ func TestAccountCreateIncorrectRoot(t *testing.T) {
 	var contractAddress common.Address
 	eipContract := new(contracts.Testcontract)
 
-	blockchain, kv, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
+	blockchain, db, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(10)),
 			fromKey,
@@ -441,7 +441,7 @@ func TestAccountCreateIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -455,7 +455,7 @@ func TestAccountCreateIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -488,7 +488,7 @@ func TestAccountUpdateIncorrectRoot(t *testing.T) {
 	var contractAddress common.Address
 	eipContract := new(contracts.Testcontract)
 
-	blockchain, kv, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
+	blockchain, db, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(10)),
 			fromKey,
@@ -516,7 +516,7 @@ func TestAccountUpdateIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -530,7 +530,7 @@ func TestAccountUpdateIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -568,7 +568,7 @@ func TestAccountDeleteIncorrectRoot(t *testing.T) {
 	var contractAddress common.Address
 	eipContract := new(contracts.Testcontract)
 
-	blockchain, kv, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
+	blockchain, db, blocks, receipts, clear, err := genBlocks(data.genesisSpec, map[int]tx{
 		0: {
 			getBlockTx(from, to, uint256.NewInt().SetUint64(10)),
 			fromKey,
@@ -596,7 +596,7 @@ func TestAccountDeleteIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st := state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st := state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -610,7 +610,7 @@ func TestAccountDeleteIncorrectRoot(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	st = state.New(state.NewDbState(kv, blockchain.CurrentBlock().NumberU64()))
+	st = state.New(state.NewDbStateReader(db))
 	if !st.Exist(from) {
 		t.Error("expected account to exist")
 	}
@@ -692,7 +692,7 @@ type tx struct {
 	key  *ecdsa.PrivateKey
 }
 
-func genBlocks(gspec *core.Genesis, txs map[int]tx) (*core.BlockChain, ethdb.KV, []*types.Block, []types.Receipts, func(), error) {
+func genBlocks(gspec *core.Genesis, txs map[int]tx) (*core.BlockChain, *ethdb.ObjectDatabase, []*types.Block, []types.Receipts, func(), error) {
 	engine := ethash.NewFaker()
 	db := ethdb.NewMemDatabase()
 	genesis := gspec.MustCommit(db)
@@ -748,7 +748,7 @@ func genBlocks(gspec *core.Genesis, txs map[int]tx) (*core.BlockChain, ethdb.KV,
 		db.Close()
 		genesisDb.Close()
 	}
-	return blockchain, db.KV(), blocks, receipts, clear, err
+	return blockchain, db, blocks, receipts, clear, err
 }
 
 type blockTx func(_ *core.BlockGen, backend bind.ContractBackend) (*types.Transaction, bool)
diff --git a/turbo/adapter/reader.go b/turbo/adapter/reader.go
index c788b30bc8697e757efaa7b5c3e8f1bdcb58f4ff..1dbd2bb8fb1b124619836f25ecfc6861955d4ed2 100644
--- a/turbo/adapter/reader.go
+++ b/turbo/adapter/reader.go
@@ -6,6 +6,7 @@ import (
 	"encoding/binary"
 	"errors"
 	"fmt"
+
 	"github.com/holiman/uint256"
 	"github.com/ledgerwatch/turbo-geth/common"
 	"github.com/ledgerwatch/turbo-geth/common/dbutils"
@@ -65,7 +66,7 @@ func (r *StateReader) GetCodeReads() [][]byte {
 
 func (r *StateReader) ReadAccountData(address common.Address) (*accounts.Account, error) {
 	r.accountReads[address] = struct{}{}
-	enc, err := state.GetAsOf(r.db, true /* plain */, false /* storage */, address[:], r.blockNr+1)
+	enc, err := state.GetAsOf(r.db, false /* storage */, address[:], r.blockNr+1)
 	if err != nil || enc == nil || len(enc) == 0 {
 		return nil, nil
 	}
@@ -84,7 +85,7 @@ func (r *StateReader) ReadAccountStorage(address common.Address, incarnation uin
 	}
 	m[*key] = struct{}{}
 	compositeKey := dbutils.PlainGenerateCompositeStorageKey(address, incarnation, *key)
-	enc, err := state.GetAsOf(r.db, true /* plain */, true /* storage */, compositeKey, r.blockNr+1)
+	enc, err := state.GetAsOf(r.db, true /* storage */, compositeKey, r.blockNr+1)
 	if err != nil || enc == nil {
 		return nil, nil
 	}
@@ -155,7 +156,7 @@ func (r *StateReader) ForEachStorage(addr common.Address, start []byte, cb func(
 	st := llrb.New()
 	var s [common.AddressLength + common.IncarnationLength + common.HashLength]byte
 	copy(s[:], addr[:])
-	accData, err := state.GetAsOf(r.db, true /* plain */, false /* storage */, addr[:], r.blockNr+1)
+	accData, err := state.GetAsOf(r.db, false /* storage */, addr[:], r.blockNr+1)
 	if err != nil {
 		if errors.Is(err, ethdb.ErrKeyNotFound) {
 			return fmt.Errorf("account %x not found at %d", addr, r.blockNr)