diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index e5bb21dceb3fa04f38982c4da0a964c239fba35f..465e8b10cee5630017e15feadbe493bda2b678fd 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -87,7 +87,7 @@ func NewSimulatedBackendWithDatabase(database ethdb.Database, alloc core.Genesis genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} genesisBlock := genesis.MustCommit(database) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(database, nil, genesis.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(database, nil, genesis.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { panic(fmt.Sprintf("%v", err)) } @@ -117,7 +117,7 @@ func NewSimulatedBackendWithConfig(alloc core.GenesisAlloc, config *params.Chain genesis := core.Genesis{Config: config, GasLimit: gasLimit, Alloc: alloc} genesisBlock := genesis.MustCommit(database) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(database, nil, genesis.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(database, nil, genesis.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { panic(err) } @@ -562,7 +562,7 @@ func (b *SimulatedBackend) callContract(_ context.Context, call ethereum.CallMsg evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. - vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) + vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}, b.blockchain.DestsCache) gaspool := new(core.GasPool).AddGas(math.MaxUint64) return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() @@ -589,7 +589,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa &b.pendingHeader.Coinbase, b.gasPool, b.pendingState, b.pendingTds.TrieStateWriter(), b.pendingHeader, tx, - &b.pendingHeader.GasUsed, vm.Config{}); err != nil { + &b.pendingHeader.GasUsed, vm.Config{}, b.blockchain.DestsCache); err != nil { return err } //fmt.Printf("==== Start producing block %d\n", (b.prependBlock.NumberU64() + 1)) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 6d68409216c4c81c1b9294697232a0eb36760993..a8e89a03408ec2501f12449637cfee6a094f6915 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -32,6 +32,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/core/vm" "github.com/ledgerwatch/turbo-geth/eth/downloader" "github.com/ledgerwatch/turbo-geth/ethdb" "github.com/ledgerwatch/turbo-geth/event" @@ -431,7 +432,7 @@ func copyDb(ctx *cli.Context) error { start := time.Now() currentHeader := hc.CurrentHeader() - if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(nil, currentHeader.Hash(), currentHeader.Number.Uint64()), syncMode); err != nil { + if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(nil, currentHeader.Hash(), currentHeader.Number.Uint64()), syncMode, vm.NewDestsCache(10000)); err != nil { return err } for dl.Synchronising() { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index a083bc4315f77209ea61a350d9a85acf7de41429..ad9a1e2e30d7907fbd1fd1293dd24b3210fe9e22 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -472,7 +472,7 @@ func startNode(ctx *cli.Context, stack *node.Node) { log.Warn("The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads") } - if err := ethereum.StartMining(threads); err != nil { + if err := ethereum.StartMining(threads, ethereum.BlockChain().DestsCache); err != nil { utils.Fatalf("Failed to start mining: %v", err) } } diff --git a/cmd/geth/retesteth.go b/cmd/geth/retesteth.go index dbec667928d9fbcbab4d544d44224108a426d51d..7cb6fc8ae7667fdbd6817465ddde2879bdd1ff9c 100644 --- a/cmd/geth/retesteth.go +++ b/cmd/geth/retesteth.go @@ -406,7 +406,7 @@ func (api *RetestethAPI) SetChainParams(_ context.Context, chainParams ChainPara } engine := &NoRewardEngine{inner: inner, rewardsOn: chainParams.SealEngine != "NoReward"} - blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil, nil, api.blockchain.DestsCache) if err != nil { return false, err } @@ -536,6 +536,7 @@ func (api *RetestethAPI) mineBlock() error { statedb, tds.TrieStateWriter(), header, tx, &header.GasUsed, *api.blockchain.GetVMConfig(), + api.blockchain.DestsCache, ) if err != nil { statedb.RevertToSnapshot(snap) @@ -686,7 +687,7 @@ func (api *RetestethAPI) AccountRange(ctx context.Context, msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), api.blockchain, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}) + vmenv := vm.NewEVM(context, statedb, api.blockchain.Config(), vm.Config{}, api.blockchain.DestsCache) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return AccountRangeResult{}, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err) } @@ -786,7 +787,7 @@ func (api *RetestethAPI) StorageRangeAt(ctx context.Context, dbstate = state.NewDbState(api.kv, header.Number.Uint64()) } else { var err error - _, _, _, dbstate, err = eth.ComputeTxEnv(ctx, api.blockchain, api.blockchain.Config(), api.blockchain, api.kv, block.Hash(), txIndex) + _, _, _, dbstate, err = eth.ComputeTxEnv(ctx, api.blockchain, api.blockchain.Config(), api.blockchain, api.kv, block.Hash(), txIndex, api.blockchain.DestsCache) if err != nil { return StorageRangeResult{}, err } diff --git a/cmd/hack/hack.go b/cmd/hack/hack.go index 276e9fcdaf97652a8a6328f508ab34445f971e74..68d4d33d4f5d7381cb04ad341768529bc93b433a 100644 --- a/cmd/hack/hack.go +++ b/cmd/hack/hack.go @@ -628,7 +628,7 @@ func mgrSchedule(chaindata string, block uint64) { db, err := ethdb.NewBoltDatabase(chaindata) check(err) - bc, err := core.NewBlockChain(db, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(db, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) defer db.Close() tds, err := bc.GetTrieDbState() @@ -773,7 +773,7 @@ func execToBlock(chaindata string, block uint64, fromScratch bool) { state.MaxTrieCacheSize = 100 * 1024 blockDb, err := ethdb.NewBoltDatabase(chaindata) check(err) - bcb, err := core.NewBlockChain(blockDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bcb, err := core.NewBlockChain(blockDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) defer blockDb.Close() if fromScratch { @@ -786,7 +786,7 @@ func execToBlock(chaindata string, block uint64, fromScratch bool) { //_, _, _, err = core.SetupGenesisBlock(stateDB, core.DefaultGenesisBlock()) _, _, _, err = core.SetupGenesisBlock(stateDB, nil, false /* history */) check(err) - bc, err := core.NewBlockChain(stateDB, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(stateDB, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) tds, err := bc.GetTrieDbState() check(err) @@ -842,7 +842,7 @@ func extractTrie(block int) { stateDb, err := ethdb.NewBoltDatabase("statedb") check(err) defer stateDb.Close() - bc, err := core.NewBlockChain(stateDb, nil, params.RopstenChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(stateDb, nil, params.RopstenChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) baseBlock := bc.GetBlockByNumber(uint64(block)) tds := state.NewTrieDbState(baseBlock.Root(), stateDb, baseBlock.NumberU64()) @@ -861,7 +861,7 @@ func testRewind(chaindata string, block, rewind int) { ethDb, err := ethdb.NewBoltDatabase(chaindata) check(err) defer ethDb.Close() - bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) currentBlock := bc.CurrentBlock() currentBlockNr := currentBlock.NumberU64() @@ -923,7 +923,7 @@ func testStartup() { ethDb, err := ethdb.NewBoltDatabase("/home/akhounov/.ethereum/geth/chaindata") check(err) defer ethDb.Close() - bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) currentBlock := bc.CurrentBlock() currentBlockNr := currentBlock.NumberU64() diff --git a/cmd/pics/state.go b/cmd/pics/state.go index 6b0a825ede36a4e55049ed18ecf1b1510a823f3f..63870f327508a9919acf1c0eaea62553a53b7b5c 100644 --- a/cmd/pics/state.go +++ b/cmd/pics/state.go @@ -320,7 +320,7 @@ func initialState1() error { genesisDb := db.MemCopy() engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { return err } diff --git a/cmd/restapi/apis/retrace_tx_api.go b/cmd/restapi/apis/retrace_tx_api.go index 7c94187d0c3f286a2a2d33fe1e26499cf6c1ddef..d27a6cc4cc1d971807f8851fba1334a57af17a45 100644 --- a/cmd/restapi/apis/retrace_tx_api.go +++ b/cmd/restapi/apis/retrace_tx_api.go @@ -114,7 +114,7 @@ func runBlock(ibs *state.IntraBlockState, txnWriter state.StateWriter, blockWrit misc.ApplyDAOHardFork(ibs) } for _, tx := range block.Transactions() { - receipt, err := core.ApplyTransaction(chainConfig, bcb, nil, gp, ibs, txnWriter, header, tx, usedGas, vmConfig) + receipt, err := core.ApplyTransaction(chainConfig, bcb, nil, gp, ibs, txnWriter, header, tx, usedGas, vmConfig, nil) if err != nil { return fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } diff --git a/cmd/rpcdaemon/commands/daemon.go b/cmd/rpcdaemon/commands/daemon.go index e773a8d135a1b757656e1740d93c3afc4a09160d..f83e35fa9b936d6ee165c953f09514c1510f2e9e 100644 --- a/cmd/rpcdaemon/commands/daemon.go +++ b/cmd/rpcdaemon/commands/daemon.go @@ -14,6 +14,7 @@ import ( "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/vm" "github.com/ledgerwatch/turbo-geth/eth" "github.com/ledgerwatch/turbo-geth/ethdb" "github.com/ledgerwatch/turbo-geth/ethdb/remote/remotechain" @@ -226,7 +227,7 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber // StorageRangeAt re-implementation of eth/api.go:StorageRangeAt func (api *PrivateDebugAPIImpl) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (eth.StorageRangeResult, error) { - _, _, _, dbstate, err := eth.ComputeTxEnv(ctx, &blockGetter{api.dbReader}, params.MainnetChainConfig, &chainContext{db: api.dbReader}, api.db, blockHash, txIndex) + _, _, _, dbstate, err := eth.ComputeTxEnv(ctx, &blockGetter{api.dbReader}, params.MainnetChainConfig, &chainContext{db: api.dbReader}, api.db, blockHash, txIndex, vm.NewDestsCache(10)) if err != nil { return eth.StorageRangeResult{}, err } diff --git a/cmd/rpctest/proofs.go b/cmd/rpctest/proofs.go index 928efb52f40d7a09dc8b0908b5c7baa6605cec3f..6d667cf7708dbef35a8ddc3f4794be01570e379b 100644 --- a/cmd/rpctest/proofs.go +++ b/cmd/rpctest/proofs.go @@ -179,7 +179,7 @@ func fixState(chaindata string, url string) { defer stateDb.Close() engine := ethash.NewFullFaker() chainConfig := params.MainnetChainConfig - bc, err := core.NewBlockChain(stateDb, nil, chainConfig, engine, vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(stateDb, nil, chainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { panic(err) } diff --git a/cmd/state/commands/verify_export.go b/cmd/state/commands/verify_export.go index 7b9b6b76771be9571f68c9b026e4ef0b01c20a43..1d010cd9b692d37679c59f8165f4a3246723bc4e 100644 --- a/cmd/state/commands/verify_export.go +++ b/cmd/state/commands/verify_export.go @@ -2,6 +2,7 @@ package commands import ( "github.com/ledgerwatch/turbo-geth/cmd/state/verify" + "github.com/spf13/cobra" ) diff --git a/cmd/state/stateless/check_change_sets.go b/cmd/state/stateless/check_change_sets.go index d1d3a49cc04ee3d17616ddd52e9ef4f0a6b2164c..5f34e7bda4c7c9b0aa0ad2cb01d96d614d2d4e7e 100644 --- a/cmd/state/stateless/check_change_sets.go +++ b/cmd/state/stateless/check_change_sets.go @@ -52,7 +52,7 @@ func CheckChangeSets(genesis *core.Genesis, blockNum uint64, chaindata string, h chainConfig := genesis.Config engine := ethash.NewFaker() vmConfig := vm.Config{} - bc, err := core.NewBlockChain(chainDb, nil, chainConfig, engine, vmConfig, nil, nil) + bc, err := core.NewBlockChain(chainDb, nil, chainConfig, engine, vmConfig, nil, nil, nil) if err != nil { return err } diff --git a/cmd/state/stateless/deps.go b/cmd/state/stateless/deps.go index 52d88d3872b8956cd43b5f6a8f8f33ed72478dd5..e25152745eb99add50b4a2f54fa105d7f5858605 100644 --- a/cmd/state/stateless/deps.go +++ b/cmd/state/stateless/deps.go @@ -133,7 +133,7 @@ func dataDependencies(blockNum uint64) { defer w.Flush() dt := NewDepTracer() vmConfig := vm.Config{Tracer: dt, Debug: true} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil, nil) check(err) interrupt := false for !interrupt { @@ -160,7 +160,7 @@ func dataDependencies(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) if result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } else { diff --git a/cmd/state/stateless/fee_market.go b/cmd/state/stateless/fee_market.go index 3d16d6f5f121e30a17e651280e5c409c72d74e8b..1d04ada8af303f4de55a46a3a7396fa67e871676 100644 --- a/cmd/state/stateless/fee_market.go +++ b/cmd/state/stateless/fee_market.go @@ -40,7 +40,7 @@ func feemarket(blockNum uint64) { defer w.Flush() vmConfig := vm.Config{} engine := ethash.NewFullFaker() - bcb, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vmConfig, nil, nil) + bcb, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vmConfig, nil, nil, nil) check(err) interrupt := false txCount := 0 diff --git a/cmd/state/stateless/naked_accouts.go b/cmd/state/stateless/naked_accouts.go index 351b519a41a57dcc282469789125f7575810f103..14c9d57fcd96fe755c8450efd6e03a1385a7075d 100644 --- a/cmd/state/stateless/naked_accouts.go +++ b/cmd/state/stateless/naked_accouts.go @@ -94,7 +94,7 @@ func accountsReadWrites(blockNum uint64) { defer w.Flush() at := NewAccountsTracer() vmConfig := vm.Config{Tracer: at, Debug: false} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil, nil) check(err) interrupt := false totalWrites := 0 @@ -120,7 +120,7 @@ func accountsReadWrites(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } diff --git a/cmd/state/stateless/naked_storage.go b/cmd/state/stateless/naked_storage.go index 1ea17bb9fe0a7569715def6084bd903b6baa2127..46a0c8e2b7cf0973657da8fc5c613778548250aa 100644 --- a/cmd/state/stateless/naked_storage.go +++ b/cmd/state/stateless/naked_storage.go @@ -122,7 +122,7 @@ func storageReadWrites(blockNum uint64) { defer w.Flush() st := NewStorageTracer() vmConfig := vm.Config{Tracer: st, Debug: true} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil, nil) check(err) interrupt := false totalSstores := 0 @@ -147,7 +147,7 @@ func storageReadWrites(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } diff --git a/cmd/state/stateless/spec_exec.go b/cmd/state/stateless/spec_exec.go index 4282cacac10aecf1673e41868c14b5b11c5d7481..35a839f7000633e3c61ffebfcdf054e57b124cbf 100644 --- a/cmd/state/stateless/spec_exec.go +++ b/cmd/state/stateless/spec_exec.go @@ -173,7 +173,7 @@ func speculativeExecution(blockNum uint64) { vmConfig1 := vm.Config{Tracer: ct1, Debug: true} vmConfig2 := vm.Config{Tracer: ct2, Debug: true} vmConfig3 := vm.Config{Tracer: ct3, Debug: true} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig1, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig1, nil, nil, nil) check(err) interrupt := false for !interrupt { @@ -194,7 +194,7 @@ func speculativeExecution(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb1, chainConfig, vmConfig1) + vmenv := vm.NewEVM(context, statedb1, chainConfig, vmConfig1, nil) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } @@ -219,7 +219,7 @@ func speculativeExecution(blockNum uint64) { msg = types.NewMessage(msg.From(), msg.To(), msg.Nonce(), msg.Value(), msg.Gas(), msg.GasPrice(), msg.Data(), false) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb2, chainConfig, vmConfig2) + vmenv := vm.NewEVM(context, statedb2, chainConfig, vmConfig2, nil) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } @@ -238,7 +238,7 @@ func speculativeExecution(blockNum uint64) { msg = types.NewMessage(msg.From(), msg.To(), msg.Nonce(), msg.Value(), msg.Gas(), msg.GasPrice(), msg.Data(), false) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb3, chainConfig, vmConfig3) + vmenv := vm.NewEVM(context, statedb3, chainConfig, vmConfig3, nil) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } @@ -261,7 +261,7 @@ func speculativeExecution(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb4, chainConfig, vmConfig2) + vmenv := vm.NewEVM(context, statedb4, chainConfig, vmConfig2, nil) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } diff --git a/cmd/state/stateless/state.go b/cmd/state/stateless/state.go index cc18c6f13a447aaefc667ff889717167bc52e1ca..3e6ac583cce19b8e266f215fad8740f7042d9fbd 100644 --- a/cmd/state/stateless/state.go +++ b/cmd/state/stateless/state.go @@ -1384,7 +1384,7 @@ func makeCreators(blockNum uint64) { ct := NewCreationTracer(w) chainConfig := params.MainnetChainConfig vmConfig := vm.Config{Tracer: ct, Debug: true} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil, nil) check(err) interrupt := false for !interrupt { @@ -1400,7 +1400,7 @@ func makeCreators(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } @@ -1962,7 +1962,7 @@ func makeSha3Preimages(blockNum uint64) { bucket := []byte("sha3") chainConfig := params.MainnetChainConfig vmConfig := vm.Config{EnablePreimageRecording: true} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil, nil) check(err) interrupt := false tx, err := f.Begin(true) @@ -1986,7 +1986,7 @@ func makeSha3Preimages(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } diff --git a/cmd/state/stateless/stateless.go b/cmd/state/stateless/stateless.go index 9a3b8c83d983f0d5f0cef404f1988b6a148d5e46..4ca47bcd462d057fd90ef6bb87ed96c10c87d55f 100644 --- a/cmd/state/stateless/stateless.go +++ b/cmd/state/stateless/stateless.go @@ -52,7 +52,7 @@ func runBlock(ibs *state.IntraBlockState, txnWriter state.StateWriter, blockWrit misc.ApplyDAOHardFork(ibs) } for _, tx := range block.Transactions() { - receipt, err := core.ApplyTransaction(chainConfig, bcb, nil, gp, ibs, txnWriter, header, tx, usedGas, vmConfig) + receipt, err := core.ApplyTransaction(chainConfig, bcb, nil, gp, ibs, txnWriter, header, tx, usedGas, vmConfig, nil) if err != nil { return fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } @@ -301,7 +301,7 @@ func Stateless( for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) var receipt *types.Receipt - receipt, err = core.ApplyTransaction(chainConfig, blockProvider, nil, gp, statedb, tds.TrieStateWriter(), header, tx, usedGas, vmConfig) + receipt, err = core.ApplyTransaction(chainConfig, blockProvider, nil, gp, statedb, tds.TrieStateWriter(), header, tx, usedGas, vmConfig, nil) if err != nil { fmt.Printf("tx %x failed: %v\n", tx.Hash(), err) return diff --git a/cmd/state/stateless/stateless_block_providers.go b/cmd/state/stateless/stateless_block_providers.go index 9d66139211d51a03ecd231de3ad424bb7c8b896b..1efecff66cde2db32b08f168ae8edfe23ef6e3fe 100644 --- a/cmd/state/stateless/stateless_block_providers.go +++ b/cmd/state/stateless/stateless_block_providers.go @@ -24,7 +24,7 @@ import ( const ( fileSchemeExportfile = "exportfile" - fileSchemeDb = "db" + fileSchemeDB = "db" ) type BlockProvider interface { @@ -34,7 +34,7 @@ type BlockProvider interface { NextBlock() (*types.Block, error) } -func BlockProviderForURI(uri string, createDbFunc CreateDbFunc) (BlockProvider, error) { +func BlockProviderForURI(uri string, createDBFunc CreateDbFunc) (BlockProvider, error) { url, err := url.Parse(uri) if err != nil { return nil, err @@ -43,11 +43,11 @@ func BlockProviderForURI(uri string, createDbFunc CreateDbFunc) (BlockProvider, case fileSchemeExportfile: fmt.Println("Source of blocks: export file @", url.Path) return NewBlockProviderFromExportFile(url.Path) - case fileSchemeDb: + case fileSchemeDB: fallthrough default: fmt.Println("Source of blocks: db @", url.Path) - return NewBlockProviderFromDb(url.Path, createDbFunc) + return NewBlockProviderFromDB(url.Path, createDBFunc) } } @@ -57,21 +57,21 @@ type BlockChainBlockProvider struct { db ethdb.Database } -func NewBlockProviderFromDb(path string, createDbFunc CreateDbFunc) (BlockProvider, error) { - ethDb, err := createDbFunc(path) +func NewBlockProviderFromDB(path string, createDBFunc CreateDbFunc) (BlockProvider, error) { + ethDB, err := createDBFunc(path) if err != nil { return nil, err } chainConfig := params.MainnetChainConfig engine := ethash.NewFullFaker() - chain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(ethDB, nil, chainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { return nil, err } return &BlockChainBlockProvider{ bc: chain, - db: ethDb, + db: ethDB, }, nil } @@ -102,7 +102,7 @@ func (p *BlockChainBlockProvider) NextBlock() (*types.Block, error) { type ExportFileBlockProvider struct { stream *rlp.Stream engine consensus.Engine - headersDb ethdb.Database + headersDB ethdb.Database batch ethdb.DbWithPendingMutations fh *os.File reader io.Reader @@ -125,8 +125,8 @@ func NewBlockProviderFromExportFile(fn string) (BlockProvider, error) { stream := rlp.NewStream(reader, 0) engine := ethash.NewFullFaker() // keeping all the past block headers in memory - headersDb := mustCreateTempDatabase() - return &ExportFileBlockProvider{stream, engine, headersDb, nil, fh, reader, -1}, nil + headersDB := mustCreateTempDatabase() + return &ExportFileBlockProvider{stream, engine, headersDB, nil, fh, reader, -1}, nil } func getTempFileName() string { @@ -153,7 +153,7 @@ func (p *ExportFileBlockProvider) Close() error { func (p *ExportFileBlockProvider) WriteHeader(h *types.Header) { if p.batch == nil { - p.batch = p.headersDb.NewBatch() + p.batch = p.headersDB.NewBatch() } rawdb.WriteHeader(context.TODO(), p.batch, h) @@ -233,5 +233,5 @@ func (p *ExportFileBlockProvider) GetHeader(h common.Hash, i uint64) *types.Head if p.batch != nil { return rawdb.ReadHeader(p.batch, h, i) } - return rawdb.ReadHeader(p.headersDb, h, i) + return rawdb.ReadHeader(p.headersDB, h, i) } diff --git a/cmd/state/stateless/tokens.go b/cmd/state/stateless/tokens.go index 712bcd3efa1bfc841d70e85b23641b1e7392262c..68ac2f727a5543efd4f682b1d386e80eea89782a 100644 --- a/cmd/state/stateless/tokens.go +++ b/cmd/state/stateless/tokens.go @@ -136,7 +136,7 @@ func makeTokens(blockNum uint64) { chainConfig := params.MainnetChainConfig tt := NewTokenTracer() vmConfig := vm.Config{Tracer: tt, Debug: true} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil, nil) check(err) if blockNum > 1 { tokenFile, err := os.Open("/Volumes/tb41/turbo-geth/tokens.csv") @@ -161,7 +161,7 @@ func makeTokens(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) if _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { panic(fmt.Errorf("tx %x failed: %v", tx.Hash(), err)) } @@ -195,7 +195,7 @@ func makeTokenBalances() { //ethDb, err := ethdb.NewBoltDatabase("/Users/alexeyakhunov/Library/Ethereum/geth/chaindata") check(err) defer ethDb.Close() - bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) currentBlock := bc.CurrentBlock() currentBlockNr := currentBlock.NumberU64() @@ -252,7 +252,7 @@ func makeTokenBalances() { vmConfig := vm.Config{EnablePreimageRecording: true} context := core.NewEVMContext(msg, currentBlock.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(math.MaxUint64)) if err != nil { fmt.Printf("Call failed with error: %v\n", err) @@ -415,7 +415,7 @@ func makeTokenAllowances() { //ethDb, err := ethdb.NewBoltDatabase("/Users/alexeyakhunov/Library/Ethereum/geth/chaindata") check(err) defer ethDb.Close() - bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, params.MainnetChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) check(err) currentBlock := bc.CurrentBlock() currentBlockNr := currentBlock.NumberU64() @@ -475,7 +475,7 @@ func makeTokenAllowances() { vmConfig := vm.Config{EnablePreimageRecording: true} context := core.NewEVMContext(msg, currentBlock.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) result, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(math.MaxUint64)) if err != nil { fmt.Printf("Call failed with error: %v\n", err) diff --git a/cmd/state/stateless/transaction_stats.go b/cmd/state/stateless/transaction_stats.go index de010a0d721a76551117b93705a7099dd3e988b7..57ad4b7e64490005a2dc90d532e7fcf3155b99fe 100644 --- a/cmd/state/stateless/transaction_stats.go +++ b/cmd/state/stateless/transaction_stats.go @@ -195,7 +195,7 @@ func transactionStats(blockNum uint64) { tt := NewTxTracer() chainConfig := params.MainnetChainConfig vmConfig := vm.Config{Tracer: tt, Debug: true} - bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil) + bc, err := core.NewBlockChain(ethDb, nil, chainConfig, ethash.NewFaker(), vmConfig, nil, nil, nil) check(err) interrupt := false for !interrupt { @@ -211,7 +211,7 @@ func transactionStats(blockNum uint64) { msg, _ := tx.AsMessage(signer) context := core.NewEVMContext(msg, block.Header(), bc, nil) // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig) + vmenv := vm.NewEVM(context, statedb, chainConfig, vmConfig, nil) tt.ResetCounters() tt.currentBlock = blockNum tt.measureCreate = tx.To() == nil diff --git a/cmd/state/verify/verify_export_file.go b/cmd/state/verify/verify_export_file.go index 945c80a11214b0de4ef64a15daacdd24f1105293..068fd5820fed12f6293405a2c975fc4c351c27af 100644 --- a/cmd/state/verify/verify_export_file.go +++ b/cmd/state/verify/verify_export_file.go @@ -22,7 +22,7 @@ func ExportFile(filePath, chaindataPath string) error { return ethdb.NewBoltDatabase(path) } - chaindata, err := stateless.NewBlockProviderFromDb(chaindataPath, createDb) + chaindata, err := stateless.NewBlockProviderFromDB(chaindataPath, createDb) if err != nil { return err } diff --git a/cmd/tester/block_generator.go b/cmd/tester/block_generator.go index 18fc5af9a3a73932d99f424861bbf1193e0b0552..60e425c165ebceeecbf4ddd7912fb1258f4a93d7 100644 --- a/cmd/tester/block_generator.go +++ b/cmd/tester/block_generator.go @@ -392,7 +392,7 @@ func NewBlockGenerator(ctx context.Context, outputFile string, initialHeight int return nil, err } - blockchain, err := core.NewBlockChain(db, nil, genesis.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, genesis.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) if err != nil { return nil, err } @@ -474,7 +474,7 @@ func NewForkGenerator(ctx context.Context, base *BlockGenerator, outputFile stri return nil, err } - blockchain, err := core.NewBlockChain(db, nil, genesis.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, genesis.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil, nil) if err != nil { return nil, err } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 93494b5d1efe3785a6013647bf05124a5865233b..a60b09bf16903f1bed648a30bf6e1bfd07e87283 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1814,7 +1814,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readOnly bool) (chain *core.B l := ctx.GlobalUint64(TxLookupLimitFlag.Name) limit = &l } - chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, limit) + chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, limit, vm.NewDestsCache(10000)) if err != nil { Fatalf("Can't create BlockChain: %v", err) } diff --git a/common/pool/buffer.go b/common/pool/buffer.go new file mode 100644 index 0000000000000000000000000000000000000000..6c5082322b02f8654e79410f99e54dae54515842 --- /dev/null +++ b/common/pool/buffer.go @@ -0,0 +1,24 @@ +package pool + +import "github.com/valyala/bytebufferpool" + +type ByteBuffer struct { + *bytebufferpool.ByteBuffer +} + +func (b ByteBuffer) Get(pos int) byte { + return b.B[pos] +} + +func (b ByteBuffer) SetBitPos(pos uint64) { + b.B[pos/8] |= 0x80 >> (pos % 8) +} + +func (b ByteBuffer) SetBit8Pos(pos uint64) { + b.B[pos/8] |= 0xFF >> (pos % 8) + b.B[pos/8+1] |= ^(0xFF >> (pos % 8)) +} + +func (b ByteBuffer) CodeSegment(pos uint64) bool { + return b.B[pos/8]&(0x80>>(pos%8)) == 0 +} diff --git a/common/pool/global_pool.go b/common/pool/global_pool.go index 5196065ec4d1d513336965b8ee852b713cc39522..a493bc6c2d6f66ac6f37b303aaecd31b66b5b400 100644 --- a/common/pool/global_pool.go +++ b/common/pool/global_pool.go @@ -1,9 +1,5 @@ package pool -import ( - "github.com/valyala/bytebufferpool" -) - var ( chunkSizeClasses = []uint{ 8, @@ -14,10 +10,16 @@ var ( 1 << 8, 1 << 9, 1 << 10, - 2 << 10, - 4 << 10, - 8 << 10, - 16 << 10, + 1 << 11, + 1 << 12, + 1 << 13, + 1 << 14, + 1 << 15, + 1 << 16, + 1 << 17, + 1 << 18, + 1 << 19, + 1 << 20, } chunkPools []*pool ) @@ -30,11 +32,7 @@ func init() { // preallocate some buffers const preAlloc = 32 - const lastSmallChunkIndex = 5 - for i, n := range chunkSizeClasses { - if i > lastSmallChunkIndex { - break - } + for _, n := range chunkSizeClasses { for i := 0; i < preAlloc; i++ { PutBuffer(GetBuffer(n)) @@ -42,7 +40,7 @@ func init() { } } -func GetBuffer(size uint) *bytebufferpool.ByteBuffer { +func GetBuffer(size uint) *ByteBuffer { var i int for i = 0; i < len(chunkSizeClasses)-1; i++ { if size <= chunkSizeClasses[i] { @@ -67,7 +65,15 @@ func GetBuffer(size uint) *bytebufferpool.ByteBuffer { return pp } -func PutBuffer(p *bytebufferpool.ByteBuffer) { +func GetBufferZeroed(size uint) *ByteBuffer { + pp := GetBuffer(size) + for i := range pp.B { + pp.B[i] = 0 + } + return pp +} + +func PutBuffer(p *ByteBuffer) { if p == nil || cap(p.B) == 0 { return } diff --git a/common/pool/pool.go b/common/pool/pool.go index ec8e3cdc4f6cadeb908bd34a4258fa404c2a697e..d5873d8033bc3a0477b6920da90dd639cd5b3ac5 100644 --- a/common/pool/pool.go +++ b/common/pool/pool.go @@ -24,27 +24,33 @@ func newPool(defaultSize uint) *pool { defaultSize: uint64(defaultSize), maxSize: uint64(defaultSize), pool: sync.Pool{ - New: func() interface{} { - return &bytebufferpool.ByteBuffer{ - B: make([]byte, 0, defaultSize), - } - }, + New: getFn(defaultSize), }, } } +func getFn(defaultSize uint) func() interface{} { + return func() interface{} { + return &ByteBuffer{ + &bytebufferpool.ByteBuffer{ + B: make([]byte, 0, defaultSize), + }, + } + } +} + // Get returns new byte buffer with zero length. // // The byte buffer may be returned to the pool via Put after the use // in order to minimize GC overhead. -func (p *pool) Get() *bytebufferpool.ByteBuffer { - return p.pool.Get().(*bytebufferpool.ByteBuffer) +func (p *pool) Get() *ByteBuffer { + return p.pool.Get().(*ByteBuffer) } // Put releases byte buffer obtained via Get to the pool. // // The buffer mustn't be accessed after returning to the pool. -func (p *pool) Put(b *bytebufferpool.ByteBuffer) { +func (p *pool) Put(b *ByteBuffer) { if b == nil || cap(b.B) == 0 { return } diff --git a/consensus/clique/clique_test.go b/consensus/clique/clique_test.go index cd95afb2fb9bcb07ffe3aa973bd794f188eebac6..ccf564a777ed6c9eee56577b01689d99df9b1398 100644 --- a/consensus/clique/clique_test.go +++ b/consensus/clique/clique_test.go @@ -57,7 +57,7 @@ func TestReimportMirroredState(t *testing.T) { genesis := genspec.MustCommit(db) // Generate a batch of blocks, each properly signed - chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() ctx := context.Background() @@ -93,7 +93,7 @@ func TestReimportMirroredState(t *testing.T) { db = ethdb.NewMemDatabase() genspec.MustCommit(db) - chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() if _, err := chain.InsertChain(context.Background(), blocks[:2]); err != nil { @@ -106,7 +106,7 @@ func TestReimportMirroredState(t *testing.T) { // Simulate a crash by creating a new chain on top of the database, without // flushing the dirty states out. Insert the last block, trigerring a sidechain // reimport. - chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil) + chain, _ = core.NewBlockChain(db, nil, params.AllCliqueProtocolChanges, engine, vm.Config{}, nil, nil, nil) defer chain.Stop() if _, err := chain.InsertChain(context.Background(), blocks[2:]); err != nil { diff --git a/consensus/clique/snapshot_test.go b/consensus/clique/snapshot_test.go index 30c67f8829c13ea002470f15b33b469ef088d71b..8fcb2c370944d70debc46cbbec4f57d69ad9a418 100644 --- a/consensus/clique/snapshot_test.go +++ b/consensus/clique/snapshot_test.go @@ -415,7 +415,7 @@ func TestClique(t *testing.T) { engine := New(config.Clique, db) engine.fakeDiff = true - chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, nil, &config, engine, vm.Config{}, nil, nil, vm.NewDestsCache(100)) if err != nil { t.Errorf("test %d: failed to create test chain: %v", i, err) continue diff --git a/core/bench_test.go b/core/bench_test.go index 18fb74283f000d2d565ea598fc70fa86c673c394..56ec1650ff1dae69074043fb111cfc354f90311b 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -176,7 +176,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { } genesis := gspec.MustCommit(db) - chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ctx := chainman.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) defer chainman.Stop() chain, _ := GenerateChain(ctx, gspec.Config, genesis, ethash.NewFaker(), db, b.N, gen) @@ -295,7 +295,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 76600f1ebe505ad896e77d478620725c82aee5b4..d34fe8dbc1eff82463025d453a1bba2e3ab09adf 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -38,7 +38,8 @@ func TestHeaderVerification(t *testing.T) { gspec = &Genesis{Config: params.TestChainConfig} genesis = gspec.MustCommit(testdb) ) - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + dests := vm.NewDestsCache(100) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, dests) ctx := chain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) defer chain.Stop() @@ -107,17 +108,19 @@ func testHeaderConcurrentVerification(t *testing.T, threads int) { old := runtime.GOMAXPROCS(threads) defer runtime.GOMAXPROCS(old) + dests := vm.NewDestsCache(100) + // Run the header checker for the entire block chain at once both for a valid and // also an invalid chain (enough if one arbitrary block is invalid). for i, valid := range []bool{true, false} { var results <-chan error if valid { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, dests) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } else { - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeFailer(uint64(len(headers)-1)), vm.Config{}, nil, nil, dests) _, results = chain.engine.VerifyHeaders(chain, headers, seals) chain.Stop() } @@ -182,7 +185,8 @@ func testHeaderConcurrentAbortion(t *testing.T, threads int) { defer runtime.GOMAXPROCS(old) // Start the verifications and immediately abort - chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil) + dests := vm.NewDestsCache(100) + chain, _ := NewBlockChain(testdb, nil, params.TestChainConfig, ethash.NewFakeDelayer(time.Millisecond), vm.Config{}, nil, nil, dests) defer chain.Stop() abort, results := chain.engine.VerifyHeaders(chain, headers, seals) diff --git a/core/blockchain.go b/core/blockchain.go index 19fc1a374db6ad9d05d424492bdcb076ff5680d9..60b35e191cdb801fc51ce0c7c29458854a6615ae 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -199,12 +199,14 @@ type BlockChain struct { enablePreimages bool // Whether we store preimages into the database resolveReads bool pruner Pruner + + DestsCache vm.Cache } // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator and // Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool, txLookupLimit *uint64) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config, shouldPreserve func(block *types.Block) bool, txLookupLimit *uint64, dests vm.Cache) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = &CacheConfig{ Pruning: false, @@ -248,6 +250,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par enableTxLookupIndex: true, enableReceipts: false, enablePreimages: true, + DestsCache: dests, } bc.validator = NewBlockValidator(chainConfig, bc, engine) bc.prefetcher = newStatePrefetcher(chainConfig, bc, engine) @@ -1762,7 +1765,7 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, verif if !bc.cacheConfig.DownloadOnly && execute { stateDB = state.New(bc.trieDbState) // Process block using the parent state as reference point. - receipts, logs, usedGas, root, err = bc.processor.PreProcess(block, stateDB, bc.trieDbState, bc.vmConfig) + receipts, logs, usedGas, root, err = bc.processor.PreProcess(block, stateDB, bc.trieDbState, bc.vmConfig, bc.DestsCache) reuseTrieDbState := true if err != nil { bc.rollbackBadBlock(block, receipts, err, reuseTrieDbState) @@ -2481,6 +2484,7 @@ func ExecuteBlockEuphemerally( block *types.Block, stateReader state.StateReader, stateWriter state.WriterWithChangeSets, + dests vm.Cache, ) error { ibs := state.New(stateReader) header := block.Header() @@ -2494,7 +2498,7 @@ func ExecuteBlockEuphemerally( noop := state.NewNoopWriter() for i, tx := range block.Transactions() { ibs.Prepare(tx.Hash(), block.Hash(), i) - receipt, err := ApplyTransaction(chainConfig, chainContext, nil, gp, ibs, noop, header, tx, usedGas, *vmConfig) + receipt, err := ApplyTransaction(chainConfig, chainContext, nil, gp, ibs, noop, header, tx, usedGas, *vmConfig, dests) if err != nil { return fmt.Errorf("tx %x failed: %v", tx.Hash(), err) } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ed9ea4b41aed9ba88c849652e233cc646d500094..f3cf936c6e4ff1a2b657ab2f637faa1c48aa14f8 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -70,7 +70,7 @@ func newCanonical(engine consensus.Engine, n int, full bool) (context.Context, e NoHistory: false, Pruning: false, } - blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) // Create and inject the requested chain @@ -167,7 +167,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { parent := blockchain.GetBlockByHash(block.ParentHash()) tds := state.NewTrieDbState(parent.Root(), blockchain.db, parent.NumberU64()) statedb := state.New(tds) - receipts, _, usedGas, root, err := blockchain.Processor().PreProcess(block, statedb, tds, vm.Config{}) + receipts, _, usedGas, root, err := blockchain.Processor().PreProcess(block, statedb, tds, vm.Config{}, nil) if err != nil { blockchain.reportBlock(block, receipts, err) return err @@ -568,7 +568,7 @@ func testReorgBadHashes(t *testing.T, full bool) { NoHistory: false, Pruning: false, } - ncm, err := NewBlockChain(blockchain.db, cacheConfig, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil) + ncm, err := NewBlockChain(blockchain.db, cacheConfig, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -698,7 +698,7 @@ func TestFastVsFullChains(t *testing.T) { NoHistory: false, Pruning: false, } - archive, _ := NewBlockChain(archiveDb, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer archive.Stop() if n, err := archive.InsertChain(context.Background(), blocks); err != nil { @@ -707,7 +707,7 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb := ethdb.NewMemDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -731,7 +731,7 @@ func TestFastVsFullChains(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } gspec.MustCommit(ancientDb) - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { @@ -835,7 +835,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { TrieTimeLimit: 5 * time.Minute, NoHistory: false, } - archive, _ := NewBlockChain(archiveDb, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + archive, _ := NewBlockChain(archiveDb, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if n, err := archive.InsertChain(context.Background(), blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -848,7 +848,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb, delfn := makeDb() defer delfn() - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -868,7 +868,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a ancient-first node and ensure all pointers are updated ancientDb, delfn := makeDb() defer delfn() - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancient.Stop() if n, err := ancient.InsertHeaderChain(headers, 1); err != nil { @@ -887,7 +887,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a light node and ensure all pointers are updated lightDb, delfn := makeDb() defer delfn() - light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -947,7 +947,7 @@ func TestChainTxReorgs(t *testing.T) { NoHistory: false, Pruning: false, } - blockchain, _ := NewBlockChain(db, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) blockchain.EnableReceipts(true) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) @@ -1049,7 +1049,7 @@ func TestLogReorgs(t *testing.T) { NoHistory: false, Pruning: false, } - blockchain, _ := NewBlockChain(db, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) blockchain.EnableReceipts(true) defer blockchain.Stop() @@ -1106,7 +1106,7 @@ func TestLogRebirth(t *testing.T) { genesis = gspec.MustCommit(db) signer = types.NewEIP155Signer(gspec.Config.ChainID) engine = ethash.NewFaker() - blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) ) blockchain.EnableReceipts(true) @@ -1171,7 +1171,7 @@ func TestSideLogRebirth(t *testing.T) { gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}} genesis = gspec.MustCommit(db) signer = types.NewEIP155Signer(gspec.Config.ChainID) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ) defer blockchain.Stop() @@ -1250,7 +1250,7 @@ func TestReorgSideEvent(t *testing.T) { signer = types.NewEIP155Signer(gspec.Config.ChainID) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) defer blockchain.Stop() @@ -1383,7 +1383,7 @@ func TestEIP155Transition(t *testing.T) { genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) defer blockchain.Stop() @@ -1507,7 +1507,7 @@ func doModesTest(history, preimages, receipts, txlookup bool) error { NoHistory: !history, } - blockchain, _ := NewBlockChain(db, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, cacheConfig, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) blockchain.EnableReceipts(receipts) blockchain.EnablePreimages(preimages) blockchain.EnableTxLookupIndex(txlookup) @@ -1654,7 +1654,7 @@ func TestEIP161AccountRemoval(t *testing.T) { genesis = gspec.MustCommit(db) genesisDb = db.MemCopy() ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) defer blockchain.Stop() @@ -1720,7 +1720,7 @@ func TestDoubleAccountRemoval(t *testing.T) { genDb = db.MemCopy() ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) defer blockchain.Stop() @@ -1797,7 +1797,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { NoHistory: false, Pruning: false, } - chain, err := NewBlockChain(diskdb, cacheConfig, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, cacheConfig, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1857,7 +1857,7 @@ func TestLargeReorgTrieGC(t *testing.T) { NoHistory: false, Pruning: false, } - chain, err := NewBlockChain(diskdb, cacheConfig, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, cacheConfig, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1921,7 +1921,7 @@ func TestBlockchainRecovery(t *testing.T) { gspec.MustCommit(ancientDb) - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) headers := make([]*types.Header, len(blocks)) for i, block := range blocks { @@ -1941,7 +1941,7 @@ func TestBlockchainRecovery(t *testing.T) { rawdb.WriteHeadFastBlockHash(ancientDb, midBlock.Hash()) // Reopen broken blockchain again - ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ = NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancient.Stop() if num := ancient.CurrentBlock().NumberU64(); num != 0 { t.Errorf("head block mismatch: have #%v, want #%v", num, 0) @@ -1979,7 +1979,7 @@ func TestIncompleteAncientReceiptChainInsertion(t *testing.T) { t.Fatalf("failed to create temp freezer db: %v", err) } gspec.MustCommit(ancientDb) - ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + ancient, _ := NewBlockChain(ancientDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer ancient.Stop() headers := make([]*types.Header, len(blocks)) @@ -2041,7 +2041,7 @@ func TestLowDiffLongChain(t *testing.T) { diskDB := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskDB) - chain, err := NewBlockChain(diskDB, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskDB, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2100,7 +2100,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon diskdb := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2198,7 +2198,7 @@ func testInsertKnownChainData(t *testing.T, typ string) { new(Genesis).MustCommit(chaindb) defer os.RemoveAll(dir) - chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(chaindb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2315,7 +2315,7 @@ func getLongAndShortChains() (*BlockChain, []*types.Block, []*types.Block, error diskdb := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { return nil, nil, nil, fmt.Errorf("failed to create tester chain: %v", err) } @@ -2471,7 +2471,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in diskdb := ethdb.NewMemDatabase() defer diskdb.Close() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -2485,7 +2485,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -2569,7 +2569,7 @@ func TestSideImportPrunedBlocks(t *testing.T) { blocks, _ := GenerateChain(context.Background(), params.TestChainConfig, genesis, engine, db, 2*triesInMemory, nil) diskdb := ethdb.NewMemDatabase() new(Genesis).MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2664,7 +2664,7 @@ func TestDeleteCreateRevert(t *testing.T) { diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2760,7 +2760,6 @@ func TestDeleteRecreateSlots(t *testing.T) { }, } genesis := gspec.MustCommit(db) - blocks, _ := GenerateChain(context.Background(), params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) // One transaction to AA, to kill it @@ -2776,7 +2775,7 @@ func TestDeleteRecreateSlots(t *testing.T) { diskdb := ethdb.NewMemDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -2856,7 +2855,7 @@ func TestDeleteRecreateAccount(t *testing.T) { Pruning: false, } - blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) blocks, _ := GenerateChain(ctx, params.TestChainConfig, genesis, engine, db, 1, func(i int, b *BlockGen) { @@ -2874,7 +2873,7 @@ func TestDeleteRecreateAccount(t *testing.T) { diskdb := ethdb.NewMemDatabase() defer diskdb.Close() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil) + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3029,7 +3028,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { Pruning: false, } - blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) blocks, _ := GenerateChain(ctx, params.TestChainConfig, genesis, engine, db, 150, func(i int, b *BlockGen) { @@ -3063,7 +3062,7 @@ func TestDeleteRecreateSlotsAcrossManyBlocks(t *testing.T) { chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -3198,7 +3197,7 @@ func TestInitThenFailCreateContract(t *testing.T) { Pruning: false, } - blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, cacheConfig, params.AllEthashProtocolChanges, engine, vm.Config{}, nil, nil, nil) ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) blocks, _ := GenerateChain(ctx, params.TestChainConfig, genesis, engine, db, 4, func(i int, b *BlockGen) { @@ -3216,7 +3215,7 @@ func TestInitThenFailCreateContract(t *testing.T) { chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{ //Debug: true, //Tracer: vm.NewJSONLogger(nil, os.Stdout), - }, nil, nil) + }, nil, nil, nil) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers.go b/core/chain_makers.go index d113c3adf8c25a5c06a6432dbb37f804197a0f79..035550c6fa333b8efab914b1e64f0c09e81e04bd 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -100,12 +100,12 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { // further limitations on the content of transactions that can be // added. If contract code relies on the BLOCKHASH instruction, // the block in chain will be returned. -func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { +func (b *BlockGen) AddTxWithChain(bc ChainContext, tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.triedbstate.TrieStateWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}) + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.triedbstate.TrieStateWriter(), b.header, tx, &b.header.GasUsed, vm.Config{}, nil) if err != nil { panic(err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 2aed6e5558d2eabadd3811ab77f49b8510d05aba..48a0b5195447c0d4b1b6ba708d3be749e773b528 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -57,7 +57,7 @@ func ExampleGenerateChain() { } genesis := gspec.MustCommit(db) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) defer blockchain.Stop() ctx := blockchain.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) diff --git a/core/dao_test.go b/core/dao_test.go index 8784dbb347af0db89ad14a80769e9eef0e21b314..aaab1dabea97274e0d1b8507d7f1bc36d3fb75f2 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -45,7 +45,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { proConf := *params.TestChainConfig proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true - proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, vm.NewDestsCache(100)) defer proBc.Stop() ctx := proBc.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) @@ -58,7 +58,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false - conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, vm.NewDestsCache(100)) defer conBc.Stop() if _, err := proBc.InsertChain(context.Background(), prefix); err != nil { @@ -75,7 +75,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { db = ethdb.NewMemDatabase() defer db.Close() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, vm.NewDestsCache(100)) defer bc.Stop() ctx = bc.WithContext(context.Background(), big.NewInt(conBc.CurrentBlock().Number().Int64()+1)) @@ -101,7 +101,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { defer db.Close() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, vm.NewDestsCache(100)) defer bc.Stop() ctx = bc.WithContext(context.Background(), big.NewInt(proBc.CurrentBlock().Number().Int64()+1)) @@ -127,7 +127,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { db = ethdb.NewMemDatabase() defer db.Close() gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}, nil, nil, vm.NewDestsCache(100)) defer bc.Stop() ctx = bc.WithContext(context.Background(), big.NewInt(conBc.CurrentBlock().Number().Int64()+1)) @@ -146,7 +146,7 @@ func TestDAOForkRangeExtradata(t *testing.T) { db = ethdb.NewMemDatabase() defer db.Close() gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil) + bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}, nil, nil, vm.NewDestsCache(100)) defer bc.Stop() ctx = bc.WithContext(context.Background(), big.NewInt(proBc.CurrentBlock().Number().Int64()+1)) diff --git a/core/genesis_test.go b/core/genesis_test.go index a3ed3c66e17ecd84f0f40267747a2a6e57f765db..5110496eca19c66ceead51cc0db4848ac0ba8412 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -126,7 +126,7 @@ func TestSetupGenesis(t *testing.T) { // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil) + bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}, nil, nil, vm.NewDestsCache(100)) defer bc.Stop() ctx := bc.WithContext(context.Background(), big.NewInt(genesis.Number().Int64()+1)) diff --git a/core/state/database_test.go b/core/state/database_test.go index 6cb2fcf4555a2c51eaa7c2f4f4576f3a567da40e..e99318161730b1cfa2771cdeaed2bbda3dffc5f8 100644 --- a/core/state/database_test.go +++ b/core/state/database_test.go @@ -72,7 +72,7 @@ func TestCreate2Revive(t *testing.T) { ) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -243,7 +243,7 @@ func TestReorgOverSelfDestruct(t *testing.T) { ) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -348,7 +348,7 @@ func TestReorgOverSelfDestruct(t *testing.T) { } // Reload blockchain from the database - blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -385,7 +385,7 @@ func TestReorgOverStateChange(t *testing.T) { ) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -480,7 +480,7 @@ func TestReorgOverStateChange(t *testing.T) { } // Reload blockchain from the database - blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -535,7 +535,7 @@ func TestDatabaseStateChangeDBSizeDebug(t *testing.T) { ) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -701,7 +701,7 @@ func TestCreateOnExistingStorage(t *testing.T) { ) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -839,7 +839,7 @@ func TestEip2200Gas(t *testing.T) { ) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -927,7 +927,7 @@ func TestWrongIncarnation(t *testing.T) { ) engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -996,7 +996,7 @@ func TestWrongIncarnation(t *testing.T) { } // Reload blockchain from the database - blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -1055,7 +1055,7 @@ func TestWrongIncarnation2(t *testing.T) { knownContractAddress := common.HexToAddress("0xdb7d6ab1f17c6b31909ae466702703daef9269cf") engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go index 15915a5cd97ba2f74f2ae45df73c121fdc894c62..03aca935a212df132c881e2c62a8d5f614a9553c 100644 --- a/core/state_prefetcher.go +++ b/core/state_prefetcher.go @@ -48,7 +48,7 @@ func newStatePrefetcher(config *params.ChainConfig, bc *BlockChain, engine conse // Prefetch processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb, but any changes are discarded. The // only goal is to pre-cache transaction signatures and state trie nodes. -func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.IntraBlockState, cfg vm.Config, interrupt *uint32) { +func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.IntraBlockState, cfg vm.Config, interrupt *uint32, dests vm.Cache) { var ( header = block.Header() gaspool = new(GasPool).AddGas(block.GasLimit()) @@ -60,7 +60,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.IntraBlock } // Block precaching permitted to continue, execute the transaction statedb.Prepare(tx.Hash(), block.Hash(), i) - if err := precacheTransaction(p.config, p.bc, nil, gaspool, statedb, header, tx, cfg); err != nil { + if err := precacheTransaction(p.config, p.bc, nil, gaspool, statedb, header, tx, cfg, dests); err != nil { return // Ugh, something went horribly wrong, bail out } } @@ -69,7 +69,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.IntraBlock // precacheTransaction attempts to apply a transaction to the given state database // and uses the input parameters for its environment. The goal is not to execute // the transaction successfully, rather to warm up touched data slots. -func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gaspool *GasPool, statedb *state.IntraBlockState, header *types.Header, tx *types.Transaction, cfg vm.Config) error { +func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gaspool *GasPool, statedb vm.IntraBlockState, header *types.Header, tx *types.Transaction, cfg vm.Config, dests vm.Cache) error { // Convert the transaction into an executable message and pre-cache its sender msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { @@ -77,7 +77,7 @@ func precacheTransaction(config *params.ChainConfig, bc ChainContext, author *co } // Create the EVM and execute the transaction context := NewEVMContext(msg, header, bc, author) - vm := vm.NewEVM(context, statedb, config, cfg) + vm := vm.NewEVM(context, statedb, config, cfg, dests) _, err = ApplyMessage(vm, msg, gaspool) return err diff --git a/core/state_processor.go b/core/state_processor.go index 2760c147fa5758ab8fec30a57cf58d3abb2901ed..063c432e0ec45e73ae4332adb89c661b772b125e 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -121,7 +121,7 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes { // // PreProcess does not calculate receipt roots (required pre-Byzantium) // and does not update the TrieDbState. For those two call PostProcess afterwards. -func (p *StateProcessor) PreProcess(block *types.Block, ibs *state.IntraBlockState, tds *state.TrieDbState, cfg vm.Config) ( +func (p *StateProcessor) PreProcess(block *types.Block, ibs *state.IntraBlockState, tds *state.TrieDbState, cfg vm.Config, dests vm.Cache) ( receipts types.Receipts, allLogs []*types.Log, usedGas uint64, root common.Hash, err error) { header := block.Header() @@ -147,7 +147,7 @@ func (p *StateProcessor) PreProcess(block *types.Block, ibs *state.IntraBlockSta writeTrace = true } var receipt *types.Receipt - receipt, err = ApplyTransaction(p.config, p.bc, nil, gp, ibs, tds.TrieStateWriter(), header, tx, &usedGas, cfg) + receipt, err = ApplyTransaction(p.config, p.bc, nil, gp, ibs, tds.TrieStateWriter(), header, tx, &usedGas, cfg, dests) // This code is useful when debugging a certain transaction. If uncommented, together with the code // at the end of this function, after the execution of transaction with given hash, the file // structlogs.txt will contain full trace of the transactin in JSON format. This can be compared @@ -213,7 +213,7 @@ func (p *StateProcessor) PostProcess(block *types.Block, tds *state.TrieDbState, // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.IntraBlockState, stateWriter state.StateWriter, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, error) { +func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.IntraBlockState, stateWriter state.StateWriter, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, dests vm.Cache) (*types.Receipt, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { return nil, err @@ -223,7 +223,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo context := NewEVMContext(msg, header, bc, author) // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. - vmenv := vm.NewEVM(context, statedb, config, cfg) + vmenv := vm.NewEVM(context, statedb, config, cfg, dests) // Apply the transaction to the current state (included in the env) result, err := ApplyMessage(vmenv, msg, gp) if err != nil { diff --git a/core/types.go b/core/types.go index 9018368b577d0d2cbd85352e011c3e69b9067b1d..4cbd59a92e213549deb09fc3a7b2f2fb28a383b4 100644 --- a/core/types.go +++ b/core/types.go @@ -44,11 +44,11 @@ type Prefetcher interface { // Prefetch processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb, but any changes are discarded. The // only goal is to pre-cache transaction signatures and state trie nodes. - Prefetch(block *types.Block, statedb *state.IntraBlockState, cfg vm.Config, interrupt *uint32) + Prefetch(block *types.Block, statedb *state.IntraBlockState, cfg vm.Config, interrupt *uint32, dests vm.Cache) } // Processor is an interface for processing blocks using a given initial state. type Processor interface { - PreProcess(block *types.Block, statedb *state.IntraBlockState, tds *state.TrieDbState, cfg vm.Config) (receipts types.Receipts, allLogs []*types.Log, usedGas uint64, root common.Hash, err error) + PreProcess(block *types.Block, statedb *state.IntraBlockState, tds *state.TrieDbState, cfg vm.Config, dests vm.Cache) (receipts types.Receipts, allLogs []*types.Log, usedGas uint64, root common.Hash, err error) PostProcess(block *types.Block, tds *state.TrieDbState, receipts types.Receipts) error } diff --git a/core/vm/analysis.go b/core/vm/analysis.go index 0ccf47b97903a7d547d1dbb0256cd2cff5ead0cc..1779b796480723930069943834b08aa0ca02df70 100644 --- a/core/vm/analysis.go +++ b/core/vm/analysis.go @@ -16,30 +16,63 @@ package vm -// bitvec is a bit vector which maps bytes in a program. -// An unset bit means the byte is an opcode, a set bit means -// it's data (i.e. argument of PUSHxx). -type bitvec []byte +import ( + "github.com/hashicorp/golang-lru" + "github.com/ledgerwatch/turbo-geth/common" + "github.com/ledgerwatch/turbo-geth/common/pool" +) -func (bits *bitvec) set(pos uint64) { - (*bits)[pos/8] |= 0x80 >> (pos % 8) +type Cache interface { + Len() int + Set(hash common.Hash, v *pool.ByteBuffer) + Get(hash common.Hash) (*pool.ByteBuffer, bool) + Clear(codeHash common.Hash, local *pool.ByteBuffer) } -func (bits *bitvec) set8(pos uint64) { - (*bits)[pos/8] |= 0xFF >> (pos % 8) - (*bits)[pos/8+1] |= ^(0xFF >> (pos % 8)) + +type DestsCache struct { + *lru.Cache +} + +func NewDestsCache(maxSize int) *DestsCache { + c, _ := lru.New(maxSize) + return &DestsCache{c} } -// codeSegment checks if the position is in a code segment. -func (bits *bitvec) codeSegment(pos uint64) bool { - return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0 +func (d *DestsCache) Set(hash common.Hash, v *pool.ByteBuffer) { + d.Add(hash, v) +} + +func (d DestsCache) Get(hash common.Hash) (*pool.ByteBuffer, bool) { + v, ok := d.Cache.Get(hash) + if !ok { + return nil, false + } + return v.(*pool.ByteBuffer), ok +} + +func (d *DestsCache) Clear(codeHash common.Hash, local *pool.ByteBuffer) { + if codeHash == (common.Hash{}) { + return + } + _, ok := d.Get(codeHash) + if ok { + return + } + // analysis is a local one + pool.PutBuffer(local) +} + +func (d *DestsCache) Len() int { + return d.Cache.Len() } // codeBitmap collects data locations in code. -func codeBitmap(code []byte) bitvec { +func codeBitmap(code []byte) *pool.ByteBuffer { // The bitmap is 4 bytes longer than necessary, in case the code // ends with a PUSH32, the algorithm will push zeroes onto the // bitvector outside the bounds of the actual code. - bits := make(bitvec, len(code)/8+1+4) + bits := pool.GetBufferZeroed(uint(len(code)/8 + 1 + 4)) + for pc := uint64(0); pc < uint64(len(code)); { op := OpCode(code[pc]) @@ -47,11 +80,11 @@ func codeBitmap(code []byte) bitvec { numbits := op - PUSH1 + 1 pc++ for ; numbits >= 8; numbits -= 8 { - bits.set8(pc) // 8 + bits.SetBit8Pos(pc) // 8 pc += 8 } for ; numbits > 0; numbits-- { - bits.set(pc) + bits.SetBitPos(pc) pc++ } } else { diff --git a/core/vm/analysis_test.go b/core/vm/analysis_test.go index 372b104b14009e5f321f2a677e4899fcf95bb723..cc8f651390a2c7521e80ceadcf71ad5768a4e7cd 100644 --- a/core/vm/analysis_test.go +++ b/core/vm/analysis_test.go @@ -17,8 +17,14 @@ package vm import ( + "fmt" + "io/ioutil" "testing" + "github.com/holiman/uint256" + + "github.com/ledgerwatch/turbo-geth/common" + "github.com/ledgerwatch/turbo-geth/common/pool" "github.com/ledgerwatch/turbo-geth/crypto" ) @@ -49,21 +55,59 @@ func TestJumpDestAnalysis(t *testing.T) { } for _, test := range tests { ret := codeBitmap(test.code) - if ret[test.which] != test.exp { - t.Fatalf("expected %x, got %02x", test.exp, ret[test.which]) + if ret.Get(test.which) != test.exp { + t.Fatalf("expected %x, got %02x", test.exp, ret.Get(test.which)) } } } -func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) { +func BenchmarkJumpdestSet8(b *testing.B) { + const size = 1000 + bits := pool.GetBuffer(size) + b.ResetTimer() + for n := 0; n < b.N; n++ { + for i := uint64(0); i < size*8-8; i++ { + bits.SetBit8Pos(i) + } + } + b.StopTimer() + fmt.Fprint(ioutil.Discard, bits.Len()) +} + +func BenchmarkJumpdestSet(b *testing.B) { + const size = 1000 + bits := pool.GetBuffer(size) + b.ResetTimer() + for n := 0; n < b.N; n++ { + for i := uint64(0); i < 8*size; i++ { + bits.SetBitPos(i) + } + } + b.StopTimer() + fmt.Fprint(ioutil.Discard, bits.Len()) +} + +func BenchmarkJumpdestAnalysisEmpty_1200k(bench *testing.B) { // 1.4 ms code := make([]byte, 1200000) bench.ResetTimer() for i := 0; i < bench.N; i++ { - codeBitmap(code) + b := codeBitmap(code) + pool.PutBuffer(b) } bench.StopTimer() } + +func BenchmarkJumpdestAnalysis_1200k(bench *testing.B) { + code := common.Hex2Bytes("6060604052361561006c5760e060020a600035046308551a53811461007457806335a063b4146100865780633fa4f245146100a6578063590e1ae3146100af5780637150d8ae146100cf57806373fac6f0146100e1578063c19d93fb146100fe578063d696069714610112575b610131610002565b610133600154600160a060020a031681565b610131600154600160a060020a0390811633919091161461015057610002565b61014660005481565b610131600154600160a060020a039081163391909116146102d557610002565b610133600254600160a060020a031681565b610131600254600160a060020a0333811691161461023757610002565b61014660025460ff60a060020a9091041681565b61013160025460009060ff60a060020a9091041681146101cc57610002565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60025460009060a060020a900460ff16811461016b57610002565b600154600160a060020a03908116908290301631606082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f72c874aeff0b183a56e2b79c71b46e1aed4dee5e09862134b8821ba2fddbf8bf9250a150565b80546002023414806101dd57610002565b6002805460a060020a60ff021973ffffffffffffffffffffffffffffffffffffffff1990911633171660a060020a1790557fd5d55c8a68912e9a110618df8d5e2e83b8d83211c57a8ddd1203df92885dc881826060a15050565b60025460019060a060020a900460ff16811461025257610002565b60025460008054600160a060020a0390921691606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517fe89152acd703c9d8c7d28829d443260b411454d45394e7995815140c8cbcbcf79250a150565b60025460019060a060020a900460ff1681146102f057610002565b6002805460008054600160a060020a0390921692909102606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f8616bbbbad963e4e65b1366f1d75dfb63f9e9704bbbf91fb01bec70849906cf79250a15056") + bench.ResetTimer() + for i := 0; i < bench.N; i++ { + b := codeBitmap(code) + pool.PutBuffer(b) + } + bench.StopTimer() +} + func BenchmarkJumpdestHashing_1200k(bench *testing.B) { // 4 ms code := make([]byte, 1200000) @@ -73,3 +117,25 @@ func BenchmarkJumpdestHashing_1200k(bench *testing.B) { } bench.StopTimer() } + +func BenchmarkJumpDest(b *testing.B) { + code := common.Hex2Bytes("6060604052361561006c5760e060020a600035046308551a53811461007457806335a063b4146100865780633fa4f245146100a6578063590e1ae3146100af5780637150d8ae146100cf57806373fac6f0146100e1578063c19d93fb146100fe578063d696069714610112575b610131610002565b610133600154600160a060020a031681565b610131600154600160a060020a0390811633919091161461015057610002565b61014660005481565b610131600154600160a060020a039081163391909116146102d557610002565b610133600254600160a060020a031681565b610131600254600160a060020a0333811691161461023757610002565b61014660025460ff60a060020a9091041681565b61013160025460009060ff60a060020a9091041681146101cc57610002565b005b600160a060020a03166060908152602090f35b6060908152602090f35b60025460009060a060020a900460ff16811461016b57610002565b600154600160a060020a03908116908290301631606082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f72c874aeff0b183a56e2b79c71b46e1aed4dee5e09862134b8821ba2fddbf8bf9250a150565b80546002023414806101dd57610002565b6002805460a060020a60ff021973ffffffffffffffffffffffffffffffffffffffff1990911633171660a060020a1790557fd5d55c8a68912e9a110618df8d5e2e83b8d83211c57a8ddd1203df92885dc881826060a15050565b60025460019060a060020a900460ff16811461025257610002565b60025460008054600160a060020a0390921691606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517fe89152acd703c9d8c7d28829d443260b411454d45394e7995815140c8cbcbcf79250a150565b60025460019060a060020a900460ff1681146102f057610002565b6002805460008054600160a060020a0390921692909102606082818181858883f150508354604051600160a060020a0391821694503090911631915082818181858883f150506002805460a060020a60ff02191660a160020a179055506040517f8616bbbbad963e4e65b1366f1d75dfb63f9e9704bbbf91fb01bec70849906cf79250a15056") + pc := new(uint256.Int) + hash := common.Hash{1, 2, 3, 4, 5} + + contractRef := dummyContractRef{} + dests := NewDestsCache(10) + + b.ResetTimer() + for n := 0; n < b.N; n++ { + contract := NewContract(contractRef, contractRef, nil, 0, dests) + contract.Code = code + contract.CodeHash = hash + + b.StartTimer() + for i := range contract.Code { + contract.validJumpdest(pc.SetUint64(uint64(i))) + } + b.StopTimer() + } +} diff --git a/core/vm/contract.go b/core/vm/contract.go index 768c7e6202cb4222121764b88dd2681dd3f8f34b..9bab9b1f3cc90a756b8f0a04bf76f4c64f425976 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -20,6 +20,7 @@ import ( "github.com/holiman/uint256" "github.com/ledgerwatch/turbo-geth/common" + "github.com/ledgerwatch/turbo-geth/common/pool" ) // ContractRef is a reference to the contract's backing object @@ -49,8 +50,8 @@ type Contract struct { caller ContractRef self ContractRef - jumpdests map[common.Hash]bitvec // Aggregated result of JUMPDEST analysis. - analysis bitvec // Locally cached result of JUMPDEST analysis + analysis *pool.ByteBuffer // Locally cached result of JUMPDEST analysis + dests Cache Code []byte CodeHash common.Hash @@ -62,22 +63,17 @@ type Contract struct { } // NewContract returns a new contract environment for the execution of EVM. -func NewContract(caller ContractRef, object ContractRef, value *uint256.Int, gas uint64) *Contract { +func NewContract(caller ContractRef, object ContractRef, value *uint256.Int, gas uint64, dests Cache) *Contract { c := &Contract{CallerAddress: caller.Address(), caller: caller, self: object} - if parent, ok := caller.(*Contract); ok { - // Reuse JUMPDEST analysis from parent context if available. - c.jumpdests = parent.jumpdests - } else { - c.jumpdests = make(map[common.Hash]bitvec) - } - // Gas should be a pointer so it can safely be reduced through the run // This pointer will be off the state transition c.Gas = gas // ensures a value is set c.value = value + c.dests = dests + return c } @@ -94,27 +90,27 @@ func (c *Contract) validJumpdest(dest *uint256.Int) bool { } // Do we have it locally already? if c.analysis != nil { - return c.analysis.codeSegment(udest) + return c.analysis.CodeSegment(udest) } // If we have the code hash (but no analysis), we should look into the // parent analysis map and see if the analysis has been made previously if c.CodeHash != (common.Hash{}) { - analysis, exist := c.jumpdests[c.CodeHash] + var exist bool + // Also stash it in current contract for faster access + c.analysis, exist = c.dests.Get(c.CodeHash) if !exist { // Do the analysis and save in parent context - analysis = codeBitmap(c.Code) - c.jumpdests[c.CodeHash] = analysis + c.analysis = codeBitmap(c.Code) + c.dests.Set(c.CodeHash, c.analysis) } - // Also stash it in current contract for faster access - c.analysis = analysis - return analysis.codeSegment(udest) + return c.analysis.CodeSegment(udest) } // We don't have the code hash, most likely a piece of initcode not already // in state trie. In that case, we do an analysis, and save it locally, so // we don't have to recalculate it for every JUMP instruction in the execution // However, we don't save it within the parent context c.analysis = codeBitmap(c.Code) - return c.analysis.codeSegment(udest) + return c.analysis.CodeSegment(udest) } // AsDelegate sets the contract to be a delegate call and returns the current diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index bbbc029ec6aa4ca3d517d281544b3577eba970a3..715f622b13bb48015ac015f1932d8242d3f179da 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -403,7 +403,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) { p := PrecompiledContractsIstanbul[common.HexToAddress(addr)] in := common.Hex2Bytes(test.input) contract := NewContract(AccountRef(common.HexToAddress("1337")), - nil, new(uint256.Int), p.RequiredGas(in)) + nil, new(uint256.Int), p.RequiredGas(in), NewDestsCache(10)) t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) { if res, err := RunPrecompiledContract(p, in, contract); err != nil { t.Error(err) @@ -422,7 +422,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) { p := PrecompiledContractsIstanbul[common.HexToAddress(addr)] in := common.Hex2Bytes(test.input) contract := NewContract(AccountRef(common.HexToAddress("1337")), - nil, new(uint256.Int), p.RequiredGas(in)-1) + nil, new(uint256.Int), p.RequiredGas(in)-1, NewDestsCache(10)) t.Run(fmt.Sprintf("%s-Gas=%d", test.name, contract.Gas), func(t *testing.T) { _, err := RunPrecompiledContract(p, in, contract) if err.Error() != "out of gas" { @@ -440,7 +440,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing p := PrecompiledContractsIstanbul[common.HexToAddress(addr)] in := common.Hex2Bytes(test.input) contract := NewContract(AccountRef(common.HexToAddress("31337")), - nil, new(uint256.Int), p.RequiredGas(in)) + nil, new(uint256.Int), p.RequiredGas(in), NewDestsCache(10)) t.Run(test.name, func(t *testing.T) { _, err := RunPrecompiledContract(p, in, contract) @@ -463,7 +463,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) { in := common.Hex2Bytes(test.input) reqGas := p.RequiredGas(in) contract := NewContract(AccountRef(common.HexToAddress("1337")), - nil, new(uint256.Int), reqGas) + nil, new(uint256.Int), reqGas, NewDestsCache(10)) var ( res []byte diff --git a/core/vm/evm.go b/core/vm/evm.go index 9255e9d5cbfae9706c3f2de9cb05e70b901c41c4..74a37b009a69a9bc85ff8cb53e72916f1dcf7b51 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -133,11 +133,16 @@ type EVM struct { // available gas is calculated in gasCall* according to the 63/64 rule and later // applied in opCall*. callGasTemp uint64 + + dests Cache } // NewEVM returns a new EVM. The returned EVM is not thread safe and should // only ever be used *once*. -func NewEVM(ctx Context, state IntraBlockState, chainConfig *params.ChainConfig, vmConfig Config) *EVM { +func NewEVM(ctx Context, state IntraBlockState, chainConfig *params.ChainConfig, vmConfig Config, dests Cache) *EVM { + if dests == nil { + dests = NewDestsCache(10) + } evm := &EVM{ Context: ctx, IntraBlockState: state, @@ -145,6 +150,7 @@ func NewEVM(ctx Context, state IntraBlockState, chainConfig *params.ChainConfig, chainConfig: chainConfig, chainRules: chainConfig.Rules(ctx.BlockNumber), interpreters: make([]Interpreter, 0, 1), + dests: dests, } if chainConfig.IsEWASM(ctx.BlockNumber) { @@ -235,8 +241,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas evm.Transfer(evm.IntraBlockState, caller.Address(), to.Address(), value) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, to, value, gas) + contract := NewContract(caller, to, value, gas, evm.GetJumpsDests()) contract.SetCallCode(&addr, evm.IntraBlockState.GetCodeHash(addr), evm.IntraBlockState.GetCode(addr)) + defer evm.GetJumpsDests().Clear(contract.CodeHash, contract.analysis) // Even if the account has no code, we need to continue because it might be a precompile start := time.Now() @@ -291,8 +298,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, ) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, to, value, gas) + contract := NewContract(caller, to, value, gas, evm.GetJumpsDests()) contract.SetCallCode(&addr, evm.IntraBlockState.GetCodeHash(addr), evm.IntraBlockState.GetCode(addr)) + defer evm.GetJumpsDests().Clear(contract.CodeHash, contract.analysis) ret, err = run(evm, contract, input, false) if err != nil { @@ -322,8 +330,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by to = AccountRef(caller.Address()) ) // Initialise a new contract and make initialise the delegate values - contract := NewContract(caller, to, nil, gas).AsDelegate() + contract := NewContract(caller, to, nil, gas, evm.GetJumpsDests()).AsDelegate() contract.SetCallCode(&addr, evm.IntraBlockState.GetCodeHash(addr), evm.IntraBlockState.GetCode(addr)) + defer evm.GetJumpsDests().Clear(contract.CodeHash, contract.analysis) ret, err = run(evm, contract, input, false) if err != nil { @@ -353,8 +362,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte ) // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, to, new(uint256.Int), gas) + contract := NewContract(caller, to, new(uint256.Int), gas, evm.GetJumpsDests()) contract.SetCallCode(&addr, evm.IntraBlockState.GetCodeHash(addr), evm.IntraBlockState.GetCode(addr)) + defer evm.GetJumpsDests().Clear(contract.CodeHash, contract.analysis) // We do an AddBalance of zero here, just in order to trigger a touch. // This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium, @@ -415,8 +425,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. - contract := NewContract(caller, AccountRef(address), value, gas) + contract := NewContract(caller, AccountRef(address), value, gas, evm.GetJumpsDests()) contract.SetCodeOptionalHash(&address, codeAndHash) + defer evm.GetJumpsDests().Clear(contract.CodeHash, contract.analysis) if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, address, gas, nil @@ -487,3 +498,10 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment * // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } + +func (evm *EVM) GetJumpsDests() Cache { + if evm.dests == nil { + evm.dests = NewDestsCache(50000) + } + return evm.dests +} diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index 92b60f1f4e89a48923a9cde13879a105bab017b8..e95c39ce0e3ceaf2d84da8acf9831917296cfa22 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -99,7 +99,8 @@ func TestEIP2200(t *testing.T) { CanTransfer: func(IntraBlockState, common.Address, *uint256.Int) bool { return true }, Transfer: func(IntraBlockState, common.Address, common.Address, *uint256.Int) {}, } - vmenv := NewEVM(vmctx, state, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) + dests := NewDestsCache(100) + vmenv := NewEVM(vmctx, state, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}, dests) _, gas, err := vmenv.Call(AccountRef(common.Address{}), address, nil, tt.gaspool, new(uint256.Int)) if err != tt.failure { diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 3b27658c49235821d165dbd2ede67f49c237f765..d36f9951327f5fb9d08e1a3905d67367bc510b78 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -94,7 +94,8 @@ func init() { func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFunc, name string) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + dests = NewDestsCache(100) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}, dests) stack = stack.New() pc = uint64(0) evmInterpreter = env.interpreter.(*EVMInterpreter) @@ -191,7 +192,8 @@ func TestSAR(t *testing.T) { // getResult is a convenience function to generate the expected values func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcase { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + dests = NewDestsCache(100) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}, dests) stack = stack.New() pc = uint64(0) interpreter = env.interpreter.(*EVMInterpreter) @@ -241,7 +243,8 @@ func TestJsonTestcases(t *testing.T) { func opBenchmark(bench *testing.B, op executionFunc, args ...string) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + dests = NewDestsCache(100) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}, dests) stack = stack.New() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) ) @@ -474,7 +477,8 @@ func BenchmarkOpIsZero(b *testing.B) { func TestOpMstore(t *testing.T) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + dests = NewDestsCache(100) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}, dests) stack = stack.New() mem = NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) @@ -500,7 +504,8 @@ func TestOpMstore(t *testing.T) { func BenchmarkOpMstore(bench *testing.B) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + dests = NewDestsCache(100) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}, dests) stack = stack.New() mem = NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) @@ -522,7 +527,8 @@ func BenchmarkOpMstore(bench *testing.B) { func BenchmarkOpSHA3(bench *testing.B) { var ( - env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}) + dests = NewDestsCache(100) + env = NewEVM(Context{}, nil, params.TestChainConfig, Config{}, dests) stack = stack.New() mem = NewMemory() evmInterpreter = NewEVMInterpreter(env, env.vmConfig) diff --git a/core/vm/logger_test.go b/core/vm/logger_test.go index 8b4fc7b251d58f4e13737cbd8ac5588c578d2851..76cc2d58fc519fe24e55aa6423a6f30ee8c20eec 100644 --- a/core/vm/logger_test.go +++ b/core/vm/logger_test.go @@ -53,11 +53,12 @@ func (*dummyStatedb) GetRefund() uint64 { return 1337 } func TestStoreCapture(t *testing.T) { var ( - env = NewEVM(Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}) + dests = NewDestsCache(100) + env = NewEVM(Context{}, &dummyStatedb{}, params.TestChainConfig, Config{}, dests) logger = NewStructLogger(nil) mem = NewMemory() stack = stack.New() - contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(uint256.Int), 0) + contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(uint256.Int), 0, NewDestsCache(10)) ) stack.Push(uint256.NewInt().SetOne()) stack.Push(uint256.NewInt()) diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 3fb12770c9d25a7538cf76cf9be571e31ecc627a..07d4c1e842104e459c1e269cf9136d25199b2a4b 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -21,7 +21,7 @@ import ( "github.com/ledgerwatch/turbo-geth/core/vm" ) -func NewEnv(cfg *Config) *vm.EVM { +func NewEnv(cfg *Config, dests vm.Cache) *vm.EVM { context := vm.Context{ CanTransfer: core.CanTransfer, Transfer: core.Transfer, @@ -35,5 +35,5 @@ func NewEnv(cfg *Config) *vm.EVM { GasPrice: cfg.GasPrice, } - return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig) + return vm.NewEVM(context, cfg.State, cfg.ChainConfig, cfg.EVMConfig, dests) } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 5676929cc03db30fd242e90232bb384eabd0ea7c..9e8bfb6ece0e7c692b6b273e0f1f9a5fc372962b 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -108,7 +108,7 @@ func Execute(code, input []byte, cfg *Config, blockNr uint64) ([]byte, *state.In } var ( address = common.BytesToAddress([]byte("contract")) - vmenv = NewEnv(cfg) + vmenv = NewEnv(cfg, nil) sender = vm.AccountRef(cfg.Origin) ) cfg.State.CreateAccount(address, true) @@ -139,7 +139,7 @@ func Create(input []byte, cfg *Config, blockNr uint64) ([]byte, common.Address, cfg.State = state.New(cfg.TrieDbSt) } var ( - vmenv = NewEnv(cfg) + vmenv = NewEnv(cfg, nil) sender = vm.AccountRef(cfg.Origin) ) @@ -161,7 +161,7 @@ func Create(input []byte, cfg *Config, blockNr uint64) ([]byte, common.Address, func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { setDefaults(cfg) - vmenv := NewEnv(cfg) + vmenv := NewEnv(cfg, nil) sender := cfg.State.GetOrNewStateObject(cfg.Origin) // Call the code with the given configuration. diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index da0ba392f80adbe10da180139c6cc5c9af8861af..96ed8c5b3eb9f3510ccf8cd2689b94a2ee1acbbf 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -148,9 +148,9 @@ func BenchmarkCall(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { for j := 0; j < 400; j++ { - Execute(code, cpurchase, nil, 0) - Execute(code, creceived, nil, 0) - Execute(code, refund, nil, 0) + _, _, _ = Execute(code, cpurchase, nil, 0) + _, _, _ = Execute(code, creceived, nil, 0) + _, _, _ = Execute(code, refund, nil, 0) } } } @@ -188,7 +188,7 @@ func benchmarkEVM_Create(bench *testing.B, code string) { // Warm up the intpools and stuff bench.ResetTimer() for i := 0; i < bench.N; i++ { - Call(receiver, []byte{}, &runtimeConfig) + _, _, _ = Call(receiver, []byte{}, &runtimeConfig) } bench.StopTimer() } @@ -344,6 +344,6 @@ func BenchmarkSimpleLoop(b *testing.B) { // }}) for i := 0; i < b.N; i++ { - Execute(code, nil, nil, 0) + _, _, _ = Execute(code, nil, nil, 0) } } diff --git a/eth/api.go b/eth/api.go index 419dff87041cd8c0c163e60812e20e581ef2902b..1f5d2a8829d9881a0836d267360565ae03d6f5c6 100644 --- a/eth/api.go +++ b/eth/api.go @@ -114,9 +114,9 @@ func NewPrivateMinerAPI(e *Ethereum) *PrivateMinerAPI { // transaction pool. func (api *PrivateMinerAPI) Start(threads *int) error { if threads == nil { - return api.e.StartMining(runtime.NumCPU()) + return api.e.StartMining(runtime.NumCPU(), api.e.blockchain.DestsCache) } - return api.e.StartMining(*threads) + return api.e.StartMining(*threads, api.e.blockchain.DestsCache) } // Stop terminates the miner, both at the consensus engine level as well as at @@ -397,7 +397,7 @@ type StorageEntry struct { // StorageRangeAt returns the storage at the given block height and transaction index. func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex uint64, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { - _, _, _, dbstate, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, txIndex) + _, _, _, dbstate, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, txIndex, api.eth.blockchain.DestsCache) if err != nil { return StorageRangeResult{}, err } diff --git a/eth/api_backend.go b/eth/api_backend.go index c537c4fdbfb58945bdefc49c78f8734fb42cd87c..02c79c79f1d6a78d510b09a3d8518ef7446b7771 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -209,7 +209,7 @@ func (b *EthAPIBackend) getReceiptsByReApplyingTransactions(block *types.Block, for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) - receipt, err := core.ApplyTransaction(b.ChainConfig(), b.eth.blockchain, nil, gp, statedb, dbstate, header, tx, usedGas, vmConfig) + receipt, err := core.ApplyTransaction(b.ChainConfig(), b.eth.blockchain, nil, gp, statedb, dbstate, header, tx, usedGas, vmConfig, b.eth.blockchain.DestsCache) if err != nil { return nil, err } @@ -256,7 +256,7 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *sta vmError := func() error { return nil } context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil) - return vm.NewEVM(context, state, b.eth.blockchain.Config(), *b.eth.blockchain.GetVMConfig()), vmError, nil + return vm.NewEVM(context, state, b.eth.blockchain.Config(), *b.eth.blockchain.GetVMConfig(), b.eth.blockchain.DestsCache), vmError, nil } func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 0d718f66ae762f68bcdd6894c628de0424f0af4d..9c8c14d6f43ea285c7bede78109ef8b206dbdc22 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -285,7 +285,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl } // Generate the next state snapshot fast without tracing processor := api.eth.blockchain.Processor() - receipts, _, _, _, err := processor.PreProcess(block, statedb, tds, vm.Config{}) + receipts, _, _, _, err := processor.PreProcess(block, statedb, tds, vm.Config{}, api.eth.blockchain.DestsCache) if err != nil { failed = err break @@ -481,7 +481,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, msg, _ := tx.AsMessage(signer) vmctx := core.NewEVMContext(msg, block.Header(), api.eth.blockchain, nil) - vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{}) + vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vm.Config{}, api.eth.blockchain.DestsCache) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil { failed = err break @@ -574,7 +574,7 @@ func (api *PrivateDebugAPI) standardTraceBlockToFile(ctx context.Context, block } } // Execute the transaction and flush any traces to disk - vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vmConf) + vmenv := vm.NewEVM(vmctx, statedb, api.eth.blockchain.Config(), vmConf, api.eth.blockchain.DestsCache) _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())) if writer != nil { writer.Flush() @@ -627,7 +627,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha if tx == nil { return nil, fmt.Errorf("transaction %#x not found", hash) } - msg, vmctx, statedb, _, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, index) + msg, vmctx, statedb, _, err := ComputeTxEnv(ctx, api.eth.blockchain, api.eth.blockchain.Config(), api.eth.blockchain, api.eth.ChainKV(), blockHash, index, api.eth.blockchain.DestsCache) if err != nil { return nil, err } @@ -673,7 +673,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v tracer = vm.NewStructLogger(config.LogConfig) } // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(vmctx, state, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer}) + vmenv := vm.NewEVM(vmctx, state, api.eth.blockchain.Config(), vm.Config{Debug: true, Tracer: tracer}, api.eth.blockchain.DestsCache) result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { @@ -706,7 +706,7 @@ type BlockGetter interface { } // computeTxEnv returns the execution environment of a certain transaction. -func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.ChainConfig, chain core.ChainContext, chainKV ethdb.KV, blockHash common.Hash, txIndex uint64) (core.Message, vm.Context, *state.IntraBlockState, *state.DbState, error) { +func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.ChainConfig, chain core.ChainContext, chainKV ethdb.KV, blockHash common.Hash, txIndex uint64, dests vm.Cache) (core.Message, vm.Context, *state.IntraBlockState, *state.DbState, error) { // Create the parent state database block := blockGetter.GetBlockByHash(blockHash) if block == nil { @@ -739,7 +739,7 @@ func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.Chai return msg, EVMcontext, statedb, dbstate, nil } // Not yet the searched for transaction, execute on top of the current state - vmenv := vm.NewEVM(EVMcontext, statedb, cfg, vm.Config{}) + vmenv := vm.NewEVM(EVMcontext, statedb, cfg, vm.Config{}, dests) if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil { return nil, vm.Context{}, nil, nil, fmt.Errorf("transaction %x failed: %v", tx.Hash(), err) } diff --git a/eth/backend.go b/eth/backend.go index ab11205164c328c89aeb485679bdff7a48b4022c..1ca9742ec261b2771134763cf82fa91cebd185cf 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -238,7 +238,9 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { ArchiveSyncInterval: uint64(config.ArchiveSyncInterval), } ) - eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit) + + dests := vm.NewDestsCache(50000) + eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, chainConfig, eth.engine, vmConfig, eth.shouldPreserve, &config.TxLookupLimit, dests) if err != nil { return nil, err } @@ -282,7 +284,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) { eth.protocolManager.SetDataDir(ctx.Config.DataDir) if config.SyncMode != downloader.StagedSync { - eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock) + eth.miner = miner.New(eth, &config.Miner, chainConfig, eth.EventMux(), eth.engine, eth.isLocalBlock, dests) _ = eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData)) } @@ -515,7 +517,7 @@ func (s *Ethereum) SetEtherbase(etherbase common.Address) { // StartMining starts the miner with the given number of CPU threads. If mining // is already running, this method adjust the number of threads allowed to use // and updates the minimum price required by the transaction pool. -func (s *Ethereum) StartMining(threads int) error { +func (s *Ethereum) StartMining(threads int, dests vm.Cache) error { // Update the thread count within the consensus engine type threaded interface { SetThreads(threads int) @@ -553,7 +555,7 @@ func (s *Ethereum) StartMining(threads int) error { // introduced to speed sync times. atomic.StoreUint32(&s.protocolManager.acceptTxs, 1) - go s.miner.Start(eb) + go s.miner.Start(eb, dests) } return nil } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index cc668e82763acff1a347e16eb54dac0a860372bf..83ce9f7b8eb62dd729773d80fbd297fb9462d085 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -345,8 +345,8 @@ func (d *Downloader) UnregisterPeer(id string) error { // Synchronise tries to sync up our local block chain with a remote peer, both // adding various sanity checks as well as wrapping it with various log entries. -func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode SyncMode) error { - err := d.synchronise(id, head, td, mode) +func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode SyncMode, dests vm.Cache) error { + err := d.synchronise(id, head, td, mode, dests) switch err { case nil: case errBusy, errCanceled: @@ -371,7 +371,7 @@ func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode // synchronise will select the peer and use it for synchronising. If an empty string is given // it will use the best peer possible and synchronize if its TD is higher than our own. If any of the // checks fail an error will be returned. This method is synchronous -func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode SyncMode) error { +func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode SyncMode, dests vm.Cache) error { // Mock out the synchronisation if testing if d.synchroniseMock != nil { return d.synchroniseMock(id, hash) @@ -434,12 +434,12 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode if p == nil { return errUnknownPeer } - return d.syncWithPeer(p, hash, td) + return d.syncWithPeer(p, hash, td, dests) } // syncWithPeer starts a block synchronization based on the hash chain from the // specified peer and head hash. -func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.Int) (err error) { +func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.Int, dests vm.Cache) (err error) { d.mux.Post(StartEvent{}) defer func() { // reset on error @@ -554,6 +554,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I d.datadir, d.quitCh, fetchers, + dests, ) } diff --git a/eth/downloader/downloader_stagedsync_test.go b/eth/downloader/downloader_stagedsync_test.go index fe554dfff9d78f30d202c706a3c3e092bbc612bf..ad1e24aa7d0049e83fd4a5374efedd78534f6d91 100644 --- a/eth/downloader/downloader_stagedsync_test.go +++ b/eth/downloader/downloader_stagedsync_test.go @@ -265,7 +265,7 @@ func (st *stagedSyncTester) sync(id string, td *big.Int) error { st.lock.RUnlock() // Synchronise with the chosen peer and ensure proper cleanup afterwards - err := st.downloader.synchronise(id, hash, td, StagedSync) + err := st.downloader.synchronise(id, hash, td, StagedSync, vm.NewDestsCache(100)) select { case <-st.downloader.cancelCh: // Ok, downloader fully cancelled after sync cycle diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index f4fa3048933c3b18f329e3d2f22327677a976a48..b30597a0348454314e4148267f397fc30a65b810 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -114,7 +114,7 @@ func (dl *downloadTester) sync(id string, td *big.Int, mode SyncMode) error { dl.lock.RUnlock() // Synchronise with the chosen peer and ensure proper cleanup afterwards - err := dl.downloader.synchronise(id, hash, td, mode) + err := dl.downloader.synchronise(id, hash, td, mode, vm.NewDestsCache(100)) select { case <-dl.downloader.cancelCh: // Ok, downloader fully cancelled after sync cycle @@ -1189,6 +1189,7 @@ func testBlockHeaderAttackerDropping(t *testing.T, protocol int) { defer tester.terminate() defer tester.peerDb.Close() chain := testChainBase.shorten(1) + dests := vm.NewDestsCache(100) for i, tt := range tests { // Register a new peer and ensure its presence @@ -1202,7 +1203,7 @@ func testBlockHeaderAttackerDropping(t *testing.T, protocol int) { // Simulate a synchronisation and check the required result tester.downloader.synchroniseMock = func(string, common.Hash) error { return tt.result } - tester.downloader.Synchronise(id, tester.genesis.Hash(), big.NewInt(1000), FullSync) + _ = tester.downloader.Synchronise(id, tester.genesis.Hash(), big.NewInt(1000), FullSync, dests) if _, ok := tester.peers[id]; !ok != tt.drop { t.Errorf("test %d: peer drop mismatch for %v: have %v, want %v", i, tt.result, !ok, tt.drop) } diff --git a/eth/handler.go b/eth/handler.go index ce491d9f3991ef16a5ead891f4ae7f60c77c7894..96366269c3adfc2c0a432a462ce8a355c4edef58 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -1013,7 +1013,7 @@ func (pm *ProtocolManager) handleDebugMsg(p *debugPeer) error { engine := pm.blockchain.Engine() pm.blockchain.ChainDb().Close() - blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(ethDb, nil, chainConfig, engine, vm.Config{}, nil, nil, vm.NewDestsCache(10)) if err != nil { return fmt.Errorf("fail in NewBlockChain: %w", err) } diff --git a/eth/handler_test.go b/eth/handler_test.go index c879029ddd3e189c907972ec6aa4edffde20b0ea..3a09759870e0041a61e96817cf843441c44967e2 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -468,7 +468,7 @@ func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpo } } // Create a checkpoint aware protocol manager - blockchain, err := core.NewBlockChain(db, nil, config, ethash.NewFaker(), vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, config, ethash.NewFaker(), vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create new blockchain: %v", err) } @@ -555,7 +555,7 @@ func testBroadcastBlock(t *testing.T, totalPeers, broadcastExpected int) { gspec = &core.Genesis{Config: config} genesis = gspec.MustCommit(db) ) - blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, config, pow, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create new blockchain: %v", err) } @@ -1324,7 +1324,7 @@ func TestBroadcastMalformedBlock(t *testing.T) { gspec = &core.Genesis{Config: config} genesis = gspec.MustCommit(db) ) - blockchain, err := core.NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatalf("failed to create new blockchain: %v", err) } diff --git a/eth/helper_test.go b/eth/helper_test.go index aaefea030b4b1dad78184369d3f32f763316df9c..791c3f49bff0f120ef6cf2b6cda90d60d4214039 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -70,7 +70,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func db := ethdb.NewMemDatabase() // Regenerate genesis block in the fresh database gspec.MustCommit(db) - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { return nil, nil, err } diff --git a/eth/protocol_test.go b/eth/protocol_test.go index e212d30260b648383553e7f1a4622d4ba16c9396..399688ad08eecfce835946b7c6a36ed71fe85914 100644 --- a/eth/protocol_test.go +++ b/eth/protocol_test.go @@ -177,8 +177,8 @@ func TestForkIDSplit(t *testing.T) { genesisNoFork = gspecNoFork.MustCommit(dbNoFork) genesisProFork = gspecProFork.MustCommit(dbProFork) - chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil) - chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil) + chainNoFork, _ = core.NewBlockChain(dbNoFork, nil, configNoFork, engine, vm.Config{}, nil, nil, nil) + chainProFork, _ = core.NewBlockChain(dbProFork, nil, configProFork, engine, vm.Config{}, nil, nil, nil) ctxNoFork = chainNoFork.WithContext(context.Background(), big.NewInt(genesisNoFork.Number().Int64()+1)) ctxProFork = chainProFork.WithContext(context.Background(), big.NewInt(genesisProFork.Number().Int64()+1)) diff --git a/eth/stagedsync/stage_execute.go b/eth/stagedsync/stage_execute.go index 0a1ce10a3712bfee7cfa7cfddd4f8411306adb27..c7798ce0940033c4a87e57ee5b6b343d6e4caf19 100644 --- a/eth/stagedsync/stage_execute.go +++ b/eth/stagedsync/stage_execute.go @@ -16,6 +16,7 @@ import ( "github.com/ledgerwatch/turbo-geth/core/rawdb" "github.com/ledgerwatch/turbo-geth/core/state" "github.com/ledgerwatch/turbo-geth/core/types/accounts" + "github.com/ledgerwatch/turbo-geth/core/vm" "github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages" "github.com/ledgerwatch/turbo-geth/ethdb" "github.com/ledgerwatch/turbo-geth/log" @@ -80,7 +81,7 @@ const StateBatchSize = 50 * 1024 * 1024 // 50 Mb const ChangeBatchSize = 1024 * 2014 // 1 Mb const prof = false -func spawnExecuteBlocksStage(s *StageState, stateDB ethdb.Database, blockchain BlockChain, quit chan struct{}) error { +func spawnExecuteBlocksStage(s *StageState, stateDB ethdb.Database, blockchain BlockChain, quit chan struct{}, dests vm.Cache) error { lastProcessedBlockNumber := s.BlockNumber nextBlockNumber := uint64(0) @@ -159,7 +160,7 @@ func spawnExecuteBlocksStage(s *StageState, stateDB ethdb.Database, blockchain B stateWriter.SetCodeSizeCache(codeSizeCache) // where the magic happens - err := core.ExecuteBlockEuphemerally(chainConfig, vmConfig, blockchain, engine, block, stateReader, stateWriter) + err := core.ExecuteBlockEuphemerally(chainConfig, vmConfig, blockchain, engine, block, stateReader, stateWriter, dests) if err != nil { return err } diff --git a/eth/stagedsync/stagedsync.go b/eth/stagedsync/stagedsync.go index cda3600a2ea92be542c5e483a1eeb4e66b28a801..8feab00ff9e21e0f2a40fd852652c51c1b4a7357 100644 --- a/eth/stagedsync/stagedsync.go +++ b/eth/stagedsync/stagedsync.go @@ -4,6 +4,7 @@ import ( "fmt" "github.com/ledgerwatch/turbo-geth/core" + "github.com/ledgerwatch/turbo-geth/core/vm" "github.com/ledgerwatch/turbo-geth/eth/stagedsync/stages" "github.com/ledgerwatch/turbo-geth/ethdb" "github.com/ledgerwatch/turbo-geth/log" @@ -18,6 +19,7 @@ func DoStagedSyncWithFetchers( datadir string, quitCh chan struct{}, headersFetchers []func() error, + dests vm.Cache, ) error { defer log.Info("Staged sync finished") @@ -47,7 +49,7 @@ func DoStagedSyncWithFetchers( ID: stages.Execution, Description: "Executing blocks w/o hash checks", ExecFunc: func(s *StageState) error { - return spawnExecuteBlocksStage(s, stateDB, blockchain, quitCh) + return spawnExecuteBlocksStage(s, stateDB, blockchain, quitCh, dests) }, }, { diff --git a/eth/sync.go b/eth/sync.go index 7a11828a6b2b73a4a4c90d69fdf36f1a8bd0fa80..13306fab531f4de33def80a115724520e4ccdd64 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -308,7 +308,7 @@ func (pm *ProtocolManager) doSync(op *chainSyncOp) error { } */ // Run the sync cycle, and disable fast sync if we're past the pivot block - err := pm.downloader.Synchronise(op.peer.id, op.head, op.td, op.mode) + err := pm.downloader.Synchronise(op.peer.id, op.head, op.td, op.mode, pm.blockchain.DestsCache) if err != nil { return err } diff --git a/eth/tracers/tracer_test.go b/eth/tracers/tracer_test.go index b926aecddb3723d1ff69b8bcb6d91194bd554cf5..fce04bd9f64c431220d1b3a4c4c5308446914ed6 100644 --- a/eth/tracers/tracer_test.go +++ b/eth/tracers/tracer_test.go @@ -53,9 +53,9 @@ type dummyStatedb struct { func (*dummyStatedb) GetRefund() uint64 { return 1337 } func runTrace(tracer *Tracer) (json.RawMessage, error) { - env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) + env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}, nil) - contract := vm.NewContract(account{}, account{}, uint256.NewInt(), 10000) + contract := vm.NewContract(account{}, account{}, uint256.NewInt(), 10000, vm.NewDestsCache(50000)) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} _, err := env.Interpreter().Run(contract, []byte{}, false) @@ -168,8 +168,8 @@ func TestHaltBetweenSteps(t *testing.T) { t.Fatal(err) } - env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}) - contract := vm.NewContract(&account{}, &account{}, uint256.NewInt(), 0) + env := vm.NewEVM(vm.Context{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer}, nil) + contract := vm.NewContract(&account{}, &account{}, uint256.NewInt(), 0, vm.NewDestsCache(50000)) tracer.CaptureState(env, 0, 0, 0, 0, nil, nil, contract, 0, nil) timeout := errors.New("stahp") diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 2e127a256d9bbb620cc86deaa556c2e113375ed6..d3c0f1c49a6552aaeb061163006651df3f23cc97 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -182,7 +182,7 @@ func TestPrestateTracerCreate2(t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(evmContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(evmContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer}, nil) msg, err := tx.AsMessage(signer) if err != nil { @@ -262,7 +262,7 @@ func TestCallTracer(t *testing.T) { if err != nil { t.Fatalf("failed to create call tracer: %v", err) } - evm := vm.NewEVM(evmContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}) + evm := vm.NewEVM(evmContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer}, nil) msg, err := tx.AsMessage(signer) if err != nil { diff --git a/miner/miner.go b/miner/miner.go index 06339c750e670f18d8925041c985e52ca631a190..abbaff8047b66dbe2d5842135057d2fb9f64cdad 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -30,6 +30,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/core/vm" "github.com/ledgerwatch/turbo-geth/eth/downloader" "github.com/ledgerwatch/turbo-geth/event" "github.com/ledgerwatch/turbo-geth/log" @@ -68,7 +69,7 @@ type Miner struct { shouldStart int32 // should start indicates whether we should start after sync } -func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(block *types.Block) bool) *Miner { +func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *event.TypeMux, engine consensus.Engine, isLocalBlock func(block *types.Block) bool, dests vm.Cache) *Miner { miner := &Miner{ eth: eth, mux: mux, @@ -77,7 +78,7 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even worker: newWorker(config, chainConfig, engine, eth, mux, hooks{isLocalBlock: isLocalBlock}, false), canStart: 1, } - go miner.update() + go miner.update(dests) return miner } @@ -86,7 +87,7 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even // It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and // the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks // and halt your mining operation for as long as the DOS continues. -func (miner *Miner) update() { +func (miner *Miner) update(dests vm.Cache) { events := miner.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) defer events.Unsubscribe() @@ -110,7 +111,7 @@ func (miner *Miner) update() { atomic.StoreInt32(&miner.canStart, 1) atomic.StoreInt32(&miner.shouldStart, 0) if shouldStart { - miner.Start(miner.coinbase) + miner.Start(miner.coinbase, dests) } // stop immediately and ignore all further pending events return @@ -121,7 +122,7 @@ func (miner *Miner) update() { } } -func (miner *Miner) Start(coinbase common.Address) { +func (miner *Miner) Start(coinbase common.Address, dests vm.Cache) { atomic.StoreInt32(&miner.shouldStart, 1) miner.SetEtherbase(coinbase) @@ -129,7 +130,7 @@ func (miner *Miner) Start(coinbase common.Address) { log.Info("Network syncing, will start miner afterwards") return } - miner.worker.start() + miner.worker.start(dests) } func (miner *Miner) Stop() { diff --git a/miner/worker.go b/miner/worker.go index 54c35251d79fd1eb4d356b1583a1d3352f34d586..52b7b14fe52f453898befe0a533754b4aa4989a1 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/core/vm" "github.com/ledgerwatch/turbo-geth/event" "github.com/ledgerwatch/turbo-geth/log" "github.com/ledgerwatch/turbo-geth/params" @@ -260,7 +261,7 @@ func (w *worker) pendingBlock() *types.Block { return w.snapshotBlock } -func (w *worker) init() { +func (w *worker) init(dests vm.Cache) { w.initOnce.Do(func() { time.Sleep(5 * time.Second) w.txsCh = make(chan core.NewTxsEvent, txChanSize) @@ -283,7 +284,7 @@ func (w *worker) init() { // commit aborts in-flight transaction execution with given signal and resubmits a new one. commit, timestamp := w.getCommit() - go w.mainLoop() + go w.mainLoop(dests) go w.newWorkLoop(recommit) go w.chainEvents(timestamp, commit) go w.taskLoop() @@ -291,10 +292,10 @@ func (w *worker) init() { } // start sets the running status as 1 and triggers new work submitting. -func (w *worker) start() { +func (w *worker) start(dests vm.Cache) { if atomic.CompareAndSwapInt32(&w.running, 0, 1) { log.Warn("worker start") - w.init() + w.init(dests) w.startCh <- struct{}{} } } @@ -404,14 +405,14 @@ func (w *worker) getCommit() (func(ctx consensus.Cancel, noempty bool, s int32), } // mainLoop is a standalone goroutine to regenerate the sealing task based on the received event. -func (w *worker) mainLoop() { +func (w *worker) mainLoop(dests vm.Cache) { defer w.txsSub.Unsubscribe() for { select { case req := <-w.newWorkCh: log.Warn("mining: a new work") - w.commitNewWork(req.cancel, req.interrupt, req.noempty, req.timestamp) + w.commitNewWork(req.cancel, req.interrupt, req.noempty, req.timestamp, dests) case ev := <-w.txsCh: //fixme can be removed? @@ -437,7 +438,7 @@ func (w *worker) mainLoop() { } txset := types.NewTransactionsByPriceAndNonce(w.current.signer, txs) tcount := w.current.tcount - w.commitTransactions(txset, coinbase, nil) + w.commitTransactions(txset, coinbase, nil, dests) // Only update the snapshot if any new transactons were added // to the pending block if tcount != w.current.tcount { @@ -448,7 +449,7 @@ func (w *worker) mainLoop() { // submit mining work here since all empty submission will be rejected // by clique. Of course the advance sealing(empty submission) is disabled. if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 { - w.commitNewWork(consensus.StabCancel(), nil, true, time.Now().Unix()) + w.commitNewWork(consensus.StabCancel(), nil, true, time.Now().Unix(), dests) } } atomic.AddInt32(&w.newTxs, int32(len(ev.Txs))) @@ -758,11 +759,11 @@ func (w *worker) updateSnapshot() { w.snapshotTds = w.current.tds.WithNewBuffer() } -func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) { +func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address, dests vm.Cache) ([]*types.Log, error) { snap := w.current.state.Snapshot() header := w.current.GetHeader() - receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.tds.TrieStateWriter(), header, tx, &header.GasUsed, *w.chain.GetVMConfig()) + receipt, err := core.ApplyTransaction(w.chainConfig, w.chain, &coinbase, w.current.gasPool, w.current.state, w.current.tds.TrieStateWriter(), header, tx, &header.GasUsed, *w.chain.GetVMConfig(), dests) if err != nil { w.current.state.RevertToSnapshot(snap) return nil, err @@ -777,7 +778,7 @@ func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Addres return receipt.Logs, nil } -func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32) bool { +func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coinbase common.Address, interrupt *int32, dests vm.Cache) bool { // Short circuit if current is nil if w.current == nil { return true @@ -838,7 +839,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin // Start executing the transaction w.current.state.Prepare(tx.Hash(), common.Hash{}, w.current.tcount) - logs, err := w.commitTransaction(tx, coinbase) + logs, err := w.commitTransaction(tx, coinbase, dests) switch err { case core.ErrGasLimitReached: // Pop the current out-of-gas transaction without shifting in the next from the account @@ -893,7 +894,7 @@ func (w *worker) commitTransactions(txs *types.TransactionsByPriceAndNonce, coin } // commitNewWork generates several new sealing tasks based on the parent block. -func (w *worker) commitNewWork(ctx consensus.Cancel, interrupt *int32, noempty bool, timestamp int64) { +func (w *worker) commitNewWork(ctx consensus.Cancel, interrupt *int32, noempty bool, timestamp int64, dests vm.Cache) { select { case <-ctx.Done(): return @@ -1034,13 +1035,13 @@ func (w *worker) commitNewWork(ctx consensus.Cancel, interrupt *int32, noempty b } if len(localTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(w.current.signer, localTxs) - if w.commitTransactions(txs, w.coinbase, interrupt) { + if w.commitTransactions(txs, w.coinbase, interrupt, dests) { return } } if len(remoteTxs) > 0 { txs := types.NewTransactionsByPriceAndNonce(w.current.signer, remoteTxs) - if w.commitTransactions(txs, w.coinbase, interrupt) { + if w.commitTransactions(txs, w.coinbase, interrupt, dests) { return } } diff --git a/miner/worker_test.go b/miner/worker_test.go index d483f7ce56df99a138c59c6ea182f6d03b4d7456..bc687c3ed4622f3176e660a8b5af530c9dbdc8f9 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -157,7 +157,7 @@ func newTestWorkerBackend(t *testing.T, testCase *testCase, chainConfig *params. genesis := gspec.MustCommit(db) dbCopy := db.MemCopy() - chain, _ := core.NewBlockChain(dbCopy, nil, gspec.Config, engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(dbCopy, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) txpool := core.NewTxPool(testCase.testTxPoolConfig, chainConfig, chain) // Generate a small n-block chain and an uncle block for it @@ -214,7 +214,7 @@ func newTestWorker(t *testCase, chainConfig *params.ChainConfig, engine consensu w := newWorker(t.testConfig, chainConfig, engine, backend, new(event.TypeMux), h, true) w.setEtherbase(t.testBankAddress) if waitInit { - w.init() + w.init(vm.NewDestsCache(100)) // Ensure worker has finished initialization timer := time.NewTicker(10 * time.Millisecond) @@ -283,7 +283,7 @@ func testGenerateBlockAndImport(t *testing.T, testCase *testCase, isClique bool) db2 := ethdb.NewMemDatabase() defer db2.Close() b.genesis.MustCommit(db2) - chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil) + chain, _ := core.NewBlockChain(db2, nil, b.chain.Config(), engine, vm.Config{}, nil, nil, nil) defer chain.Stop() // Ignore empty commit here for less noise @@ -296,7 +296,7 @@ func testGenerateBlockAndImport(t *testing.T, testCase *testCase, isClique bool) defer sub.Unsubscribe() // Start mining! - w.start() + w.start(vm.NewDestsCache(100)) for i := 0; i < 5; i++ { if err := b.txPool.AddLocal(b.newRandomTx(testCase, true)); err != nil { @@ -438,7 +438,7 @@ func testEmptyWork(t *testing.T, testCase *testCase, chainConfig *params.ChainCo w := newTestWorker(testCase, chainConfig, engine, backend, h, true) defer w.close() - w.start() + w.start(vm.NewDestsCache(100)) for i := 0; i < 3; i++ { select { case <-taskCh: @@ -507,7 +507,7 @@ func TestStreamUncleBlock(t *testing.T) { w := newTestWorker(testCase, testCase.ethashChainConfig, ethash, b, h, true) defer w.close() - w.start() + w.start(vm.NewDestsCache(100)) // Ignore the first two works for i := 0; i < 2; i += 1 { @@ -577,7 +577,7 @@ func testRegenerateMiningBlock(t *testing.T, testCase *testCase, chainConfig *pa w := newTestWorker(testCase, chainConfig, engine, b, h, true) defer w.close() - w.start() + w.start(vm.NewDestsCache(100)) // Ignore the first two works for i := 0; i < 2; i += 1 { select { @@ -670,7 +670,7 @@ func testAdjustInterval(t *testing.T, testCase *testCase, chainConfig *params.Ch w := newTestWorker(testCase, chainConfig, engine, backend, h, true) defer w.close() - w.start() + w.start(vm.NewDestsCache(100)) time.Sleep(time.Second) // Ensure two tasks have been summitted due to start opt atomic.StoreUint32(&start, 1) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 9e993e36a3d55768cf2379ce7e3cbf6c9c790ea7..947c32aef1cab9519a32ea8ee4df58b85a371047 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -120,7 +120,7 @@ func (t *BlockTest) Run(_ bool) error { } else { engine = ethash.NewShared() } - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0, Pruning: false}, config, engine, vm.Config{}, nil, nil) + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0, Pruning: false}, config, engine, vm.Config{}, nil, nil, nil) if err != nil { return err } diff --git a/tests/pruner_test.go b/tests/pruner_test.go index d2c6768ee1f8e7e6d511b98b7b0e6922e5d9f887..f63619c336c102f28c8ff920e5be8d0009aea349 100644 --- a/tests/pruner_test.go +++ b/tests/pruner_test.go @@ -69,7 +69,7 @@ func TestBasisAccountPruning(t *testing.T) { numBlocks := 10 engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -232,7 +232,7 @@ func TestBasisAccountPruningNoHistory(t *testing.T) { NoHistory: true, ArchiveSyncInterval: 1, } - blockchain, err := core.NewBlockChain(db, &cacheConfig, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, &cacheConfig, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -382,7 +382,7 @@ func TestStoragePruning(t *testing.T) { defer genesisDb.Close() engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -584,7 +584,7 @@ func TestBasisAccountPruningStrategy(t *testing.T) { numBlocks := 25 engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 7b01ad3f9e381d5ca9c06392b32f3000b62bbe3b..f37c2ce6ae318c7102cffd47dc3a91490fede5a4 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -194,7 +194,7 @@ func (t *StateTest) RunNoVerify(ctx context.Context, subtest StateSubtest, vmcon } context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase) context.GetHash = vmTestBlockHash - evm := vm.NewEVM(context, statedb, config, vmconfig) + evm := vm.NewEVM(context, statedb, config, vmconfig, nil) gaspool := new(core.GasPool) gaspool.AddGas(block.GasLimit()) diff --git a/tests/statedb_chain_test.go b/tests/statedb_chain_test.go index b4eda4b35c96b831a9218c218fbfd0b1d07f9148..7104542df25eb4068669df259230312b88f8b820 100644 --- a/tests/statedb_chain_test.go +++ b/tests/statedb_chain_test.go @@ -65,7 +65,7 @@ func TestSelfDestructReceive(t *testing.T) { defer genesisDB.Close() engine := ethash.NewFaker() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } @@ -120,7 +120,7 @@ func TestSelfDestructReceive(t *testing.T) { } // Reload blockchain from the database, then inserting an empty block (3) will cause rebuilding of the trie - blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { t.Fatal(err) } diff --git a/tests/statedb_insert_chain_transaction_test.go b/tests/statedb_insert_chain_transaction_test.go index 4ffb81b1ea2699768d857e4c02704519b0899842..29dbda2e69c0a110c667b242cfead127a675ffe7 100644 --- a/tests/statedb_insert_chain_transaction_test.go +++ b/tests/statedb_insert_chain_transaction_test.go @@ -697,7 +697,7 @@ func genBlocks(gspec *core.Genesis, txs map[int]tx) (*core.BlockChain, ethdb.KV, genesis := gspec.MustCommit(db) genesisDb := db.MemCopy() - blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil) + blockchain, err := core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}, nil, nil, nil) if err != nil { return nil, nil, nil, nil, nil, err } diff --git a/tests/vm_test_util.go b/tests/vm_test_util.go index e19d68373374a9b9cf9bfbe7533c152be740322b..44b637ee84437fce2ec9acfa9651a5f9d893ad0e 100644 --- a/tests/vm_test_util.go +++ b/tests/vm_test_util.go @@ -162,7 +162,7 @@ func (t *VMTest) newEVM(state vm.IntraBlockState, vmconfig vm.Config) *vm.EVM { GasPrice: t.json.Exec.GasPrice, } vmconfig.NoRecursion = true - return vm.NewEVM(context, state, params.MainnetChainConfig, vmconfig) + return vm.NewEVM(context, state, params.MainnetChainConfig, vmconfig, nil) } func vmTestBlockHash(n uint64) common.Hash {