Files
explorer-monorepo/backend/indexer/track2/block_indexer.go

99 lines
2.4 KiB
Go

package track2
import (
"context"
"fmt"
"math/big"
"time"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/jackc/pgx/v5/pgxpool"
)
// BlockIndexer indexes blocks for Track 2
type BlockIndexer struct {
db *pgxpool.Pool
client *ethclient.Client
chainID int
}
// NewBlockIndexer creates a new block indexer
func NewBlockIndexer(db *pgxpool.Pool, client *ethclient.Client, chainID int) *BlockIndexer {
return &BlockIndexer{
db: db,
client: client,
chainID: chainID,
}
}
// IndexBlock indexes a single block
func (bi *BlockIndexer) IndexBlock(ctx context.Context, blockNumber uint64) error {
block, err := bi.client.BlockByNumber(ctx, big.NewInt(int64(blockNumber)))
if err != nil {
return fmt.Errorf("failed to get block: %w", err)
}
// Check if block already indexed
var exists bool
checkQuery := `SELECT EXISTS(SELECT 1 FROM blocks WHERE chain_id = $1 AND number = $2)`
err = bi.db.QueryRow(ctx, checkQuery, bi.chainID, blockNumber).Scan(&exists)
if err != nil {
return fmt.Errorf("failed to check block existence: %w", err)
}
if exists {
return nil // Already indexed
}
// Insert block
insertQuery := `
INSERT INTO blocks (
chain_id, number, hash, parent_hash, miner, difficulty, total_difficulty,
size, gas_limit, gas_used, timestamp, transaction_count, base_fee_per_gas
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
ON CONFLICT (chain_id, number) DO NOTHING
`
_, err = bi.db.Exec(ctx, insertQuery,
bi.chainID,
block.Number().Int64(),
block.Hash().Hex(),
block.ParentHash().Hex(),
block.Coinbase().Hex(),
block.Difficulty().String(),
"0", // total_difficulty
block.Size(),
block.GasLimit(),
block.GasUsed(),
time.Unix(int64(block.Time()), 0),
len(block.Transactions()),
block.BaseFee(),
)
if err != nil {
return fmt.Errorf("failed to insert block: %w", err)
}
return nil
}
// IndexLatestBlocks indexes the latest N blocks
func (bi *BlockIndexer) IndexLatestBlocks(ctx context.Context, count int) error {
header, err := bi.client.HeaderByNumber(ctx, nil)
if err != nil {
return fmt.Errorf("failed to get latest header: %w", err)
}
latestBlock := header.Number.Uint64()
for i := 0; i < count && latestBlock-uint64(i) >= 0; i++ {
blockNum := latestBlock - uint64(i)
if err := bi.IndexBlock(ctx, blockNum); err != nil {
// Log error but continue
fmt.Printf("Failed to index block %d: %v\n", blockNum, err)
}
}
return nil
}