diff options
-rw-r--r-- | blockpool/blockpool.go | 3 | ||||
-rw-r--r-- | blockpool/peers.go | 46 | ||||
-rw-r--r-- | blockpool/section.go | 4 | ||||
-rw-r--r-- | blockpool/status.go | 6 | ||||
-rw-r--r-- | cmd/ethereum/main.go | 2 | ||||
-rw-r--r-- | cmd/evm/main.go | 58 | ||||
-rw-r--r-- | eth/backend.go | 5 | ||||
-rw-r--r-- | miner/miner.go | 8 | ||||
-rw-r--r-- | rpc/api.go | 23 | ||||
-rw-r--r-- | rpc/miner_agest.go | 70 | ||||
-rw-r--r-- | xeth/xeth.go | 2 |
11 files changed, 162 insertions, 65 deletions
diff --git a/blockpool/blockpool.go b/blockpool/blockpool.go index 09b9e7b0b..1ca97e0ca 100644 --- a/blockpool/blockpool.go +++ b/blockpool/blockpool.go @@ -757,6 +757,9 @@ func (self *BlockPool) checkTD(nodes ...*node) { plog.DebugDetailf("peer td %v =?= block td %v", n.td, n.block.Td) if n.td.Cmp(n.block.Td) != 0 { self.peers.peerError(n.blockBy, ErrIncorrectTD, "on block %x", n.hash) + self.status.lock.Lock() + self.status.badPeers[n.blockBy]++ + self.status.lock.Unlock() } } } diff --git a/blockpool/peers.go b/blockpool/peers.go index 80168b206..6bff38e87 100644 --- a/blockpool/peers.go +++ b/blockpool/peers.go @@ -46,7 +46,8 @@ type peer struct { // timers for head section process blockHashesRequestTimer <-chan time.Time blocksRequestTimer <-chan time.Time - suicideC <-chan time.Time + headInfoTimer <-chan time.Time + bestIdleTimer <-chan time.Time addToBlacklist func(id string) @@ -256,8 +257,10 @@ func (self *peers) addPeer( plog.Debugf("addPeer: <%s> already the best peer. Request new head section info from %s", id, hex(currentBlockHash)) if (previousBlockHash != common.Hash{}) { + plog.DebugDetailf("addPeer: <%s> head changed: %s -> %s ", id, hex(previousBlockHash), hex(currentBlockHash)) + p.headSectionC <- nil if entry := self.bp.get(previousBlockHash); entry != nil { - p.headSectionC <- nil + plog.DebugDetailf("addPeer: <%s> previous head : %v found in pool, activate", id, hex(previousBlockHash)) self.bp.activateChain(entry.section, p, nil) p.sections = append(p.sections, previousBlockHash) } @@ -410,7 +413,8 @@ func (self *peer) handleSection(sec *section) { self.bp.syncing() } - self.suicideC = time.After(self.bp.Config.BlockHashesTimeout) + self.headInfoTimer = time.After(self.bp.Config.BlockHashesTimeout) + self.bestIdleTimer = nil plog.DebugDetailf("HeadSection: <%s> head block hash changed (mined block received). New head %s", self.id, hex(self.currentBlockHash)) } else { @@ -418,8 +422,10 @@ func (self *peer) handleSection(sec *section) { self.idle = true self.bp.wg.Done() } - plog.DebugDetailf("HeadSection: <%s> (head: %s) head section [%s] created", self.id, hex(self.currentBlockHash), sectionhex(sec)) - self.suicideC = time.After(self.bp.Config.IdleBestPeerTimeout) + + self.headInfoTimer = nil + self.bestIdleTimer = time.After(self.bp.Config.IdleBestPeerTimeout) + plog.DebugDetailf("HeadSection: <%s> (head: %s) head section [%s] created. Idle...", self.id, hex(self.currentBlockHash), sectionhex(sec)) } } @@ -452,14 +458,13 @@ func (self *peer) getCurrentBlock(currentBlock *types.Block) { self.blocksRequestTimer = nil } -func (self *peer) getBlockHashes() { +func (self *peer) getBlockHashes() bool { //if connecting parent is found if self.bp.hasBlock(self.parentHash) { plog.DebugDetailf("HeadSection: <%s> parent block %s found in blockchain", self.id, hex(self.parentHash)) err := self.bp.insertChain(types.Blocks([]*types.Block{self.currentBlock})) self.bp.status.lock.Lock() - self.bp.status.badPeers[self.id]++ self.bp.status.values.BlocksInChain++ self.bp.status.values.BlocksInPool-- if err != nil { @@ -469,18 +474,18 @@ func (self *peer) getBlockHashes() { if self.currentBlock.Td != nil { if self.td.Cmp(self.currentBlock.Td) != 0 { self.addError(ErrIncorrectTD, "on block %x", self.currentBlockHash) + self.bp.status.badPeers[self.id]++ } } - headKey := self.parentHash.Str() + headKey := self.parentHash height := self.bp.status.chain[headKey] + 1 - self.bp.status.chain[self.currentBlockHash.Str()] = height + self.bp.status.chain[self.currentBlockHash] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height } delete(self.bp.status.chain, headKey) } self.bp.status.lock.Unlock() - } else { if parent := self.bp.get(self.parentHash); parent != nil { if self.bp.get(self.currentBlockHash) == nil { @@ -501,15 +506,17 @@ func (self *peer) getBlockHashes() { plog.DebugDetailf("HeadSection: <%s> section [%s] requestBlockHashes", self.id, sectionhex(self.headSection)) self.requestBlockHashes(self.currentBlockHash) self.blockHashesRequestTimer = time.After(self.bp.Config.BlockHashesRequestInterval) - return + return false } } self.blockHashesRequestTimer = nil if !self.idle { self.idle = true - self.suicideC = nil + self.headInfoTimer = nil + self.bestIdleTimer = time.After(self.bp.Config.IdleBestPeerTimeout) self.bp.wg.Done() } + return true } // main loop for head section process @@ -522,9 +529,7 @@ func (self *peer) run() { self.blockHashesRequestTimer = nil self.blocksRequestTimer = time.After(0) - self.suicideC = time.After(self.bp.Config.BlockHashesTimeout) - - var quit <-chan time.Time + self.headInfoTimer = time.After(self.bp.Config.BlockHashesTimeout) var ping = time.NewTicker(5 * time.Second) @@ -539,13 +544,6 @@ LOOP: // if sec == nil, it signals that chain info has updated (new block message) case sec := <-self.headSectionC: self.handleSection(sec) - if sec == nil { - plog.Debugf("HeadSection: <%s> (headsection [%s], received: [%s]) quit channel set to nil, catchup happening", self.id, sectionhex(self.headSection), sectionhex(sec)) - quit = nil - } else { - plog.Debugf("HeadSection: <%s> (headsection [%s], received: [%s]) quit channel set to go off in IdleBestPeerTimeout", self.id, sectionhex(self.headSection), sectionhex(sec)) - quit = time.After(self.bp.Config.IdleBestPeerTimeout) - } // periodic check for block hashes or parent block/section case <-self.blockHashesRequestTimer: @@ -560,7 +558,7 @@ LOOP: self.getCurrentBlock(nil) // quitting on timeout - case <-self.suicideC: + case <-self.headInfoTimer: self.peerError(self.bp.peers.errors.New(ErrInsufficientChainInfo, "timed out without providing block hashes or head block (td: %v, head: %s)", self.td, hex(self.currentBlockHash))) self.bp.status.lock.Lock() @@ -583,7 +581,7 @@ LOOP: break LOOP // quit - case <-quit: + case <-self.bestIdleTimer: self.peerError(self.bp.peers.errors.New(ErrIdleTooLong, "timed out without providing new blocks (td: %v, head: %s)...quitting", self.td, hex(self.currentBlockHash))) self.bp.status.lock.Lock() diff --git a/blockpool/section.go b/blockpool/section.go index bcbd71cfc..14e91cf33 100644 --- a/blockpool/section.go +++ b/blockpool/section.go @@ -176,9 +176,9 @@ func (self *section) addSectionToBlockChain(p *peer) { self.bp.status.lock.Lock() if err == nil { - headKey := blocks[0].ParentHash().Str() + headKey := blocks[0].ParentHash() height := self.bp.status.chain[headKey] + len(blocks) - self.bp.status.chain[blocks[len(blocks)-1].Hash().Str()] = height + self.bp.status.chain[blocks[len(blocks)-1].Hash()] = height if height > self.bp.status.values.LongestChain { self.bp.status.values.LongestChain = height } diff --git a/blockpool/status.go b/blockpool/status.go index 4529c77fe..02e358510 100644 --- a/blockpool/status.go +++ b/blockpool/status.go @@ -3,6 +3,8 @@ package blockpool import ( "fmt" "sync" + + "github.com/ethereum/go-ethereum/common" ) type statusValues struct { @@ -26,7 +28,7 @@ type statusValues struct { type status struct { lock sync.Mutex values statusValues - chain map[string]int + chain map[common.Hash]int peers map[string]int bestPeers map[string]int badPeers map[string]int @@ -35,7 +37,7 @@ type status struct { func newStatus() *status { return &status{ - chain: make(map[string]int), + chain: make(map[common.Hash]int), peers: make(map[string]int), bestPeers: make(map[string]int), badPeers: make(map[string]int), diff --git a/cmd/ethereum/main.go b/cmd/ethereum/main.go index 17dcbb59e..e351453b1 100644 --- a/cmd/ethereum/main.go +++ b/cmd/ethereum/main.go @@ -42,7 +42,7 @@ import ( const ( ClientIdentifier = "Ethereum(G)" - Version = "0.9.1" + Version = "0.9.2" ) var ( diff --git a/cmd/evm/main.go b/cmd/evm/main.go index af15dd4d4..17137e4bb 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -30,10 +30,10 @@ import ( "runtime" "time" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/vm" @@ -60,12 +60,12 @@ func main() { logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel))) db, _ := ethdb.NewMemDatabase() - statedb := state.New(nil, db) - sender := statedb.NewStateObject([]byte("sender")) - receiver := statedb.NewStateObject([]byte("receiver")) + statedb := state.New(common.Hash{}, db) + sender := statedb.NewStateObject(common.StringToAddress("sender")) + receiver := statedb.NewStateObject(common.StringToAddress("receiver")) receiver.SetCode(common.Hex2Bytes(*code)) - vmenv := NewEnv(statedb, []byte("evmuser"), common.Big(*value)) + vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(*value)) tstart := time.Now() @@ -98,7 +98,7 @@ type VMEnv struct { state *state.StateDB block *types.Block - transactor []byte + transactor *common.Address value *big.Int depth int @@ -106,33 +106,32 @@ type VMEnv struct { time int64 } -func NewEnv(state *state.StateDB, transactor []byte, value *big.Int) *VMEnv { +func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int) *VMEnv { return &VMEnv{ state: state, - transactor: transactor, + transactor: &transactor, value: value, time: time.Now().Unix(), } } -func (self *VMEnv) State() *state.StateDB { return self.state } -func (self *VMEnv) Origin() []byte { return self.transactor } -func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 } -func (self *VMEnv) PrevHash() []byte { return make([]byte, 32) } -func (self *VMEnv) Coinbase() []byte { return self.transactor } -func (self *VMEnv) Time() int64 { return self.time } -func (self *VMEnv) Difficulty() *big.Int { return common.Big1 } -func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) } -func (self *VMEnv) Value() *big.Int { return self.value } -func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) } -func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy } -func (self *VMEnv) Depth() int { return 0 } -func (self *VMEnv) SetDepth(i int) { self.depth = i } -func (self *VMEnv) GetHash(n uint64) []byte { +func (self *VMEnv) State() *state.StateDB { return self.state } +func (self *VMEnv) Origin() common.Address { return *self.transactor } +func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 } +func (self *VMEnv) Coinbase() common.Address { return *self.transactor } +func (self *VMEnv) Time() int64 { return self.time } +func (self *VMEnv) Difficulty() *big.Int { return common.Big1 } +func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) } +func (self *VMEnv) Value() *big.Int { return self.value } +func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) } +func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy } +func (self *VMEnv) Depth() int { return 0 } +func (self *VMEnv) SetDepth(i int) { self.depth = i } +func (self *VMEnv) GetHash(n uint64) common.Hash { if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 { return self.block.Hash() } - return nil + return common.Hash{} } func (self *VMEnv) AddLog(log state.Log) { self.state.AddLog(log) @@ -141,23 +140,24 @@ func (self *VMEnv) Transfer(from, to vm.Account, amount *big.Int) error { return vm.Transfer(from, to, amount) } -func (self *VMEnv) vm(addr, data []byte, gas, price, value *big.Int) *core.Execution { +func (self *VMEnv) vm(addr *common.Address, data []byte, gas, price, value *big.Int) *core.Execution { return core.NewExecution(self, addr, data, gas, price, value) } -func (self *VMEnv) Call(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { - exe := self.vm(addr, data, gas, price, value) +func (self *VMEnv) Call(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { + exe := self.vm(&addr, data, gas, price, value) ret, err := exe.Call(addr, caller) self.Gas = exe.Gas return ret, err } -func (self *VMEnv) CallCode(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error) { - exe := self.vm(caller.Address(), data, gas, price, value) +func (self *VMEnv) CallCode(caller vm.ContextRef, addr common.Address, data []byte, gas, price, value *big.Int) ([]byte, error) { + a := caller.Address() + exe := self.vm(&a, data, gas, price, value) return exe.Call(addr, caller) } -func (self *VMEnv) Create(caller vm.ContextRef, addr, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { +func (self *VMEnv) Create(caller vm.ContextRef, addr *common.Address, data []byte, gas, price, value *big.Int) ([]byte, error, vm.ContextRef) { exe := self.vm(addr, data, gas, price, value) return exe.Create(caller) } diff --git a/eth/backend.go b/eth/backend.go index c253a064e..06c3cbd17 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -303,8 +303,9 @@ func (s *Ethereum) StartMining() error { return nil } -func (s *Ethereum) StopMining() { s.miner.Stop() } -func (s *Ethereum) IsMining() bool { return s.miner.Mining() } +func (s *Ethereum) StopMining() { s.miner.Stop() } +func (s *Ethereum) IsMining() bool { return s.miner.Mining() } +func (s *Ethereum) Miner() *miner.Miner { return s.miner } // func (s *Ethereum) Logger() logger.LogSystem { return s.logger } func (s *Ethereum) Name() string { return s.net.Name } diff --git a/miner/miner.go b/miner/miner.go index ccc19c754..d46fabc1e 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -26,7 +26,7 @@ type Miner struct { func New(eth core.Backend, pow pow.PoW, minerThreads int) *Miner { // note: minerThreads is currently ignored because // ethash is not thread safe. - return &Miner{eth: eth, pow: pow} + return &Miner{eth: eth, pow: pow, worker: newWorker(common.Address{}, eth)} } func (self *Miner) Mining() bool { @@ -35,7 +35,7 @@ func (self *Miner) Mining() bool { func (self *Miner) Start(coinbase common.Address) { self.mining = true - self.worker = newWorker(coinbase, self.eth) + self.worker.coinbase = coinbase self.worker.register(NewCpuMiner(0, self.pow)) self.pow.(*ethash.Ethash).UpdateDAG() @@ -44,6 +44,10 @@ func (self *Miner) Start(coinbase common.Address) { self.worker.commitNewWork() } +func (self *Miner) Register(agent Agent) { + self.worker.register(agent) +} + func (self *Miner) Stop() { self.mining = false self.worker.stop() diff --git a/rpc/api.go b/rpc/api.go index 34d4ff0fc..d5e18eec8 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -17,15 +17,20 @@ type EthereumApi struct { eth *xeth.XEth xethMu sync.RWMutex db common.Database + + // Miner agent + agent *Agent } func NewEthereumApi(eth *xeth.XEth, dataDir string) *EthereumApi { // What about when dataDir is empty? db, _ := ethdb.NewLDBDatabase(path.Join(dataDir, "dapps")) api := &EthereumApi{ - eth: eth, - db: db, + eth: eth, + db: db, + agent: NewAgent(), } + eth.Backend().Miner().Register(api.agent) return api } @@ -342,7 +347,13 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } opts := toFilterOptions(args) *reply = NewLogsRes(p.xeth().AllLogs(opts)) - case "eth_getWork", "eth_submitWork": + case "eth_getWork": + *reply = p.getWork() + case "eth_submitWork": + // TODO what is the reply here? + // TODO what are the arguments? + p.agent.SetResult(0, common.Hash{}, common.Hash{}) + return NewNotImplementedError(req.Method) case "db_putString": args := new(DbArgs) @@ -427,6 +438,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } *reply = p.xeth().Whisper().Messages(args.Id) + // case "eth_register": // // Placeholder for actual type // args := new(HashIndexArgs) @@ -454,6 +466,11 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return nil } +func (p *EthereumApi) getWork() string { + p.xeth().SetMining(true) + return p.agent.GetWork().Hex() +} + func toFilterOptions(options *BlockFilterArgs) *core.FilterOptions { var opts core.FilterOptions diff --git a/rpc/miner_agest.go b/rpc/miner_agest.go new file mode 100644 index 000000000..64dba82a6 --- /dev/null +++ b/rpc/miner_agest.go @@ -0,0 +1,70 @@ +package rpc + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/miner" +) + +type Agent struct { + work *types.Block + currentWork *types.Block + + quit chan struct{} + workCh chan *types.Block + returnCh chan<- miner.Work +} + +func NewAgent() *Agent { + agent := &Agent{} + go agent.run() + + return agent +} + +func (a *Agent) Work() chan<- *types.Block { + return a.workCh +} + +func (a *Agent) SetWorkCh(returnCh chan<- miner.Work) { + a.returnCh = returnCh +} + +func (a *Agent) Start() { + a.quit = make(chan struct{}) + a.workCh = make(chan *types.Block, 1) +} + +func (a *Agent) Stop() { + close(a.quit) + close(a.workCh) +} + +func (a *Agent) GetHashRate() int64 { return 0 } + +func (a *Agent) run() { +out: + for { + select { + case <-a.quit: + break out + case work := <-a.workCh: + a.work = work + } + } +} + +func (a *Agent) GetWork() common.Hash { + // XXX Wait here untill work != nil ?. + if a.work != nil { + return a.work.HashNoNonce() + } + return common.Hash{} +} + +func (a *Agent) SetResult(nonce uint64, mixDigest, seedHash common.Hash) { + // Make sure the external miner was working on the right hash + if a.currentWork != nil && a.work != nil && a.currentWork.Hash() == a.work.Hash() { + a.returnCh <- miner.Work{a.currentWork.Number().Uint64(), nonce, mixDigest.Bytes(), seedHash.Bytes()} + } +} diff --git a/xeth/xeth.go b/xeth/xeth.go index 9f183aa61..d3c3131d4 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -17,6 +17,7 @@ import ( "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event/filter" "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/whisper" @@ -43,6 +44,7 @@ type Backend interface { ExtraDb() common.Database EventMux() *event.TypeMux Whisper() *whisper.Whisper + Miner() *miner.Miner IsMining() bool StartMining() error |