diff --git a/cmd/geth/main.go b/cmd/geth/main.go index b8e2a78b8..68aa7d45f 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -244,6 +244,12 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso // Start system runtime metrics collection go metrics.CollectProcessMetrics(3 * time.Second) + // This should be the only place where reporting is enabled + // because it is not intended to run while testing. + // In addition to this check, bad block reports are sent only + // for chains with the main network genesis block and network id 1. + eth.EnableBadBlockReporting = true + utils.SetupNetwork(ctx) // Deprecation warning. diff --git a/core/bad_block.go b/core/bad_block.go deleted file mode 100644 index cd3fb575a..000000000 --- a/core/bad_block.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package core - -import ( - "bytes" - "encoding/json" - "io/ioutil" - "net/http" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/logger/glog" - "github.com/ethereum/go-ethereum/rlp" -) - -// DisabledBadBlockReporting can be set to prevent blocks being reported. -var DisableBadBlockReporting = true - -// ReportBlock reports the block to the block reporting tool found at -// badblocks.ethdev.com -func ReportBlock(block *types.Block, err error) { - if DisableBadBlockReporting { - return - } - - const url = "https://badblocks.ethdev.com" - - blockRlp, _ := rlp.EncodeToBytes(block) - data := map[string]interface{}{ - "block": common.Bytes2Hex(blockRlp), - "errortype": err.Error(), - "hints": map[string]interface{}{ - "receipts": "NYI", - "vmtrace": "NYI", - }, - } - jsonStr, _ := json.Marshal(map[string]interface{}{"method": "eth_badBlock", "params": []interface{}{data}, "id": "1", "jsonrpc": "2.0"}) - - req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr)) - req.Header.Set("Content-Type", "application/json") - - client := &http.Client{} - resp, err := client.Do(req) - if err != nil { - glog.V(logger.Error).Infoln("POST err:", err) - return - } - defer resp.Body.Close() - - if glog.V(logger.Debug) { - glog.Infoln("response Status:", resp.Status) - glog.Infoln("response Headers:", resp.Header) - body, _ := ioutil.ReadAll(resp.Body) - glog.Infoln("response Body:", string(body)) - } -} diff --git a/core/blockchain.go b/core/blockchain.go index 4598800d5..171a49e53 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1117,15 +1117,12 @@ func (self *BlockChain) update() { } } -// reportBlock reports the given block and error using the canonical block -// reporting tool. Reporting the block to the service is handled in a separate -// goroutine. +// reportBlock logs a bad block error. func reportBlock(block *types.Block, err error) { if glog.V(logger.Error) { glog.Errorf("Bad block #%v (%s)\n", block.Number(), block.Hash().Hex()) glog.Errorf(" %v", err) } - go ReportBlock(block, err) } // InsertHeaderChain attempts to insert the given header chain in to the local diff --git a/core/types/block.go b/core/types/block.go index 387a063ae..37b6f3ec1 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -141,8 +141,10 @@ type Block struct { // of the chain up to and including the block. td *big.Int - // ReceivedAt is used by package eth to track block propagation time. - ReceivedAt time.Time + // These fields are used by package eth to track + // inter-peer block relay. + ReceivedAt time.Time + ReceivedFrom interface{} } // DeprecatedTd is an old relic for extracting the TD of a block. It is in the diff --git a/eth/bad_block.go b/eth/bad_block.go new file mode 100644 index 000000000..3a6c3d85c --- /dev/null +++ b/eth/bad_block.go @@ -0,0 +1,74 @@ +// Copyright 2015 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package eth + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/logger/glog" + "github.com/ethereum/go-ethereum/rlp" +) + +const ( + // The Ethereum main network genesis block. + defaultGenesisHash = "0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3" + badBlocksURL = "https://badblocks.ethdev.com" +) + +var EnableBadBlockReporting = false + +func sendBadBlockReport(block *types.Block, err error) { + if !EnableBadBlockReporting { + return + } + + var ( + blockRLP, _ = rlp.EncodeToBytes(block) + params = map[string]interface{}{ + "block": common.Bytes2Hex(blockRLP), + "blockHash": block.Hash().Hex(), + "errortype": err.Error(), + "client": "go", + } + ) + if !block.ReceivedAt.IsZero() { + params["receivedAt"] = block.ReceivedAt.UTC().String() + } + if p, ok := block.ReceivedFrom.(*peer); ok { + params["receivedFrom"] = map[string]interface{}{ + "enode": fmt.Sprintf("enode://%x@%v", p.ID(), p.RemoteAddr()), + "name": p.Name(), + "protocolVersion": p.version, + } + } + jsonStr, _ := json.Marshal(map[string]interface{}{"method": "eth_badBlock", "id": "1", "jsonrpc": "2.0", "params": []interface{}{params}}) + client := http.Client{Timeout: 8 * time.Second} + resp, err := client.Post(badBlocksURL, "application/json", bytes.NewReader(jsonStr)) + if err != nil { + glog.V(logger.Debug).Infoln(err) + return + } + glog.V(logger.Debug).Infof("Bad Block Report posted (%d)", resp.StatusCode) + resp.Body.Close() +} diff --git a/eth/handler.go b/eth/handler.go index 202acdc78..58869a2ee 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -83,6 +83,8 @@ type ProtocolManager struct { // wait group is used for graceful shutdowns during downloading // and processing wg sync.WaitGroup + + badBlockReportingEnabled bool } // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable @@ -150,7 +152,7 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int, // Construct the different synchronisation mechanisms manager.downloader = downloader.New(chaindb, manager.eventMux, blockchain.HasHeader, blockchain.HasBlockAndState, blockchain.GetHeader, blockchain.GetBlock, blockchain.CurrentHeader, blockchain.CurrentBlock, blockchain.CurrentFastBlock, blockchain.FastSyncCommitHead, - blockchain.GetTd, blockchain.InsertHeaderChain, blockchain.InsertChain, blockchain.InsertReceiptChain, blockchain.Rollback, + blockchain.GetTd, blockchain.InsertHeaderChain, manager.insertChain, blockchain.InsertReceiptChain, blockchain.Rollback, manager.removePeer) validator := func(block *types.Block, parent *types.Block) error { @@ -159,11 +161,24 @@ func NewProtocolManager(config *core.ChainConfig, fastSync bool, networkId int, heighter := func() uint64 { return blockchain.CurrentBlock().NumberU64() } - manager.fetcher = fetcher.New(blockchain.GetBlock, validator, manager.BroadcastBlock, heighter, blockchain.InsertChain, manager.removePeer) + manager.fetcher = fetcher.New(blockchain.GetBlock, validator, manager.BroadcastBlock, heighter, manager.insertChain, manager.removePeer) + + if blockchain.Genesis().Hash().Hex() == defaultGenesisHash && networkId == 1 { + glog.V(logger.Debug).Infoln("Bad Block Reporting is enabled") + manager.badBlockReportingEnabled = true + } return manager, nil } +func (pm *ProtocolManager) insertChain(blocks types.Blocks) (i int, err error) { + i, err = pm.blockchain.InsertChain(blocks) + if pm.badBlockReportingEnabled && core.IsValidationErr(err) && i < len(blocks) { + go sendBadBlockReport(blocks[i], err) + } + return i, err +} + func (pm *ProtocolManager) removePeer(id string) { // Short circuit if the peer was already removed peer := pm.peers.Peer(id) @@ -378,6 +393,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { // Update the receive timestamp of each block for _, block := range blocks { block.ReceivedAt = msg.ReceivedAt + block.ReceivedFrom = p } // Filter out any explicitly requested blocks, deliver the rest to the downloader if blocks := pm.fetcher.FilterBlocks(blocks); len(blocks) > 0 { @@ -664,6 +680,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { return errResp(ErrDecode, "block validation %v: %v", msg, err) } request.Block.ReceivedAt = msg.ReceivedAt + request.Block.ReceivedFrom = p // Mark the peer as owning the block and schedule it for import p.MarkBlock(request.Block.Hash()) diff --git a/tests/init.go b/tests/init.go index 5112b274d..0c07f8b23 100644 --- a/tests/init.go +++ b/tests/init.go @@ -25,8 +25,6 @@ import ( "net/http" "os" "path/filepath" - - "github.com/ethereum/go-ethereum/core" ) var ( @@ -59,11 +57,6 @@ var ( VmSkipTests = []string{} ) -// Disable reporting bad blocks for the tests -func init() { - core.DisableBadBlockReporting = true -} - func readJson(reader io.Reader, value interface{}) error { data, err := ioutil.ReadAll(reader) if err != nil {