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 := ð.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)