Fixed backend fetching to use context

This commit is contained in:
Nick Johnson 2018-10-17 13:30:40 +01:00
parent c5f893d24c
commit 205f82e721
2 changed files with 220 additions and 166 deletions

View file

@ -42,31 +42,16 @@ import (
"github.com/graph-gophers/graphql-go/relay" "github.com/graph-gophers/graphql-go/relay"
) )
// getBackend fetches the Ethereum instannce from the provided node, and returns
// the API backend from that.
func getBackend(n *node.Node) (*eth.EthAPIBackend, error) {
var ethereum *eth.Ethereum
if err := n.Service(&ethereum); err != nil {
return nil, err
}
return ethereum.APIBackend, nil
}
// Account represents an Ethereum account at a particular block. // Account represents an Ethereum account at a particular block.
type Account struct { type Account struct {
node *node.Node backend *eth.EthAPIBackend
address common.Address address common.Address
blockNumber rpc.BlockNumber blockNumber rpc.BlockNumber
} }
// getState fetches the StateDB object for an account. // getState fetches the StateDB object for an account.
func (a *Account) getState(ctx context.Context) (*state.StateDB, error) { func (a *Account) getState(ctx context.Context) (*state.StateDB, error) {
be, err := getBackend(a.node) state, _, err := a.backend.StateAndHeaderByNumber(ctx, a.blockNumber)
if err != nil {
return nil, err
}
state, _, err := be.StateAndHeaderByNumber(ctx, a.blockNumber)
return state, err return state, err
} }
@ -112,7 +97,7 @@ func (a *Account) Storage(ctx context.Context, args struct{ Slot common.Hash })
// Log represents an individual log message. All arguments are mandatory. // Log represents an individual log message. All arguments are mandatory.
type Log struct { type Log struct {
node *node.Node backend *eth.EthAPIBackend
transaction *Transaction transaction *Transaction
log *types.Log log *types.Log
} }
@ -123,7 +108,7 @@ func (l *Log) Transaction(ctx context.Context) *Transaction {
func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account { func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account {
return &Account{ return &Account{
node: l.node, backend: l.backend,
address: l.log.Address, address: l.log.Address,
blockNumber: args.Number(), blockNumber: args.Number(),
} }
@ -142,33 +127,28 @@ func (l *Log) Data(ctx context.Context) hexutil.Bytes {
} }
// Transactionn represents an Ethereum transaction. // Transactionn represents an Ethereum transaction.
// node and hash are mandatory; all others will be fetched when required. // backend and hash are mandatory; all others will be fetched when required.
type Transaction struct { type Transaction struct {
node *node.Node backend *eth.EthAPIBackend
hash common.Hash hash common.Hash
tx *types.Transaction tx *types.Transaction
block *Block block *Block
index uint64 index uint64
} }
// resolve returns the internal transaction object, fetching it if needed. // resolve returns the internal transaction object, fetching it if needed.
func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) { func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) {
if t.tx == nil { if t.tx == nil {
be, err := getBackend(t.node) tx, blockHash, _, index := rawdb.ReadTransaction(t.backend.ChainDb(), t.hash)
if err != nil {
return nil, err
}
tx, blockHash, _, index := rawdb.ReadTransaction(be.ChainDb(), t.hash)
if tx != nil { if tx != nil {
t.tx = tx t.tx = tx
t.block = &Block{ t.block = &Block{
node: t.node, backend: t.backend,
hash: blockHash, hash: blockHash,
} }
t.index = index t.index = index
} else { } else {
t.tx = be.GetPoolTransaction(t.hash) t.tx = t.backend.GetPoolTransaction(t.hash)
} }
} }
return t.tx, nil return t.tx, nil
@ -230,7 +210,7 @@ func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, e
} }
return &Account{ return &Account{
node: t.node, backend: t.backend,
address: *to, address: *to,
blockNumber: args.Number(), blockNumber: args.Number(),
}, nil }, nil
@ -249,7 +229,7 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account,
from, _ := types.Sender(signer, tx) from, _ := types.Sender(signer, tx)
return &Account{ return &Account{
node: t.node, backend: t.backend,
address: from, address: from,
blockNumber: args.Number(), blockNumber: args.Number(),
}, nil }, nil
@ -328,7 +308,7 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs)
} }
return &Account{ return &Account{
node: t.node, backend: t.backend,
address: receipt.ContractAddress, address: receipt.ContractAddress,
blockNumber: args.Number(), blockNumber: args.Number(),
}, nil }, nil
@ -343,7 +323,7 @@ func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) {
ret := make([]*Log, 0, len(receipt.Logs)) ret := make([]*Log, 0, len(receipt.Logs))
for _, log := range receipt.Logs { for _, log := range receipt.Logs {
ret = append(ret, &Log{ ret = append(ret, &Log{
node: t.node, backend: t.backend,
transaction: t, transaction: t,
log: log, log: log,
}) })
@ -352,10 +332,10 @@ func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) {
} }
// Block represennts an Ethereum block. // Block represennts an Ethereum block.
// node, and either num or hash are mandatory. All other fields are lazily fetched // backend, and either num or hash are mandatory. All other fields are lazily fetched
// when required. // when required.
type Block struct { type Block struct {
node *node.Node backend *eth.EthAPIBackend
num *rpc.BlockNumber num *rpc.BlockNumber
hash common.Hash hash common.Hash
header *types.Header header *types.Header
@ -370,15 +350,11 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) {
return b.block, nil return b.block, nil
} }
be, err := getBackend(b.node) var err error
if err != nil {
return nil, err
}
if b.hash != (common.Hash{}) { if b.hash != (common.Hash{}) {
b.block, err = be.GetBlock(ctx, b.hash) b.block, err = b.backend.GetBlock(ctx, b.hash)
} else { } else {
b.block, err = be.BlockByNumber(ctx, *b.num) b.block, err = b.backend.BlockByNumber(ctx, *b.num)
} }
if b.block != nil { if b.block != nil {
b.header = b.block.Header() b.header = b.block.Header()
@ -402,11 +378,6 @@ func (b *Block) resolveHeader(ctx context.Context) (*types.Header, error) {
// if necessary. // if necessary.
func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) { func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) {
if b.receipts == nil { if b.receipts == nil {
be, err := getBackend(b.node)
if err != nil {
return nil, err
}
hash := b.hash hash := b.hash
if hash == (common.Hash{}) { if hash == (common.Hash{}) {
header, err := b.resolveHeader(ctx) header, err := b.resolveHeader(ctx)
@ -416,7 +387,7 @@ func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) {
hash = header.Hash() hash = header.Hash()
} }
receipts, err := be.GetReceipts(ctx, hash) receipts, err := b.backend.GetReceipts(ctx, hash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -475,15 +446,15 @@ func (b *Block) Parent(ctx context.Context) (*Block, error) {
if b.header != nil && b.block.NumberU64() > 0 { if b.header != nil && b.block.NumberU64() > 0 {
num := rpc.BlockNumber(b.header.Number.Uint64() - 1) num := rpc.BlockNumber(b.header.Number.Uint64() - 1)
return &Block{ return &Block{
node: b.node, backend: b.backend,
num: &num, num: &num,
hash: b.header.ParentHash, hash: b.header.ParentHash,
}, nil }, nil
} else if b.num != nil && *b.num != 0 { } else if b.num != nil && *b.num != 0 {
num := *b.num - 1 num := *b.num - 1
return &Block{ return &Block{
node: b.node, backend: b.backend,
num: &num, num: &num,
}, nil }, nil
} }
return nil, nil return nil, nil
@ -572,10 +543,10 @@ func (b *Block) Ommers(ctx context.Context) (*[]*Block, error) {
for _, uncle := range block.Uncles() { for _, uncle := range block.Uncles() {
blockNumber := rpc.BlockNumber(uncle.Number.Uint64()) blockNumber := rpc.BlockNumber(uncle.Number.Uint64())
ret = append(ret, &Block{ ret = append(ret, &Block{
node: b.node, backend: b.backend,
num: &blockNumber, num: &blockNumber,
hash: uncle.Hash(), hash: uncle.Hash(),
header: uncle, header: uncle,
}) })
} }
return &ret, nil return &ret, nil
@ -607,12 +578,7 @@ func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) {
h = header.Hash() h = header.Hash()
} }
be, err := getBackend(b.node) return hexutil.Big(*b.backend.GetTd(h)), nil
if err != nil {
return hexutil.Big{}, err
}
return hexutil.Big(*be.GetTd(h)), nil
} }
// BlockNumberArgs encapsulates arguments to accessors that specify a block number. // BlockNumberArgs encapsulates arguments to accessors that specify a block number.
@ -636,7 +602,7 @@ func (b *Block) Miner(ctx context.Context, args BlockNumberArgs) (*Account, erro
} }
return &Account{ return &Account{
node: b.node, backend: b.backend,
address: block.Coinbase(), address: block.Coinbase(),
blockNumber: args.Number(), blockNumber: args.Number(),
}, nil }, nil
@ -660,11 +626,11 @@ func (b *Block) Transactions(ctx context.Context) (*[]*Transaction, error) {
ret := make([]*Transaction, 0, len(block.Transactions())) ret := make([]*Transaction, 0, len(block.Transactions()))
for i, tx := range block.Transactions() { for i, tx := range block.Transactions() {
ret = append(ret, &Transaction{ ret = append(ret, &Transaction{
node: b.node, backend: b.backend,
hash: tx.Hash(), hash: tx.Hash(),
tx: tx, tx: tx,
block: b, block: b,
index: uint64(i), index: uint64(i),
}) })
} }
return &ret, nil return &ret, nil
@ -683,11 +649,11 @@ func (b *Block) TransactionAt(ctx context.Context, args struct{ Index int32 }) (
tx := txes[args.Index] tx := txes[args.Index]
return &Transaction{ return &Transaction{
node: b.node, backend: b.backend,
hash: tx.Hash(), hash: tx.Hash(),
tx: tx, tx: tx,
block: b, block: b,
index: uint64(args.Index), index: uint64(args.Index),
}, nil }, nil
} }
@ -705,10 +671,10 @@ func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block
uncle := uncles[args.Index] uncle := uncles[args.Index]
blockNumber := rpc.BlockNumber(uncle.Number.Uint64()) blockNumber := rpc.BlockNumber(uncle.Number.Uint64())
return &Block{ return &Block{
node: b.node, backend: b.backend,
num: &blockNumber, num: &blockNumber,
hash: uncle.Hash(), hash: uncle.Hash(),
header: uncle, header: uncle,
}, nil }, nil
} }
@ -733,7 +699,7 @@ type BlockFilterCriteria struct {
// runFilter accepts a filter and executes it, returning all its results as // runFilter accepts a filter and executes it, returning all its results as
// `Log` objects. // `Log` objects.
func runFilter(ctx context.Context, node *node.Node, filter *filters.Filter) ([]*Log, error) { func runFilter(ctx context.Context, be *eth.EthAPIBackend, filter *filters.Filter) ([]*Log, error) {
logs, err := filter.Logs(ctx) logs, err := filter.Logs(ctx)
if err != nil || logs == nil { if err != nil || logs == nil {
return nil, err return nil, err
@ -742,8 +708,8 @@ func runFilter(ctx context.Context, node *node.Node, filter *filters.Filter) ([]
ret := make([]*Log, 0, len(logs)) ret := make([]*Log, 0, len(logs))
for _, log := range logs { for _, log := range logs {
ret = append(ret, &Log{ ret = append(ret, &Log{
node: node, backend: be,
transaction: &Transaction{node: node, hash: log.TxHash}, transaction: &Transaction{backend: be, hash: log.TxHash},
log: log, log: log,
}) })
} }
@ -751,11 +717,6 @@ func runFilter(ctx context.Context, node *node.Node, filter *filters.Filter) ([]
} }
func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteria }) ([]*Log, error) { func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteria }) ([]*Log, error) {
be, err := getBackend(b.node)
if err != nil {
return nil, err
}
var addresses []common.Address var addresses []common.Address
if args.Filter.Addresses != nil { if args.Filter.Addresses != nil {
addresses = *args.Filter.Addresses addresses = *args.Filter.Addresses
@ -776,15 +737,15 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri
} }
// Construct the range filter // Construct the range filter
filter := filters.NewBlockFilter(be, hash, addresses, topics) filter := filters.NewBlockFilter(b.backend, hash, addresses, topics)
// Run the filter and return all the logs // Run the filter and return all the logs
return runFilter(ctx, b.node, filter) return runFilter(ctx, b.backend, filter)
} }
// Resolver is the top-level object in the GraphQL heirarchy. // Resolver is the top-level object in the GraphQL heirarchy.
type Resolver struct { type Resolver struct {
node *node.Node backend *eth.EthAPIBackend
} }
func (r *Resolver) Block(ctx context.Context, args struct { func (r *Resolver) Block(ctx context.Context, args struct {
@ -795,19 +756,19 @@ func (r *Resolver) Block(ctx context.Context, args struct {
if args.Number != nil { if args.Number != nil {
num := rpc.BlockNumber(uint64(*args.Number)) num := rpc.BlockNumber(uint64(*args.Number))
block = &Block{ block = &Block{
node: r.node, backend: r.backend,
num: &num, num: &num,
} }
} else if args.Hash != nil { } else if args.Hash != nil {
block = &Block{ block = &Block{
node: r.node, backend: r.backend,
hash: *args.Hash, hash: *args.Hash,
} }
} else { } else {
num := rpc.LatestBlockNumber num := rpc.LatestBlockNumber
block = &Block{ block = &Block{
node: r.node, backend: r.backend,
num: &num, num: &num,
} }
} }
@ -825,18 +786,13 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
From hexutil.Uint64 From hexutil.Uint64
To *hexutil.Uint64 To *hexutil.Uint64
}) ([]*Block, error) { }) ([]*Block, error) {
be, err := getBackend(r.node)
if err != nil {
return nil, err
}
from := rpc.BlockNumber(args.From) from := rpc.BlockNumber(args.From)
var to rpc.BlockNumber var to rpc.BlockNumber
if args.To != nil { if args.To != nil {
to = rpc.BlockNumber(*args.To) to = rpc.BlockNumber(*args.To)
} else { } else {
to = rpc.BlockNumber(be.CurrentBlock().Number().Int64()) to = rpc.BlockNumber(r.backend.CurrentBlock().Number().Int64())
} }
if to < from { if to < from {
@ -847,8 +803,8 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
for i := from; i <= to; i++ { for i := from; i <= to; i++ {
num := i num := i
ret = append(ret, &Block{ ret = append(ret, &Block{
node: r.node, backend: r.backend,
num: &num, num: &num,
}) })
} }
return ret, nil return ret, nil
@ -864,7 +820,7 @@ func (r *Resolver) Account(ctx context.Context, args struct {
} }
return &Account{ return &Account{
node: r.node, backend: r.backend,
address: args.Address, address: args.Address,
blockNumber: blockNumber, blockNumber: blockNumber,
} }
@ -872,8 +828,8 @@ func (r *Resolver) Account(ctx context.Context, args struct {
func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Hash }) (*Transaction, error) { func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Hash }) (*Transaction, error) {
tx := &Transaction{ tx := &Transaction{
node: r.node, backend: r.backend,
hash: args.Hash, hash: args.Hash,
} }
// Resolve the transaction; if it doesn't exist, return nil. // Resolve the transaction; if it doesn't exist, return nil.
@ -887,16 +843,11 @@ func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Has
} }
func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hexutil.Bytes }) (common.Hash, error) { func (r *Resolver) SendRawTransaction(ctx context.Context, args struct{ Data hexutil.Bytes }) (common.Hash, error) {
be, err := getBackend(r.node)
if err != nil {
return common.Hash{}, err
}
tx := new(types.Transaction) tx := new(types.Transaction)
if err := rlp.DecodeBytes(args.Data, tx); err != nil { if err := rlp.DecodeBytes(args.Data, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
hash, err := ethapi.SubmitTransaction(ctx, be, tx) hash, err := ethapi.SubmitTransaction(ctx, r.backend, tx)
return hash, err return hash, err
} }
@ -934,17 +885,12 @@ func (r *Resolver) Call(ctx context.Context, args struct {
Data ethapi.CallArgs Data ethapi.CallArgs
BlockNumber *hexutil.Uint64 BlockNumber *hexutil.Uint64
}) (*CallResult, error) { }) (*CallResult, error) {
be, err := getBackend(r.node)
if err != nil {
return nil, err
}
blockNumber := rpc.LatestBlockNumber blockNumber := rpc.LatestBlockNumber
if args.BlockNumber != nil { if args.BlockNumber != nil {
blockNumber = rpc.BlockNumber(*args.BlockNumber) blockNumber = rpc.BlockNumber(*args.BlockNumber)
} }
result, gas, failed, err := ethapi.DoCall(ctx, be, args.Data, blockNumber, vm.Config{}, 5*time.Second) result, gas, failed, err := ethapi.DoCall(ctx, r.backend, args.Data, blockNumber, vm.Config{}, 5*time.Second)
status := hexutil.Uint64(1) status := hexutil.Uint64(1)
if failed { if failed {
status = 0 status = 0
@ -960,17 +906,12 @@ func (r *Resolver) EstimateGas(ctx context.Context, args struct {
Data ethapi.CallArgs Data ethapi.CallArgs
BlockNumber *hexutil.Uint64 BlockNumber *hexutil.Uint64
}) (hexutil.Uint64, error) { }) (hexutil.Uint64, error) {
be, err := getBackend(r.node)
if err != nil {
return 0, err
}
blockNumber := rpc.LatestBlockNumber blockNumber := rpc.LatestBlockNumber
if args.BlockNumber != nil { if args.BlockNumber != nil {
blockNumber = rpc.BlockNumber(*args.BlockNumber) blockNumber = rpc.BlockNumber(*args.BlockNumber)
} }
gas, err := ethapi.DoEstimateGas(ctx, be, args.Data, blockNumber) gas, err := ethapi.DoEstimateGas(ctx, r.backend, args.Data, blockNumber)
return hexutil.Uint64(gas), err return hexutil.Uint64(gas), err
} }
@ -995,11 +936,6 @@ type FilterCriteria struct {
} }
func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria }) ([]*Log, error) { func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria }) ([]*Log, error) {
be, err := getBackend(r.node)
if err != nil {
return nil, err
}
// Convert the RPC block numbers into internal representations // Convert the RPC block numbers into internal representations
begin := rpc.LatestBlockNumber.Int64() begin := rpc.LatestBlockNumber.Int64()
if args.Filter.FromBlock != nil { if args.Filter.FromBlock != nil {
@ -1021,28 +957,18 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria
} }
// Construct the range filter // Construct the range filter
filter := filters.NewRangeFilter(filters.Backend(be), begin, end, addresses, topics) filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics)
return runFilter(ctx, r.node, filter) return runFilter(ctx, r.backend, filter)
} }
func (r *Resolver) GasPrice(ctx context.Context) (hexutil.Big, error) { func (r *Resolver) GasPrice(ctx context.Context) (hexutil.Big, error) {
be, err := getBackend(r.node) price, err := r.backend.SuggestPrice(ctx)
if err != nil {
return hexutil.Big{}, err
}
price, err := be.SuggestPrice(ctx)
return hexutil.Big(*price), err return hexutil.Big(*price), err
} }
func (r *Resolver) ProtocolVersion(ctx context.Context) (int32, error) { func (r *Resolver) ProtocolVersion(ctx context.Context) (int32, error) {
be, err := getBackend(r.node) return int32(r.backend.ProtocolVersion()), nil
if err != nil {
return 0, err
}
return int32(be.ProtocolVersion()), nil
} }
// SyncState represents the synchronisation status returned from the `syncing` accessor. // SyncState represents the synchronisation status returned from the `syncing` accessor.
@ -1080,11 +1006,7 @@ func (s *SyncState) KnownStates() *hexutil.Uint64 {
// - pulledStates: number of state entries processed until now // - pulledStates: number of state entries processed until now
// - knownStates: number of known state entries that still need to be pulled // - knownStates: number of known state entries that still need to be pulled
func (r *Resolver) Syncing() (*SyncState, error) { func (r *Resolver) Syncing() (*SyncState, error) {
be, err := getBackend(r.node) progress := r.backend.Downloader().Progress()
if err != nil {
return nil, err
}
progress := be.Downloader().Progress()
// Return not syncing if the synchronisation already completed // Return not syncing if the synchronisation already completed
if progress.CurrentBlock >= progress.HighestBlock { if progress.CurrentBlock >= progress.HighestBlock {
@ -1096,8 +1018,8 @@ func (r *Resolver) Syncing() (*SyncState, error) {
// NewHandler returns a new `http.Handler` that will answer GraphQL queries. // NewHandler returns a new `http.Handler` that will answer GraphQL queries.
// It additionally exports an interactive query browser on the / endpoint. // It additionally exports an interactive query browser on the / endpoint.
func NewHandler(n *node.Node) (http.Handler, error) { func NewHandler(be *eth.EthAPIBackend) (http.Handler, error) {
q := Resolver{n} q := Resolver{be}
s, err := graphql.ParseSchema(schema, &q) s, err := graphql.ParseSchema(schema, &q)
if err != nil { if err != nil {
@ -1114,13 +1036,13 @@ func NewHandler(n *node.Node) (http.Handler, error) {
// Service encapsulates an ETHGraphQL service. // Service encapsulates an ETHGraphQL service.
type Service struct { type Service struct {
endpoint string // The host:port endpoint for this service. endpoint string // The host:port endpoint for this service.
cors []string // Allowed CORS domains cors []string // Allowed CORS domains
vhosts []string // Recognised vhosts vhosts []string // Recognised vhosts
timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests. timeouts rpc.HTTPTimeouts // Timeout settings for HTTP requests.
node *node.Node // The node that queries will operate onn. backend *eth.EthAPIBackend // The backend that queries will operate onn.
handler http.Handler // The `http.Handler` used to answer queries. handler http.Handler // The `http.Handler` used to answer queries.
listener net.Listener // The listening socket. listener net.Listener // The listening socket.
} }
// Protocols returns the list of protocols exported by this service. // Protocols returns the list of protocols exported by this service.
@ -1133,7 +1055,7 @@ func (s *Service) APIs() []rpc.API { return nil }
// layer was also initialized to spawn any goroutines required by the service. // layer was also initialized to spawn any goroutines required by the service.
func (s *Service) Start(server *p2p.Server) error { func (s *Service) Start(server *p2p.Server) error {
var err error var err error
s.handler, err = NewHandler(s.node) s.handler, err = NewHandler(s.backend)
if err != nil { if err != nil {
return err return err
} }
@ -1159,19 +1081,23 @@ func (s *Service) Stop() error {
} }
// NewService constructs a new service instance. // NewService constructs a new service instance.
func NewService(ctx *node.ServiceContext, stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) { func NewService(backend *eth.EthAPIBackend, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) (*Service, error) {
return &Service{ return &Service{
endpoint: endpoint, endpoint: endpoint,
cors: cors, cors: cors,
vhosts: vhosts, vhosts: vhosts,
timeouts: timeouts, timeouts: timeouts,
node: stack, backend: backend,
}, nil }, nil
} }
// RegisterGraphQLService is a utility function to construct a new service and register it against a node. // 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 { func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) error {
return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return NewService(ctx, stack, endpoint, cors, vhosts, timeouts) var ethereum *eth.Ethereum
if err := ctx.Service(&ethereum); err != nil {
return nil, err
}
return NewService(ethereum.APIBackend, endpoint, cors, vhosts, timeouts)
}) })
} }

128
ethgraphql/schema.go Normal file
View file

@ -0,0 +1,128 @@
package ethgraphql
const schema string = `
scalar Bytes32
scalar Address
scalar Bytes
scalar BigInt
scalar Long
schema {
query: Query
mutation: Mutation
}
type Account {
address: Address!
balance: BigInt!
transactionCount: Long!
code: Bytes!
storage(slot: Bytes32!): Bytes32!
}
type Log {
index: Int!
account(block: Long): Account!
topics: [Bytes32!]!
data: Bytes!
transaction: Transaction!
}
type Transaction {
hash: Bytes32!
nonce: Long!
index: Int
from(block: Long): Account!
to(block: Long): Account
value: BigInt!
gasPrice: BigInt!
gas: Long!
inputData: Bytes!
block: Block
status: Long
gasUsed: Long
cumulativeGasUsed: Long
createdContract(block: Long): Account
logs: [Log!]
}
input BlockFilterCriteria {
addresses: [Address!]
topics: [[Bytes32!]!]
}
type Block {
number: Long!
hash: Bytes32!
parent: Block
nonce: Bytes!
transactionsRoot: Bytes32!
transactionCount: Int
stateRoot: Bytes32!
receiptsRoot: Bytes32!
miner(block: Long): Account!
extraData: Bytes!
gasLimit: Long!
gasUsed: Long!
timestamp: BigInt!
logsBloom: Bytes!
mixHash: Bytes32!
difficulty: BigInt!
totalDifficulty: BigInt!
ommerCount: Int
ommers: [Block]
ommerAt(index: Int!): Block
ommerHash: Bytes32!
transactions: [Transaction!]
transactionAt(index: Int!): Transaction
logs(filter: BlockFilterCriteria!): [Log!]!
}
input CallData {
from: Address
to: Address
gas: Long
gasPrice: BigInt
value: BigInt
data: Bytes
}
type CallResult {
data: Bytes!
gasUsed: Long!
status: Long!
}
input FilterCriteria {
fromBlock: Long
toBlock: Long
addresses: [Address!]
topics: [[Bytes32!]!]
}
type SyncState{
startingBlock: Long!
currentBlock: Long!
highestBlock: Long!
pulledStates: Long
knownStates: Long
}
type Query {
account(address: Address!, blockNumber: Long): Account!
block(number: Long, hash: Bytes32): Block
blocks(from: Long!, to: Long): [Block!]!
transaction(hash: Bytes32!): Transaction
call(data: CallData!, blockNumber: Long): CallResult
estimateGas(data: CallData!, blockNumber: Long): Long!
logs(filter: FilterCriteria!): [Log!]!
gasPrice: BigInt!
protocolVersion: Int!
syncing: SyncState
}
type Mutation {
sendRawTransaction(data: Bytes!): Bytes32!
}
`