grpahql: add EIP-2718 and EIP-1559 features to graphql API

EIP-2718:
- chainID: Long! of Query
- chainID: Long of Transaction

EIP-1559:
- baseFeePerGas: BigInt of Block
- effectiveGasPrice: BigInt of Transaction
- maxFeePerGas: BigInt of Transaction
- maxPriorityFeePerGas: BigInt of Transaction
This commit is contained in:
jangko 2021-09-20 19:58:24 +07:00
parent 7a42d037f2
commit f3d194c05e
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
3 changed files with 119 additions and 11 deletions

View File

@ -49,6 +49,7 @@ type
blockNumber: BlockNumber
receipt: Receipt
gasUsed: GasInt
baseFee: Option[UInt256]
LogNode = ref object of Node
log: Log
@ -88,14 +89,15 @@ proc accountNode(ctx: GraphqlContextRef, acc: Account, address: EthAddress, db:
db: db
)
proc txNode(ctx: GraphqlContextRef, tx: Transaction, index: int, blockNumber: BlockNumber): Node =
proc txNode(ctx: GraphqlContextRef, tx: Transaction, index: int, blockNumber: BlockNumber, baseFee: Option[UInt256]): Node =
TxNode(
kind: nkMap,
typeName: ctx.ids[ethTransaction],
pos: Pos(),
tx: tx,
index: index,
blockNumber: blockNumber
blockNumber: blockNumber,
baseFee: baseFee
)
proc logNode(ctx: GraphqlContextRef, log: Log, index: int, tx: TxNode): Node =
@ -254,7 +256,7 @@ proc getTxs(ctx: GraphqlContextRef, header: BlockHeader): RespResult =
var index = 0
for n in getBlockTransactionData(ctx.chainDB, header.txRoot):
let tx = rlp.decode(n, Transaction)
list.add txNode(ctx, tx, index, header.blockNumber)
list.add txNode(ctx, tx, index, header.blockNumber, header.fee)
inc index
index = 0
@ -276,7 +278,7 @@ proc getTxAt(ctx: GraphqlContextRef, header: BlockHeader, index: int): RespResul
try:
var tx: Transaction
if getTransaction(ctx.chainDB, header.txRoot, index, tx):
let txn = txNode(ctx, tx, index, header.blockNumber)
let txn = txNode(ctx, tx, index, header.blockNumber, header.fee)
var i = 0
var prevUsed = 0.GasInt
@ -595,9 +597,46 @@ proc txValue(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.}
bigIntNode(tx.tx.value)
proc txGasPrice(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
let tx = TxNode(parent)
bigIntNode(tx.tx.gasPrice)
if tx.tx.txType == TxEip1559:
if tx.baseFee.isNone:
return bigIntNode(tx.tx.gasPrice)
let baseFee = tx.baseFee.get().truncate(GasInt)
let priorityFee = min(tx.tx.maxPriorityFee, tx.tx.maxFee - baseFee)
bigIntNode(priorityFee + baseFee)
else:
bigIntNode(tx.tx.gasPrice)
proc txMaxFeePerGas(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
if tx.tx.txType == TxEip1559:
bigIntNode(tx.tx.maxFee)
else:
ok(respNull())
proc txMaxPriorityFeePerGas(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
if tx.tx.txType == TxEip1559:
bigIntNode(tx.tx.maxPriorityFee)
else:
ok(respNull())
proc txEffectiveGasPrice(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
if tx.baseFee.isNone:
return bigIntNode(tx.tx.gasPrice)
let baseFee = tx.baseFee.get().truncate(GasInt)
let priorityFee = min(tx.tx.maxPriorityFee, tx.tx.maxFee - baseFee)
bigIntNode(priorityFee + baseFee)
proc txChainId(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let tx = TxNode(parent)
if tx.tx.txType == TxLegacy:
ok(respNull())
else:
longNode(tx.tx.chainId.uint64)
proc txGas(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
@ -706,7 +745,11 @@ const txProcs = {
"s": txS,
"v": txV,
"type": txType,
"accessList": txAccessList
"accessList": txAccessList,
"maxFeePerGas": txMaxFeePerGas,
"maxPriorityFeePerGas": txMaxPriorityFeePerGas,
"effectiveGasPrice": txEffectiveGasPrice,
"chainID": txChainId
}
proc aclAddress(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
@ -919,6 +962,13 @@ proc blockEstimateGas(ud: RootRef, params: Args, parent: Node): RespResult {.api
except Exception as em:
err("estimateGas error: " & em.msg)
proc blockBaseFeePerGas(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let h = HeaderNode(parent)
if h.header.fee.isSome:
bigIntNode(h.header.fee.get)
else:
ok(respNull())
const blockProcs = {
"parent": blockParent,
"number": blockNumberImpl,
@ -946,7 +996,8 @@ const blockProcs = {
"logs": blockLogs,
"account": blockAccount,
"call": blockCall,
"estimateGas": blockEstimateGas
"estimateGas": blockEstimateGas,
"baseFeePerGas": blockBaseFeePerGas
}
proc callResultData(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
@ -1118,6 +1169,14 @@ proc querySyncing(ud: RootRef, params: Args, parent: Node): RespResult {.apiPrag
let ctx = GraphqlContextRef(ud)
ok(respMap(ctx.ids[ethSyncState]))
proc queryMaxPriorityFeePerGas(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
# TODO: stub, missing impl
err("not implemented")
proc queryChainId(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =
let ctx = GraphqlContextRef(ud)
longNode(ctx.chainDB.config.chainId.uint64)
const queryProcs = {
"account": queryAccount,
"block": queryBlock,
@ -1127,7 +1186,9 @@ const queryProcs = {
"logs": queryLogs,
"gasPrice": queryGasPrice,
"protocolVersion": queryProtocolVersion,
"syncing": querySyncing
"syncing": querySyncing,
"maxPriorityFeePerGas": queryMaxPriorityFeePerGas,
"chainID": queryChainId
}
proc sendRawTransaction(ud: RootRef, params: Args, parent: Node): RespResult {.apiPragma.} =

View File

@ -66,7 +66,7 @@ type Log {
type AccessTuple {
# access list address
address: Address!
# access list storage keys, null if not present
storageKeys: [Bytes32!]
}
@ -97,6 +97,12 @@ type Transaction {
# GasPrice is the price offered to miners for gas, in wei per unit.
gasPrice: BigInt!
# MaxFeePerGas is the maximum fee per gas offered to include a transaction, in wei.
maxFeePerGas: BigInt
# MaxPriorityFeePerGas is the maximum miner tip per gas offered to include a transaction, in wei.
maxPriorityFeePerGas: BigInt
# Gas is the maximum amount of gas this transaction can consume.
gas: Long!
@ -124,6 +130,14 @@ type Transaction {
# will be null.
cumulativeGasUsed: Long
# EffectiveGasPrice is actual value per gas deducted from the sender's
# account. Before EIP-1559, this is equal to the transaction's gas price.
# After EIP-1559, it is baseFeePerGas + min(maxFeePerGas - baseFeePerGas,
# maxPriorityFeePerGas). Legacy transactions and EIP-2930 transactions are
# coerced into the EIP-1559 format by setting both maxFeePerGas and
# maxPriorityFeePerGas as the transaction's gas price.
effectiveGasPrice: BigInt
# CreatedContract is the account that was created by a contract creation
# transaction. If the transaction was not a contract creation transaction,
# or it has not yet been mined, this field will be null.
@ -147,6 +161,10 @@ type Transaction {
# EIP 2930: optional access list, null if not present
accessList: [AccessTuple!]
# If type == 0, chainID returns null.
# If type > 0, chainID returns replay protection chainID
chainID: Long
}
# BlockFilterCriteria encapsulates log filter criteria for a filter applied
@ -209,6 +227,9 @@ type Block {
# GasUsed is the amount of gas that was used executing transactions in this block.
gasUsed: Long!
# BaseFeePerGas is the fee perunit of gas burned by the protocol in this block.
baseFeePerGas: BigInt
# Timestamp is the unix timestamp at which this block was mined.
timestamp: BigInt!
@ -282,6 +303,12 @@ input CallData {
# GasPrice is the price, in wei, offered for each unit of gas.
gasPrice: BigInt
# MaxFeePerGas is the maximum fee per gas offered, in wei.
maxFeePerGas: BigInt
# MaxPriorityFeePerGas is the maximum miner tip per gas offered, in wei.
maxPriorityFeePerGas: BigInt
# Value is the value, in wei, sent along with the call.
value: BigInt
@ -394,11 +421,18 @@ type Query {
# ensure a transaction is mined in a timely fashion.
gasPrice: BigInt!
# MaxPriorityFeePerGas returns the node's estimate of a gas tip sufficient
# to ensure a transaction is mined in a timely fashion.
maxPriorityFeePerGas: BigInt!
# ProtocolVersion returns the current wire protocol version number.
protocolVersion: Int!
# Syncing returns information on the current synchronisation state.
syncing: SyncState
# ChainID returns the current chain ID for transaction replay protection.
chainID: Long!
}
type Mutation {

View File

@ -45,6 +45,7 @@
name = "query.block(number)"
code = """
{
chainID
block(number: 3) {
__typename
number
@ -68,6 +69,7 @@
}
extraData
gasLimit
baseFeePerGas
gasUsed
timestamp
logsBloom
@ -104,6 +106,7 @@
"""
result = """
{
"chainID":1,
"block":{
"__typename":"Block",
"number":3,
@ -127,6 +130,7 @@
},
"extraData":"0x42",
"gasLimit":3141592,
"baseFeePerGas":null,
"gasUsed":21000,
"timestamp":"0x54c99839",
"logsBloom":"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
@ -203,6 +207,11 @@
address
storageKeys
}
maxFeePerGas
maxPriorityFeePerGas
effectiveGasPrice
chainID
}
transactionAt(index: 0) {
__typename
@ -244,7 +253,11 @@
"s":"0x773806df18e22db29acde1dd96c0418e28738af7f520e5e2c5c673494029e5",
"v":"0x1b",
"type":0,
"accessList":null
"accessList":null,
"maxFeePerGas":null,
"maxPriorityFeePerGas":null,
"effectiveGasPrice":"0x3e8",
"chainID":null
}
],
"transactionAt":{