From 8fc983097150325063a2e7558e0e14b2a8acca34 Mon Sep 17 00:00:00 2001 From: Jeffrey Wilcke Date: Fri, 17 Jul 2015 15:43:16 +0200 Subject: [PATCH] cmd/core,xeth: removed unneeded states & added batch writes --- cmd/evm/main.go | 112 +++++++++++++++++++++++++++---------- core/chain_manager.go | 22 -------- core/chain_manager_test.go | 1 - core/transaction_util.go | 42 ++++++++++++-- xeth/xeth.go | 2 +- 5 files changed, 120 insertions(+), 59 deletions(-) diff --git a/cmd/evm/main.go b/cmd/evm/main.go index ab4d3f82a0..9659943820 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -18,79 +18,129 @@ package main import ( - "flag" "fmt" - "log" "math/big" "os" "runtime" "time" + "github.com/codegangsta/cli" + "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/logger" ) var ( - code = flag.String("code", "", "evm code") - loglevel = flag.Int("log", 4, "log level") - gas = flag.String("gas", "1000000000", "gas amount") - price = flag.String("price", "0", "gas price") - value = flag.String("value", "0", "tx value") - dump = flag.Bool("dump", false, "dump state after run") - data = flag.String("data", "", "data") + app *cli.App + DebugFlag = cli.BoolFlag{ + Name: "debug", + Usage: "output full trace logs", + } + CodeFlag = cli.StringFlag{ + Name: "code", + Usage: "EVM code", + } + GasFlag = cli.StringFlag{ + Name: "gas", + Usage: "gas limit for the evm", + Value: "10000000000", + } + PriceFlag = cli.StringFlag{ + Name: "price", + Usage: "price set for the evm", + Value: "0", + } + ValueFlag = cli.StringFlag{ + Name: "value", + Usage: "value set for the evm", + Value: "0", + } + DumpFlag = cli.BoolFlag{ + Name: "dump", + Usage: "dumps the state after the run", + } + InputFlag = cli.StringFlag{ + Name: "input", + Usage: "input for the EVM", + } + SysStatFlag = cli.BoolFlag{ + Name: "sysstat", + Usage: "display system stats", + } ) -func perr(v ...interface{}) { - fmt.Println(v...) - //os.Exit(1) +func init() { + app = utils.NewApp("0.2", "the evm command line interface") + app.Flags = []cli.Flag{ + DebugFlag, + SysStatFlag, + CodeFlag, + GasFlag, + PriceFlag, + ValueFlag, + DumpFlag, + InputFlag, + } + app.Action = run } -func main() { - flag.Parse() - - logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel))) +func run(ctx *cli.Context) { + vm.Debug = ctx.GlobalBool(DebugFlag.Name) - vm.Debug = true db, _ := ethdb.NewMemDatabase() statedb := state.New(common.Hash{}, db) sender := statedb.CreateAccount(common.StringToAddress("sender")) receiver := statedb.CreateAccount(common.StringToAddress("receiver")) - receiver.SetCode(common.Hex2Bytes(*code)) + receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))) - vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(*value)) + vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name))) tstart := time.Now() + ret, e := vmenv.Call( + sender, + receiver.Address(), + common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), + common.Big(ctx.GlobalString(GasFlag.Name)), + common.Big(ctx.GlobalString(PriceFlag.Name)), + common.Big(ctx.GlobalString(ValueFlag.Name)), + ) + vmdone := time.Since(tstart) - ret, e := vmenv.Call(sender, receiver.Address(), common.Hex2Bytes(*data), common.Big(*gas), common.Big(*price), common.Big(*value)) - - logger.Flush() if e != nil { - perr(e) + fmt.Println(e) + os.Exit(1) } - if *dump { + if ctx.GlobalBool(DumpFlag.Name) { fmt.Println(string(statedb.Dump())) } - vm.StdErrFormat(vmenv.StructLogs()) - var mem runtime.MemStats - runtime.ReadMemStats(&mem) - fmt.Printf("vm took %v\n", time.Since(tstart)) - fmt.Printf(`alloc: %d + if ctx.GlobalBool(SysStatFlag.Name) { + var mem runtime.MemStats + runtime.ReadMemStats(&mem) + fmt.Printf("vm took %v\n", vmdone) + fmt.Printf(`alloc: %d tot alloc: %d no. malloc: %d heap alloc: %d heap objs: %d num gc: %d `, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) + } - fmt.Printf("%x\n", ret) + fmt.Printf("OUT: 0x%x\n", ret) +} + +func main() { + if err := app.Run(os.Args); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } } type VMEnv struct { diff --git a/core/chain_manager.go b/core/chain_manager.go index b2fcb677c8..0f008dfa70 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -73,9 +73,6 @@ type ChainManager struct { lastBlockHash common.Hash currentGasLimit *big.Int - transState *state.StateDB - txState *state.ManagedState - cache *lru.Cache // cache is the LRU caching futureBlocks *lru.Cache // future blocks are blocks added for later processing @@ -128,9 +125,7 @@ func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux } } - bc.transState = bc.State().Copy() // Take ownership of this particular state - bc.txState = state.ManageState(bc.State().Copy()) bc.futureBlocks, _ = lru.New(maxFutureBlocks) bc.makeCache() @@ -152,9 +147,6 @@ func (bc *ChainManager) SetHead(head *types.Block) { bc.currentBlock = head bc.makeCache() - statedb := state.New(head.Root(), bc.stateDb) - bc.txState = state.ManageState(statedb) - bc.transState = statedb.Copy() bc.setTotalDifficulty(head.Td) bc.insert(head) bc.setLastState() @@ -203,17 +195,6 @@ func (self *ChainManager) State() *state.StateDB { return state.New(self.CurrentBlock().Root(), self.stateDb) } -func (self *ChainManager) TransState() *state.StateDB { - self.tsmu.RLock() - defer self.tsmu.RUnlock() - - return self.transState -} - -func (self *ChainManager) setTransState(statedb *state.StateDB) { - self.transState = statedb -} - func (bc *ChainManager) recover() bool { data, _ := bc.blockDb.Get([]byte("checkpoint")) if len(data) != 0 { @@ -529,9 +510,6 @@ func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status wr self.insert(block) self.mu.Unlock() - self.setTransState(state.New(block.Root(), self.stateDb)) - self.txState.SetState(state.New(block.Root(), self.stateDb)) - status = CanonStatTy } else { status = SideStatTy diff --git a/core/chain_manager_test.go b/core/chain_manager_test.go index d247c3e506..e2ad869423 100644 --- a/core/chain_manager_test.go +++ b/core/chain_manager_test.go @@ -392,7 +392,6 @@ func chm(genesis *types.Block, db common.Database) *ChainManager { bc.futureBlocks, _ = lru.New(100) bc.processor = bproc{} bc.ResetWithGenesisBlock(genesis) - bc.txState = state.ManageState(bc.State()) return bc } diff --git a/core/transaction_util.go b/core/transaction_util.go index 1020fbd6e0..d4b9f53c9a 100644 --- a/core/transaction_util.go +++ b/core/transaction_util.go @@ -19,9 +19,11 @@ package core import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/rlp" + "github.com/syndtr/goleveldb/leveldb" ) var ( @@ -31,13 +33,21 @@ var ( // PutTransactions stores the transactions in the given database func PutTransactions(db common.Database, block *types.Block, txs types.Transactions) { + batch := new(leveldb.Batch) + _, batchWrite := db.(*ethdb.LDBDatabase) + for i, tx := range block.Transactions() { rlpEnc, err := rlp.EncodeToBytes(tx) if err != nil { glog.V(logger.Debug).Infoln("Failed encoding tx", err) return } - db.Put(tx.Hash().Bytes(), rlpEnc) + + if batchWrite { + batch.Put(tx.Hash().Bytes(), rlpEnc) + } else { + db.Put(tx.Hash().Bytes(), rlpEnc) + } var txExtra struct { BlockHash common.Hash @@ -52,20 +62,44 @@ func PutTransactions(db common.Database, block *types.Block, txs types.Transacti glog.V(logger.Debug).Infoln("Failed encoding tx meta data", err) return } - db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) + + if batchWrite { + batch.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) + } else { + db.Put(append(tx.Hash().Bytes(), 0x0001), rlpMeta) + } + } + + if db, ok := db.(*ethdb.LDBDatabase); ok { + if err := db.LDB().Write(batch, nil); err != nil { + glog.V(logger.Error).Infoln("db write err:", err) + } } } // PutReceipts stores the receipts in the current database func PutReceipts(db common.Database, receipts types.Receipts) error { + batch := new(leveldb.Batch) + _, batchWrite := db.(*ethdb.LDBDatabase) + for _, receipt := range receipts { storageReceipt := (*types.ReceiptForStorage)(receipt) bytes, err := rlp.EncodeToBytes(storageReceipt) if err != nil { return err } - err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes) - if err != nil { + + if batchWrite { + batch.Put(append(receiptsPre, receipt.TxHash[:]...), bytes) + } else { + err = db.Put(append(receiptsPre, receipt.TxHash[:]...), bytes) + if err != nil { + return err + } + } + } + if db, ok := db.(*ethdb.LDBDatabase); ok { + if err := db.LDB().Write(batch, nil); err != nil { return err } } diff --git a/xeth/xeth.go b/xeth/xeth.go index 3bc22a43d2..078a3fb8ac 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -123,7 +123,7 @@ func New(ethereum *eth.Ethereum, frontend Frontend) *XEth { if frontend == nil { xeth.frontend = dummyFrontend{} } - xeth.state = NewState(xeth, xeth.backend.ChainManager().TransState()) + xeth.state = NewState(xeth, xeth.backend.ChainManager().State()) go xeth.start() go xeth.filterManager.Start()