Implement graphql query to get header with transactions
This commit is contained in:
parent
248d9eb7a2
commit
f144d932cd
@ -576,7 +576,7 @@ func (ecr *CIDRetriever) RetrieveBlockByNumber(blockNumber int64) (models.Header
|
|||||||
// RetrieveHeaderCIDByHash returns the header for the given block hash
|
// RetrieveHeaderCIDByHash returns the header for the given block hash
|
||||||
func (ecr *CIDRetriever) RetrieveHeaderCIDByHash(tx *sqlx.Tx, blockHash common.Hash) (models.HeaderModel, error) {
|
func (ecr *CIDRetriever) RetrieveHeaderCIDByHash(tx *sqlx.Tx, blockHash common.Hash) (models.HeaderModel, error) {
|
||||||
log.Debug("retrieving header cids for block hash ", blockHash.String())
|
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`
|
WHERE block_hash = $1`
|
||||||
var headerCID models.HeaderModel
|
var headerCID models.HeaderModel
|
||||||
return headerCID, tx.Get(&headerCID, pgStr, blockHash.String())
|
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
|
var rctCIDs []models.ReceiptModel
|
||||||
return rctCIDs, tx.Select(&rctCIDs, pgStr, pq.Array(txHashes))
|
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
|
||||||
|
}
|
||||||
|
@ -22,6 +22,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@ -32,6 +34,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
"github.com/ethereum/go-ethereum/statediff/indexer/models"
|
||||||
|
|
||||||
"github.com/vulcanize/ipld-eth-server/v3/pkg/eth"
|
"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
|
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
|
return &StorageResult{value: eth.EmptyNodeValue, cid: cid, ipldBlock: ipldBlock}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1122,3 +1125,140 @@ func decomposeGQLLogs(logCIDs []eth.LogResult) []logsCID {
|
|||||||
|
|
||||||
return logs
|
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, ðHeaderCidNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EthHeaderCidsConnection{
|
||||||
|
nodes: resultNodes,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
@ -138,16 +138,16 @@ const schema string = `
|
|||||||
# empty, results will not be filtered by address.
|
# empty, results will not be filtered by address.
|
||||||
addresses: [Address!]
|
addresses: [Address!]
|
||||||
# Topics list restricts matches to particular event topics. Each event has a list
|
# 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
|
# 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
|
# topic. Non-empty elements represent an alternative that matches any of the
|
||||||
# contained topics.
|
# contained topics.
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# - [] or nil matches any topic list
|
# - [] or nil matches any topic list
|
||||||
# - [[A]] matches topic A in first position
|
# - [[A]] matches topic A in first position
|
||||||
# - [[], [B]] matches any topic in first position, B in second 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]] 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
|
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
|
||||||
topics: [[Bytes32!]!]
|
topics: [[Bytes32!]!]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,16 +258,16 @@ const schema string = `
|
|||||||
# empty, results will not be filtered by address.
|
# empty, results will not be filtered by address.
|
||||||
addresses: [Address!]
|
addresses: [Address!]
|
||||||
# Topics list restricts matches to particular event topics. Each event has a list
|
# 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
|
# 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
|
# topic. Non-empty elements represent an alternative that matches any of the
|
||||||
# contained topics.
|
# contained topics.
|
||||||
#
|
#
|
||||||
# Examples:
|
# Examples:
|
||||||
# - [] or nil matches any topic list
|
# - [] or nil matches any topic list
|
||||||
# - [[A]] matches topic A in first position
|
# - [[A]] matches topic A in first position
|
||||||
# - [[], [B]] matches any topic in first position, B in second 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]] 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
|
# - [[A, B]], [C, D]] matches topic (A OR B) in first position, (C OR D) in second position
|
||||||
topics: [[Bytes32!]!]
|
topics: [[Bytes32!]!]
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,6 +282,36 @@ const schema string = `
|
|||||||
ipldBlock: Bytes!
|
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 {
|
type Query {
|
||||||
# Block fetches an Ethereum block by number or by hash. If neither is
|
# Block fetches an Ethereum block by number or by hash. If neither is
|
||||||
# supplied, the most recent known block is returned.
|
# supplied, the most recent known block is returned.
|
||||||
@ -302,5 +332,7 @@ const schema string = `
|
|||||||
|
|
||||||
# Get contract logs by block hash and contract address.
|
# Get contract logs by block hash and contract address.
|
||||||
getLogs(blockHash: Bytes32!, contract: Address): [Log!]
|
getLogs(blockHash: Bytes32!, contract: Address): [Log!]
|
||||||
|
|
||||||
|
allEthHeaderCids(condition: EthHeaderCidCondition): EthHeaderCidsConnection
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
Loading…
Reference in New Issue
Block a user