99 lines
2.4 KiB
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
|
|
}
|