Skip to content

Commit

Permalink
Explicit type check for backend (ethereum#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
renaynay committed Jul 21, 2020
1 parent 816b1d8 commit 2d8fa6b
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 75 deletions.
17 changes: 9 additions & 8 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package main

import (
"fmt"
"github.com/ethereum/go-ethereum/eth"
"math"
"os"
godebug "runtime/debug"
Expand Down Expand Up @@ -376,7 +377,6 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
if err != nil {
utils.Fatalf("Failed to attach to self: %v", err)
}

ethClient := ethclient.NewClient(rpcClient)

go func() {
Expand Down Expand Up @@ -442,23 +442,24 @@ func startNode(ctx *cli.Context, stack *node.Node, backend ethapi.Backend) {
if ctx.GlobalString(utils.SyncModeFlag.Name) == "light" {
utils.Fatalf("Light clients do not support mining")
}
ethBackend, ok := backend.(*eth.EthAPIBackend)
if !ok {
utils.Fatalf("Ethereum service not running: %v", err)
}

// Set the gas price to the limits from the CLI and start mining
gasprice := utils.GlobalBig(ctx, utils.MinerGasPriceFlag.Name)
if ctx.GlobalIsSet(utils.LegacyMinerGasPriceFlag.Name) && !ctx.GlobalIsSet(utils.MinerGasPriceFlag.Name) {
gasprice = utils.GlobalBig(ctx, utils.LegacyMinerGasPriceFlag.Name)
}
txpool := backend.TxPool()
if txpool == nil {
utils.Fatalf("Ethereum service not running: %v", err)
}
txpool.SetGasPrice(gasprice)

ethBackend.TxPool().SetGasPrice(gasprice)
// start mining
threads := ctx.GlobalInt(utils.MinerThreadsFlag.Name)
if ctx.GlobalIsSet(utils.LegacyMinerThreadsFlag.Name) && !ctx.GlobalIsSet(utils.MinerThreadsFlag.Name) {
threads = ctx.GlobalInt(utils.LegacyMinerThreadsFlag.Name)
log.Warn("The flag --minerthreads is deprecated and will be removed in the future, please use --miner.threads")
}
if err := backend.StartMining(threads); err != nil {
if err := ethBackend.StartMining(threads); err != nil {
utils.Fatalf("Failed to start mining: %v", err)
}
}
Expand Down
4 changes: 0 additions & 4 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,6 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine
}

func (b *EthAPIBackend) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
return b.eth.blockchain.GetBlockByNumber(number), nil
}

func (b *EthAPIBackend) CurrentHeader() *types.Header {
return b.eth.blockchain.CurrentHeader()
}
Expand Down
100 changes: 69 additions & 31 deletions ethstats/ethstats.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/rpc"
"math/big"
"net/http"
"regexp"
Expand All @@ -36,7 +40,6 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
Expand All @@ -56,14 +59,29 @@ const (
chainHeadChanSize = 10
)

// Backend encompasses the backend behaviors needed for the ethstats service.
type Backend ethapi.Backend
type backend interface{
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription
CurrentHeader() *types.Header
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
GetTd(blockHash common.Hash) *big.Int
Stats() (pending int, queued int)
Downloader() *downloader.Downloader
}

type fullNodeBackend interface{
backend
Miner() *miner.Miner
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
CurrentBlock() *types.Block
SuggestPrice(ctx context.Context) (*big.Int, error)
}

// Service implements an Ethereum netstats reporting daemon that pushes local
// chain statistics up to a monitoring server.
type Service struct {
server *p2p.Server // Peer-to-peer server to retrieve networking infos
backend Backend
backend backend
engine consensus.Engine // Consensus engine to retrieve variadic block fields

node string // Name of the node to display on the monitoring page
Expand All @@ -75,7 +93,7 @@ type Service struct {
}

// New returns a monitoring service ready for stats reporting.
func New(node *node.Node, backend Backend, engine consensus.Engine, url string) error {
func New(node *node.Node, backend backend, engine consensus.Engine, url string) error {
// Parse the netstats connection url
re := regexp.MustCompile("([^:@]*)(:([^@]*))?@(.+)")
parts := re.FindStringSubmatch(url)
Expand Down Expand Up @@ -530,18 +548,30 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats {
uncles []*types.Header
)

// Full nodes have all needed information available
if block == nil {
block = s.backend.CurrentBlock()
}
header = block.Header()
td = s.backend.GetTd(header.Hash()) // TODO is it okay to just call `GetTD` with just the hash and not number?
// check if backend is a full node
fullBackend, ok := s.backend.(fullNodeBackend)
if ok {
if block == nil {
block = fullBackend.CurrentBlock()
}
header = block.Header()
td = fullBackend.GetTd(header.Hash())

txs = make([]txStats, len(block.Transactions()))
for i, tx := range block.Transactions() {
txs[i].Hash = tx.Hash()
txs = make([]txStats, len(block.Transactions()))
for i, tx := range block.Transactions() {
txs[i].Hash = tx.Hash()
}
uncles = block.Uncles()
} else {
// Light nodes would need on-demand lookups for transactions/uncles, skip
if block != nil {
header = block.Header()
} else {
header = s.backend.CurrentHeader()
}
td = s.backend.GetTd(header.Hash())
txs = []txStats{}
}
uncles = block.Uncles()

// Assemble and return the block stats
author, _ := s.engine.Author(header)
Expand Down Expand Up @@ -585,12 +615,16 @@ func (s *Service) reportHistory(conn *websocket.Conn, list []uint64) error {
// Gather the batch of blocks to report
history := make([]*blockStats, len(indexes))
for i, number := range indexes {
fullBackend, ok := s.backend.(fullNodeBackend)
// Retrieve the next block if it's known to us
block, err := s.backend.GetBlockByNumber(context.Background(), number)
if err != nil {
return err
var block *types.Block
if ok {
block, _ = fullBackend.BlockByNumber(context.Background(), rpc.BlockNumber(number)) // TODO ignore error here ?
} else {
if header, _ := s.backend.HeaderByNumber(context.Background(), rpc.BlockNumber(number)); header != nil {
block = types.NewBlockWithHeader(header)
}
}

// If we do have the block, add to the history and continue
if block != nil {
history[len(history)-1-i] = s.assembleBlockStats(block)
Expand Down Expand Up @@ -652,27 +686,31 @@ type nodeStats struct {
Uptime int `json:"uptime"`
}

// reportPending retrieves various stats about the node at the networking and
// reportStats retrieves various stats about the node at the networking and
// mining layer and reports it to the stats server.
func (s *Service) reportStats(conn *websocket.Conn) error {
// Gather the syncing and mining infos from the local miner instance
var (
mining bool
hashrate int
syncing bool
gasprice int
)
// check if backend is a full node
fullBackend, ok := s.backend.(fullNodeBackend)
if ok {
mining = fullBackend.Miner().Mining()
hashrate = int(fullBackend.Miner().HashRate())

mine := s.backend.Miner()
if mine != nil {
mining = mine.Mining()
hashrate = int(s.backend.Miner().HashRate())
}

sync := s.backend.Downloader().Progress()
syncing := s.backend.CurrentHeader().Number.Uint64() >= sync.HighestBlock

price, _ := s.backend.SuggestPrice(context.Background())
gasprice := int(price.Uint64())
sync := fullBackend.Downloader().Progress()
syncing = fullBackend.CurrentHeader().Number.Uint64() >= sync.HighestBlock

price, _ := fullBackend.SuggestPrice(context.Background())
gasprice = int(price.Uint64())
} else {
sync := s.backend.Downloader().Progress()
syncing = s.backend.CurrentHeader().Number.Uint64() >= sync.HighestBlock
}
// Assemble the node stats and send it to the server
log.Trace("Sending node details to ethstats")

Expand Down
5 changes: 0 additions & 5 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -218,20 +218,15 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6 h1:a6cXbcDDUkSBlpnkWV1bJ+vv3mOgQEltEJ2rPxroVu0=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/urfave/cli.v1 v1.20.0 h1:NdAVW6RYxDif9DhDHaAortIu956m2c0v+09AZBPTbE0=
gopkg.in/urfave/cli.v1 v1.20.0/go.mod h1:vuBzUtMdQeixQj8LVd+/98pzhxNGQoyuPBlsXHOQNO0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
9 changes: 1 addition & 8 deletions internal/ethapi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import (
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
Expand All @@ -47,8 +46,8 @@ type Backend interface {
ChainDb() ethdb.Database
AccountManager() *accounts.Manager
ExtRPCEnabled() bool
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection
RPCTxFeeCap() float64 // global tx fee cap for all transaction related APIs
RPCGasCap() uint64 // global gas cap for eth_call over rpc: DoS protection

// Blockchain API
SetHead(number uint64)
Expand All @@ -60,7 +59,6 @@ type Backend interface {
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error)
GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error)
StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error)
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
Expand All @@ -78,13 +76,8 @@ type Backend interface {
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
Stats() (pending int, queued int)
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
TxPool() *core.TxPool
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription

// Mining API
Miner() *miner.Miner
StartMining(threads int) error

// Filter API
BloomStatus() (uint64, uint64)
GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
Expand Down
19 changes: 0 additions & 19 deletions les/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package les
import (
"context"
"errors"
"fmt"
"math/big"

"github.com/ethereum/go-ethereum/accounts"
Expand All @@ -36,7 +35,6 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
Expand Down Expand Up @@ -290,23 +288,6 @@ func (b *LesApiBackend) Engine() consensus.Engine {
return b.eth.engine
}

func (b *LesApiBackend) GetBlockByNumber(ctx context.Context, number uint64) (*types.Block, error) {
header := b.eth.blockchain.GetHeaderByNumber(number)
return types.NewBlockWithHeader(header), nil // TODO is this okay?
}

func (b *LesApiBackend) CurrentHeader() *types.Header {
return b.eth.blockchain.CurrentHeader()
}

func (b *LesApiBackend) Miner() *miner.Miner {
return nil
}

func (b *LesApiBackend) StartMining(threads int) error {
return fmt.Errorf("Light clients do not support mining") // TODO is this okay?
}

func (b *LesApiBackend) TxPool() *core.TxPool {
return nil // TODO is this okay?
}

0 comments on commit 2d8fa6b

Please sign in to comment.