Implement graphql query to get header with transactions

This commit is contained in:
Prathamesh Musale 2022-05-25 18:43:53 +05:30 committed by nabarun
parent 248d9eb7a2
commit f144d932cd
3 changed files with 277 additions and 22 deletions

View File

@ -576,7 +576,7 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (models.Header
// RetrieveHeaderCIDByHash returns the header for the given block hash
func (ecr *CIDRetriever) RetrieveHeaderCIDByHash(tx *sqlx.Tx, blockHash common.Hash) (models.HeaderModel, error) {
log.Debug("retrieving header cids for block hash ", blockHash.String())
pgStr := `SELECT block_hash,cid,mh_key FROM eth.header_cids
pgStr := `SELECT block_hash, CAST(block_number as Text), parent_hash, cid, mh_key, timestamp FROM eth.header_cids
WHERE block_hash = $1`
var headerCID models.HeaderModel
return headerCID, tx.Get(&headerCID, pgStr, blockHash.String())
@ -604,3 +604,86 @@ func (ecr *CIDRetriever) RetrieveReceiptCIDsByTxIDs(tx *sqlx.Tx, txHashes []stri
var rctCIDs []models.ReceiptModel
return rctCIDs, tx.Select(&rctCIDs, pgStr, pq.Array(txHashes))
}
func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockNumber(blockNumber int64) ([]models.HeaderModel, [][]models.TxModel, error) {
log.Debug("retrieving header cids and tx cids for block number ", blockNumber)
// Begin new db tx
tx, err := ecr.db.Beginx()
if err != nil {
return nil, nil, err
}
defer func() {
if p := recover(); p != nil {
shared.Rollback(tx)
panic(p)
} else if err != nil {
shared.Rollback(tx)
} else {
err = tx.Commit()
}
}()
var headerCIDs []models.HeaderModel
headerCIDs, err = ecr.RetrieveHeaderCIDs(tx, blockNumber)
if err != nil {
log.Error("header cid retrieval error")
return nil, nil, err
}
if len(headerCIDs) < 1 {
return nil, nil, fmt.Errorf("header cid retrieval error, no header CIDs found at block %d", blockNumber)
}
var allTxCIDs [][]models.TxModel
for _, headerCID := range headerCIDs {
var txCIDs []models.TxModel
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.BlockHash)
if err != nil {
log.Error("tx cid retrieval error")
return nil, nil, err
}
allTxCIDs = append(allTxCIDs, txCIDs)
}
return headerCIDs, allTxCIDs, nil
}
func (ecr *CIDRetriever) RetrieveHeaderAndTxCIDsByBlockHash(blockHash common.Hash) (models.HeaderModel, []models.TxModel, error) {
log.Debug("retrieving header cid and tx cids for block hash ", blockHash.String())
// Begin new db tx
tx, err := ecr.db.Beginx()
if err != nil {
return models.HeaderModel{}, nil, err
}
defer func() {
if p := recover(); p != nil {
shared.Rollback(tx)
panic(p)
} else if err != nil {
shared.Rollback(tx)
} else {
err = tx.Commit()
}
}()
var headerCID models.HeaderModel
headerCID, err = ecr.RetrieveHeaderCIDByHash(tx, blockHash)
if err != nil {
log.Error("header cid retrieval error")
return models.HeaderModel{}, nil, err
}
if err != nil {
return models.HeaderModel{}, nil, err
}
fmt.Println("RetrieveHeaderAndTxCIDsByBlockHash", headerCID.ParentHash, headerCID.Timestamp)
var txCIDs []models.TxModel
txCIDs, err = ecr.RetrieveTxCIDsByHeaderID(tx, headerCID.BlockHash)
if err != nil {
log.Error("tx cid retrieval error")
return models.HeaderModel{}, nil, err
}
return headerCID, txCIDs, nil
}

View File

@ -22,6 +22,8 @@ import (
"context"
"database/sql"
"errors"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/common"
@ -32,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/statediff/indexer/models"
"github.com/vulcanize/ipld-eth-server/v3/pkg/eth"
)
@ -1017,7 +1020,7 @@ func (r *Resolver) GetStorageAt(ctx context.Context, args struct {
return nil, err
}
if bytes.Compare(rlpValue, eth.EmptyNodeValue) == 0 {
if bytes.Equal(rlpValue, eth.EmptyNodeValue) {
return &StorageResult{value: eth.EmptyNodeValue, cid: cid, ipldBlock: ipldBlock}, nil
}
@ -1122,3 +1125,140 @@ func decomposeGQLLogs(logCIDs []eth.LogResult) []logsCID {
return logs
}
type EthTransactionCid struct {
cid string
txHash string
index int32
src string
dst string
}
func (t EthTransactionCid) Cid(ctx context.Context) string {
return t.cid
}
func (t EthTransactionCid) TxHash(ctx context.Context) string {
return t.txHash
}
func (t EthTransactionCid) Index(ctx context.Context) int32 {
return t.index
}
func (t EthTransactionCid) Src(ctx context.Context) string {
return t.src
}
func (t EthTransactionCid) Dst(ctx context.Context) string {
return t.dst
}
type EthTransactionCidsConnection struct {
nodes []*EthTransactionCid
}
func (transactionCIDResult EthTransactionCidsConnection) Nodes(ctx context.Context) []*EthTransactionCid {
return transactionCIDResult.nodes
}
type EthHeaderCid struct {
cid string
blockNumber hexutil.Uint64
blockHash string
parentHash string
timestamp hexutil.Uint64
transactions []*EthTransactionCid
}
func (h EthHeaderCid) Cid(ctx context.Context) string {
return h.cid
}
func (h EthHeaderCid) BlockNumber(ctx context.Context) hexutil.Uint64 {
return h.blockNumber
}
func (h EthHeaderCid) BlockHash(ctx context.Context) string {
return h.blockHash
}
func (h EthHeaderCid) ParentHash(ctx context.Context) string {
return h.parentHash
}
func (h EthHeaderCid) Timestamp(ctx context.Context) hexutil.Uint64 {
return h.timestamp
}
func (h EthHeaderCid) EthTransactionCidsByHeaderId(ctx context.Context) EthTransactionCidsConnection {
return EthTransactionCidsConnection{nodes: h.transactions}
}
type EthHeaderCidsConnection struct {
nodes []*EthHeaderCid
}
func (headerCIDResult EthHeaderCidsConnection) Nodes(ctx context.Context) []*EthHeaderCid {
return headerCIDResult.nodes
}
type EthHeaderCidCondition struct {
BlockNumber *hexutil.Big
BlockHash *string
}
func (r *Resolver) AllEthHeaderCids(ctx context.Context, args struct {
Condition *EthHeaderCidCondition
}) (*EthHeaderCidsConnection, error) {
var headerCIDs []models.HeaderModel
var allTxCIDs [][]models.TxModel
var err error
if args.Condition.BlockHash != nil {
headerCID, txCIDs, err := r.backend.Retriever.RetrieveHeaderAndTxCIDsByBlockHash(common.HexToHash(*args.Condition.BlockHash))
if err != nil {
return nil, err
}
headerCIDs = append(headerCIDs, headerCID)
allTxCIDs = append(allTxCIDs, txCIDs)
} else if args.Condition.BlockNumber != nil {
headerCIDs, allTxCIDs, err = r.backend.Retriever.RetrieveHeaderAndTxCIDsByBlockNumber(args.Condition.BlockNumber.ToInt().Int64())
if err != nil {
return nil, err
}
} else {
return nil, fmt.Errorf("provide block number or block hash")
}
var resultNodes []*EthHeaderCid
for idx, headerCID := range headerCIDs {
blockNumber := new(big.Int)
blockNumber.SetString(headerCID.BlockNumber, 10)
ethHeaderCidNode := EthHeaderCid{
cid: headerCID.CID,
blockNumber: hexutil.Uint64(blockNumber.Uint64()),
blockHash: headerCID.BlockHash,
parentHash: headerCID.ParentHash,
timestamp: hexutil.Uint64(headerCID.Timestamp),
}
txCIDs := allTxCIDs[idx]
for _, txCID := range txCIDs {
ethHeaderCidNode.transactions = append(ethHeaderCidNode.transactions, &EthTransactionCid{
cid: txCID.CID,
txHash: txCID.TxHash,
index: int32(txCID.Index),
src: txCID.Src,
dst: txCID.Dst,
})
}
resultNodes = append(resultNodes, &ethHeaderCidNode)
}
return &EthHeaderCidsConnection{
nodes: resultNodes,
}, nil
}

View File

@ -138,16 +138,16 @@ const schema string = `
# empty, results will not be filtered by address.
addresses: [Address!]
# Topics list restricts matches to particular event topics. Each event has a list
# of topics. Topics matches a prefix of that list. An empty element array matches any
# topic. Non-empty elements represent an alternative that matches any of the
# contained topics.
#
# Examples:
# - [] or nil matches any topic list
# - [[A]] matches topic A in first position
# - [[], [B]] matches any topic in first position, B in second position
# - [[A], [B]] matches topic A in first position, B in second position
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
# of topics. Topics matches a prefix of that list. An empty element array matches any
# topic. Non-empty elements represent an alternative that matches any of the
# contained topics.
#
# Examples:
# - [] or nil matches any topic list
# - [[A]] matches topic A in first position
# - [[], [B]] matches any topic in first position, B in second position
# - [[A], [B]] matches topic A in first position, B in second position
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
topics: [[Bytes32!]!]
}
@ -258,16 +258,16 @@ const schema string = `
# empty, results will not be filtered by address.
addresses: [Address!]
# Topics list restricts matches to particular event topics. Each event has a list
# of topics. Topics matches a prefix of that list. An empty element array matches any
# topic. Non-empty elements represent an alternative that matches any of the
# contained topics.
#
# Examples:
# - [] or nil matches any topic list
# - [[A]] matches topic A in first position
# - [[], [B]] matches any topic in first position, B in second position
# - [[A], [B]] matches topic A in first position, B in second position
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
# of topics. Topics matches a prefix of that list. An empty element array matches any
# topic. Non-empty elements represent an alternative that matches any of the
# contained topics.
#
# Examples:
# - [] or nil matches any topic list
# - [[A]] matches topic A in first position
# - [[], [B]] matches any topic in first position, B in second position
# - [[A], [B]] matches topic A in first position, B in second position
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
topics: [[Bytes32!]!]
}
@ -282,6 +282,36 @@ const schema string = `
ipldBlock: Bytes!
}
input EthHeaderCidCondition {
blockNumber: BigInt
blockHash: String
}
type EthTransactionCid {
cid: String!
txHash: String!
index: Int!
src: String!
dst: String!
}
type EthTransactionCidsConnection {
nodes: [EthTransactionCid]!
}
type EthHeaderCid {
cid: String!
blockNumber: Long!
blockHash: String!
parentHash: String!
timestamp: Long!
ethTransactionCidsByHeaderId: EthTransactionCidsConnection!
}
type EthHeaderCidsConnection {
nodes: [EthHeaderCid]!
}
type Query {
# Block fetches an Ethereum block by number or by hash. If neither is
# supplied, the most recent known block is returned.
@ -302,5 +332,7 @@ const schema string = `
# Get contract logs by block hash and contract address.
getLogs(blockHash: Bytes32!, contract: Address): [Log!]
allEthHeaderCids(condition: EthHeaderCidCondition): EthHeaderCidsConnection
}
`