Merge pull request #1604 from obscuren/db-merge
core, eth, trie, xeth: merged state, chain, extra databases in one
This commit is contained in:
		@@ -74,10 +74,10 @@ func importChain(ctx *cli.Context) {
 | 
				
			|||||||
	if len(ctx.Args()) != 1 {
 | 
						if len(ctx.Args()) != 1 {
 | 
				
			||||||
		utils.Fatalf("This command requires an argument.")
 | 
							utils.Fatalf("This command requires an argument.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	chain, blockDB, stateDB, extraDB := utils.MakeChain(ctx)
 | 
						chain, chainDb := utils.MakeChain(ctx)
 | 
				
			||||||
	start := time.Now()
 | 
						start := time.Now()
 | 
				
			||||||
	err := utils.ImportChain(chain, ctx.Args().First())
 | 
						err := utils.ImportChain(chain, ctx.Args().First())
 | 
				
			||||||
	closeAll(blockDB, stateDB, extraDB)
 | 
						chainDb.Close()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		utils.Fatalf("Import error: %v", err)
 | 
							utils.Fatalf("Import error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -88,7 +88,7 @@ func exportChain(ctx *cli.Context) {
 | 
				
			|||||||
	if len(ctx.Args()) < 1 {
 | 
						if len(ctx.Args()) < 1 {
 | 
				
			||||||
		utils.Fatalf("This command requires an argument.")
 | 
							utils.Fatalf("This command requires an argument.")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	chain, _, _, _ := utils.MakeChain(ctx)
 | 
						chain, _ := utils.MakeChain(ctx)
 | 
				
			||||||
	start := time.Now()
 | 
						start := time.Now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
@@ -136,8 +136,8 @@ func removeDB(ctx *cli.Context) {
 | 
				
			|||||||
func upgradeDB(ctx *cli.Context) {
 | 
					func upgradeDB(ctx *cli.Context) {
 | 
				
			||||||
	glog.Infoln("Upgrading blockchain database")
 | 
						glog.Infoln("Upgrading blockchain database")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	chain, blockDB, stateDB, extraDB := utils.MakeChain(ctx)
 | 
						chain, chainDb := utils.MakeChain(ctx)
 | 
				
			||||||
	v, _ := blockDB.Get([]byte("BlockchainVersion"))
 | 
						v, _ := chainDb.Get([]byte("BlockchainVersion"))
 | 
				
			||||||
	bcVersion := int(common.NewValue(v).Uint())
 | 
						bcVersion := int(common.NewValue(v).Uint())
 | 
				
			||||||
	if bcVersion == 0 {
 | 
						if bcVersion == 0 {
 | 
				
			||||||
		bcVersion = core.BlockChainVersion
 | 
							bcVersion = core.BlockChainVersion
 | 
				
			||||||
@@ -149,15 +149,14 @@ func upgradeDB(ctx *cli.Context) {
 | 
				
			|||||||
	if err := utils.ExportChain(chain, exportFile); err != nil {
 | 
						if err := utils.ExportChain(chain, exportFile); err != nil {
 | 
				
			||||||
		utils.Fatalf("Unable to export chain for reimport %s", err)
 | 
							utils.Fatalf("Unable to export chain for reimport %s", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	closeAll(blockDB, stateDB, extraDB)
 | 
						chainDb.Close()
 | 
				
			||||||
	os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "blockchain"))
 | 
						os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "chaindata"))
 | 
				
			||||||
	os.RemoveAll(filepath.Join(ctx.GlobalString(utils.DataDirFlag.Name), "state"))
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Import the chain file.
 | 
						// Import the chain file.
 | 
				
			||||||
	chain, blockDB, stateDB, extraDB = utils.MakeChain(ctx)
 | 
						chain, chainDb = utils.MakeChain(ctx)
 | 
				
			||||||
	blockDB.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
 | 
						chainDb.Put([]byte("BlockchainVersion"), common.NewValue(core.BlockChainVersion).Bytes())
 | 
				
			||||||
	err := utils.ImportChain(chain, exportFile)
 | 
						err := utils.ImportChain(chain, exportFile)
 | 
				
			||||||
	closeAll(blockDB, stateDB, extraDB)
 | 
						chainDb.Close()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
 | 
							utils.Fatalf("Import error %v (a backup is made in %s, use the import command to import it)", err, exportFile)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@@ -167,7 +166,7 @@ func upgradeDB(ctx *cli.Context) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func dump(ctx *cli.Context) {
 | 
					func dump(ctx *cli.Context) {
 | 
				
			||||||
	chain, _, stateDB, _ := utils.MakeChain(ctx)
 | 
						chain, chainDb := utils.MakeChain(ctx)
 | 
				
			||||||
	for _, arg := range ctx.Args() {
 | 
						for _, arg := range ctx.Args() {
 | 
				
			||||||
		var block *types.Block
 | 
							var block *types.Block
 | 
				
			||||||
		if hashish(arg) {
 | 
							if hashish(arg) {
 | 
				
			||||||
@@ -180,10 +179,11 @@ func dump(ctx *cli.Context) {
 | 
				
			|||||||
			fmt.Println("{}")
 | 
								fmt.Println("{}")
 | 
				
			||||||
			utils.Fatalf("block not found")
 | 
								utils.Fatalf("block not found")
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			state := state.New(block.Root(), stateDB)
 | 
								state := state.New(block.Root(), chainDb)
 | 
				
			||||||
			fmt.Printf("%s\n", state.Dump())
 | 
								fmt.Printf("%s\n", state.Dump())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						chainDb.Close()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// hashish returns true for strings that look like hashes.
 | 
					// hashish returns true for strings that look like hashes.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -458,23 +458,17 @@ func SetupVM(ctx *cli.Context) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MakeChain creates a chain manager from set command line flags.
 | 
					// MakeChain creates a chain manager from set command line flags.
 | 
				
			||||||
func MakeChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, extraDB common.Database) {
 | 
					func MakeChain(ctx *cli.Context) (chain *core.ChainManager, chainDb common.Database) {
 | 
				
			||||||
	datadir := ctx.GlobalString(DataDirFlag.Name)
 | 
						datadir := ctx.GlobalString(DataDirFlag.Name)
 | 
				
			||||||
	cache := ctx.GlobalInt(CacheFlag.Name)
 | 
						cache := ctx.GlobalInt(CacheFlag.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	if blockDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "blockchain"), cache); err != nil {
 | 
						if chainDb, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "chaindata"), cache); err != nil {
 | 
				
			||||||
		Fatalf("Could not open database: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if stateDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "state"), cache); err != nil {
 | 
					 | 
				
			||||||
		Fatalf("Could not open database: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if extraDB, err = ethdb.NewLDBDatabase(filepath.Join(datadir, "extra"), cache); err != nil {
 | 
					 | 
				
			||||||
		Fatalf("Could not open database: %v", err)
 | 
							Fatalf("Could not open database: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if ctx.GlobalBool(OlympicFlag.Name) {
 | 
						if ctx.GlobalBool(OlympicFlag.Name) {
 | 
				
			||||||
		InitOlympic()
 | 
							InitOlympic()
 | 
				
			||||||
		_, err := core.WriteTestNetGenesisBlock(stateDB, blockDB, 42)
 | 
							_, err := core.WriteTestNetGenesisBlock(chainDb, 42)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			glog.Fatalln(err)
 | 
								glog.Fatalln(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -483,14 +477,14 @@ func MakeChain(ctx *cli.Context) (chain *core.ChainManager, blockDB, stateDB, ex
 | 
				
			|||||||
	eventMux := new(event.TypeMux)
 | 
						eventMux := new(event.TypeMux)
 | 
				
			||||||
	pow := ethash.New()
 | 
						pow := ethash.New()
 | 
				
			||||||
	//genesis := core.GenesisBlock(uint64(ctx.GlobalInt(GenesisNonceFlag.Name)), blockDB)
 | 
						//genesis := core.GenesisBlock(uint64(ctx.GlobalInt(GenesisNonceFlag.Name)), blockDB)
 | 
				
			||||||
	chain, err = core.NewChainManager(blockDB, stateDB, extraDB, pow, eventMux)
 | 
						chain, err = core.NewChainManager(chainDb, pow, eventMux)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		Fatalf("Could not start chainmanager: %v", err)
 | 
							Fatalf("Could not start chainmanager: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	proc := core.NewBlockProcessor(stateDB, extraDB, pow, chain, eventMux)
 | 
						proc := core.NewBlockProcessor(chainDb, pow, chain, eventMux)
 | 
				
			||||||
	chain.SetProcessor(proc)
 | 
						chain.SetProcessor(proc)
 | 
				
			||||||
	return chain, blockDB, stateDB, extraDB
 | 
						return chain, chainDb
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MakeChain creates an account manager from set command line flags.
 | 
					// MakeChain creates an account manager from set command line flags.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -168,8 +168,8 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
 | 
				
			|||||||
	// Time the insertion of the new chain.
 | 
						// Time the insertion of the new chain.
 | 
				
			||||||
	// State and blocks are stored in the same DB.
 | 
						// State and blocks are stored in the same DB.
 | 
				
			||||||
	evmux := new(event.TypeMux)
 | 
						evmux := new(event.TypeMux)
 | 
				
			||||||
	chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
 | 
						chainman, _ := NewChainManager(db, FakePow{}, evmux)
 | 
				
			||||||
	chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux))
 | 
						chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux))
 | 
				
			||||||
	defer chainman.Stop()
 | 
						defer chainman.Stop()
 | 
				
			||||||
	b.ReportAllocs()
 | 
						b.ReportAllocs()
 | 
				
			||||||
	b.ResetTimer()
 | 
						b.ResetTimer()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -41,8 +41,7 @@ const (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type BlockProcessor struct {
 | 
					type BlockProcessor struct {
 | 
				
			||||||
	db      common.Database
 | 
						chainDb common.Database
 | 
				
			||||||
	extraDb common.Database
 | 
					 | 
				
			||||||
	// Mutex for locking the block processor. Blocks can only be handled one at a time
 | 
						// Mutex for locking the block processor. Blocks can only be handled one at a time
 | 
				
			||||||
	mutex sync.Mutex
 | 
						mutex sync.Mutex
 | 
				
			||||||
	// Canonical block chain
 | 
						// Canonical block chain
 | 
				
			||||||
@@ -57,10 +56,9 @@ type BlockProcessor struct {
 | 
				
			|||||||
	eventMux *event.TypeMux
 | 
						eventMux *event.TypeMux
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewBlockProcessor(db, extra common.Database, pow pow.PoW, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
 | 
					func NewBlockProcessor(db common.Database, pow pow.PoW, chainManager *ChainManager, eventMux *event.TypeMux) *BlockProcessor {
 | 
				
			||||||
	sm := &BlockProcessor{
 | 
						sm := &BlockProcessor{
 | 
				
			||||||
		db:       db,
 | 
							chainDb:  db,
 | 
				
			||||||
		extraDb:  extra,
 | 
					 | 
				
			||||||
		mem:      make(map[string]*big.Int),
 | 
							mem:      make(map[string]*big.Int),
 | 
				
			||||||
		Pow:      pow,
 | 
							Pow:      pow,
 | 
				
			||||||
		bc:       chainManager,
 | 
							bc:       chainManager,
 | 
				
			||||||
@@ -199,7 +197,7 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs state.Logs, receipts
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, receipts types.Receipts, err error) {
 | 
					func (sm *BlockProcessor) processWithParent(block, parent *types.Block) (logs state.Logs, receipts types.Receipts, err error) {
 | 
				
			||||||
	// Create a new state based on the parent's root (e.g., create copy)
 | 
						// Create a new state based on the parent's root (e.g., create copy)
 | 
				
			||||||
	state := state.New(parent.Root(), sm.db)
 | 
						state := state.New(parent.Root(), sm.chainDb)
 | 
				
			||||||
	header := block.Header()
 | 
						header := block.Header()
 | 
				
			||||||
	uncles := block.Uncles()
 | 
						uncles := block.Uncles()
 | 
				
			||||||
	txs := block.Transactions()
 | 
						txs := block.Transactions()
 | 
				
			||||||
@@ -340,7 +338,7 @@ func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *ty
 | 
				
			|||||||
// GetBlockReceipts returns the receipts beloniging to the block hash
 | 
					// GetBlockReceipts returns the receipts beloniging to the block hash
 | 
				
			||||||
func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
 | 
					func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
 | 
				
			||||||
	if block := sm.ChainManager().GetBlock(bhash); block != nil {
 | 
						if block := sm.ChainManager().GetBlock(bhash); block != nil {
 | 
				
			||||||
		return GetBlockReceipts(sm.extraDb, block.Hash())
 | 
							return GetBlockReceipts(sm.chainDb, block.Hash())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
@@ -350,7 +348,7 @@ func (sm *BlockProcessor) GetBlockReceipts(bhash common.Hash) types.Receipts {
 | 
				
			|||||||
// where it tries to get it from the (updated) method which gets them from the receipts or
 | 
					// where it tries to get it from the (updated) method which gets them from the receipts or
 | 
				
			||||||
// the depricated way by re-processing the block.
 | 
					// the depricated way by re-processing the block.
 | 
				
			||||||
func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
 | 
					func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err error) {
 | 
				
			||||||
	receipts := GetBlockReceipts(sm.extraDb, block.Hash())
 | 
						receipts := GetBlockReceipts(sm.chainDb, block.Hash())
 | 
				
			||||||
	if len(receipts) > 0 {
 | 
						if len(receipts) > 0 {
 | 
				
			||||||
		// coalesce logs
 | 
							// coalesce logs
 | 
				
			||||||
		for _, receipt := range receipts {
 | 
							for _, receipt := range receipts {
 | 
				
			||||||
@@ -362,7 +360,7 @@ func (sm *BlockProcessor) GetLogs(block *types.Block) (logs state.Logs, err erro
 | 
				
			|||||||
	// TODO: remove backward compatibility
 | 
						// TODO: remove backward compatibility
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		parent = sm.bc.GetBlock(block.ParentHash())
 | 
							parent = sm.bc.GetBlock(block.ParentHash())
 | 
				
			||||||
		state  = state.New(parent.Root(), sm.db)
 | 
							state  = state.New(parent.Root(), sm.chainDb)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sm.TransitionState(state, parent, block, true)
 | 
						sm.TransitionState(state, parent, block, true)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,19 +33,19 @@ func proc() (*BlockProcessor, *ChainManager) {
 | 
				
			|||||||
	db, _ := ethdb.NewMemDatabase()
 | 
						db, _ := ethdb.NewMemDatabase()
 | 
				
			||||||
	var mux event.TypeMux
 | 
						var mux event.TypeMux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WriteTestNetGenesisBlock(db, db, 0)
 | 
						WriteTestNetGenesisBlock(db, 0)
 | 
				
			||||||
	chainMan, err := NewChainManager(db, db, db, thePow(), &mux)
 | 
						chainMan, err := NewChainManager(db, thePow(), &mux)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		fmt.Println(err)
 | 
							fmt.Println(err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return NewBlockProcessor(db, db, ezp.New(), chainMan, &mux), chainMan
 | 
						return NewBlockProcessor(db, ezp.New(), chainMan, &mux), chainMan
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestNumber(t *testing.T) {
 | 
					func TestNumber(t *testing.T) {
 | 
				
			||||||
	pow := ezp.New()
 | 
						pow := ezp.New()
 | 
				
			||||||
	_, chain := proc()
 | 
						_, chain := proc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	statedb := state.New(chain.Genesis().Root(), chain.stateDb)
 | 
						statedb := state.New(chain.Genesis().Root(), chain.chainDb)
 | 
				
			||||||
	header := makeHeader(chain.Genesis(), statedb)
 | 
						header := makeHeader(chain.Genesis(), statedb)
 | 
				
			||||||
	header.Number = big.NewInt(3)
 | 
						header.Number = big.NewInt(3)
 | 
				
			||||||
	err := ValidateHeader(pow, header, chain.Genesis(), false)
 | 
						err := ValidateHeader(pow, header, chain.Genesis(), false)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -184,9 +184,9 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
 | 
				
			|||||||
func newCanonical(n int, db common.Database) (*BlockProcessor, error) {
 | 
					func newCanonical(n int, db common.Database) (*BlockProcessor, error) {
 | 
				
			||||||
	evmux := &event.TypeMux{}
 | 
						evmux := &event.TypeMux{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WriteTestNetGenesisBlock(db, db, 0)
 | 
						WriteTestNetGenesisBlock(db, 0)
 | 
				
			||||||
	chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
 | 
						chainman, _ := NewChainManager(db, FakePow{}, evmux)
 | 
				
			||||||
	bman := NewBlockProcessor(db, db, FakePow{}, chainman, evmux)
 | 
						bman := NewBlockProcessor(db, FakePow{}, chainman, evmux)
 | 
				
			||||||
	bman.bc.SetProcessor(bman)
 | 
						bman.bc.SetProcessor(bman)
 | 
				
			||||||
	parent := bman.bc.CurrentBlock()
 | 
						parent := bman.bc.CurrentBlock()
 | 
				
			||||||
	if n == 0 {
 | 
						if n == 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -77,8 +77,8 @@ func ExampleGenerateChain() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Import the chain. This runs all block validation rules.
 | 
						// Import the chain. This runs all block validation rules.
 | 
				
			||||||
	evmux := &event.TypeMux{}
 | 
						evmux := &event.TypeMux{}
 | 
				
			||||||
	chainman, _ := NewChainManager(db, db, db, FakePow{}, evmux)
 | 
						chainman, _ := NewChainManager(db, FakePow{}, evmux)
 | 
				
			||||||
	chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux))
 | 
						chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux))
 | 
				
			||||||
	if i, err := chainman.InsertChain(chain); err != nil {
 | 
						if i, err := chainman.InsertChain(chain); err != nil {
 | 
				
			||||||
		fmt.Printf("insert error (block %d): %v\n", i, err)
 | 
							fmt.Printf("insert error (block %d): %v\n", i, err)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,9 +56,7 @@ const (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type ChainManager struct {
 | 
					type ChainManager struct {
 | 
				
			||||||
	//eth          EthManager
 | 
						//eth          EthManager
 | 
				
			||||||
	blockDb      common.Database
 | 
						chainDb      common.Database
 | 
				
			||||||
	stateDb      common.Database
 | 
					 | 
				
			||||||
	extraDb      common.Database
 | 
					 | 
				
			||||||
	processor    types.BlockProcessor
 | 
						processor    types.BlockProcessor
 | 
				
			||||||
	eventMux     *event.TypeMux
 | 
						eventMux     *event.TypeMux
 | 
				
			||||||
	genesisBlock *types.Block
 | 
						genesisBlock *types.Block
 | 
				
			||||||
@@ -85,12 +83,10 @@ type ChainManager struct {
 | 
				
			|||||||
	pow pow.PoW
 | 
						pow pow.PoW
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux *event.TypeMux) (*ChainManager, error) {
 | 
					func NewChainManager(chainDb common.Database, pow pow.PoW, mux *event.TypeMux) (*ChainManager, error) {
 | 
				
			||||||
	cache, _ := lru.New(blockCacheLimit)
 | 
						cache, _ := lru.New(blockCacheLimit)
 | 
				
			||||||
	bc := &ChainManager{
 | 
						bc := &ChainManager{
 | 
				
			||||||
		blockDb:  blockDb,
 | 
							chainDb:  chainDb,
 | 
				
			||||||
		stateDb:  stateDb,
 | 
					 | 
				
			||||||
		extraDb:  extraDb,
 | 
					 | 
				
			||||||
		eventMux: mux,
 | 
							eventMux: mux,
 | 
				
			||||||
		quit:     make(chan struct{}),
 | 
							quit:     make(chan struct{}),
 | 
				
			||||||
		cache:    cache,
 | 
							cache:    cache,
 | 
				
			||||||
@@ -103,7 +99,7 @@ func NewChainManager(blockDb, stateDb, extraDb common.Database, pow pow.PoW, mux
 | 
				
			|||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bc.genesisBlock, err = WriteGenesisBlock(stateDb, blockDb, reader)
 | 
							bc.genesisBlock, err = WriteGenesisBlock(chainDb, reader)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -195,15 +191,15 @@ func (self *ChainManager) SetProcessor(proc types.BlockProcessor) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *ChainManager) State() *state.StateDB {
 | 
					func (self *ChainManager) State() *state.StateDB {
 | 
				
			||||||
	return state.New(self.CurrentBlock().Root(), self.stateDb)
 | 
						return state.New(self.CurrentBlock().Root(), self.chainDb)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (bc *ChainManager) recover() bool {
 | 
					func (bc *ChainManager) recover() bool {
 | 
				
			||||||
	data, _ := bc.blockDb.Get([]byte("checkpoint"))
 | 
						data, _ := bc.chainDb.Get([]byte("checkpoint"))
 | 
				
			||||||
	if len(data) != 0 {
 | 
						if len(data) != 0 {
 | 
				
			||||||
		block := bc.GetBlock(common.BytesToHash(data))
 | 
							block := bc.GetBlock(common.BytesToHash(data))
 | 
				
			||||||
		if block != nil {
 | 
							if block != nil {
 | 
				
			||||||
			err := bc.blockDb.Put([]byte("LastBlock"), block.Hash().Bytes())
 | 
								err := bc.chainDb.Put([]byte("LastBlock"), block.Hash().Bytes())
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				glog.Fatalln("db write err:", err)
 | 
									glog.Fatalln("db write err:", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -217,7 +213,7 @@ func (bc *ChainManager) recover() bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (bc *ChainManager) setLastState() error {
 | 
					func (bc *ChainManager) setLastState() error {
 | 
				
			||||||
	data, _ := bc.blockDb.Get([]byte("LastBlock"))
 | 
						data, _ := bc.chainDb.Get([]byte("LastBlock"))
 | 
				
			||||||
	if len(data) != 0 {
 | 
						if len(data) != 0 {
 | 
				
			||||||
		block := bc.GetBlock(common.BytesToHash(data))
 | 
							block := bc.GetBlock(common.BytesToHash(data))
 | 
				
			||||||
		if block != nil {
 | 
							if block != nil {
 | 
				
			||||||
@@ -264,7 +260,7 @@ func (bc *ChainManager) Reset() {
 | 
				
			|||||||
	bc.cache, _ = lru.New(blockCacheLimit)
 | 
						bc.cache, _ = lru.New(blockCacheLimit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Prepare the genesis block
 | 
						// Prepare the genesis block
 | 
				
			||||||
	err := WriteBlock(bc.blockDb, bc.genesisBlock)
 | 
						err := WriteBlock(bc.chainDb, bc.genesisBlock)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		glog.Fatalln("db err:", err)
 | 
							glog.Fatalln("db err:", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -277,7 +273,7 @@ func (bc *ChainManager) Reset() {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (bc *ChainManager) removeBlock(block *types.Block) {
 | 
					func (bc *ChainManager) removeBlock(block *types.Block) {
 | 
				
			||||||
	bc.blockDb.Delete(append(blockHashPre, block.Hash().Bytes()...))
 | 
						bc.chainDb.Delete(append(blockHashPre, block.Hash().Bytes()...))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
 | 
					func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
 | 
				
			||||||
@@ -292,7 +288,7 @@ func (bc *ChainManager) ResetWithGenesisBlock(gb *types.Block) {
 | 
				
			|||||||
	gb.Td = gb.Difficulty()
 | 
						gb.Td = gb.Difficulty()
 | 
				
			||||||
	bc.genesisBlock = gb
 | 
						bc.genesisBlock = gb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err := WriteBlock(bc.blockDb, bc.genesisBlock)
 | 
						err := WriteBlock(bc.chainDb, bc.genesisBlock)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		glog.Fatalln("db err:", err)
 | 
							glog.Fatalln("db err:", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -339,14 +335,14 @@ func (self *ChainManager) ExportN(w io.Writer, first uint64, last uint64) error
 | 
				
			|||||||
// insert injects a block into the current chain block chain. Note, this function
 | 
					// insert injects a block into the current chain block chain. Note, this function
 | 
				
			||||||
// assumes that the `mu` mutex is held!
 | 
					// assumes that the `mu` mutex is held!
 | 
				
			||||||
func (bc *ChainManager) insert(block *types.Block) {
 | 
					func (bc *ChainManager) insert(block *types.Block) {
 | 
				
			||||||
	err := WriteHead(bc.blockDb, block)
 | 
						err := WriteHead(bc.chainDb, block)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		glog.Fatal("db write fail:", err)
 | 
							glog.Fatal("db write fail:", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bc.checkpoint++
 | 
						bc.checkpoint++
 | 
				
			||||||
	if bc.checkpoint > checkpointLimit {
 | 
						if bc.checkpoint > checkpointLimit {
 | 
				
			||||||
		err = bc.blockDb.Put([]byte("checkpoint"), block.Hash().Bytes())
 | 
							err = bc.chainDb.Put([]byte("checkpoint"), block.Hash().Bytes())
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			glog.Fatal("db write fail:", err)
 | 
								glog.Fatal("db write fail:", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -369,7 +365,7 @@ func (bc *ChainManager) HasBlock(hash common.Hash) bool {
 | 
				
			|||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data, _ := bc.blockDb.Get(append(blockHashPre, hash[:]...))
 | 
						data, _ := bc.chainDb.Get(append(blockHashPre, hash[:]...))
 | 
				
			||||||
	return len(data) != 0
 | 
						return len(data) != 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -399,7 +395,7 @@ func (self *ChainManager) GetBlock(hash common.Hash) *types.Block {
 | 
				
			|||||||
		return block.(*types.Block)
 | 
							return block.(*types.Block)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	block := GetBlockByHash(self.blockDb, hash)
 | 
						block := GetBlockByHash(self.chainDb, hash)
 | 
				
			||||||
	if block == nil {
 | 
						if block == nil {
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -433,7 +429,7 @@ func (self *ChainManager) GetBlocksFromHash(hash common.Hash, n int) (blocks []*
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// non blocking version
 | 
					// non blocking version
 | 
				
			||||||
func (self *ChainManager) getBlockByNumber(num uint64) *types.Block {
 | 
					func (self *ChainManager) getBlockByNumber(num uint64) *types.Block {
 | 
				
			||||||
	return GetBlockByNumber(self.blockDb, num)
 | 
						return GetBlockByNumber(self.chainDb, num)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
 | 
					func (self *ChainManager) GetUnclesInChain(block *types.Block, length int) (uncles []*types.Header) {
 | 
				
			||||||
@@ -521,7 +517,7 @@ func (self *ChainManager) WriteBlock(block *types.Block, queued bool) (status wr
 | 
				
			|||||||
		status = SideStatTy
 | 
							status = SideStatTy
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = WriteBlock(self.blockDb, block)
 | 
						err = WriteBlock(self.chainDb, block)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		glog.Fatalln("db err:", err)
 | 
							glog.Fatalln("db err:", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -638,9 +634,9 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
 | 
				
			|||||||
			queueEvent.canonicalCount++
 | 
								queueEvent.canonicalCount++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			// This puts transactions in a extra db for rpc
 | 
								// This puts transactions in a extra db for rpc
 | 
				
			||||||
			PutTransactions(self.extraDb, block, block.Transactions())
 | 
								PutTransactions(self.chainDb, block, block.Transactions())
 | 
				
			||||||
			// store the receipts
 | 
								// store the receipts
 | 
				
			||||||
			PutReceipts(self.extraDb, receipts)
 | 
								PutReceipts(self.chainDb, receipts)
 | 
				
			||||||
		case SideStatTy:
 | 
							case SideStatTy:
 | 
				
			||||||
			if glog.V(logger.Detail) {
 | 
								if glog.V(logger.Detail) {
 | 
				
			||||||
				glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
 | 
									glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart))
 | 
				
			||||||
@@ -651,7 +647,7 @@ func (self *ChainManager) InsertChain(chain types.Blocks) (int, error) {
 | 
				
			|||||||
			queue[i] = ChainSplitEvent{block, logs}
 | 
								queue[i] = ChainSplitEvent{block, logs}
 | 
				
			||||||
			queueEvent.splitCount++
 | 
								queueEvent.splitCount++
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		PutBlockReceipts(self.extraDb, block, receipts)
 | 
							PutBlockReceipts(self.chainDb, block, receipts)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		stats.processed++
 | 
							stats.processed++
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -733,8 +729,8 @@ func (self *ChainManager) merge(oldBlock, newBlock *types.Block) error {
 | 
				
			|||||||
		// insert the block in the canonical way, re-writing history
 | 
							// insert the block in the canonical way, re-writing history
 | 
				
			||||||
		self.insert(block)
 | 
							self.insert(block)
 | 
				
			||||||
		// write canonical receipts and transactions
 | 
							// write canonical receipts and transactions
 | 
				
			||||||
		PutTransactions(self.extraDb, block, block.Transactions())
 | 
							PutTransactions(self.chainDb, block, block.Transactions())
 | 
				
			||||||
		PutReceipts(self.extraDb, GetBlockReceipts(self.extraDb, block.Hash()))
 | 
							PutReceipts(self.chainDb, GetBlockReceipts(self.chainDb, block.Hash()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	self.mu.Unlock()
 | 
						self.mu.Unlock()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,14 +48,14 @@ func thePow() pow.PoW {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func theChainManager(db common.Database, t *testing.T) *ChainManager {
 | 
					func theChainManager(db common.Database, t *testing.T) *ChainManager {
 | 
				
			||||||
	var eventMux event.TypeMux
 | 
						var eventMux event.TypeMux
 | 
				
			||||||
	WriteTestNetGenesisBlock(db, db, 0)
 | 
						WriteTestNetGenesisBlock(db, 0)
 | 
				
			||||||
	chainMan, err := NewChainManager(db, db, db, thePow(), &eventMux)
 | 
						chainMan, err := NewChainManager(db, thePow(), &eventMux)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error("failed creating chainmanager:", err)
 | 
							t.Error("failed creating chainmanager:", err)
 | 
				
			||||||
		t.FailNow()
 | 
							t.FailNow()
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	blockMan := NewBlockProcessor(db, db, nil, chainMan, &eventMux)
 | 
						blockMan := NewBlockProcessor(db, nil, chainMan, &eventMux)
 | 
				
			||||||
	chainMan.SetProcessor(blockMan)
 | 
						chainMan.SetProcessor(blockMan)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return chainMan
 | 
						return chainMan
 | 
				
			||||||
@@ -125,7 +125,7 @@ func testChain(chainB types.Blocks, bman *BlockProcessor) (*big.Int, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		bman.bc.mu.Lock()
 | 
							bman.bc.mu.Lock()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			WriteBlock(bman.bc.blockDb, block)
 | 
								WriteBlock(bman.bc.chainDb, block)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bman.bc.mu.Unlock()
 | 
							bman.bc.mu.Unlock()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -387,7 +387,7 @@ func makeChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func chm(genesis *types.Block, db common.Database) *ChainManager {
 | 
					func chm(genesis *types.Block, db common.Database) *ChainManager {
 | 
				
			||||||
	var eventMux event.TypeMux
 | 
						var eventMux event.TypeMux
 | 
				
			||||||
	bc := &ChainManager{extraDb: db, blockDb: db, stateDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: FakePow{}}
 | 
						bc := &ChainManager{chainDb: db, genesisBlock: genesis, eventMux: &eventMux, pow: FakePow{}}
 | 
				
			||||||
	bc.cache, _ = lru.New(100)
 | 
						bc.cache, _ = lru.New(100)
 | 
				
			||||||
	bc.futureBlocks, _ = lru.New(100)
 | 
						bc.futureBlocks, _ = lru.New(100)
 | 
				
			||||||
	bc.processor = bproc{}
 | 
						bc.processor = bproc{}
 | 
				
			||||||
@@ -399,7 +399,7 @@ func chm(genesis *types.Block, db common.Database) *ChainManager {
 | 
				
			|||||||
func TestReorgLongest(t *testing.T) {
 | 
					func TestReorgLongest(t *testing.T) {
 | 
				
			||||||
	db, _ := ethdb.NewMemDatabase()
 | 
						db, _ := ethdb.NewMemDatabase()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	genesis, err := WriteTestNetGenesisBlock(db, db, 0)
 | 
						genesis, err := WriteTestNetGenesisBlock(db, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		t.FailNow()
 | 
							t.FailNow()
 | 
				
			||||||
@@ -422,7 +422,7 @@ func TestReorgLongest(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func TestReorgShortest(t *testing.T) {
 | 
					func TestReorgShortest(t *testing.T) {
 | 
				
			||||||
	db, _ := ethdb.NewMemDatabase()
 | 
						db, _ := ethdb.NewMemDatabase()
 | 
				
			||||||
	genesis, err := WriteTestNetGenesisBlock(db, db, 0)
 | 
						genesis, err := WriteTestNetGenesisBlock(db, 0)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Error(err)
 | 
							t.Error(err)
 | 
				
			||||||
		t.FailNow()
 | 
							t.FailNow()
 | 
				
			||||||
@@ -446,13 +446,13 @@ func TestReorgShortest(t *testing.T) {
 | 
				
			|||||||
func TestInsertNonceError(t *testing.T) {
 | 
					func TestInsertNonceError(t *testing.T) {
 | 
				
			||||||
	for i := 1; i < 25 && !t.Failed(); i++ {
 | 
						for i := 1; i < 25 && !t.Failed(); i++ {
 | 
				
			||||||
		db, _ := ethdb.NewMemDatabase()
 | 
							db, _ := ethdb.NewMemDatabase()
 | 
				
			||||||
		genesis, err := WriteTestNetGenesisBlock(db, db, 0)
 | 
							genesis, err := WriteTestNetGenesisBlock(db, 0)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Error(err)
 | 
								t.Error(err)
 | 
				
			||||||
			t.FailNow()
 | 
								t.FailNow()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		bc := chm(genesis, db)
 | 
							bc := chm(genesis, db)
 | 
				
			||||||
		bc.processor = NewBlockProcessor(db, db, bc.pow, bc, bc.eventMux)
 | 
							bc.processor = NewBlockProcessor(db, bc.pow, bc, bc.eventMux)
 | 
				
			||||||
		blocks := makeChain(bc.currentBlock, i, db, 0)
 | 
							blocks := makeChain(bc.currentBlock, i, db, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fail := rand.Int() % len(blocks)
 | 
							fail := rand.Int() % len(blocks)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -33,7 +33,7 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WriteGenesisBlock writes the genesis block to the database as block number 0
 | 
					// WriteGenesisBlock writes the genesis block to the database as block number 0
 | 
				
			||||||
func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*types.Block, error) {
 | 
					func WriteGenesisBlock(chainDb common.Database, reader io.Reader) (*types.Block, error) {
 | 
				
			||||||
	contents, err := ioutil.ReadAll(reader)
 | 
						contents, err := ioutil.ReadAll(reader)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@@ -59,7 +59,7 @@ func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*typ
 | 
				
			|||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	statedb := state.New(common.Hash{}, stateDb)
 | 
						statedb := state.New(common.Hash{}, chainDb)
 | 
				
			||||||
	for addr, account := range genesis.Alloc {
 | 
						for addr, account := range genesis.Alloc {
 | 
				
			||||||
		address := common.HexToAddress(addr)
 | 
							address := common.HexToAddress(addr)
 | 
				
			||||||
		statedb.AddBalance(address, common.String2Big(account.Balance))
 | 
							statedb.AddBalance(address, common.String2Big(account.Balance))
 | 
				
			||||||
@@ -84,9 +84,9 @@ func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*typ
 | 
				
			|||||||
	}, nil, nil, nil)
 | 
						}, nil, nil, nil)
 | 
				
			||||||
	block.Td = difficulty
 | 
						block.Td = difficulty
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if block := GetBlockByHash(blockDb, block.Hash()); block != nil {
 | 
						if block := GetBlockByHash(chainDb, block.Hash()); block != nil {
 | 
				
			||||||
		glog.V(logger.Info).Infoln("Genesis block already in chain. Writing canonical number")
 | 
							glog.V(logger.Info).Infoln("Genesis block already in chain. Writing canonical number")
 | 
				
			||||||
		err := WriteCanonNumber(blockDb, block)
 | 
							err := WriteCanonNumber(chainDb, block)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -95,11 +95,11 @@ func WriteGenesisBlock(stateDb, blockDb common.Database, reader io.Reader) (*typ
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	statedb.Sync()
 | 
						statedb.Sync()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = WriteBlock(blockDb, block)
 | 
						err = WriteBlock(chainDb, block)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	err = WriteHead(blockDb, block)
 | 
						err = WriteHead(chainDb, block)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -133,11 +133,11 @@ func WriteGenesisBlockForTesting(db common.Database, addr common.Address, balanc
 | 
				
			|||||||
		"0x%x":{"balance":"0x%x"}
 | 
							"0x%x":{"balance":"0x%x"}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), addr, balance.Bytes())
 | 
					}`, types.EncodeNonce(0), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes(), addr, balance.Bytes())
 | 
				
			||||||
	block, _ := WriteGenesisBlock(db, db, strings.NewReader(testGenesis))
 | 
						block, _ := WriteGenesisBlock(db, strings.NewReader(testGenesis))
 | 
				
			||||||
	return block
 | 
						return block
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func WriteTestNetGenesisBlock(stateDb, blockDb common.Database, nonce uint64) (*types.Block, error) {
 | 
					func WriteTestNetGenesisBlock(chainDb common.Database, nonce uint64) (*types.Block, error) {
 | 
				
			||||||
	testGenesis := fmt.Sprintf(`{
 | 
						testGenesis := fmt.Sprintf(`{
 | 
				
			||||||
	"nonce":"0x%x",
 | 
						"nonce":"0x%x",
 | 
				
			||||||
	"gasLimit":"0x%x",
 | 
						"gasLimit":"0x%x",
 | 
				
			||||||
@@ -157,5 +157,5 @@ func WriteTestNetGenesisBlock(stateDb, blockDb common.Database, nonce uint64) (*
 | 
				
			|||||||
		"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
 | 
							"1a26338f0d905e295fccb71fa9ea849ffa12aaf4": {"balance": "1606938044258990275541962092341162602522202993782792835301376"}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
 | 
					}`, types.EncodeNonce(nonce), params.GenesisGasLimit.Bytes(), params.GenesisDifficulty.Bytes())
 | 
				
			||||||
	return WriteGenesisBlock(stateDb, blockDb, strings.NewReader(testGenesis))
 | 
						return WriteGenesisBlock(chainDb, strings.NewReader(testGenesis))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,8 +28,7 @@ type Backend interface {
 | 
				
			|||||||
	BlockProcessor() *BlockProcessor
 | 
						BlockProcessor() *BlockProcessor
 | 
				
			||||||
	ChainManager() *ChainManager
 | 
						ChainManager() *ChainManager
 | 
				
			||||||
	TxPool() *TxPool
 | 
						TxPool() *TxPool
 | 
				
			||||||
	BlockDb() common.Database
 | 
						ChainDb() common.Database
 | 
				
			||||||
	StateDb() common.Database
 | 
						DappDb() common.Database
 | 
				
			||||||
	ExtraDb() common.Database
 | 
					 | 
				
			||||||
	EventMux() *event.TypeMux
 | 
						EventMux() *event.TypeMux
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										192
									
								
								eth/backend.go
									
									
									
									
									
								
							
							
						
						
									
										192
									
								
								eth/backend.go
									
									
									
									
									
								
							@@ -45,6 +45,7 @@ import (
 | 
				
			|||||||
	"github.com/ethereum/go-ethereum/p2p"
 | 
						"github.com/ethereum/go-ethereum/p2p"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/p2p/discover"
 | 
						"github.com/ethereum/go-ethereum/p2p/discover"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/p2p/nat"
 | 
						"github.com/ethereum/go-ethereum/p2p/nat"
 | 
				
			||||||
 | 
						"github.com/ethereum/go-ethereum/trie"
 | 
				
			||||||
	"github.com/ethereum/go-ethereum/whisper"
 | 
						"github.com/ethereum/go-ethereum/whisper"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -206,9 +207,8 @@ type Ethereum struct {
 | 
				
			|||||||
	shutdownChan chan bool
 | 
						shutdownChan chan bool
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// DB interfaces
 | 
						// DB interfaces
 | 
				
			||||||
	blockDb common.Database // Block chain database
 | 
						chainDb common.Database // Block chain databe
 | 
				
			||||||
	stateDb common.Database // State changes database
 | 
						dappDb  common.Database // Dapp database
 | 
				
			||||||
	extraDb common.Database // Extra database (txs, etc)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Closed when databases are flushed and closed
 | 
						// Closed when databases are flushed and closed
 | 
				
			||||||
	databasesClosed chan bool
 | 
						databasesClosed chan bool
 | 
				
			||||||
@@ -266,27 +266,27 @@ func New(config *Config) (*Ethereum, error) {
 | 
				
			|||||||
	if newdb == nil {
 | 
						if newdb == nil {
 | 
				
			||||||
		newdb = func(path string) (common.Database, error) { return ethdb.NewLDBDatabase(path, config.DatabaseCache) }
 | 
							newdb = func(path string) (common.Database, error) { return ethdb.NewLDBDatabase(path, config.DatabaseCache) }
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	blockDb, err := newdb(filepath.Join(config.DataDir, "blockchain"))
 | 
					
 | 
				
			||||||
 | 
						// attempt to merge database together, upgrading from an old version
 | 
				
			||||||
 | 
						if err := mergeDatabases(config.DataDir, newdb); err != nil {
 | 
				
			||||||
 | 
							return nil, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						chainDb, err := newdb(filepath.Join(config.DataDir, "chaindata"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("blockchain db err: %v", err)
 | 
							return nil, fmt.Errorf("blockchain db err: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if db, ok := blockDb.(*ethdb.LDBDatabase); ok {
 | 
						if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
 | 
				
			||||||
		db.Meter("eth/db/block/")
 | 
							db.Meter("eth/db/chaindata/")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	stateDb, err := newdb(filepath.Join(config.DataDir, "state"))
 | 
						dappDb, err := newdb(filepath.Join(config.DataDir, "dapp"))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("state db err: %v", err)
 | 
							return nil, fmt.Errorf("dapp db err: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if db, ok := stateDb.(*ethdb.LDBDatabase); ok {
 | 
						if db, ok := dappDb.(*ethdb.LDBDatabase); ok {
 | 
				
			||||||
		db.Meter("eth/db/state/")
 | 
							db.Meter("eth/db/dapp/")
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	extraDb, err := newdb(filepath.Join(config.DataDir, "extra"))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return nil, fmt.Errorf("extra db err: %v", err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if db, ok := extraDb.(*ethdb.LDBDatabase); ok {
 | 
					 | 
				
			||||||
		db.Meter("eth/db/extra/")
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	nodeDb := filepath.Join(config.DataDir, "nodes")
 | 
						nodeDb := filepath.Join(config.DataDir, "nodes")
 | 
				
			||||||
	glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
 | 
						glog.V(logger.Info).Infof("Protocol Versions: %v, Network Id: %v", ProtocolVersions, config.NetworkId)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -296,7 +296,7 @@ func New(config *Config) (*Ethereum, error) {
 | 
				
			|||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		block, err := core.WriteGenesisBlock(stateDb, blockDb, fr)
 | 
							block, err := core.WriteGenesisBlock(chainDb, fr)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -304,7 +304,7 @@ func New(config *Config) (*Ethereum, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if config.Olympic {
 | 
						if config.Olympic {
 | 
				
			||||||
		_, err := core.WriteTestNetGenesisBlock(stateDb, blockDb, 42)
 | 
							_, err := core.WriteTestNetGenesisBlock(chainDb, 42)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return nil, err
 | 
								return nil, err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -313,26 +313,25 @@ func New(config *Config) (*Ethereum, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// This is for testing only.
 | 
						// This is for testing only.
 | 
				
			||||||
	if config.GenesisBlock != nil {
 | 
						if config.GenesisBlock != nil {
 | 
				
			||||||
		core.WriteBlock(blockDb, config.GenesisBlock)
 | 
							core.WriteBlock(chainDb, config.GenesisBlock)
 | 
				
			||||||
		core.WriteHead(blockDb, config.GenesisBlock)
 | 
							core.WriteHead(chainDb, config.GenesisBlock)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !config.SkipBcVersionCheck {
 | 
						if !config.SkipBcVersionCheck {
 | 
				
			||||||
		b, _ := blockDb.Get([]byte("BlockchainVersion"))
 | 
							b, _ := chainDb.Get([]byte("BlockchainVersion"))
 | 
				
			||||||
		bcVersion := int(common.NewValue(b).Uint())
 | 
							bcVersion := int(common.NewValue(b).Uint())
 | 
				
			||||||
		if bcVersion != config.BlockChainVersion && bcVersion != 0 {
 | 
							if bcVersion != config.BlockChainVersion && bcVersion != 0 {
 | 
				
			||||||
			return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, config.BlockChainVersion)
 | 
								return nil, fmt.Errorf("Blockchain DB version mismatch (%d / %d). Run geth upgradedb.\n", bcVersion, config.BlockChainVersion)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		saveBlockchainVersion(blockDb, config.BlockChainVersion)
 | 
							saveBlockchainVersion(chainDb, config.BlockChainVersion)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
 | 
						glog.V(logger.Info).Infof("Blockchain DB Version: %d", config.BlockChainVersion)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eth := &Ethereum{
 | 
						eth := &Ethereum{
 | 
				
			||||||
		shutdownChan:            make(chan bool),
 | 
							shutdownChan:            make(chan bool),
 | 
				
			||||||
		databasesClosed:         make(chan bool),
 | 
							databasesClosed:         make(chan bool),
 | 
				
			||||||
		blockDb:                 blockDb,
 | 
							chainDb:                 chainDb,
 | 
				
			||||||
		stateDb:                 stateDb,
 | 
							dappDb:                  dappDb,
 | 
				
			||||||
		extraDb:                 extraDb,
 | 
					 | 
				
			||||||
		eventMux:                &event.TypeMux{},
 | 
							eventMux:                &event.TypeMux{},
 | 
				
			||||||
		accountManager:          config.AccountManager,
 | 
							accountManager:          config.AccountManager,
 | 
				
			||||||
		DataDir:                 config.DataDir,
 | 
							DataDir:                 config.DataDir,
 | 
				
			||||||
@@ -362,7 +361,7 @@ func New(config *Config) (*Ethereum, error) {
 | 
				
			|||||||
		eth.pow = ethash.New()
 | 
							eth.pow = ethash.New()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	//genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
 | 
						//genesis := core.GenesisBlock(uint64(config.GenesisNonce), stateDb)
 | 
				
			||||||
	eth.chainManager, err = core.NewChainManager(blockDb, stateDb, extraDb, eth.pow, eth.EventMux())
 | 
						eth.chainManager, err = core.NewChainManager(chainDb, eth.pow, eth.EventMux())
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		if err == core.ErrNoGenesis {
 | 
							if err == core.ErrNoGenesis {
 | 
				
			||||||
			return nil, fmt.Errorf(`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`)
 | 
								return nil, fmt.Errorf(`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`)
 | 
				
			||||||
@@ -372,7 +371,7 @@ func New(config *Config) (*Ethereum, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)
 | 
						eth.txPool = core.NewTxPool(eth.EventMux(), eth.chainManager.State, eth.chainManager.GasLimit)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	eth.blockProcessor = core.NewBlockProcessor(stateDb, extraDb, eth.pow, eth.chainManager, eth.EventMux())
 | 
						eth.blockProcessor = core.NewBlockProcessor(chainDb, eth.pow, eth.chainManager, eth.EventMux())
 | 
				
			||||||
	eth.chainManager.SetProcessor(eth.blockProcessor)
 | 
						eth.chainManager.SetProcessor(eth.blockProcessor)
 | 
				
			||||||
	eth.protocolManager = NewProtocolManager(config.NetworkId, eth.eventMux, eth.txPool, eth.pow, eth.chainManager)
 | 
						eth.protocolManager = NewProtocolManager(config.NetworkId, eth.eventMux, eth.txPool, eth.pow, eth.chainManager)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -520,9 +519,8 @@ func (s *Ethereum) BlockProcessor() *core.BlockProcessor { return s.blockProcess
 | 
				
			|||||||
func (s *Ethereum) TxPool() *core.TxPool                 { return s.txPool }
 | 
					func (s *Ethereum) TxPool() *core.TxPool                 { return s.txPool }
 | 
				
			||||||
func (s *Ethereum) Whisper() *whisper.Whisper            { return s.whisper }
 | 
					func (s *Ethereum) Whisper() *whisper.Whisper            { return s.whisper }
 | 
				
			||||||
func (s *Ethereum) EventMux() *event.TypeMux             { return s.eventMux }
 | 
					func (s *Ethereum) EventMux() *event.TypeMux             { return s.eventMux }
 | 
				
			||||||
func (s *Ethereum) BlockDb() common.Database             { return s.blockDb }
 | 
					func (s *Ethereum) ChainDb() common.Database             { return s.chainDb }
 | 
				
			||||||
func (s *Ethereum) StateDb() common.Database             { return s.stateDb }
 | 
					func (s *Ethereum) DappDb() common.Database              { return s.dappDb }
 | 
				
			||||||
func (s *Ethereum) ExtraDb() common.Database             { return s.extraDb }
 | 
					 | 
				
			||||||
func (s *Ethereum) IsListening() bool                    { return true } // Always listening
 | 
					func (s *Ethereum) IsListening() bool                    { return true } // Always listening
 | 
				
			||||||
func (s *Ethereum) PeerCount() int                       { return s.net.PeerCount() }
 | 
					func (s *Ethereum) PeerCount() int                       { return s.net.PeerCount() }
 | 
				
			||||||
func (s *Ethereum) Peers() []*p2p.Peer                   { return s.net.Peers() }
 | 
					func (s *Ethereum) Peers() []*p2p.Peer                   { return s.net.Peers() }
 | 
				
			||||||
@@ -569,23 +567,19 @@ done:
 | 
				
			|||||||
		select {
 | 
							select {
 | 
				
			||||||
		case <-ticker.C:
 | 
							case <-ticker.C:
 | 
				
			||||||
			// don't change the order of database flushes
 | 
								// don't change the order of database flushes
 | 
				
			||||||
			if err := s.extraDb.Flush(); err != nil {
 | 
								if err := s.dappDb.Flush(); err != nil {
 | 
				
			||||||
				glog.Fatalf("fatal error: flush extraDb: %v (Restart your node. We are aware of this issue)\n", err)
 | 
									glog.Fatalf("fatal error: flush dappDb: %v (Restart your node. We are aware of this issue)\n", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if err := s.stateDb.Flush(); err != nil {
 | 
								if err := s.chainDb.Flush(); err != nil {
 | 
				
			||||||
				glog.Fatalf("fatal error: flush stateDb: %v (Restart your node. We are aware of this issue)\n", err)
 | 
									glog.Fatalf("fatal error: flush chainDb: %v (Restart your node. We are aware of this issue)\n", err)
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if err := s.blockDb.Flush(); err != nil {
 | 
					 | 
				
			||||||
				glog.Fatalf("fatal error: flush blockDb: %v (Restart your node. We are aware of this issue)\n", err)
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case <-s.shutdownChan:
 | 
							case <-s.shutdownChan:
 | 
				
			||||||
			break done
 | 
								break done
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s.blockDb.Close()
 | 
						s.chainDb.Close()
 | 
				
			||||||
	s.stateDb.Close()
 | 
						s.dappDb.Close()
 | 
				
			||||||
	s.extraDb.Close()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	close(s.databasesClosed)
 | 
						close(s.databasesClosed)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -683,14 +677,6 @@ func (self *Ethereum) StartAutoDAG() {
 | 
				
			|||||||
	}()
 | 
						}()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
 | 
					 | 
				
			||||||
// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
 | 
					 | 
				
			||||||
func dagFiles(epoch uint64) (string, string) {
 | 
					 | 
				
			||||||
	seedHash, _ := ethash.GetSeedHash(epoch * epochLength)
 | 
					 | 
				
			||||||
	dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8])
 | 
					 | 
				
			||||||
	return dag, "full-R" + dag
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// stopAutoDAG stops automatic DAG pregeneration by quitting the loop
 | 
					// stopAutoDAG stops automatic DAG pregeneration by quitting the loop
 | 
				
			||||||
func (self *Ethereum) StopAutoDAG() {
 | 
					func (self *Ethereum) StopAutoDAG() {
 | 
				
			||||||
	if self.autodagquit != nil {
 | 
						if self.autodagquit != nil {
 | 
				
			||||||
@@ -700,30 +686,6 @@ func (self *Ethereum) StopAutoDAG() {
 | 
				
			|||||||
	glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
 | 
						glog.V(logger.Info).Infof("Automatic pregeneration of ethash DAG OFF (ethash dir: %s)", ethash.DefaultDir)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
	// The databases were previously tied to protocol versions. Currently we
 | 
					 | 
				
			||||||
	// are moving away from this decision as approaching Frontier. The below
 | 
					 | 
				
			||||||
	// code was left in for now but should eventually be just dropped.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	func saveProtocolVersion(db common.Database, protov int) {
 | 
					 | 
				
			||||||
		d, _ := db.Get([]byte("ProtocolVersion"))
 | 
					 | 
				
			||||||
		protocolVersion := common.NewValue(d).Uint()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if protocolVersion == 0 {
 | 
					 | 
				
			||||||
			db.Put([]byte("ProtocolVersion"), common.NewValue(protov).Bytes())
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func saveBlockchainVersion(db common.Database, bcVersion int) {
 | 
					 | 
				
			||||||
	d, _ := db.Get([]byte("BlockchainVersion"))
 | 
					 | 
				
			||||||
	blockchainVersion := common.NewValue(d).Uint()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if blockchainVersion == 0 {
 | 
					 | 
				
			||||||
		db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (self *Ethereum) Solc() (*compiler.Solidity, error) {
 | 
					func (self *Ethereum) Solc() (*compiler.Solidity, error) {
 | 
				
			||||||
	var err error
 | 
						var err error
 | 
				
			||||||
	if self.solc == nil {
 | 
						if self.solc == nil {
 | 
				
			||||||
@@ -738,3 +700,87 @@ func (self *Ethereum) SetSolc(solcPath string) (*compiler.Solidity, error) {
 | 
				
			|||||||
	self.solc = nil
 | 
						self.solc = nil
 | 
				
			||||||
	return self.Solc()
 | 
						return self.Solc()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// dagFiles(epoch) returns the two alternative DAG filenames (not a path)
 | 
				
			||||||
 | 
					// 1) <revision>-<hex(seedhash[8])> 2) full-R<revision>-<hex(seedhash[8])>
 | 
				
			||||||
 | 
					func dagFiles(epoch uint64) (string, string) {
 | 
				
			||||||
 | 
						seedHash, _ := ethash.GetSeedHash(epoch * epochLength)
 | 
				
			||||||
 | 
						dag := fmt.Sprintf("full-R%d-%x", ethashRevision, seedHash[:8])
 | 
				
			||||||
 | 
						return dag, "full-R" + dag
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func saveBlockchainVersion(db common.Database, bcVersion int) {
 | 
				
			||||||
 | 
						d, _ := db.Get([]byte("BlockchainVersion"))
 | 
				
			||||||
 | 
						blockchainVersion := common.NewValue(d).Uint()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if blockchainVersion == 0 {
 | 
				
			||||||
 | 
							db.Put([]byte("BlockchainVersion"), common.NewValue(bcVersion).Bytes())
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// mergeDatabases when required merge old database layout to one single database
 | 
				
			||||||
 | 
					func mergeDatabases(datadir string, newdb func(path string) (common.Database, error)) error {
 | 
				
			||||||
 | 
						// Check if already upgraded
 | 
				
			||||||
 | 
						data := filepath.Join(datadir, "chaindata")
 | 
				
			||||||
 | 
						if _, err := os.Stat(data); !os.IsNotExist(err) {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// make sure it's not just a clean path
 | 
				
			||||||
 | 
						chainPath := filepath.Join(datadir, "blockchain")
 | 
				
			||||||
 | 
						if _, err := os.Stat(chainPath); os.IsNotExist(err) {
 | 
				
			||||||
 | 
							return nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						glog.Infoln("Database upgrade required. Upgrading...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						database, err := newdb(data)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("creating data db err: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer database.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glog.Infoln("Merging blockchain database...")
 | 
				
			||||||
 | 
						chainDb, err := newdb(chainPath)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("state db err: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer chainDb.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
 | 
				
			||||||
 | 
							it := db.NewIterator()
 | 
				
			||||||
 | 
							for it.Next() {
 | 
				
			||||||
 | 
								database.Put(it.Key(), it.Value())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glog.Infoln("Merging state database...")
 | 
				
			||||||
 | 
						state := filepath.Join(datadir, "state")
 | 
				
			||||||
 | 
						stateDb, err := newdb(state)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("state db err: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer stateDb.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
 | 
				
			||||||
 | 
							it := db.NewIterator()
 | 
				
			||||||
 | 
							for it.Next() {
 | 
				
			||||||
 | 
								database.Put(append(trie.StatePre, it.Key()...), it.Value())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						glog.Infoln("Merging transaction database...")
 | 
				
			||||||
 | 
						extra := filepath.Join(datadir, "extra")
 | 
				
			||||||
 | 
						extraDb, err := newdb(extra)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return fmt.Errorf("state db err: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						defer extraDb.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if db, ok := chainDb.(*ethdb.LDBDatabase); ok {
 | 
				
			||||||
 | 
							it := db.NewIterator()
 | 
				
			||||||
 | 
							for it.Next() {
 | 
				
			||||||
 | 
								database.Put(it.Key(), it.Value())
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -179,10 +179,10 @@ type testPeer struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func newProtocolManagerForTesting(txAdded chan<- []*types.Transaction) *ProtocolManager {
 | 
					func newProtocolManagerForTesting(txAdded chan<- []*types.Transaction) *ProtocolManager {
 | 
				
			||||||
	db, _ := ethdb.NewMemDatabase()
 | 
						db, _ := ethdb.NewMemDatabase()
 | 
				
			||||||
	core.WriteTestNetGenesisBlock(db, db, 0)
 | 
						core.WriteTestNetGenesisBlock(db, 0)
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		em       = new(event.TypeMux)
 | 
							em       = new(event.TypeMux)
 | 
				
			||||||
		chain, _ = core.NewChainManager(db, db, db, core.FakePow{}, em)
 | 
							chain, _ = core.NewChainManager(db, core.FakePow{}, em)
 | 
				
			||||||
		txpool   = &fakeTxPool{added: txAdded}
 | 
							txpool   = &fakeTxPool{added: txAdded}
 | 
				
			||||||
		pm       = NewProtocolManager(NetworkId, em, txpool, core.FakePow{}, chain)
 | 
							pm       = NewProtocolManager(NetworkId, em, txpool, core.FakePow{}, chain)
 | 
				
			||||||
	)
 | 
						)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,9 +39,8 @@ var OpenFileLimit = 64
 | 
				
			|||||||
// cacheRatio specifies how the total alloted cache is distributed between the
 | 
					// cacheRatio specifies how the total alloted cache is distributed between the
 | 
				
			||||||
// various system databases.
 | 
					// various system databases.
 | 
				
			||||||
var cacheRatio = map[string]float64{
 | 
					var cacheRatio = map[string]float64{
 | 
				
			||||||
	"blockchain": 1.0 / 13.0,
 | 
						"dapp":      2.0 / 13.0,
 | 
				
			||||||
	"extra":      2.0 / 13.0,
 | 
						"chaindata": 11.0 / 13.0,
 | 
				
			||||||
	"state":      10.0 / 13.0,
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type LDBDatabase struct {
 | 
					type LDBDatabase struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -100,7 +100,7 @@ type worker struct {
 | 
				
			|||||||
	eth     core.Backend
 | 
						eth     core.Backend
 | 
				
			||||||
	chain   *core.ChainManager
 | 
						chain   *core.ChainManager
 | 
				
			||||||
	proc    *core.BlockProcessor
 | 
						proc    *core.BlockProcessor
 | 
				
			||||||
	extraDb common.Database
 | 
						chainDb common.Database
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	coinbase common.Address
 | 
						coinbase common.Address
 | 
				
			||||||
	gasPrice *big.Int
 | 
						gasPrice *big.Int
 | 
				
			||||||
@@ -126,7 +126,7 @@ func newWorker(coinbase common.Address, eth core.Backend) *worker {
 | 
				
			|||||||
	worker := &worker{
 | 
						worker := &worker{
 | 
				
			||||||
		eth:            eth,
 | 
							eth:            eth,
 | 
				
			||||||
		mux:            eth.EventMux(),
 | 
							mux:            eth.EventMux(),
 | 
				
			||||||
		extraDb:        eth.ExtraDb(),
 | 
							chainDb:        eth.ChainDb(),
 | 
				
			||||||
		recv:           make(chan *Result, resultQueueSize),
 | 
							recv:           make(chan *Result, resultQueueSize),
 | 
				
			||||||
		gasPrice:       new(big.Int),
 | 
							gasPrice:       new(big.Int),
 | 
				
			||||||
		chain:          eth.ChainManager(),
 | 
							chain:          eth.ChainManager(),
 | 
				
			||||||
@@ -291,9 +291,9 @@ func (self *worker) wait() {
 | 
				
			|||||||
				// check if canon block and write transactions
 | 
									// check if canon block and write transactions
 | 
				
			||||||
				if stat == core.CanonStatTy {
 | 
									if stat == core.CanonStatTy {
 | 
				
			||||||
					// This puts transactions in a extra db for rpc
 | 
										// This puts transactions in a extra db for rpc
 | 
				
			||||||
					core.PutTransactions(self.extraDb, block, block.Transactions())
 | 
										core.PutTransactions(self.chainDb, block, block.Transactions())
 | 
				
			||||||
					// store the receipts
 | 
										// store the receipts
 | 
				
			||||||
					core.PutReceipts(self.extraDb, work.receipts)
 | 
										core.PutReceipts(self.chainDb, work.receipts)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				// broadcast before waiting for validation
 | 
									// broadcast before waiting for validation
 | 
				
			||||||
@@ -344,7 +344,7 @@ func (self *worker) push(work *Work) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// makeCurrent creates a new environment for the current cycle.
 | 
					// makeCurrent creates a new environment for the current cycle.
 | 
				
			||||||
func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
 | 
					func (self *worker) makeCurrent(parent *types.Block, header *types.Header) {
 | 
				
			||||||
	state := state.New(parent.Root(), self.eth.StateDb())
 | 
						state := state.New(parent.Root(), self.eth.ChainDb())
 | 
				
			||||||
	work := &Work{
 | 
						work := &Work{
 | 
				
			||||||
		state:     state,
 | 
							state:     state,
 | 
				
			||||||
		ancestors: set.New(),
 | 
							ancestors: set.New(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -119,7 +119,7 @@ func (self *debugApi) DumpBlock(req *shared.Request) (interface{}, error) {
 | 
				
			|||||||
		return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
 | 
							return nil, fmt.Errorf("block #%d not found", args.BlockNumber)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	stateDb := state.New(block.Root(), self.ethereum.StateDb())
 | 
						stateDb := state.New(block.Root(), self.ethereum.ChainDb())
 | 
				
			||||||
	if stateDb == nil {
 | 
						if stateDb == nil {
 | 
				
			||||||
		return nil, nil
 | 
							return nil, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -204,7 +204,7 @@ func (test *BlockTest) makeEthConfig() *eth.Config {
 | 
				
			|||||||
// InsertPreState populates the given database with the genesis
 | 
					// InsertPreState populates the given database with the genesis
 | 
				
			||||||
// accounts defined by the test.
 | 
					// accounts defined by the test.
 | 
				
			||||||
func (t *BlockTest) InsertPreState(ethereum *eth.Ethereum) (*state.StateDB, error) {
 | 
					func (t *BlockTest) InsertPreState(ethereum *eth.Ethereum) (*state.StateDB, error) {
 | 
				
			||||||
	db := ethereum.StateDb()
 | 
						db := ethereum.ChainDb()
 | 
				
			||||||
	statedb := state.New(common.Hash{}, db)
 | 
						statedb := state.New(common.Hash{}, db)
 | 
				
			||||||
	for addrString, acct := range t.preAccounts {
 | 
						for addrString, acct := range t.preAccounts {
 | 
				
			||||||
		addr, err := hex.DecodeString(addrString)
 | 
							addr, err := hex.DecodeString(addrString)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,8 @@ func NewCache(backend Backend) *Cache {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *Cache) Get(key []byte) []byte {
 | 
					func (self *Cache) Get(key []byte) []byte {
 | 
				
			||||||
 | 
						key = append(StatePre, key...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data := self.store[string(key)]
 | 
						data := self.store[string(key)]
 | 
				
			||||||
	if data == nil {
 | 
						if data == nil {
 | 
				
			||||||
		data, _ = self.backend.Get(key)
 | 
							data, _ = self.backend.Get(key)
 | 
				
			||||||
@@ -47,8 +49,8 @@ func (self *Cache) Get(key []byte) []byte {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *Cache) Put(key []byte, data []byte) {
 | 
					func (self *Cache) Put(key []byte, data []byte) {
 | 
				
			||||||
	// write the data to the ldb batch
 | 
						key = append(StatePre, key...)
 | 
				
			||||||
	//self.batch.Put(key, rle.Compress(data))
 | 
					
 | 
				
			||||||
	self.batch.Put(key, data)
 | 
						self.batch.Put(key, data)
 | 
				
			||||||
	self.store[string(key)] = data
 | 
						self.store[string(key)] = data
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,8 @@ import (
 | 
				
			|||||||
	"github.com/ethereum/go-ethereum/crypto"
 | 
						"github.com/ethereum/go-ethereum/crypto"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var StatePre = []byte("state-")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) {
 | 
					func ParanoiaCheck(t1 *Trie, backend Backend) (bool, *Trie) {
 | 
				
			||||||
	t2 := New(nil, backend)
 | 
						t2 := New(nil, backend)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,7 +45,7 @@ func (self *State) SafeGet(addr string) *Object {
 | 
				
			|||||||
func (self *State) safeGet(addr string) *state.StateObject {
 | 
					func (self *State) safeGet(addr string) *state.StateObject {
 | 
				
			||||||
	object := self.state.GetStateObject(common.HexToAddress(addr))
 | 
						object := self.state.GetStateObject(common.HexToAddress(addr))
 | 
				
			||||||
	if object == nil {
 | 
						if object == nil {
 | 
				
			||||||
		object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.StateDb())
 | 
							object = state.NewStateObject(common.HexToAddress(addr), self.xeth.backend.ChainDb())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return object
 | 
						return object
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										16
									
								
								xeth/xeth.go
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								xeth/xeth.go
									
									
									
									
									
								
							@@ -213,9 +213,9 @@ func (self *XEth) AtStateNum(num int64) *XEth {
 | 
				
			|||||||
		st = self.backend.Miner().PendingState().Copy()
 | 
							st = self.backend.Miner().PendingState().Copy()
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		if block := self.getBlockByHeight(num); block != nil {
 | 
							if block := self.getBlockByHeight(num); block != nil {
 | 
				
			||||||
			st = state.New(block.Root(), self.backend.StateDb())
 | 
								st = state.New(block.Root(), self.backend.ChainDb())
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			st = state.New(self.backend.ChainManager().GetBlockByNumber(0).Root(), self.backend.StateDb())
 | 
								st = state.New(self.backend.ChainManager().GetBlockByNumber(0).Root(), self.backend.ChainDb())
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -259,7 +259,7 @@ func (self *XEth) UpdateState() (wait chan *big.Int) {
 | 
				
			|||||||
						wait <- n
 | 
											wait <- n
 | 
				
			||||||
						n = nil
 | 
											n = nil
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					statedb := state.New(ev.Block.Root(), self.backend.StateDb())
 | 
										statedb := state.New(ev.Block.Root(), self.backend.ChainDb())
 | 
				
			||||||
					self.state = NewState(self, statedb)
 | 
										self.state = NewState(self, statedb)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			case n, ok = <-wait:
 | 
								case n, ok = <-wait:
 | 
				
			||||||
@@ -311,7 +311,7 @@ func (self *XEth) EthBlockByHash(strHash string) *types.Block {
 | 
				
			|||||||
func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blhash common.Hash, blnum *big.Int, txi uint64) {
 | 
					func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blhash common.Hash, blnum *big.Int, txi uint64) {
 | 
				
			||||||
	// Due to increasing return params and need to determine if this is from transaction pool or
 | 
						// Due to increasing return params and need to determine if this is from transaction pool or
 | 
				
			||||||
	// some chain, this probably needs to be refactored for more expressiveness
 | 
						// some chain, this probably needs to be refactored for more expressiveness
 | 
				
			||||||
	data, _ := self.backend.ExtraDb().Get(common.FromHex(hash))
 | 
						data, _ := self.backend.ChainDb().Get(common.FromHex(hash))
 | 
				
			||||||
	if len(data) != 0 {
 | 
						if len(data) != 0 {
 | 
				
			||||||
		dtx := new(types.Transaction)
 | 
							dtx := new(types.Transaction)
 | 
				
			||||||
		if err := rlp.DecodeBytes(data, dtx); err != nil {
 | 
							if err := rlp.DecodeBytes(data, dtx); err != nil {
 | 
				
			||||||
@@ -330,7 +330,7 @@ func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blha
 | 
				
			|||||||
		Index      uint64
 | 
							Index      uint64
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	v, dberr := self.backend.ExtraDb().Get(append(common.FromHex(hash), 0x0001))
 | 
						v, dberr := self.backend.ChainDb().Get(append(common.FromHex(hash), 0x0001))
 | 
				
			||||||
	// TODO check specifically for ErrNotFound
 | 
						// TODO check specifically for ErrNotFound
 | 
				
			||||||
	if dberr != nil {
 | 
						if dberr != nil {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -365,7 +365,7 @@ func (self *XEth) GetBlockReceipts(bhash common.Hash) types.Receipts {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *XEth) GetTxReceipt(txhash common.Hash) *types.Receipt {
 | 
					func (self *XEth) GetTxReceipt(txhash common.Hash) *types.Receipt {
 | 
				
			||||||
	return core.GetReceipt(self.backend.ExtraDb(), txhash)
 | 
						return core.GetReceipt(self.backend.ChainDb(), txhash)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (self *XEth) GasLimit() *big.Int {
 | 
					func (self *XEth) GasLimit() *big.Int {
 | 
				
			||||||
@@ -408,13 +408,13 @@ func (self *XEth) SetSolc(solcPath string) (*compiler.Solidity, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// store DApp value in extra database
 | 
					// store DApp value in extra database
 | 
				
			||||||
func (self *XEth) DbPut(key, val []byte) bool {
 | 
					func (self *XEth) DbPut(key, val []byte) bool {
 | 
				
			||||||
	self.backend.ExtraDb().Put(append(dappStorePre, key...), val)
 | 
						self.backend.DappDb().Put(append(dappStorePre, key...), val)
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// retrieve DApp value from extra database
 | 
					// retrieve DApp value from extra database
 | 
				
			||||||
func (self *XEth) DbGet(key []byte) ([]byte, error) {
 | 
					func (self *XEth) DbGet(key []byte) ([]byte, error) {
 | 
				
			||||||
	val, err := self.backend.ExtraDb().Get(append(dappStorePre, key...))
 | 
						val, err := self.backend.DappDb().Get(append(dappStorePre, key...))
 | 
				
			||||||
	return val, err
 | 
						return val, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user