aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPéter Szilágyi <peterke@gmail.com>2019-06-20 14:54:53 +0800
committerGitHub <noreply@github.com>2019-06-20 14:54:53 +0800
commitc94068a8bbbc111e9886c928afddabcdd7be131a (patch)
tree0e158cd96f59a7c9c99e1940657411d6e851db1f
parent8d815e365cd2cda2e865dd2e272ebb5a3d4b8772 (diff)
parente3ec77f50e7e11c7f38bc87b1981afe9df240a2a (diff)
downloadgo-tangerine-c94068a8bbbc111e9886c928afddabcdd7be131a.tar
go-tangerine-c94068a8bbbc111e9886c928afddabcdd7be131a.tar.gz
go-tangerine-c94068a8bbbc111e9886c928afddabcdd7be131a.tar.bz2
go-tangerine-c94068a8bbbc111e9886c928afddabcdd7be131a.tar.lz
go-tangerine-c94068a8bbbc111e9886c928afddabcdd7be131a.tar.xz
go-tangerine-c94068a8bbbc111e9886c928afddabcdd7be131a.tar.zst
go-tangerine-c94068a8bbbc111e9886c928afddabcdd7be131a.zip
Merge pull request #19700 from karalabe/cleanup-graphql
cmd, graphql, node: graphql flag polishes, les integration
-rw-r--r--cmd/geth/config.go9
-rw-r--r--cmd/geth/usage.go13
-rw-r--r--cmd/utils/flags.go90
-rw-r--r--graphql/graphiql.go10
-rw-r--r--graphql/graphql.go110
-rw-r--r--graphql/graphql_test.go3
-rw-r--r--graphql/service.go103
-rw-r--r--internal/ethapi/backend.go13
-rw-r--r--node/defaults.go16
9 files changed, 203 insertions, 164 deletions
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index 8f0bae822..3b63d6913 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -30,7 +30,6 @@ import (
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/dashboard"
"github.com/ethereum/go-ethereum/eth"
- "github.com/ethereum/go-ethereum/graphql"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
@@ -177,14 +176,10 @@ func makeFullNode(ctx *cli.Context) *node.Node {
}
utils.RegisterShhService(stack, &cfg.Shh)
}
-
- // Configure GraphQL if required
+ // Configure GraphQL if requested
if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) {
- if err := graphql.RegisterGraphQLService(stack, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts); err != nil {
- utils.Fatalf("Failed to register the Ethereum service: %v", err)
- }
+ utils.RegisterGraphQLService(stack, cfg.Node.GraphQLEndpoint(), cfg.Node.GraphQLCors, cfg.Node.GraphQLVirtualHosts, cfg.Node.HTTPTimeouts)
}
-
// Add the Ethereum Stats daemon if requested.
if cfg.Ethstats.URL != "" {
utils.RegisterEthStatsService(stack, cfg.Ethstats.URL)
diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go
index 4cc77b912..58a3b87a4 100644
--- a/cmd/geth/usage.go
+++ b/cmd/geth/usage.go
@@ -156,20 +156,25 @@ var AppHelpFlagGroups = []flagGroup{
{
Name: "API AND CONSOLE",
Flags: []cli.Flag{
+ utils.IPCDisabledFlag,
+ utils.IPCPathFlag,
utils.RPCEnabledFlag,
utils.RPCListenAddrFlag,
utils.RPCPortFlag,
utils.RPCApiFlag,
utils.RPCGlobalGasCap,
+ utils.RPCCORSDomainFlag,
+ utils.RPCVirtualHostsFlag,
utils.WSEnabledFlag,
utils.WSListenAddrFlag,
utils.WSPortFlag,
utils.WSApiFlag,
utils.WSAllowedOriginsFlag,
- utils.IPCDisabledFlag,
- utils.IPCPathFlag,
- utils.RPCCORSDomainFlag,
- utils.RPCVirtualHostsFlag,
+ utils.GraphQLEnabledFlag,
+ utils.GraphQLListenAddrFlag,
+ utils.GraphQLPortFlag,
+ utils.GraphQLCORSDomainFlag,
+ utils.GraphQLVirtualHostsFlag,
utils.JSpathFlag,
utils.ExecFlag,
utils.PreloadJSFlag,
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 973e47ea0..8c5a0c99a 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -20,6 +20,7 @@ package utils
import (
"crypto/ecdsa"
"encoding/json"
+ "errors"
"fmt"
"io/ioutil"
"math/big"
@@ -45,6 +46,7 @@ import (
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethstats"
+ "github.com/ethereum/go-ethereum/graphql"
"github.com/ethereum/go-ethereum/les"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/metrics"
@@ -57,6 +59,7 @@ import (
"github.com/ethereum/go-ethereum/p2p/nat"
"github.com/ethereum/go-ethereum/p2p/netutil"
"github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/rpc"
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
pcsclite "github.com/gballet/go-libpcsclite"
cli "gopkg.in/urfave/cli.v1"
@@ -474,6 +477,14 @@ var (
Usage: "Disables db compaction after import",
}
// RPC settings
+ IPCDisabledFlag = cli.BoolFlag{
+ Name: "ipcdisable",
+ Usage: "Disable the IPC-RPC server",
+ }
+ IPCPathFlag = DirectoryFlag{
+ Name: "ipcpath",
+ Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
+ }
RPCEnabledFlag = cli.BoolFlag{
Name: "rpc",
Usage: "Enable the HTTP-RPC server",
@@ -488,30 +499,6 @@ var (
Usage: "HTTP-RPC server listening port",
Value: node.DefaultHTTPPort,
}
- GraphQLEnabledFlag = cli.BoolFlag{
- Name: "graphql",
- Usage: "Enable the GraphQL server",
- }
- GraphQLListenAddrFlag = cli.StringFlag{
- Name: "graphql.addr",
- Usage: "GraphQL server listening interface",
- Value: node.DefaultGraphQLHost,
- }
- GraphQLPortFlag = cli.IntFlag{
- Name: "graphql.port",
- Usage: "GraphQL server listening port",
- Value: node.DefaultGraphQLPort,
- }
- GraphQLCORSDomainFlag = cli.StringFlag{
- Name: "graphql.rpccorsdomain",
- Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
- Value: "",
- }
- GraphQLVirtualHostsFlag = cli.StringFlag{
- Name: "graphql.rpcvhosts",
- Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
- Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
- }
RPCCORSDomainFlag = cli.StringFlag{
Name: "rpccorsdomain",
Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
@@ -527,14 +514,6 @@ var (
Usage: "API's offered over the HTTP-RPC interface",
Value: "",
}
- IPCDisabledFlag = cli.BoolFlag{
- Name: "ipcdisable",
- Usage: "Disable the IPC-RPC server",
- }
- IPCPathFlag = DirectoryFlag{
- Name: "ipcpath",
- Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
- }
WSEnabledFlag = cli.BoolFlag{
Name: "ws",
Usage: "Enable the WS-RPC server",
@@ -559,6 +538,30 @@ var (
Usage: "Origins from which to accept websockets requests",
Value: "",
}
+ GraphQLEnabledFlag = cli.BoolFlag{
+ Name: "graphql",
+ Usage: "Enable the GraphQL server",
+ }
+ GraphQLListenAddrFlag = cli.StringFlag{
+ Name: "graphql.addr",
+ Usage: "GraphQL server listening interface",
+ Value: node.DefaultGraphQLHost,
+ }
+ GraphQLPortFlag = cli.IntFlag{
+ Name: "graphql.port",
+ Usage: "GraphQL server listening port",
+ Value: node.DefaultGraphQLPort,
+ }
+ GraphQLCORSDomainFlag = cli.StringFlag{
+ Name: "graphql.corsdomain",
+ Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
+ Value: "",
+ }
+ GraphQLVirtualHostsFlag = cli.StringFlag{
+ Name: "graphql.vhosts",
+ Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
+ Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","),
+ }
ExecFlag = cli.StringFlag{
Name: "exec",
Usage: "Execute JavaScript statement",
@@ -874,7 +877,6 @@ func setHTTP(ctx *cli.Context, cfg *node.Config) {
cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name)
}
}
-
if ctx.GlobalIsSet(RPCPortFlag.Name) {
cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
}
@@ -916,7 +918,6 @@ func setWS(ctx *cli.Context, cfg *node.Config) {
cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
}
}
-
if ctx.GlobalIsSet(WSPortFlag.Name) {
cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
}
@@ -1546,12 +1547,33 @@ func RegisterEthStatsService(stack *node.Node, url string) {
var lesServ *les.LightEthereum
ctx.Service(&lesServ)
+ // Let ethstats use whichever is not nil
return ethstats.New(url, ethServ, lesServ)
}); err != nil {
Fatalf("Failed to register the Ethereum Stats service: %v", err)
}
}
+// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
+func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
+ if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
+ // Try to construct the GraphQL service backed by a full node
+ var ethServ *eth.Ethereum
+ if err := ctx.Service(&ethServ); err == nil {
+ return graphql.New(ethServ.APIBackend, endpoint, cors, vhosts, timeouts)
+ }
+ // Try to construct the GraphQL service backed by a light node
+ var lesServ *les.LightEthereum
+ if err := ctx.Service(&lesServ); err == nil {
+ return graphql.New(lesServ.ApiBackend, endpoint, cors, vhosts, timeouts)
+ }
+ // Well, this should not have happened, bail out
+ return nil, errors.New("no Ethereum service")
+ }); err != nil {
+ Fatalf("Failed to register the GraphQL service: %v", err)
+ }
+}
+
func SetupMetrics(ctx *cli.Context) {
if metrics.Enabled {
log.Info("Enabling metrics collection")
diff --git a/graphql/graphiql.go b/graphql/graphiql.go
index 6d9dda3e8..e72609254 100644
--- a/graphql/graphiql.go
+++ b/graphql/graphiql.go
@@ -60,11 +60,11 @@ var graphiql = []byte(`
<!DOCTYPE html>
<html>
<head>
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.11/graphiql.css"/>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.3/fetch.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
- <script src="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.11.11/graphiql.min.js"></script>
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.13.0/graphiql.css"/>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/fetch/3.0.0/fetch.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.5/umd/react.production.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.5/umd/react-dom.production.min.js"></script>
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/graphiql/0.13.0/graphiql.min.js"></script>
</head>
<body style="width: 100%; height: 100%; margin: 0; overflow: hidden;">
<div id="graphiql" style="height: 100vh;">Loading...</div>
diff --git a/graphql/graphql.go b/graphql/graphql.go
index d22a3afb6..3f6bcab99 100644
--- a/graphql/graphql.go
+++ b/graphql/graphql.go
@@ -20,9 +20,6 @@ package graphql
import (
"context"
"errors"
- "fmt"
- "net"
- "net/http"
"time"
"github.com/ethereum/go-ethereum"
@@ -32,16 +29,10 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/internal/ethapi"
- "github.com/ethereum/go-ethereum/log"
- "github.com/ethereum/go-ethereum/node"
- "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
- graphqlgo "github.com/graph-gophers/graphql-go"
- "github.com/graph-gophers/graphql-go/relay"
)
var OnlyOnMainChainError = errors.New("This operation is only available for blocks on the canonical chain.")
@@ -49,7 +40,7 @@ var BlockInvariantError = errors.New("Block objects must be instantiated with at
// Account represents an Ethereum account at a particular block.
type Account struct {
- backend *eth.EthAPIBackend
+ backend ethapi.Backend
address common.Address
blockNumber rpc.BlockNumber
}
@@ -102,7 +93,7 @@ func (a *Account) Storage(ctx context.Context, args struct{ Slot common.Hash })
// Log represents an individual log message. All arguments are mandatory.
type Log struct {
- backend *eth.EthAPIBackend
+ backend ethapi.Backend
transaction *Transaction
log *types.Log
}
@@ -134,7 +125,7 @@ func (l *Log) Data(ctx context.Context) hexutil.Bytes {
// Transaction represents an Ethereum transaction.
// backend and hash are mandatory; all others will be fetched when required.
type Transaction struct {
- backend *eth.EthAPIBackend
+ backend ethapi.Backend
hash common.Hash
tx *types.Transaction
block *Block
@@ -349,7 +340,7 @@ const (
// backend, and either num or hash are mandatory. All other fields are lazily fetched
// when required.
type Block struct {
- backend *eth.EthAPIBackend
+ backend ethapi.Backend
num *rpc.BlockNumber
hash common.Hash
header *types.Header
@@ -745,7 +736,7 @@ type BlockFilterCriteria struct {
// runFilter accepts a filter and executes it, returning all its results as
// `Log` objects.
-func runFilter(ctx context.Context, be *eth.EthAPIBackend, filter *filters.Filter) ([]*Log, error) {
+func runFilter(ctx context.Context, be ethapi.Backend, filter *filters.Filter) ([]*Log, error) {
logs, err := filter.Logs(ctx)
if err != nil || logs == nil {
return nil, err
@@ -888,7 +879,7 @@ func (b *Block) EstimateGas(ctx context.Context, args struct {
}
type Pending struct {
- backend *eth.EthAPIBackend
+ backend ethapi.Backend
}
func (p *Pending) TransactionCount(ctx context.Context) (int32, error) {
@@ -947,7 +938,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct {
// Resolver is the top-level object in the GraphQL hierarchy.
type Resolver struct {
- backend *eth.EthAPIBackend
+ backend ethapi.Backend
}
func (r *Resolver) Block(ctx context.Context, args struct {
@@ -1088,7 +1079,6 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria
// Construct the range filter
filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics)
-
return runFilter(ctx, r.backend, filter)
}
@@ -1145,89 +1135,3 @@ func (r *Resolver) Syncing() (*SyncState, error) {
// Otherwise gather the block sync stats
return &SyncState{progress}, nil
}
-
-// NewHandler returns a new `http.Handler` that will answer GraphQL queries.
-// It additionally exports an interactive query browser on the / endpoint.
-func NewHandler(be *eth.EthAPIBackend) (http.Handler, error) {
- q := Resolver{be}
-
- s, err := graphqlgo.ParseSchema(schema, &q)
- if err != nil {
- return nil, err
- }
- h := &relay.Handler{Schema: s}
-
- mux := http.NewServeMux()
- mux.Handle("/", GraphiQL{})
- mux.Handle("/graphql", h)
- mux.Handle("/graphql/", h)
- return mux, nil
-}
-
-// Service encapsulates a GraphQL service.
-type Service struct {
- endpoint string // The host:port endpoint for this service.
- cors []string // Allowed CORS domains
- vhosts []string // Recognised vhosts
- timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests.
- backend *eth.EthAPIBackend // The backend that queries will operate onn.
- handler http.Handler // The `http.Handler` used to answer queries.
- listener net.Listener // The listening socket.
-}
-
-// Protocols returns the list of protocols exported by this service.
-func (s *Service) Protocols() []p2p.Protocol { return nil }
-
-// APIs returns the list of APIs exported by this service.
-func (s *Service) APIs() []rpc.API { return nil }
-
-// Start is called after all services have been constructed and the networking
-// layer was also initialized to spawn any goroutines required by the service.
-func (s *Service) Start(server *p2p.Server) error {
- var err error
- s.handler, err = NewHandler(s.backend)
- if err != nil {
- return err
- }
-
- if s.listener, err = net.Listen("tcp", s.endpoint); err != nil {
- return err
- }
-
- go rpc.NewHTTPServer(s.cors, s.vhosts, s.timeouts, s.handler).Serve(s.listener)
- log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.endpoint))
- return nil
-}
-
-// Stop terminates all goroutines belonging to the service, blocking until they
-// are all terminated.
-func (s *Service) Stop() error {
- if s.listener != nil {
- s.listener.Close()
- s.listener = nil
- log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.endpoint))
- }
- return nil
-}
-
-// NewService constructs a new service instance.
-func NewService(backend *eth.EthAPIBackend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
- return &Service{
- endpoint: endpoint,
- cors: cors,
- vhosts: vhosts,
- timeouts: timeouts,
- backend: backend,
- }, nil
-}
-
-// RegisterGraphQLService is a utility function to construct a new service and register it against a node.
-func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
- return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- var ethereum *eth.Ethereum
- if err := ctx.Service(&ethereum); err != nil {
- return nil, err
- }
- return NewService(ethereum.APIBackend, endpoint, cors, vhosts, timeouts)
- })
-}
diff --git a/graphql/graphql_test.go b/graphql/graphql_test.go
index d63418398..22182833b 100644
--- a/graphql/graphql_test.go
+++ b/graphql/graphql_test.go
@@ -22,8 +22,7 @@ import (
func TestBuildSchema(t *testing.T) {
// Make sure the schema can be parsed and matched up to the object model.
- _, err := NewHandler(nil)
- if err != nil {
+ if _, err := newHandler(nil); err != nil {
t.Errorf("Could not construct GraphQL handler: %v", err)
}
}
diff --git a/graphql/service.go b/graphql/service.go
new file mode 100644
index 000000000..f64075680
--- /dev/null
+++ b/graphql/service.go
@@ -0,0 +1,103 @@
+// Copyright 2019 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 <http://www.gnu.org/licenses/>.
+
+package graphql
+
+import (
+ "fmt"
+ "net"
+ "net/http"
+
+ "github.com/ethereum/go-ethereum/internal/ethapi"
+ "github.com/ethereum/go-ethereum/log"
+ "github.com/ethereum/go-ethereum/p2p"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/graph-gophers/graphql-go"
+ "github.com/graph-gophers/graphql-go/relay"
+)
+
+// Service encapsulates a GraphQL service.
+type Service struct {
+ endpoint string // The host:port endpoint for this service.
+ cors []string // Allowed CORS domains
+ vhosts []string // Recognised vhosts
+ timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests.
+ backend ethapi.Backend // The backend that queries will operate onn.
+ handler http.Handler // The `http.Handler` used to answer queries.
+ listener net.Listener // The listening socket.
+}
+
+// New constructs a new GraphQL service instance.
+func New(backend ethapi.Backend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
+ return &Service{
+ endpoint: endpoint,
+ cors: cors,
+ vhosts: vhosts,
+ timeouts: timeouts,
+ backend: backend,
+ }, nil
+}
+
+// Protocols returns the list of protocols exported by this service.
+func (s *Service) Protocols() []p2p.Protocol { return nil }
+
+// APIs returns the list of APIs exported by this service.
+func (s *Service) APIs() []rpc.API { return nil }
+
+// Start is called after all services have been constructed and the networking
+// layer was also initialized to spawn any goroutines required by the service.
+func (s *Service) Start(server *p2p.Server) error {
+ var err error
+ s.handler, err = newHandler(s.backend)
+ if err != nil {
+ return err
+ }
+ if s.listener, err = net.Listen("tcp", s.endpoint); err != nil {
+ return err
+ }
+ go rpc.NewHTTPServer(s.cors, s.vhosts, s.timeouts, s.handler).Serve(s.listener)
+ log.Info("GraphQL endpoint opened", "url", fmt.Sprintf("http://%s", s.endpoint))
+ return nil
+}
+
+// newHandler returns a new `http.Handler` that will answer GraphQL queries.
+// It additionally exports an interactive query browser on the / endpoint.
+func newHandler(backend ethapi.Backend) (http.Handler, error) {
+ q := Resolver{backend}
+
+ s, err := graphql.ParseSchema(schema, &q)
+ if err != nil {
+ return nil, err
+ }
+ h := &relay.Handler{Schema: s}
+
+ mux := http.NewServeMux()
+ mux.Handle("/", GraphiQL{})
+ mux.Handle("/graphql", h)
+ mux.Handle("/graphql/", h)
+ return mux, nil
+}
+
+// Stop terminates all goroutines belonging to the service, blocking until they
+// are all terminated.
+func (s *Service) Stop() error {
+ if s.listener != nil {
+ s.listener.Close()
+ s.listener = nil
+ log.Info("GraphQL endpoint closed", "url", fmt.Sprintf("http://%s", s.endpoint))
+ }
+ return nil
+}
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index 9229ccfb6..28ec69897 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -47,9 +48,10 @@ type Backend interface {
ExtRPCEnabled() bool
RPCGasCap() *big.Int // global gas cap for eth_call over rpc: DoS protection
- // BlockChain API
+ // Blockchain API
SetHead(number uint64)
HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error)
+ HeaderByHash(ctx context.Context, blockHash common.Hash) (*types.Header, error)
BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error)
StateAndHeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*state.StateDB, *types.Header, error)
GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error)
@@ -60,7 +62,7 @@ type Backend interface {
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
- // TxPool API
+ // Transaction pool API
SendTx(ctx context.Context, signedTx *types.Transaction) error
GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error)
GetPoolTransactions() (types.Transactions, error)
@@ -70,6 +72,13 @@ type Backend interface {
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
+ // Filter API
+ BloomStatus() (uint64, uint64)
+ GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error)
+ ServiceFilter(ctx context.Context, session *bloombits.MatcherSession)
+ SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription
+ SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
+
ChainConfig() *params.ChainConfig
CurrentBlock() *types.Block
}
diff --git a/node/defaults.go b/node/defaults.go
index 564bb35b4..f84a5d547 100644
--- a/node/defaults.go
+++ b/node/defaults.go
@@ -38,13 +38,15 @@ const (
// DefaultConfig contains reasonable default settings.
var DefaultConfig = Config{
- DataDir: DefaultDataDir(),
- HTTPPort: DefaultHTTPPort,
- HTTPModules: []string{"net", "web3"},
- HTTPVirtualHosts: []string{"localhost"},
- HTTPTimeouts: rpc.DefaultHTTPTimeouts,
- WSPort: DefaultWSPort,
- WSModules: []string{"net", "web3"},
+ DataDir: DefaultDataDir(),
+ HTTPPort: DefaultHTTPPort,
+ HTTPModules: []string{"net", "web3"},
+ HTTPVirtualHosts: []string{"localhost"},
+ HTTPTimeouts: rpc.DefaultHTTPTimeouts,
+ WSPort: DefaultWSPort,
+ WSModules: []string{"net", "web3"},
+ GraphQLPort: DefaultGraphQLPort,
+ GraphQLVirtualHosts: []string{"localhost"},
P2P: p2p.Config{
ListenAddr: ":30303",
MaxPeers: 50,