add more query fields and resolvers to graphql api

after EIP2718/EIP2930, we have additional fields:

type AccessTuple {
  address: Address!
  storageKeys : [Bytes32!]
}

type Transaction {
  r: BigInt!
  s: BigInt!
  v: BigInt!
  # Envelope transaction support
  type: Int
  accessList: [AccessTuple!]
}

close #606
This commit is contained in:
jangko 2021-05-17 20:45:37 +07:00
parent af1537fcab
commit 0ecf9fe1af
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
3 changed files with 111 additions and 8 deletions

View File

@ -33,6 +33,7 @@ type
ethPending = "Pending"
ethQuery = "Query"
ethMutation = "Mutation"
ethAccessTuple = "AccessTuple"
HeaderNode = ref object of Node
header: BlockHeader
@ -54,6 +55,9 @@ type
index: int
tx: TxNode
AclNode = ref object of Node
acl: AccessPair
GraphqlContextRef = ref GraphqlContextObj
GraphqlContextObj = object of Graphql
ids: array[EthTypes, Name]
@ -104,6 +108,14 @@ proc logNode(ctx: GraphqlContextRef, log: Log, index: int, tx: TxNode): Node =
tx: tx
)
proc aclNode(ctx: GraphqlContextRef, accessPair: AccessPair): Node =
AclNode(
kind: nkMap,
typeName: ctx.ids[ethAccessTuple],
pos: Pos(),
acl: accessPair
)
proc getAccountDb(chainDB: BaseChainDB, header: BlockHeader): ReadOnlyStateDB =
## Retrieves the account db from canonical head
## we don't use accounst_cache here because it's only read operations
@ -638,6 +650,34 @@ proc txLogs(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
list.add logNode(ctx, n, i, tx)
ok(list)
proc txR(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
bigIntNode(tx.tx.R)
proc txS(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
bigIntNode(tx.tx.S)
proc txV(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
bigIntNode(tx.tx.V)
proc txType(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
let typ = resp(ord(tx.tx.txType))
ok(typ)
proc txAccessList(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
let tx = TxNode(parent)
if tx.tx.txType == LegacyTxType:
ok(respNull())
else:
var list = respList()
for x in tx.tx.accessListTx.accessList:
list.add aclNode(ctx, x)
ok(list)
const txProcs = {
"from": txFrom,
"hash": txHash,
@ -653,7 +693,31 @@ const txProcs = {
"gasUsed": txGasUsed,
"cumulativeGasUsed": txCumulativeGasUsed,
"createdContract": txCreatedContract,
"logs": txLogs
"logs": txLogs,
"r": txR,
"s": txS,
"v": txV,
"type": txType,
"accessList": txAccessList
}
proc aclAddress(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let acl = AclNode(parent)
resp(acl.acl.address)
proc aclStorageKeys(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let acl = AclNode(parent)
if acl.acl.storageKeys.len == 0:
ok(respNull())
else:
var list = respList()
for n in acl.acl.storageKeys:
list.add resp(n).get()
ok(list)
const aclProcs = {
"address": aclAddress,
"storageKeys": aclStorageKeys
}
proc blockNumberImpl(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
@ -1086,17 +1150,17 @@ type
qcFields = "fields"
qcBlock = "block"
qcTransaction = "Transaction"
EthQueryComplexity = ref object of QueryComplexity
names: array[QcNames, Name]
proc calcQC(qc: QueryComplexity, field: FieldRef): int {.cdecl,
proc calcQC(qc: QueryComplexity, field: FieldRef): int {.cdecl,
gcsafe, raises: [Defect, CatchableError].} =
let qc = EthQueryComplexity(qc)
if field.parentType.sym.name == qc.names[qcType] and
field.field.name.name == qc.names[qcFields]:
return 100
elif field.parentType.sym.name == qc.names[qcTransaction] and
elif field.parentType.sym.name == qc.names[qcTransaction] and
field.field.name.name == qc.names[qcBlock]:
return 100
else:
@ -1110,7 +1174,7 @@ proc newQC(ctx: GraphqlContextRef): EthQueryComplexity =
let name = ctx.createName($n)
qc.names[n] = name
qc
proc initEthApi(ctx: GraphqlContextRef) =
ctx.customScalar("Bytes32", scalarBytes32)
ctx.customScalar("Address", scalarAddress)
@ -1131,10 +1195,11 @@ proc initEthApi(ctx: GraphqlContextRef) =
ctx.addResolvers(ctx, ctx.ids[ethPending ], pendingProcs)
ctx.addResolvers(ctx, ctx.ids[ethQuery ], queryProcs)
ctx.addResolvers(ctx, ctx.ids[ethMutation ], mutationProcs)
ctx.addResolvers(ctx, ctx.ids[ethAccessTuple], aclProcs)
var qc = newQC(ctx)
ctx.addInstrument(qc)
let res = ctx.parseSchema(ethSchema)
if res.isErr:
echo res.error

View File

@ -62,6 +62,15 @@ type Log {
transaction: Transaction!
}
# EIP-2718 Access List
type AccessTuple {
# access list address
address: Address!
# access list storage keys, null if not present
storageKeys: [Bytes32!]
}
# Transaction is an Ethereum transaction.
type Transaction {
# Hash is the hash of this transaction.
@ -123,6 +132,21 @@ type Transaction {
# Logs is a list of log entries emitted by this transaction. If the
# transaction has not yet been mined, this field will be null.
logs: [Log!]
# signature field R
r: BigInt!
# signature fields S
s: BigInt!
# signature fields V
v: BigInt!
# EIP 2718: envelope transaction support
type: Int
# EIP 2930: optional access list, null if not present
accessList: [AccessTuple!]
}
# BlockFilterCriteria encapsulates log filter criteria for a filter applied

View File

@ -29,6 +29,7 @@
{"name":"Bytes"},
{"name":"String"},
{"name":"Bytes32"},
{"name":"AccessTuple"},
{"name":"BlockFilterCriteria"},
{"name":"ID"},
{"name":"Pending"},
@ -194,6 +195,14 @@
logs {
__typename
}
r
s
v
type
accessList {
address
storageKeys
}
}
transactionAt(index: 0) {
__typename
@ -230,7 +239,12 @@
"gasUsed":21000,
"cumulativeGasUsed":21000,
"createdContract":null,
"logs":[]
"logs":[],
"r":"0x77c7cd36820c71821c1aed59de46e70e701c4a8dd89c9ba508ab722210f60da8",
"s":"0x3f29825d40c7c3f7bff3ca69267e0f3fb74b2d18b8c2c4e3c135b5d3b06e288d",
"v":"0x1b",
"type":0,
"accessList":null
}
],
"transactionAt":{