graphql: embed *Resolver instead of backend interface (#25468)

This creates some infrastructure to share resources between graphql
API objects.
pull/25472/head
Felix Lange 2 years ago committed by GitHub
parent 948e08d55b
commit f809cf6ea6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 132
      graphql/graphql.go
  2. 4
      graphql/service.go

@ -76,14 +76,14 @@ func (b *Long) UnmarshalGraphQL(input interface{}) error {
// Account represents an Ethereum account at a particular block.
type Account struct {
backend ethapi.Backend
r *Resolver
address common.Address
blockNrOrHash rpc.BlockNumberOrHash
}
// getState fetches the StateDB object for an account.
func (a *Account) getState(ctx context.Context) (*state.StateDB, error) {
state, _, err := a.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash)
state, _, err := a.r.backend.StateAndHeaderByNumberOrHash(ctx, a.blockNrOrHash)
return state, err
}
@ -106,7 +106,7 @@ func (a *Account) Balance(ctx context.Context) (hexutil.Big, error) {
func (a *Account) TransactionCount(ctx context.Context) (hexutil.Uint64, error) {
// Ask transaction pool for the nonce which includes pending transactions
if blockNr, ok := a.blockNrOrHash.Number(); ok && blockNr == rpc.PendingBlockNumber {
nonce, err := a.backend.GetPoolNonce(ctx, a.address)
nonce, err := a.r.backend.GetPoolNonce(ctx, a.address)
if err != nil {
return 0, err
}
@ -137,7 +137,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 ethapi.Backend
r *Resolver
transaction *Transaction
log *types.Log
}
@ -148,7 +148,7 @@ func (l *Log) Transaction(ctx context.Context) *Transaction {
func (l *Log) Account(ctx context.Context, args BlockNumberArgs) *Account {
return &Account{
backend: l.backend,
r: l.r,
address: l.log.Address,
blockNrOrHash: args.NumberOrLatest(),
}
@ -183,30 +183,30 @@ func (at *AccessTuple) StorageKeys(ctx context.Context) []common.Hash {
// Transaction represents an Ethereum transaction.
// backend and hash are mandatory; all others will be fetched when required.
type Transaction struct {
backend ethapi.Backend
hash common.Hash
tx *types.Transaction
block *Block
index uint64
r *Resolver
hash common.Hash
tx *types.Transaction
block *Block
index uint64
}
// resolve returns the internal transaction object, fetching it if needed.
func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, error) {
if t.tx == nil {
// Try to return an already finalized transaction
tx, blockHash, _, index, err := t.backend.GetTransaction(ctx, t.hash)
tx, blockHash, _, index, err := t.r.backend.GetTransaction(ctx, t.hash)
if err == nil && tx != nil {
t.tx = tx
blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false)
t.block = &Block{
backend: t.backend,
r: t.r,
numberOrHash: &blockNrOrHash,
}
t.index = index
return t.tx, nil
}
// No finalized transaction, try to retrieve it from the pool
t.tx = t.backend.GetPoolTransaction(t.hash)
t.tx = t.r.backend.GetPoolTransaction(t.hash)
}
return t.tx, nil
}
@ -354,7 +354,7 @@ func (t *Transaction) To(ctx context.Context, args BlockNumberArgs) (*Account, e
return nil, nil
}
return &Account{
backend: t.backend,
r: t.r,
address: *to,
blockNrOrHash: args.NumberOrLatest(),
}, nil
@ -365,10 +365,10 @@ func (t *Transaction) From(ctx context.Context, args BlockNumberArgs) (*Account,
if err != nil || tx == nil {
return nil, err
}
signer := types.LatestSigner(t.backend.ChainConfig())
signer := types.LatestSigner(t.r.backend.ChainConfig())
from, _ := types.Sender(signer, tx)
return &Account{
backend: t.backend,
r: t.r,
address: from,
blockNrOrHash: args.NumberOrLatest(),
}, nil
@ -443,7 +443,7 @@ func (t *Transaction) CreatedContract(ctx context.Context, args BlockNumberArgs)
return nil, err
}
return &Account{
backend: t.backend,
r: t.r,
address: receipt.ContractAddress,
blockNrOrHash: args.NumberOrLatest(),
}, nil
@ -457,7 +457,7 @@ func (t *Transaction) Logs(ctx context.Context) (*[]*Log, error) {
ret := make([]*Log, 0, len(receipt.Logs))
for _, log := range receipt.Logs {
ret = append(ret, &Log{
backend: t.backend,
r: t.r,
transaction: t,
log: log,
})
@ -539,7 +539,7 @@ type BlockType int
// backend, and numberOrHash are mandatory. All other fields are lazily fetched
// when required.
type Block struct {
backend ethapi.Backend
r *Resolver
numberOrHash *rpc.BlockNumberOrHash
hash common.Hash
header *types.Header
@ -558,7 +558,7 @@ func (b *Block) resolve(ctx context.Context) (*types.Block, error) {
b.numberOrHash = &latest
}
var err error
b.block, err = b.backend.BlockByNumberOrHash(ctx, *b.numberOrHash)
b.block, err = b.r.backend.BlockByNumberOrHash(ctx, *b.numberOrHash)
if b.block != nil && b.header == nil {
b.header = b.block.Header()
if hash, ok := b.numberOrHash.Hash(); ok {
@ -578,9 +578,9 @@ func (b *Block) resolveHeader(ctx context.Context) (*types.Header, error) {
var err error
if b.header == nil {
if b.hash != (common.Hash{}) {
b.header, err = b.backend.HeaderByHash(ctx, b.hash)
b.header, err = b.r.backend.HeaderByHash(ctx, b.hash)
} else {
b.header, err = b.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash)
b.header, err = b.r.backend.HeaderByNumberOrHash(ctx, *b.numberOrHash)
}
}
return b.header, err
@ -598,7 +598,7 @@ func (b *Block) resolveReceipts(ctx context.Context) ([]*types.Receipt, error) {
}
hash = header.Hash()
}
receipts, err := b.backend.GetReceipts(ctx, hash)
receipts, err := b.r.backend.GetReceipts(ctx, hash)
if err != nil {
return nil, err
}
@ -659,7 +659,7 @@ func (b *Block) NextBaseFeePerGas(ctx context.Context) (*hexutil.Big, error) {
if err != nil {
return nil, err
}
chaincfg := b.backend.ChainConfig()
chaincfg := b.r.backend.ChainConfig()
if header.BaseFee == nil {
// Make sure next block doesn't enable EIP-1559
if !chaincfg.IsLondon(new(big.Int).Add(header.Number, common.Big1)) {
@ -679,7 +679,7 @@ func (b *Block) Parent(ctx context.Context) (*Block, error) {
}
num := rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(b.header.Number.Uint64() - 1))
return &Block{
backend: b.backend,
r: b.r,
numberOrHash: &num,
hash: b.header.ParentHash,
}, nil
@ -767,7 +767,7 @@ func (b *Block) Ommers(ctx context.Context) (*[]*Block, error) {
for _, uncle := range block.Uncles() {
blockNumberOrHash := rpc.BlockNumberOrHashWithHash(uncle.Hash(), false)
ret = append(ret, &Block{
backend: b.backend,
r: b.r,
numberOrHash: &blockNumberOrHash,
header: uncle,
})
@ -800,7 +800,7 @@ func (b *Block) TotalDifficulty(ctx context.Context) (hexutil.Big, error) {
}
h = header.Hash()
}
td := b.backend.GetTd(ctx, h)
td := b.r.backend.GetTd(ctx, h)
if td == nil {
return hexutil.Big{}, fmt.Errorf("total difficulty not found %x", b.hash)
}
@ -853,7 +853,7 @@ func (b *Block) Miner(ctx context.Context, args BlockNumberArgs) (*Account, erro
return nil, err
}
return &Account{
backend: b.backend,
r: b.r,
address: header.Coinbase,
blockNrOrHash: args.NumberOrLatest(),
}, nil
@ -876,11 +876,11 @@ func (b *Block) Transactions(ctx context.Context) (*[]*Transaction, error) {
ret := make([]*Transaction, 0, len(block.Transactions()))
for i, tx := range block.Transactions() {
ret = append(ret, &Transaction{
backend: b.backend,
hash: tx.Hash(),
tx: tx,
block: b,
index: uint64(i),
r: b.r,
hash: tx.Hash(),
tx: tx,
block: b,
index: uint64(i),
})
}
return &ret, nil
@ -897,11 +897,11 @@ func (b *Block) TransactionAt(ctx context.Context, args struct{ Index int32 }) (
}
tx := txs[args.Index]
return &Transaction{
backend: b.backend,
hash: tx.Hash(),
tx: tx,
block: b,
index: uint64(args.Index),
r: b.r,
hash: tx.Hash(),
tx: tx,
block: b,
index: uint64(args.Index),
}, nil
}
@ -917,7 +917,7 @@ func (b *Block) OmmerAt(ctx context.Context, args struct{ Index int32 }) (*Block
uncle := uncles[args.Index]
blockNumberOrHash := rpc.BlockNumberOrHashWithHash(uncle.Hash(), false)
return &Block{
backend: b.backend,
r: b.r,
numberOrHash: &blockNumberOrHash,
header: uncle,
}, nil
@ -944,7 +944,7 @@ type BlockFilterCriteria struct {
// runFilter accepts a filter and executes it, returning all its results as
// `Log` objects.
func runFilter(ctx context.Context, be ethapi.Backend, filter *filters.Filter) ([]*Log, error) {
func runFilter(ctx context.Context, r *Resolver, filter *filters.Filter) ([]*Log, error) {
logs, err := filter.Logs(ctx)
if err != nil || logs == nil {
return nil, err
@ -952,8 +952,8 @@ func runFilter(ctx context.Context, be ethapi.Backend, filter *filters.Filter) (
ret := make([]*Log, 0, len(logs))
for _, log := range logs {
ret = append(ret, &Log{
backend: be,
transaction: &Transaction{backend: be, hash: log.TxHash},
r: r,
transaction: &Transaction{r: r, hash: log.TxHash},
log: log,
})
}
@ -978,10 +978,10 @@ func (b *Block) Logs(ctx context.Context, args struct{ Filter BlockFilterCriteri
hash = header.Hash()
}
// Construct the range filter
filter := filters.NewBlockFilter(b.backend, hash, addresses, topics)
filter := filters.NewBlockFilter(b.r.backend, hash, addresses, topics)
// Run the filter and return all the logs
return runFilter(ctx, b.backend, filter)
return runFilter(ctx, b.r, filter)
}
func (b *Block) Account(ctx context.Context, args struct {
@ -994,7 +994,7 @@ func (b *Block) Account(ctx context.Context, args struct {
}
}
return &Account{
backend: b.backend,
r: b.r,
address: args.Address,
blockNrOrHash: *b.numberOrHash,
}, nil
@ -1041,7 +1041,7 @@ func (b *Block) Call(ctx context.Context, args struct {
return nil, err
}
}
result, err := ethapi.DoCall(ctx, b.backend, args.Data, *b.numberOrHash, nil, b.backend.RPCEVMTimeout(), b.backend.RPCGasCap())
result, err := ethapi.DoCall(ctx, b.r.backend, args.Data, *b.numberOrHash, nil, b.r.backend.RPCEVMTimeout(), b.r.backend.RPCGasCap())
if err != nil {
return nil, err
}
@ -1066,31 +1066,31 @@ func (b *Block) EstimateGas(ctx context.Context, args struct {
return 0, err
}
}
gas, err := ethapi.DoEstimateGas(ctx, b.backend, args.Data, *b.numberOrHash, b.backend.RPCGasCap())
gas, err := ethapi.DoEstimateGas(ctx, b.r.backend, args.Data, *b.numberOrHash, b.r.backend.RPCGasCap())
return Long(gas), err
}
type Pending struct {
backend ethapi.Backend
r *Resolver
}
func (p *Pending) TransactionCount(ctx context.Context) (int32, error) {
txs, err := p.backend.GetPoolTransactions()
txs, err := p.r.backend.GetPoolTransactions()
return int32(len(txs)), err
}
func (p *Pending) Transactions(ctx context.Context) (*[]*Transaction, error) {
txs, err := p.backend.GetPoolTransactions()
txs, err := p.r.backend.GetPoolTransactions()
if err != nil {
return nil, err
}
ret := make([]*Transaction, 0, len(txs))
for i, tx := range txs {
ret = append(ret, &Transaction{
backend: p.backend,
hash: tx.Hash(),
tx: tx,
index: uint64(i),
r: p.r,
hash: tx.Hash(),
tx: tx,
index: uint64(i),
})
}
return &ret, nil
@ -1101,7 +1101,7 @@ func (p *Pending) Account(ctx context.Context, args struct {
}) *Account {
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
return &Account{
backend: p.backend,
r: p.r,
address: args.Address,
blockNrOrHash: pendingBlockNr,
}
@ -1111,7 +1111,7 @@ func (p *Pending) Call(ctx context.Context, args struct {
Data ethapi.TransactionArgs
}) (*CallResult, error) {
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
result, err := ethapi.DoCall(ctx, p.backend, args.Data, pendingBlockNr, nil, p.backend.RPCEVMTimeout(), p.backend.RPCGasCap())
result, err := ethapi.DoCall(ctx, p.r.backend, args.Data, pendingBlockNr, nil, p.r.backend.RPCEVMTimeout(), p.r.backend.RPCGasCap())
if err != nil {
return nil, err
}
@ -1131,7 +1131,7 @@ func (p *Pending) EstimateGas(ctx context.Context, args struct {
Data ethapi.TransactionArgs
}) (Long, error) {
pendingBlockNr := rpc.BlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
gas, err := ethapi.DoEstimateGas(ctx, p.backend, args.Data, pendingBlockNr, p.backend.RPCGasCap())
gas, err := ethapi.DoEstimateGas(ctx, p.r.backend, args.Data, pendingBlockNr, p.r.backend.RPCGasCap())
return Long(gas), err
}
@ -1152,19 +1152,19 @@ func (r *Resolver) Block(ctx context.Context, args struct {
number := rpc.BlockNumber(*args.Number)
numberOrHash := rpc.BlockNumberOrHashWithNumber(number)
block = &Block{
backend: r.backend,
r: r,
numberOrHash: &numberOrHash,
}
} else if args.Hash != nil {
numberOrHash := rpc.BlockNumberOrHashWithHash(*args.Hash, false)
block = &Block{
backend: r.backend,
r: r,
numberOrHash: &numberOrHash,
}
} else {
numberOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
block = &Block{
backend: r.backend,
r: r,
numberOrHash: &numberOrHash,
}
}
@ -1199,7 +1199,7 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
for i := from; i <= to; i++ {
numberOrHash := rpc.BlockNumberOrHashWithNumber(i)
block := &Block{
backend: r.backend,
r: r,
numberOrHash: &numberOrHash,
}
// Resolve the header to check for existence.
@ -1218,13 +1218,13 @@ func (r *Resolver) Blocks(ctx context.Context, args struct {
}
func (r *Resolver) Pending(ctx context.Context) *Pending {
return &Pending{r.backend}
return &Pending{r}
}
func (r *Resolver) Transaction(ctx context.Context, args struct{ Hash common.Hash }) (*Transaction, error) {
tx := &Transaction{
backend: r.backend,
hash: args.Hash,
r: r,
hash: args.Hash,
}
// Resolve the transaction; if it doesn't exist, return nil.
t, err := tx.resolve(ctx)
@ -1284,8 +1284,8 @@ func (r *Resolver) Logs(ctx context.Context, args struct{ Filter FilterCriteria
topics = *args.Filter.Topics
}
// Construct the range filter
filter := filters.NewRangeFilter(filters.Backend(r.backend), begin, end, addresses, topics)
return runFilter(ctx, r.backend, filter)
filter := filters.NewRangeFilter(r.backend, begin, end, addresses, topics)
return runFilter(ctx, r, filter)
}
func (r *Resolver) GasPrice(ctx context.Context) (hexutil.Big, error) {

@ -56,10 +56,6 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// New constructs a new GraphQL service instance.
func New(stack *node.Node, backend ethapi.Backend, cors, vhosts []string) error {
if backend == nil {
panic("missing backend")
}
// check if http server with given endpoint exists and enable graphQL on it
return newHandler(stack, backend, cors, vhosts)
}

Loading…
Cancel
Save