Merge remote-tracking branch 'upstream/develop' into bzz

This commit is contained in:
zelig 2015-05-28 00:43:37 +01:00
commit a83e02416a
8 changed files with 138 additions and 100 deletions

View file

@ -259,8 +259,8 @@ func (js *jsre) setHead(call otto.FunctionCall) otto.Value {
} }
func (js *jsre) downloadProgress(call otto.FunctionCall) otto.Value { func (js *jsre) downloadProgress(call otto.FunctionCall) otto.Value {
current, max := js.ethereum.Downloader().Stats() pending, cached := js.ethereum.Downloader().Stats()
v, _ := call.Otto.ToValue(fmt.Sprintf("%d/%d", current, max)) v, _ := call.Otto.ToValue(map[string]interface{}{"pending": pending, "cached": cached})
return v return v
} }

View file

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
"os/signal"
"path/filepath" "path/filepath"
"strings" "strings"
@ -49,7 +50,8 @@ type dumbterm struct{ r *bufio.Reader }
func (r dumbterm) Prompt(p string) (string, error) { func (r dumbterm) Prompt(p string) (string, error) {
fmt.Print(p) fmt.Print(p)
return r.r.ReadString('\n') line, err := r.r.ReadString('\n')
return strings.TrimSuffix(line, "\n"), err
} }
func (r dumbterm) PasswordPrompt(p string) (string, error) { func (r dumbterm) PasswordPrompt(p string) (string, error) {
@ -190,30 +192,52 @@ func (self *jsre) exec(filename string) error {
} }
func (self *jsre) interactive() { func (self *jsre) interactive() {
for { // Read input lines.
input, err := self.Prompt(self.ps1) prompt := make(chan string)
if err != nil { inputln := make(chan string)
break go func() {
} defer close(inputln)
if input == "" { for {
continue line, err := self.Prompt(<-prompt)
} if err != nil {
str += input + "\n" return
self.setIndent() }
if indentCount <= 0 { inputln <- line
if input == "exit" { }
break }()
// Wait for Ctrl-C, too.
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt)
defer func() {
if self.atexit != nil {
self.atexit()
}
self.re.Stop(false)
}()
for {
prompt <- self.ps1
select {
case <-sig:
fmt.Println("caught interrupt, exiting")
return
case input, ok := <-inputln:
if !ok || indentCount <= 0 && input == "exit" {
return
}
if input == "" {
continue
}
str += input + "\n"
self.setIndent()
if indentCount <= 0 {
hist := str[:len(str)-1]
self.AppendHistory(hist)
self.parseInput(str)
str = ""
} }
hist := str[:len(str)-1]
self.AppendHistory(hist)
self.parseInput(str)
str = ""
} }
} }
if self.atexit != nil {
self.atexit()
}
self.re.Stop(false)
} }
func (self *jsre) withHistory(op func(*os.File)) { func (self *jsre) withHistory(op func(*os.File)) {

View file

@ -5,7 +5,6 @@ type Database interface {
Put(key []byte, value []byte) Put(key []byte, value []byte)
Get(key []byte) ([]byte, error) Get(key []byte) ([]byte, error)
Delete(key []byte) error Delete(key []byte) error
LastKnownTD() []byte
Close() Close()
Flush() error Flush() error
} }

View file

@ -285,9 +285,8 @@ func (self *BlockProcessor) GetBlockReceipts(bhash common.Hash) (receipts types.
} }
// Validates the current block. Returns an error if the block was invalid, // See YP section 4.3.4. "Block Header Validity"
// an uncle or anything that isn't on the current block chain. // Validates a block. Returns an error if the block is invalid.
// Validation validates easy over difficult (dagger takes longer time = difficult)
func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow bool) error { func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow bool) error {
if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 { if big.NewInt(int64(len(block.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
return fmt.Errorf("Block extra data too long (%d)", len(block.Extra)) return fmt.Errorf("Block extra data too long (%d)", len(block.Extra))
@ -298,16 +297,14 @@ func (sm *BlockProcessor) ValidateHeader(block, parent *types.Header, checkPow b
return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd) return fmt.Errorf("Difficulty check failed for block %v, %v", block.Difficulty, expd)
} }
// block.gasLimit - parent.gasLimit <= parent.gasLimit / GasLimitBoundDivisor
a := new(big.Int).Sub(block.GasLimit, parent.GasLimit) a := new(big.Int).Sub(block.GasLimit, parent.GasLimit)
a.Abs(a) a.Abs(a)
b := new(big.Int).Div(parent.GasLimit, params.GasLimitBoundDivisor) b := new(big.Int).Div(parent.GasLimit, params.GasLimitBoundDivisor)
if !(a.Cmp(b) <= 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) { if !(a.Cmp(b) < 0) || (block.GasLimit.Cmp(params.MinGasLimit) == -1) {
return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b) return fmt.Errorf("GasLimit check failed for block %v (%v > %v)", block.GasLimit, a, b)
} }
// Allow future blocks up to 10 seconds if int64(block.Time) > time.Now().Unix() {
if int64(block.Time) > time.Now().Unix()+4 {
return BlockFutureErr return BlockFutureErr
} }

View file

@ -69,6 +69,7 @@ func CalcGasLimit(parent *types.Block) *big.Int {
gl := new(big.Int).Sub(parent.GasLimit(), decay) gl := new(big.Int).Sub(parent.GasLimit(), decay)
gl = gl.Add(gl, contrib) gl = gl.Add(gl, contrib)
gl = gl.Add(gl, big.NewInt(1))
gl = common.BigMax(gl, params.MinGasLimit) gl = common.BigMax(gl, params.MinGasLimit)
if gl.Cmp(params.GenesisGasLimit) < 0 { if gl.Cmp(params.GenesisGasLimit) < 0 {

View file

@ -93,14 +93,22 @@ func NewProtocolManager(protocolVersion, networkId int, mux *event.TypeMux, txpo
} }
func (pm *ProtocolManager) removePeer(id string) { func (pm *ProtocolManager) removePeer(id string) {
// Unregister the peer from the downloader // Short circuit if the peer was already removed
pm.downloader.UnregisterPeer(id) peer := pm.peers.Peer(id)
if peer == nil {
return
}
glog.V(logger.Debug).Infoln("Removing peer", id)
// Remove the peer from the Ethereum peer set too // Unregister the peer from the downloader and Ethereum peer set
glog.V(logger.Detail).Infoln("Removing peer", id) pm.downloader.UnregisterPeer(id)
if err := pm.peers.Unregister(id); err != nil { if err := pm.peers.Unregister(id); err != nil {
glog.V(logger.Error).Infoln("Removal failed:", err) glog.V(logger.Error).Infoln("Removal failed:", err)
} }
// Hard disconnect at the networking layer
if peer != nil {
peer.Peer.Disconnect(p2p.DiscUselessPeer)
}
} }
func (pm *ProtocolManager) Start() { func (pm *ProtocolManager) Start() {

View file

@ -1,8 +1,6 @@
package ethdb package ethdb
import ( import (
"sync"
"github.com/ethereum/go-ethereum/compression/rle" "github.com/ethereum/go-ethereum/compression/rle"
"github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
@ -15,14 +13,10 @@ import (
var OpenFileLimit = 64 var OpenFileLimit = 64
type LDBDatabase struct { type LDBDatabase struct {
// filename for reporting
fn string fn string
// LevelDB instance
mu sync.Mutex
db *leveldb.DB db *leveldb.DB
queue map[string][]byte
quit chan struct{}
} }
// NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by // NewLDBDatabase returns a LevelDB wrapped object. LDBDatabase does not persist data by
@ -40,85 +34,39 @@ func NewLDBDatabase(file string) (*LDBDatabase, error) {
return nil, err return nil, err
} }
database := &LDBDatabase{ database := &LDBDatabase{
fn: file, fn: file,
db: db, db: db,
quit: make(chan struct{}),
} }
database.makeQueue()
return database, nil return database, nil
} }
func (self *LDBDatabase) makeQueue() {
self.queue = make(map[string][]byte)
}
// Put puts the given key / value to the queue // Put puts the given key / value to the queue
func (self *LDBDatabase) Put(key []byte, value []byte) { func (self *LDBDatabase) Put(key []byte, value []byte) {
self.mu.Lock() self.db.Put(key, rle.Compress(value), nil)
defer self.mu.Unlock()
self.queue[string(key)] = value
} }
// Get returns the given key if it's present. // Get returns the given key if it's present.
func (self *LDBDatabase) Get(key []byte) ([]byte, error) { func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
self.mu.Lock()
defer self.mu.Unlock()
// Check queue first
if dat, ok := self.queue[string(key)]; ok {
return dat, nil
}
dat, err := self.db.Get(key, nil) dat, err := self.db.Get(key, nil)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return rle.Decompress(dat) return rle.Decompress(dat)
} }
// Delete deletes the key from the queue and database // Delete deletes the key from the queue and database
func (self *LDBDatabase) Delete(key []byte) error { func (self *LDBDatabase) Delete(key []byte) error {
self.mu.Lock()
defer self.mu.Unlock()
// make sure it's not in the queue
delete(self.queue, string(key))
return self.db.Delete(key, nil) return self.db.Delete(key, nil)
} }
func (self *LDBDatabase) LastKnownTD() []byte {
data, _ := self.Get([]byte("LTD"))
if len(data) == 0 {
data = []byte{0x0}
}
return data
}
func (self *LDBDatabase) NewIterator() iterator.Iterator { func (self *LDBDatabase) NewIterator() iterator.Iterator {
return self.db.NewIterator(nil, nil) return self.db.NewIterator(nil, nil)
} }
// Flush flushes out the queue to leveldb // Flush flushes out the queue to leveldb
func (self *LDBDatabase) Flush() error { func (self *LDBDatabase) Flush() error {
self.mu.Lock() return nil
defer self.mu.Unlock()
batch := new(leveldb.Batch)
for key, value := range self.queue {
batch.Put([]byte(key), rle.Compress(value))
}
self.makeQueue() // reset the queue
glog.V(logger.Detail).Infoln("Flush database: ", self.fn)
return self.db.Write(batch, nil)
} }
func (self *LDBDatabase) Write(batch *leveldb.Batch) error { func (self *LDBDatabase) Write(batch *leveldb.Batch) error {

View file

@ -38,6 +38,13 @@ type Agent interface {
GetHashRate() int64 GetHashRate() int64
} }
const miningLogAtDepth = 5
type uint64RingBuffer struct {
ints []uint64 //array of all integers in buffer
next int //where is the next insertion? assert 0 <= next < len(ints)
}
// environment is the workers current environment and holds // environment is the workers current environment and holds
// all of the current state information // all of the current state information
type environment struct { type environment struct {
@ -54,6 +61,7 @@ type environment struct {
lowGasTransactors *set.Set lowGasTransactors *set.Set
ownedAccounts *set.Set ownedAccounts *set.Set
lowGasTxs types.Transactions lowGasTxs types.Transactions
localMinedBlocks *uint64RingBuffer // the most recent block numbers that were mined locally (used to check block inclusion)
} }
// env returns a new environment for the current cycle // env returns a new environment for the current cycle
@ -209,6 +217,18 @@ out:
events.Unsubscribe() events.Unsubscribe()
} }
func newLocalMinedBlock(blockNumber uint64, prevMinedBlocks *uint64RingBuffer) (minedBlocks *uint64RingBuffer) {
if prevMinedBlocks == nil {
minedBlocks = &uint64RingBuffer{next: 0, ints: make([]uint64, miningLogAtDepth+1)}
} else {
minedBlocks = prevMinedBlocks
}
minedBlocks.ints[minedBlocks.next] = blockNumber
minedBlocks.next = (minedBlocks.next + 1) % len(minedBlocks.ints)
return minedBlocks
}
func (self *worker) wait() { func (self *worker) wait() {
for { for {
for block := range self.recv { for block := range self.recv {
@ -224,13 +244,16 @@ func (self *worker) wait() {
} }
self.mux.Post(core.NewMinedBlockEvent{block}) self.mux.Post(core.NewMinedBlockEvent{block})
var stale string var stale, confirm string
canonBlock := self.chain.GetBlockByNumber(block.NumberU64()) canonBlock := self.chain.GetBlockByNumber(block.NumberU64())
if canonBlock != nil && canonBlock.Hash() != block.Hash() { if canonBlock != nil && canonBlock.Hash() != block.Hash() {
stale = "stale-" stale = "stale "
} else {
confirm = "Wait 5 blocks for confirmation"
self.current.localMinedBlocks = newLocalMinedBlock(block.Number().Uint64(), self.current.localMinedBlocks)
} }
glog.V(logger.Info).Infof("🔨 Mined %sblock #%v (%x)", stale, block.Number(), block.Hash().Bytes()[:4]) glog.V(logger.Info).Infof("🔨 Mined %sblock (#%v / %x). %s", stale, block.Number(), block.Hash().Bytes()[:4], confirm)
jsonlogger.LogJson(&logger.EthMinerNewBlock{ jsonlogger.LogJson(&logger.EthMinerNewBlock{
BlockHash: block.Hash().Hex(), BlockHash: block.Hash().Hex(),
@ -265,8 +288,10 @@ func (self *worker) push() {
func (self *worker) makeCurrent() { func (self *worker) makeCurrent() {
block := self.chain.NewBlock(self.coinbase) block := self.chain.NewBlock(self.coinbase)
if block.Time() == self.chain.CurrentBlock().Time() { parent := self.chain.GetBlock(block.ParentHash())
block.Header().Time++
if block.Time() <= parent.Time() {
block.Header().Time = parent.Header().Time + 1
} }
block.Header().Extra = self.extra block.Header().Extra = self.extra
@ -286,8 +311,10 @@ func (self *worker) makeCurrent() {
current.ignoredTransactors = set.New() current.ignoredTransactors = set.New()
current.lowGasTransactors = set.New() current.lowGasTransactors = set.New()
current.ownedAccounts = accountAddressesSet(accounts) current.ownedAccounts = accountAddressesSet(accounts)
if self.current != nil {
current.localMinedBlocks = self.current.localMinedBlocks
}
parent := self.chain.GetBlock(current.block.ParentHash())
current.coinbase.SetGasPool(core.CalcGasLimit(parent)) current.coinbase.SetGasPool(core.CalcGasLimit(parent))
self.current = current self.current = current
@ -304,6 +331,38 @@ func (w *worker) setGasPrice(p *big.Int) {
w.mux.Post(core.GasPriceChanged{w.gasPrice}) w.mux.Post(core.GasPriceChanged{w.gasPrice})
} }
func (self *worker) isBlockLocallyMined(deepBlockNum uint64) bool {
//Did this instance mine a block at {deepBlockNum} ?
var isLocal = false
for idx, blockNum := range self.current.localMinedBlocks.ints {
if deepBlockNum == blockNum {
isLocal = true
self.current.localMinedBlocks.ints[idx] = 0 //prevent showing duplicate logs
break
}
}
//Short-circuit on false, because the previous and following tests must both be true
if !isLocal {
return false
}
//Does the block at {deepBlockNum} send earnings to my coinbase?
var block = self.chain.GetBlockByNumber(deepBlockNum)
return block.Header().Coinbase == self.coinbase
}
func (self *worker) logLocalMinedBlocks(previous *environment) {
if previous != nil && self.current.localMinedBlocks != nil {
nextBlockNum := self.current.block.Number().Uint64()
for checkBlockNum := previous.block.Number().Uint64(); checkBlockNum < nextBlockNum; checkBlockNum++ {
inspectBlockNum := checkBlockNum - miningLogAtDepth
if self.isBlockLocallyMined(inspectBlockNum) {
glog.V(logger.Info).Infof("🔨 🔗 Mined %d blocks back: block #%v", miningLogAtDepth, inspectBlockNum)
}
}
}
}
func (self *worker) commitNewWork() { func (self *worker) commitNewWork() {
self.mu.Lock() self.mu.Lock()
defer self.mu.Unlock() defer self.mu.Unlock()
@ -312,6 +371,7 @@ func (self *worker) commitNewWork() {
self.currentMu.Lock() self.currentMu.Lock()
defer self.currentMu.Unlock() defer self.currentMu.Unlock()
previous := self.current
self.makeCurrent() self.makeCurrent()
current := self.current current := self.current
@ -347,6 +407,7 @@ func (self *worker) commitNewWork() {
// We only care about logging if we're actually mining // We only care about logging if we're actually mining
if atomic.LoadInt32(&self.mining) == 1 { if atomic.LoadInt32(&self.mining) == 1 {
glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles\n", current.block.Number(), current.tcount, len(uncles)) glog.V(logger.Info).Infof("commit new work on block %v with %d txs & %d uncles\n", current.block.Number(), current.tcount, len(uncles))
self.logLocalMinedBlocks(previous)
} }
for _, hash := range badUncles { for _, hash := range badUncles {