diff --git a/core/block_processor.go b/core/block_processor.go index 3a224059b..3f10e5efd 100644 --- a/core/block_processor.go +++ b/core/block_processor.go @@ -15,6 +15,7 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/pow" "github.com/ethereum/go-ethereum/rlp" + "gopkg.in/fatih/set.v0" ) const ( @@ -346,50 +347,39 @@ func AccumulateRewards(statedb *state.StateDB, block *types.Block) { } func (sm *BlockProcessor) VerifyUncles(statedb *state.StateDB, block, parent *types.Block) error { - //ancestors := set.New() - //uncles := set.New() - ancestors := make(map[common.Hash]struct{}) - uncles := make(map[common.Hash]struct{}) + ancestors := set.New() + uncles := set.New() ancestorHeaders := make(map[common.Hash]*types.Header) for _, ancestor := range sm.bc.GetAncestors(block, 7) { ancestorHeaders[ancestor.Hash()] = ancestor.Header() - //ancestors.Add(ancestor.Hash()) - ancestors[ancestor.Hash()] = struct{}{} + ancestors.Add(ancestor.Hash()) // Include ancestors uncles in the uncle set. Uncles must be unique. for _, uncle := range ancestor.Uncles() { - //uncles.Add(uncle.Hash()) - uncles[uncle.Hash()] = struct{}{} + uncles.Add(uncle.Hash()) } } - //uncles.Add(block.Hash()) - uncles[block.Hash()] = struct{}{} + uncles.Add(block.Hash()) for i, uncle := range block.Uncles() { hash := uncle.Hash() - //if uncles.Has(hash) { - if _, has := uncles[hash]; has { + if uncles.Has(hash) { // Error not unique return UncleError("uncle[%d](%x) not unique", i, hash[:4]) } - uncles[hash] = struct{}{} + uncles.Add(hash) - //if ancestors.Has(hash) { - if _, has := ancestors[hash]; has { - var branch string - //ancestors.Each(func(item interface{}) bool { - for hash := range ancestors { + if ancestors.Has(hash) { + branch := fmt.Sprintf(" O - %x\n |\n", block.Hash()) + ancestors.Each(func(item interface{}) bool { branch += fmt.Sprintf(" O - %x\n |\n", hash) - //return true - } - //}) - branch += fmt.Sprintf(" O - %x\n |\n", block.Hash()) + return true + }) glog.Infoln(branch) return UncleError("uncle[%d](%x) is ancestor", i, hash[:4]) } - //if !ancestors.Has(uncle.ParentHash) { - if _, has := ancestors[uncle.ParentHash]; !has { + if !ancestors.Has(uncle.ParentHash) { return UncleError("uncle[%d](%x)'s parent unknown (%x)", i, hash[:4], uncle.ParentHash[0:4]) } diff --git a/eth/backend.go b/eth/backend.go index 44ceb89e8..69504fd94 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -213,7 +213,7 @@ func New(config *Config) (*Ethereum, error) { // Let the database take 3/4 of the max open files (TODO figure out a way to get the actual limit of the open files) const dbCount = 3 - ethdb.OpenFileLimit = 256 / (dbCount + 1) + ethdb.OpenFileLimit = 128 / (dbCount + 1) newdb := config.NewDB if newdb == nil { diff --git a/ethdb/database.go b/ethdb/database.go index c351c024a..9bf09467b 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -7,6 +7,7 @@ import ( "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger/glog" "github.com/syndtr/goleveldb/leveldb" + "github.com/syndtr/goleveldb/leveldb/errors" "github.com/syndtr/goleveldb/leveldb/iterator" "github.com/syndtr/goleveldb/leveldb/opt" ) @@ -24,9 +25,17 @@ type LDBDatabase struct { quit chan struct{} } +// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by +// it self but requires a background poller which syncs every X. `Flush` should be called +// when data needs to be stored and written to disk. func NewLDBDatabase(file string) (*LDBDatabase, error) { // Open the db db, err := leveldb.OpenFile(file, &opt.Options{OpenFilesCacheCapacity: OpenFileLimit}) + // check for curruption and attempt to recover + if _, iscorrupted := err.(*errors.ErrCorrupted); iscorrupted { + db, err = leveldb.RecoverFile(file, nil) + } + // (re) check for errors and abort if opening of the db failed if err != nil { return nil, err } @@ -44,21 +53,15 @@ func (self *LDBDatabase) makeQueue() { self.queue = make(map[string][]byte) } +// Put puts the given key / value to the queue func (self *LDBDatabase) Put(key []byte, value []byte) { self.mu.Lock() defer self.mu.Unlock() self.queue[string(key)] = value - /* - value = rle.Compress(value) - - err := self.db.Put(key, value, nil) - if err != nil { - fmt.Println("Error put", err) - } - */ } +// Get returns the given key if it's present. func (self *LDBDatabase) Get(key []byte) ([]byte, error) { self.mu.Lock() defer self.mu.Unlock() @@ -76,6 +79,7 @@ func (self *LDBDatabase) Get(key []byte) ([]byte, error) { return rle.Decompress(dat) } +// Delete deletes the key from the queue and database func (self *LDBDatabase) Delete(key []byte) error { self.mu.Lock() defer self.mu.Unlock() @@ -100,6 +104,7 @@ func (self *LDBDatabase) NewIterator() iterator.Iterator { return self.db.NewIterator(nil, nil) } +// Flush flushes out the queue to leveldb func (self *LDBDatabase) Flush() error { self.mu.Lock() defer self.mu.Unlock() diff --git a/miner/miner.go b/miner/miner.go index 3f87e8151..c9427f302 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -39,6 +39,10 @@ func New(eth core.Backend, mux *event.TypeMux, pow pow.PoW) *Miner { return miner } +// update keeps track of the downloader events. Please be aware that this is a one shot type of update loop. +// It's entered once and as soon as `Done` or `Failed` has been broadcasted the events are unregistered and +// the loop is exited. This to prevent a major security vuln where external parties can DOS you with blocks +// and halt your mining operation for as long as the DOS continues. func (self *Miner) update() { events := self.mux.Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{}) for ev := range events.Chan() { @@ -59,6 +63,8 @@ func (self *Miner) update() { self.Start(self.coinbase, self.threads) } } + // unsubscribe. we're only interested in this event once + events.Unsubscribe() } } diff --git a/xeth/xeth.go b/xeth/xeth.go index 3ec3f7dd4..b90e0aa47 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -881,7 +881,7 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS var ( from = common.HexToAddress(fromStr) to = common.HexToAddress(toStr) - value = common.NewValue(valueStr) + value = common.Big(valueStr) gas = common.Big(gasStr) price = common.Big(gasPriceStr) data []byte @@ -928,9 +928,9 @@ func (self *XEth) Transact(fromStr, toStr, nonceStr, valueStr, gasStr, gasPriceS var tx *types.Transaction if contractCreation { - tx = types.NewContractCreationTx(value.BigInt(), gas, price, data) + tx = types.NewContractCreationTx(value, gas, price, data) } else { - tx = types.NewTransactionMessage(to, value.BigInt(), gas, price, data) + tx = types.NewTransactionMessage(to, value, gas, price, data) } state := self.backend.ChainManager().TxState()