consensys / ethql Goto Github PK
View Code? Open in Web Editor NEWA GraphQL interface to Ethereum :fire:
License: Apache License 2.0
A GraphQL interface to Ethereum :fire:
License: Apache License 2.0
ethql should be published as an npm module that other projects can import and add to their applications. This is a placeholder description that will be enhanced as the requirement is specified further.
Currently the Block->transactions
field takes a TransactionFilter
as an argument that can filter transactions with input data (i.e. messages). We can introduce first-class support for message calls, such that we allow retrieving the function signature and an array of parameters, only from those transactions that are indeed messages.
Just an idea:
block(number: 123) {
messageCalls(matching: 'functionName(uint256,bytes32)') {
param1: parameter(index: 0)
param2: parameter(index: 1)
}
}
The goal is to create a test suite that starts ethql with different sets of CLI flags and checks that the effective configuration is as expected in each case.
The Block->parent
and Block->miner
fields are modelled, but they are not being populated at the current time.
web3.eth.getBlock
with the parent's hash and would return an EthqlBlock
.EthqlAccount
initialised with the miner's address.If a transaction creates a contract (i.e. to
address is null and the transaction receipt includes a contractAddress
field), the field createdContract
on the Transaction
type must be an Account
entity for the newly created contract address. Else, the field must be null.
We are currently assuming the latest
block in all JSON-RPC queries that accept a quantity. Instead, allow the user to select the block to which queries will be applied to, for example, fetch balances and transaction counts. Possible values: before TX, after TX, latest.
It may be useful to filter transactions by inputData content. This would allow users to target transactions that invoke arbitrary contract methods. The filter might look something like: transactions(filter: { inputStartsWith: "0x12345678" })
.
ethql should refer to classes or entities rather than specific standards. For example, all of ERC20, ERC223, ERC827 relate to tokens.
It is sometimes unfeasible (or hardly worthwhile) to distinguish exactly which standards a given contract implements (although it could be achieved if the contract implements ERC165, or by inspecting the bytecode). Users are generally concerned with the underlying entity.
In the future we might introduce "standards inference" as a functionality, but for now that's not the goal.
Tasks:
In the future, we'll introduce a NonFungibleTokenTxDecoder, in #33.
During the resolution of a single query, it's possible to incur in the same web3 request twice, which is wasteful. This could happen if the user selects the balances
of all to
accounts in all transactions
from a block
, where the same account could've been the recipient of two transactions or more.
Current thinking is to evaluate DataLoader's caching facility, as it appears to be local to single queries.
I was under the impression that a singleton instance of the DataLoader automatically scoped cache reads/writes to the GraphQL request at hand, but it's not the case. Instead, each request needs its own DL instance, if we are to follow the request-scoped cache model.
When requesting transaction values and account balances, the user should have the ability to specify the unit it wants them in:
{
account("0x1234...") {
balance(unit: "finney")
}
}
ethql already has an enum type in the schema with all the units supported by web3, so it's a matter of using the field argument and performing the conversion using web3.utils.fromWei()
.
When deploying ethql as part of a dApp stack, users may want to enhance the list of supported transaction decoders, or even add application-specific queries or entities.
This query selects a block based on a hash or a number, and an offset. The offset can be positive, negative or zero.
Validation: either hash or number MUST be informed, but not both, and offset MUST be informed.
Behaviour:
getBlock
with the hash, add the offset to the block number that comes back, fetch that block and return it.Tests:
The ERC165 standard allows us to interrogate if a contract supports a specific function. It also appears to be a prerequisite for univocally identifying ERC721 contracts (#33).
The current proposal is to add a new field on the Account
type. Suggested definition:
supportsInterface(selector: String!): ERC165Result!
Where ERC165Result is an enum with values:
SUPPORTED
=> if the contract has a supportsInterface(bytes4)
function as mandated by the standard, and the result of the call is true.NOT_SUPPORTED
=> if the contract has a supportsInterface(bytes4)
function as mandated by the standard, and the result of the call is false.NON_INTROSPECTABLE
=> if the contract doesn't expose a supportsInterface(bytes4)
function.The selector argument is the String representation of the function selector (e.g. transfer(address,uint)
). More info here: http://solidity.readthedocs.io/en/v0.4.21/abi-spec.html#function-selector.
The resolver would need to convert the String representation into its corresponding binary representation as per the link above (there might be functions in the web3 lib to do this).
We're seeing recurrent test failures due to intermittent Infura timeouts. It was OK to depend on an external party at the beginning, but now that we have 100+ tests it is brittle to do so.
The proposed solution consists of intercepting web3 requests via the Provider
and responding to them from a filesystem cache which has been populated from mainnet data.
There would be three modes of operation:
record
=> requests and responses are recorded in the filesystem. When writing tests during development, you want to use this mode to automate creating the test data.replay
=> use the local test data created through the record
mode to respond to web3 calls, where possible. If a cache entry cannot be found, invoke the endpoint.passthrough
=> allow all requests to go through to the endpoint.Currently we are calling web3.eth.getBlock(..., true)
when resolving a block, which means that we are fetching all transactions from JSON-RPC unconditionally.
It is possible that the inner query does not request any transactions, e.g.
block(number: 123) {
parent {
hash
}
}
The above case it would've been superfluous to fetch transactions.
Goal:
Make ethql intelligent enough so that it calls getBlock(number, true)
only when resolving the query would require fetching all transaction data. In all other cases, it would call getBlock(number, false)
.
Transactions should be fetched when the query requests these fields:
NOT with:
Design:
To decide whether to fetch transaction or not, we should use the 4th parameter the GraphQL resolvers, as it gives us access to the "GraphQL Resolve Info" object. See https://graphql.org/graphql-js/type/#graphqlobjecttype.
See library: https://github.com/jakepusateri/graphql-list-fields for a way to obtain a list of the inner fields queried.
See specification here: ethereum/EIPs#223
Some function names == ERC-20, so we'll need a mechanism to discriminate between standards when a single function fingerprint is not enough.
In our transition towards a modular and extensible EthQL, we want users to be able to add "capabilities" to EthQL.
A capability is a collection of the following namespaced items, which together define a unit of functionality to be added to EthQL:
extend
keyword to enrich the prior schema, e.g. add tokenContract
to the root query
object in the case of ERC20.Tasks:
The goal is to extend the Address
scalar type to accept and resolve .eth
names, such that the resolvers only see the resolved address. The ethereum-ens library could be used to perform the resolution.
We'll need to introduce an extra configuration option to set the address of the ENS contract. We can also support a keyword identifying the network against a set of hardcoded values (e.g. MAINNET, ROPSTEN, KOVAN, etc.).
Notes:
parseValue
and parseLiteral
of the Address scalar type would perform the ENS name => address resolution. It is not clear to me if these methods can be async or can return a promise, and if graphql-js will await on it before invoking the resolvers.Design a schema to cover these entities.
Add documentation under the Github wiki.
Documentation should include:
What else should be added?
I'd love to use ethql for a project I'm working on where I would be analyzing a specific token. Except for a couple examples in the readme, I don't see any documentation on how to use this tool for querying Ethereum. What's the best way to approach this?
Consider the following query:
{
account(address: "0x1234...") {
tokenHoldings {
snt: tokenContract(address: "0x744d70fdbe2ba4cf95131626614a1763df805b9e")
}
}
}
In the future, ethql could allow the user to configure static addresses for tokens they know/are interested in.
Lower the load on Infura too for https://ethql-alpha.infura.io/graphql
https://blog.apollographql.com/announcing-apollo-server-2-2b69fb4702ce?gi=c9f8d90c7e53
When storage is called on an account generated by "transaction -> to" it returns an error message "Provided address "null" is invalid, the capitalization checksum test failed, or its an indrect IBAN address which can't be converted." and then the data itself.
Example query:
{ block(number: 5000000) { transactions { to { storage { value(at: 0) } } } } }
Hello Raul :)
where is the public meteor accounts-blockstack
https://twitter.com/raulvk/status/938863422103539713
Consider the following selection of an ERC20 transaction:
{
block(number: 1234) {
transactions {
decoded {
... on ERC20Transfer {
symbol // new
totalSupply // new
from {
address
tokenBalance // new
allowance(spender: "0x1923...") // new
}
to {
address
}
value
}
}
}
}
}
ethql currently supports a request-scoped cache, but there is benefit to shared caching. In a production scenario, it is likely that the youngest blocks will be hottest, and that highly used smart contracts will garner higher ethql traffic.
However, there is also risk:
Ultimately I see a two-level cache:
The goal is to aggregate all web3 requests that occur within a single tick of the Node.js runtime into a single JSON-RPC batch request. We can leverage Facebook's DataLoader for this.
Proposal:
web3.eth
object. One way or another, the calling code would only see a Promise
back.See: https://graphql.org/learn/pagination/
The edges->nodes
indirection advised on that doc may be too heavyweight for us. A simpler aproach like making pageable entities implement a Pageable
interface that adds an inner field cursor
may be sufficient. See discussion below.
transactionsRoles with the 'to' and 'from' fields specified is returning transactions that satisfy either the 'to' address or the 'from' address or satisfy both. It should return just transactions that satisfy both the 'from' and the 'to' address.
Enum with values:
EthQL currently models data entities through a variety of classes like EthqlAccount, EthqlBlock, EthqlTransaction, etc. Some of these inherit from their web3 counterparts, overriding scalar fields with entity relations.
In this manner, an EthqlTransaction no longer refers to accounts by their string addresses, but by references to EthqlAccounts, essentially adding referentiality to data entities.
However, these entities also contain the GraphQL resolution logic, which makes them heavy and difficult to extend. In a modular EthQL, modules should be able to add, extend, modify and remove resolvers, which proves difficult if these are buried in Typescript classes.
Tasks:
resolvers/account.ts
, resolvers/block.ts
, etc.This epic groups transaction decoding components, of which ERC-20 was the first one to be implemented in ethql.
This field maps to the status
field in the response of getTransactionReceipt
, which should be called with the transaction hash. Value 1 maps to SUCCESS
and value 0 maps to FAILURE
.
An empty status
is also possible, because this field was introduced in Byzantium (after block 4,370,000). If that's the case, this field should be empty.
Three test cases:
Add support for decoding ERC-721 transactions.
Some standards build upon others, e.g. ERC20 vs ERC223, so identifying the underlying standard may prove difficult, and sometimes impossible, without inspecting the contract bytecode.
If we were to inspect the bytecode, we could look for EVM JUMPDEST
and match those against function signature hashes, to try to infer the external interface of a contract against a known set of ABIs.
However, if both interfaces are equivalent, we are out of luck.
Hence, instead of referring to standard numbers, ethql could refer to the concept behind the standard, e.g. tokens (or fungibleTokens, to differentiate from ERC-721).
Mono repo with lerna and yarn workspaces?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.