go-ethereum icon indicating copy to clipboard operation
go-ethereum copied to clipboard

graphql: fix return types to be compatible with schema definition

Open Shiti opened this issue 2 years ago • 19 comments

According to the schema definition and spec defined here, the transaction fields gas, nonce and the block field timestamp should be decimal. This is inline with the other Long values like transaction status, etc

Shiti avatar Nov 05 '22 15:11 Shiti

@s1na or @gballet PTAL as codeowners

holiman avatar Nov 07 '22 08:11 holiman

Just noting here that this is a compatibility-breaking change. We've been returning hex-encoded strings from graphql for years, so there will likely be issues in some client software trying to parse these results. Maybe the schema should be changed instead?

fjl avatar Nov 07 '22 16:11 fjl

I think that we should update the version and release notes to indicate this. Changing schema definition will result in incompatibility with the ethereum api-spec

Shiti avatar Nov 07 '22 17:11 Shiti

@s1na is in charge of the spec, so he'll be able to make a good decision here.

fjl avatar Nov 07 '22 17:11 fjl

Just noting here that this is a compatibility-breaking change.

IMO, if there is a spec, and we are not following it, then we're in the wrong and need to change it.

holiman avatar Nov 09 '22 07:11 holiman

I agree we should change these to decimal. Right now we have some fields that return a hex-encoded value, some that return decimal, all with a Long type in the schema. To stay consistent we should change one of these groups which would be a breaking change anyway.

From discussion:

The intention is that longs are read and formatted as numbers; GraphQL only specifies a 31 bit integer type, and it’s useful to be able to use a longer (52 bit, safely in Javascript) numeric type.

I think this intention prompted PRs such as https://github.com/ethereum/go-ethereum/pull/21883. At the time not all fields were converted. IMO we should do this now.

In addition to the ones you converted there are also the SyncState fields that currently return hexutil.Uint64. Can you please change those too?

s1na avatar Nov 09 '22 14:11 s1na

It's weird, many of the methods defined for SyncState have no corresponding field in the schema. I.e. they're not queryable. We should either drop them or add them to schema.

s1na avatar Nov 09 '22 15:11 s1na

The api-spec does not mention or refer to SyncState. Based on the code, it looks like those types and methods are not exposed in graphql either. I think it would be best to create a separate PR for changes to that code, be it cleanup or refactoring since it is unrelated to these changes. I can create that PR depending on how we want to deal with that code.

Shiti avatar Nov 09 '22 18:11 Shiti

The API specification (https://github.com/ethereum/execution-apis) was created only very recently, and we literally copied the existing GraphQL schema there without changing it. It would be good to get to the point where schema and responses align again, but keeping the de-facto API outputs stable should be preferred over changing the output to match the existing (but apparently wrong) schema.

The GraphQL stance on versioning seems to be that

new capabilities can be added via new types and new fields on those types without creating a breaking change. This has led to a common practice of always avoiding breaking changes and serving a versionless API.

i.e. they recommend just adding new fields with a different type, which could then be requested. I guess, if we take that literally, the correct solution is adding new fields like timestampNumeric.

fjl avatar Nov 10 '22 13:11 fjl

We literally copied it over means it was not created recently. It's an old standard, and we have not been compliant. Graphql has always been schema-first, as opposed to out old json-rpc. Imo we are at liberty to ruthlessly pursue standard compliance for graphql, since it's newer and more schema-centric. So I still think we should just fix our erroneous behavior. 

holiman avatar Nov 10 '22 13:11 holiman

Account.TransactionCount seems to be wrong too

karalabe avatar Nov 30 '22 13:11 karalabe

@karalabe thanks for catching that. I've updated the PR

Shiti avatar Nov 30 '22 20:11 Shiti

The following job is failing but I dont think it is related to these changes. Could someone guide me on how to resolve this ?

Image: Visual Studio 2019; Environment: GETH_ARCH=386, GETH_MINGW=C:\msys64\mingw32

Shiti avatar Dec 03 '22 21:12 Shiti

Thats a flaky test, we can just ignore it. Not a showstopper for your pr

MariusVanDerWijden avatar Dec 06 '22 10:12 MariusVanDerWijden

Discussion result:

Going back to the spec, we find that the definition of Long does not explicitly state the scalar type. It can be interpreted to mean that Long values should be integers, but strings are also permitted by "kind": "SCALAR".

So a follow-up task is defining this better in the spec. If we choose to do it the way it's implemented in the PR, we should explicitly define Long as an integer.

fjl avatar Dec 06 '22 14:12 fjl

We have already defined the custom scalar Long as an integer in our graphql server setup - https://github.com/ethereum/go-ethereum/blob/master/graphql/graphql.go#L45-L76

Do we wish to modify this and throw an error when base 10 strings are passed to unmarshal ? Or are you referring to something else ? Am I missing something ?

Shiti avatar Dec 07 '22 19:12 Shiti

My comment was mostly for @s1na, and was referring to the execution-apis spec: https://github.com/ethereum/execution-apis/blob/f33432b3a3f3d6de6ff5e7977f580376df9b57d9/graphql.json#L1226-L1235

fjl avatar Dec 07 '22 21:12 fjl

@fjl thanks for the clarification.

I think the ethereum API spec is correct as its the implementation's responsibility to ensure type validation

In most GraphQL service implementations, there is also a way to specify custom scalar types. For example, we could define a Date type:

scalar Date

Then it's up to our implementation to define how that type should be serialized, deserialized, and validated. For example, you could specify that the Date type should always be serialized into an integer timestamp, and your client should know to expect that format for any date fields.

https://graphql.org/learn/schema/#scalar-types

Shiti avatar Dec 08 '22 02:12 Shiti

@s1na @fjl Is there anything I can do to help with this ?

Shiti avatar Jan 09 '23 17:01 Shiti

@s1na, since #26894 is merged, should this PR be closed, or what is the status?

holiman avatar Apr 26 '23 13:04 holiman

Yes, closing this as resolved.

s1na avatar Apr 27 '23 08:04 s1na