Skip to content

Instantly share code, notes, and snippets.

@Arachnid
Created September 28, 2018 15:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Arachnid/2f95b7d8566366b34fb4751ad55c5dc4 to your computer and use it in GitHub Desktop.
Save Arachnid/2f95b7d8566366b34fb4751ad55c5dc4 to your computer and use it in GitHub Desktop.
#import asyncio
import logging
from flask import Blueprint, Flask, request, render_template, g
from flask_graphql import GraphQLView
from google.cloud import logging as glogging
#from graphql.execution.executors.asyncio import AsyncioExecutor
from web3 import Web3, HTTPProvider
from werkzeug.serving import run_simple
from graphql import (
graphql,
GraphQLArgument,
GraphQLSchema,
GraphQLObjectType,
GraphQLField,
GraphQLList,
GraphQLString,
GraphQLFloat,
GraphQLInt,
GraphQLBoolean
)
from graphql.type.scalars import (
GraphQLScalarType,
coerce_string,
parse_string_literal
)
def get_blocks(hashes):
return [web3.eth.getBlock(hash) for hash in hashes]
def get_transactions(hashes):
return [web3.eth.getTransaction(hash) for hash in hashes]
def coerce_hash(hash):
return hash.hex()
GraphQLHexBytes = GraphQLScalarType(name="HexBytes", serialize=coerce_hash, parse_value=coerce_string, parse_literal=parse_string_literal)
Log = GraphQLObjectType(
name='Log',
fields=lambda:{
"address": GraphQLField(GraphQLString),
"topics": GraphQLField(GraphQLList(GraphQLHexBytes)),
"data": GraphQLField(GraphQLString),
"transactionHash": GraphQLField(GraphQLHexBytes),
"transactionIndex": GraphQLField(GraphQLInt),
"transaction": GraphQLField(Transaction, resolver=lambda root, info: web3.eth.getTransaction(root.transactionHash)),
"blockNumber": GraphQLField(GraphQLInt),
"blockHash": GraphQLField(GraphQLHexBytes),
"block": GraphQLField(Block, resolver=lambda root, info: web3.eth.getBlock(root.blockHash)),
"logIndex": GraphQLField(GraphQLInt),
"removed": GraphQLField(GraphQLBoolean),
}
)
TransactionReceipt = GraphQLObjectType(
name='TransactionReceipt',
fields=lambda:{
"block": GraphQLField(Block, resolver=lambda root, info: web3.eth.getBlock(root.blockHash)),
"blockHash": GraphQLField(GraphQLHexBytes),
"blockNumber": GraphQLField(GraphQLInt),
"contractAddress": GraphQLField(GraphQLString),
"cumulativeGasUsed": GraphQLField(GraphQLInt),
"from": GraphQLField(GraphQLString),
"gasUsed": GraphQLField(GraphQLInt),
"logs": GraphQLField(GraphQLList(Log)),
"logsBloom": GraphQLField(GraphQLHexBytes),
"status": GraphQLField(GraphQLInt),
"to": GraphQLField(GraphQLString),
"transactionHash": GraphQLField(GraphQLString),
"transactionIndex": GraphQLField(GraphQLInt),
"transaction": GraphQLField(Transaction, resolver=lambda root, info: web3.eth.getTransaction(root.transactionHash)),
}
)
Transaction = GraphQLObjectType(
name='Transaction',
fields=lambda:{
"block": GraphQLField(Block, resolver=lambda root, info: web3.eth.getBlock(root.blockHash)),
"blockHash": GraphQLField(GraphQLHexBytes),
"blockNumber": GraphQLField(GraphQLInt),
"from": GraphQLField(GraphQLString),
"to": GraphQLField(GraphQLString),
"gas": GraphQLField(GraphQLInt),
"gasPrice": GraphQLField(GraphQLInt),
"hash": GraphQLField(GraphQLHexBytes),
"input": GraphQLField(GraphQLString),
"nonce": GraphQLField(GraphQLInt),
"transactionIndex": GraphQLField(GraphQLInt),
"value": GraphQLField(GraphQLString),
"v": GraphQLField(GraphQLInt),
"r": GraphQLField(GraphQLHexBytes),
"s": GraphQLField(GraphQLHexBytes),
"receipt": GraphQLField(TransactionReceipt, resolver=lambda root, info: web3.eth.getTransactionReceipt(root.hash)),
}
)
Block = GraphQLObjectType(
name='Block',
fields=lambda:{
"difficulty": GraphQLField(GraphQLFloat),
"extraData": GraphQLField(GraphQLHexBytes),
"gasLimit": GraphQLField(GraphQLInt),
"gasUsed": GraphQLField(GraphQLInt),
"hash": GraphQLField(GraphQLHexBytes),
"logsBloom": GraphQLField(GraphQLHexBytes),
"miner": GraphQLField(GraphQLHexBytes),
"mixHash": GraphQLField(GraphQLHexBytes),
"nonce": GraphQLField(GraphQLHexBytes),
"number": GraphQLField(GraphQLInt),
"parentHash": GraphQLField(GraphQLHexBytes),
"parent": GraphQLField(Block, resolver=lambda root, info: web3.eth.getBlock(root.parentHash)),
"receiptsRoot": GraphQLField(GraphQLHexBytes),
"sha3Uncles": GraphQLField(GraphQLHexBytes),
"size": GraphQLField(GraphQLInt),
"stateRoot": GraphQLField(GraphQLHexBytes),
"timestamp": GraphQLField(GraphQLInt),
"totalDifficulty": GraphQLField(GraphQLFloat),
"transactions": GraphQLField(GraphQLList(Transaction), resolver=lambda root, info: get_transactions(root.transactions)),
"transactionsRoot": GraphQLField(GraphQLHexBytes),
"uncles": GraphQLField(GraphQLList(Block), resolver=lambda root, info: get_blocks(root.uncles)),
}
)
schema = GraphQLSchema(
query= GraphQLObjectType(
name='Query',
fields={
'block': GraphQLField(
Block,
args={
"number": GraphQLArgument(type=GraphQLInt),
"hash": GraphQLArgument(type=GraphQLString)
},
resolver=lambda root, info, number=None, hash=None: web3.eth.getBlock(number or hash)
),
'transaction': GraphQLField(
Transaction,
args={
"hash": GraphQLArgument(type=GraphQLString)
},
resolver=lambda root, info, hash: web3.eth.getTransaction(hash)
)
}
)
)
web3 = Web3(HTTPProvider())
app = Flask(__name__)
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True, context=web3))
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
run_simple('localhost', 8080, app, use_reloader=True)
else:
logger = glogging.Client()
logger.setup_logging(log_level=logging.INFO)
@veox
Copy link

veox commented Sep 28, 2018

Copy-paste from gitter (highlight mine):

I thought I'd see how easy it was to use web3.py to create a graphql endpoint from the web3 API. Turns out, surprisingly easy! https://gist.github.com/Arachnid/2f95b7d8566366b34fb4751ad55c5dc4

Run that in an environment with a local node, and web3.py, graphql-core and flask-graphql installed, and it'll give you a nifty explorer for querying your node using graphql

Currently it only supports blocks, transactions, receipts, and logs, but it'd be easy to add more.

@fubuloubu
Copy link

$ python web3graphql.py 
Traceback (most recent call last):
  File "web3graphql.py", line 5, in <module>
    from google.cloud import logging as glogging
ModuleNotFoundError: No module named 'google'

$ pip install google
Collecting google
...
Successfully installed beautifulsoup4-4.6.3 google-2.0.1

$ python web3graphql.py 
Traceback (most recent call last):
  File "web3graphql.py", line 5, in <module>
    from google.cloud import logging as glogging
ModuleNotFoundError: No module named 'google'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment