From cd856cb2133d390758bb24b88fa3b538bb7bc306 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 6 Mar 2015 18:26:16 +0100 Subject: [PATCH] Separated block db from state db. Partial fix for #416 --- cmd/ethereum/js.go | 2 +- cmd/ethereum/main.go | 6 +++--- cmd/mist/bindings.go | 2 +- cmd/utils/cmd.go | 2 +- cmd/utils/flags.go | 11 ++++++++--- core/chain_makers.go | 2 +- core/chain_manager.go | 31 ++++++++++++++++--------------- core/manager.go | 3 ++- eth/backend.go | 28 ++++++++++++++++++---------- miner/worker.go | 2 +- rpc/api.go | 2 +- xeth/state.go | 2 +- xeth/xeth.go | 3 ++- 13 files changed, 56 insertions(+), 40 deletions(-) diff --git a/cmd/ethereum/js.go b/cmd/ethereum/js.go index 9125ccbba..d5cf62146 100644 --- a/cmd/ethereum/js.go +++ b/cmd/ethereum/js.go @@ -229,7 +229,7 @@ func (self *repl) dump(call otto.FunctionCall) otto.Value { block = self.ethereum.ChainManager().CurrentBlock() } - statedb := state.New(block.Root(), self.ethereum.Db()) + statedb := state.New(block.Root(), self.ethereum.StateDb()) v, _ := self.re.Vm.ToValue(statedb.RawDump()) diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index d9fbabdb7..d29ae3f78 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -171,7 +171,7 @@ func importchain(ctx *cli.Context) { if len(ctx.Args()) != 1 { utils.Fatalf("This command requires an argument.") } - chain, _ := utils.GetChain(ctx) + chain, _, _ := utils.GetChain(ctx) start := time.Now() err := utils.ImportChain(chain, ctx.Args().First()) if err != nil { @@ -182,7 +182,7 @@ func importchain(ctx *cli.Context) { } func dump(ctx *cli.Context) { - chain, db := utils.GetChain(ctx) + chain, _, stateDb := utils.GetChain(ctx) for _, arg := range ctx.Args() { var block *types.Block if hashish(arg) { @@ -195,7 +195,7 @@ func dump(ctx *cli.Context) { fmt.Println("{}") utils.Fatalf("block not found") } else { - statedb := state.New(block.Root(), db) + statedb := state.New(block.Root(), stateDb) fmt.Printf("%s\n", statedb.Dump()) // fmt.Println(block) } diff --git a/cmd/mist/bindings.go b/cmd/mist/bindings.go index f21aa3135..c63f11591 100644 --- a/cmd/mist/bindings.go +++ b/cmd/mist/bindings.go @@ -113,7 +113,7 @@ func (self *Gui) DumpState(hash, path string) { return } - stateDump = state.New(block.Root(), self.eth.Db()).Dump() + stateDump = state.New(block.Root(), self.eth.StateDb()).Dump() } file, err := os.OpenFile(path[7:], os.O_CREATE|os.O_RDWR, os.ModePerm) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 3c3d3955d..99e60ff9e 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -197,7 +197,7 @@ func BlockDo(ethereum *eth.Ethereum, hash []byte) error { parent := ethereum.ChainManager().GetBlock(block.ParentHash()) - statedb := state.New(parent.Root(), ethereum.Db()) + statedb := state.New(parent.Root(), ethereum.StateDb()) _, err := ethereum.BlockProcessor().TransitionState(statedb, parent, block, true) if err != nil { return err diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index d363ef280..88ff3558d 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -175,11 +175,16 @@ func GetEthereum(clientID, version string, ctx *cli.Context) *eth.Ethereum { return ethereum } -func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database) { +func GetChain(ctx *cli.Context) (*core.ChainManager, ethutil.Database, ethutil.Database) { dataDir := ctx.GlobalString(DataDirFlag.Name) - db, err := ethdb.NewLDBDatabase(path.Join(dataDir, "blockchain")) + blockDb, err := ethdb.NewLDBDatabase(path.Join(dataDir, "blockchain")) if err != nil { Fatalf("Could not open database: %v", err) } - return core.NewChainManager(db, new(event.TypeMux)), db + + stateDb, err := ethdb.NewLDBDatabase(path.Join(dataDir, "state")) + if err != nil { + Fatalf("Could not open database: %v", err) + } + return core.NewChainManager(blockDb, stateDb, new(event.TypeMux)), blockDb, stateDb } diff --git a/core/chain_makers.go b/core/chain_makers.go index fad9ac97b..b5c50dc3d 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -108,7 +108,7 @@ func makeChain(bman *BlockProcessor, parent *types.Block, max int, db ethutil.Da // Create a new chain manager starting from given block // Effectively a fork factory func newChainManager(block *types.Block, eventMux *event.TypeMux, db ethutil.Database) *ChainManager { - bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: eventMux} + bc := &ChainManager{blockDb: db, stateDb: db, genesisBlock: GenesisBlock(db), eventMux: eventMux} if block == nil { bc.Reset() } else { diff --git a/core/chain_manager.go b/core/chain_manager.go index 20a1737ad..7ee182734 100644 --- a/core/chain_manager.go +++ b/core/chain_manager.go @@ -75,7 +75,8 @@ func CalcGasLimit(parent, block *types.Block) *big.Int { type ChainManager struct { //eth EthManager - db ethutil.Database + blockDb ethutil.Database + stateDb ethutil.Database processor types.BlockProcessor eventMux *event.TypeMux genesisBlock *types.Block @@ -92,8 +93,8 @@ type ChainManager struct { quit chan struct{} } -func NewChainManager(db ethutil.Database, mux *event.TypeMux) *ChainManager { - bc := &ChainManager{db: db, genesisBlock: GenesisBlock(db), eventMux: mux, quit: make(chan struct{})} +func NewChainManager(blockDb, stateDb ethutil.Database, mux *event.TypeMux) *ChainManager { + bc := &ChainManager{blockDb: blockDb, stateDb: stateDb, genesisBlock: GenesisBlock(stateDb), eventMux: mux, quit: make(chan struct{})} bc.setLastBlock() bc.transState = bc.State().Copy() bc.txState = bc.State().Copy() @@ -135,7 +136,7 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) { } func (self *ChainManager) State() *state.StateDB { - return state.New(self.CurrentBlock().Root(), self.db) + return state.New(self.CurrentBlock().Root(), self.stateDb) } func (self *ChainManager) TransState() *state.StateDB { @@ -163,7 +164,7 @@ func (self *ChainManager) setTransState(statedb *state.StateDB) { } func (bc *ChainManager) setLastBlock() { - data, _ := bc.db.Get([]byte("LastBlock")) + data, _ := bc.blockDb.Get([]byte("LastBlock")) if len(data) != 0 { var block types.Block rlp.Decode(bytes.NewReader(data), &block) @@ -171,7 +172,7 @@ func (bc *ChainManager) setLastBlock() { bc.lastBlockHash = block.Hash() // Set the last know difficulty (might be 0x0 as initial value, Genesis) - bc.td = ethutil.BigD(bc.db.LastKnownTD()) + bc.td = ethutil.BigD(bc.blockDb.LastKnownTD()) } else { bc.Reset() } @@ -220,7 +221,7 @@ func (bc *ChainManager) Reset() { defer bc.mu.Unlock() for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) { - bc.db.Delete(block.Hash()) + bc.blockDb.Delete(block.Hash()) } // Prepare the genesis block @@ -236,7 +237,7 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) { defer bc.mu.Unlock() for block := bc.currentBlock; block != nil; block = bc.GetBlock(block.Header().ParentHash) { - bc.db.Delete(block.Hash()) + bc.blockDb.Delete(block.Hash()) } // Prepare the genesis block @@ -262,14 +263,14 @@ func (self *ChainManager) Export() []byte { func (bc *ChainManager) insert(block *types.Block) { encodedBlock := ethutil.Encode(block) - bc.db.Put([]byte("LastBlock"), encodedBlock) + bc.blockDb.Put([]byte("LastBlock"), encodedBlock) bc.currentBlock = block bc.lastBlockHash = block.Hash() } func (bc *ChainManager) write(block *types.Block) { encodedBlock := ethutil.Encode(block.RlpDataForStorage()) - bc.db.Put(block.Hash(), encodedBlock) + bc.blockDb.Put(block.Hash(), encodedBlock) } // Accessors @@ -279,7 +280,7 @@ func (bc *ChainManager) Genesis() *types.Block { // Block fetching methods func (bc *ChainManager) HasBlock(hash []byte) bool { - data, _ := bc.db.Get(hash) + data, _ := bc.blockDb.Get(hash) return len(data) != 0 } @@ -307,7 +308,7 @@ func (self *ChainManager) GetBlockHashesFromHash(hash []byte, max uint64) (chain } func (self *ChainManager) GetBlock(hash []byte) *types.Block { - data, _ := self.db.Get(hash) + data, _ := self.blockDb.Get(hash) if len(data) == 0 { return nil } @@ -361,7 +362,7 @@ func (self *ChainManager) GetBlockByNumber(num uint64) *types.Block { } func (bc *ChainManager) setTotalDifficulty(td *big.Int) { - bc.db.Put([]byte("LTD"), td.Bytes()) + bc.blockDb.Put([]byte("LTD"), td.Bytes()) bc.td = td } @@ -448,7 +449,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) error { }) */ - self.setTransState(state.New(block.Root(), self.db)) + self.setTransState(state.New(block.Root(), self.stateDb)) queue[i] = ChainEvent{block} queueEvent.canonicalCount++ } else { @@ -487,7 +488,7 @@ out: // On chain splits we need to reset the transaction state. We can't be sure whether the actual // state of the accounts are still valid. if i == ev.splitCount { - self.setTxState(state.New(event.Block.Root(), self.db)) + self.setTxState(state.New(event.Block.Root(), self.stateDb)) } } diff --git a/core/manager.go b/core/manager.go index bb039d063..803069377 100644 --- a/core/manager.go +++ b/core/manager.go @@ -15,6 +15,7 @@ type Backend interface { IsListening() bool Peers() []*p2p.Peer KeyManager() *crypto.KeyManager - Db() ethutil.Database + BlockDb() ethutil.Database + StateDb() ethutil.Database EventMux() *event.TypeMux } diff --git a/eth/backend.go b/eth/backend.go index 799937510..584d60c7e 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -111,7 +111,8 @@ type Ethereum struct { shutdownChan chan bool // DB interface - db ethutil.Database + blockDb ethutil.Database + stateDb ethutil.Database //*** SERVICES *** // State manager for processing new blocks and managing the over all states @@ -140,13 +141,17 @@ func New(config *Config) (*Ethereum, error) { // Boostrap database ethlogger := logger.New(config.DataDir, config.LogFile, config.LogLevel, config.LogFormat) - db, err := ethdb.NewLDBDatabase(path.Join(config.DataDir, "blockchain")) + blockDb, err := ethdb.NewLDBDatabase(path.Join(config.DataDir, "blockchain")) + if err != nil { + return nil, err + } + stateDb, err := ethdb.NewLDBDatabase(path.Join(config.DataDir, "state")) if err != nil { return nil, err } // Perform database sanity checks - d, _ := db.Get([]byte("ProtocolVersion")) + d, _ := blockDb.Get([]byte("ProtocolVersion")) protov := ethutil.NewValue(d).Uint() if protov != ProtocolVersion && protov != 0 { path := path.Join(config.DataDir, "blockchain") @@ -157,7 +162,7 @@ func New(config *Config) (*Ethereum, error) { var keyManager *crypto.KeyManager switch config.KeyStore { case "db": - keyManager = crypto.NewDBKeyManager(db) + keyManager = crypto.NewDBKeyManager(blockDb) case "file": keyManager = crypto.NewFileKeyManager(config.DataDir) default: @@ -166,23 +171,24 @@ func New(config *Config) (*Ethereum, error) { // Initialise the keyring keyManager.Init(config.KeyRing, 0, false) - saveProtocolVersion(db) + saveProtocolVersion(blockDb) //ethutil.Config.Db = db eth := &Ethereum{ shutdownChan: make(chan bool), - db: db, + blockDb: blockDb, + stateDb: stateDb, keyManager: keyManager, eventMux: &event.TypeMux{}, logger: ethlogger, DataDir: config.DataDir, } - eth.chainManager = core.NewChainManager(db, eth.EventMux()) + eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux()) pow := ethash.New(eth.chainManager) eth.txPool = core.NewTxPool(eth.EventMux()) - eth.blockProcessor = core.NewBlockProcessor(db, pow, eth.txPool, eth.chainManager, eth.EventMux()) + eth.blockProcessor = core.NewBlockProcessor(stateDb, pow, eth.txPool, eth.chainManager, eth.EventMux()) eth.chainManager.SetProcessor(eth.blockProcessor) eth.whisper = whisper.New() eth.miner = miner.New(keyManager.Address(), eth, pow, config.MinerThreads) @@ -228,7 +234,8 @@ func (s *Ethereum) TxPool() *core.TxPool { return s.txPool } func (s *Ethereum) BlockPool() *blockpool.BlockPool { return s.blockPool } func (s *Ethereum) Whisper() *whisper.Whisper { return s.whisper } func (s *Ethereum) EventMux() *event.TypeMux { return s.eventMux } -func (s *Ethereum) Db() ethutil.Database { return s.db } +func (s *Ethereum) BlockDb() ethutil.Database { return s.blockDb } +func (s *Ethereum) StateDb() ethutil.Database { return s.stateDb } func (s *Ethereum) Miner() *miner.Miner { return s.miner } func (s *Ethereum) IsListening() bool { return true } // Always listening func (s *Ethereum) PeerCount() int { return s.net.PeerCount() } @@ -279,7 +286,8 @@ func (self *Ethereum) SuggestPeer(nodeURL string) error { func (s *Ethereum) Stop() { // Close the database - defer s.db.Close() + defer s.blockDb.Close() + defer s.stateDb.Close() s.txSub.Unsubscribe() // quits txBroadcastLoop s.blockSub.Unsubscribe() // quits blockBroadcastLoop diff --git a/miner/worker.go b/miner/worker.go index cd105fa73..21a0522e8 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -30,7 +30,7 @@ type environment struct { } func env(block *types.Block, eth core.Backend) *environment { - state := state.New(block.Root(), eth.Db()) + state := state.New(block.Root(), eth.StateDb()) env := &environment{ totalUsedGas: new(big.Int), state: state, diff --git a/rpc/api.go b/rpc/api.go index 28024c206..ae1e1504f 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -83,7 +83,7 @@ func (self *EthereumApi) setStateByBlockNumber(num int64) { block = chain.GetBlockByNumber(uint64(num)) if block != nil { - self.useState(state.New(block.Root(), self.xeth().Backend().Db())) + self.useState(state.New(block.Root(), self.xeth().Backend().StateDb())) } else { self.useState(chain.State()) } diff --git a/xeth/state.go b/xeth/state.go index e2562613c..0f6a042b3 100644 --- a/xeth/state.go +++ b/xeth/state.go @@ -26,7 +26,7 @@ func (self *State) SafeGet(addr string) *Object { func (self *State) safeGet(addr string) *state.StateObject { object := self.state.GetStateObject(fromHex(addr)) if object == nil { - object = state.NewStateObject(fromHex(addr), self.xeth.eth.Db()) + object = state.NewStateObject(fromHex(addr), self.xeth.eth.StateDb()) } return object diff --git a/xeth/xeth.go b/xeth/xeth.go index 677d40fd5..6ee581e4e 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -32,7 +32,8 @@ type Backend interface { IsListening() bool Peers() []*p2p.Peer KeyManager() *crypto.KeyManager - Db() ethutil.Database + BlockDb() ethutil.Database + StateDb() ethutil.Database EventMux() *event.TypeMux Whisper() *whisper.Whisper Miner() *miner.Miner