Files
2026-03-02 12:14:13 -08:00

134 lines
3.5 KiB
Go

package rest
import (
"context"
"database/sql"
"encoding/json"
"net/http"
"time"
)
// handleGetBlockByNumber handles GET /api/v1/blocks/{chain_id}/{number}
func (s *Server) handleGetBlockByNumber(w http.ResponseWriter, r *http.Request, blockNumber int64) {
// Validate input (already validated in routes.go, but double-check)
if blockNumber < 0 {
writeValidationError(w, ErrInvalidBlockNumber)
return
}
// Add query timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
query := `
SELECT chain_id, number, hash, parent_hash, timestamp, timestamp_iso, miner,
transaction_count, gas_used, gas_limit, size, logs_bloom
FROM blocks
WHERE chain_id = $1 AND number = $2
`
var chainID, number, transactionCount int
var hash, parentHash, miner string
var timestamp time.Time
var timestampISO sql.NullString
var gasUsed, gasLimit, size int64
var logsBloom sql.NullString
err := s.db.QueryRow(ctx, query, s.chainID, blockNumber).Scan(
&chainID, &number, &hash, &parentHash, &timestamp, &timestampISO, &miner,
&transactionCount, &gasUsed, &gasLimit, &size, &logsBloom,
)
if err != nil {
writeNotFound(w, "Block")
return
}
block := map[string]interface{}{
"chain_id": chainID,
"number": number,
"hash": hash,
"parent_hash": parentHash,
"timestamp": timestamp,
"miner": miner,
"transaction_count": transactionCount,
"gas_used": gasUsed,
"gas_limit": gasLimit,
"size": size,
}
if timestampISO.Valid {
block["timestamp_iso"] = timestampISO.String
}
if logsBloom.Valid {
block["logs_bloom"] = logsBloom.String
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"data": block,
})
}
// handleGetBlockByHash handles GET /api/v1/blocks/{chain_id}/hash/{hash}
func (s *Server) handleGetBlockByHash(w http.ResponseWriter, r *http.Request, hash string) {
// Validate hash format (already validated in routes.go, but double-check)
if !isValidHash(hash) {
writeValidationError(w, ErrInvalidHash)
return
}
// Add query timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
query := `
SELECT chain_id, number, hash, parent_hash, timestamp, timestamp_iso, miner,
transaction_count, gas_used, gas_limit, size, logs_bloom
FROM blocks
WHERE chain_id = $1 AND hash = $2
`
var chainID, number, transactionCount int
var blockHash, parentHash, miner string
var timestamp time.Time
var timestampISO sql.NullString
var gasUsed, gasLimit, size int64
var logsBloom sql.NullString
err := s.db.QueryRow(ctx, query, s.chainID, hash).Scan(
&chainID, &number, &blockHash, &parentHash, &timestamp, &timestampISO, &miner,
&transactionCount, &gasUsed, &gasLimit, &size, &logsBloom,
)
if err != nil {
writeNotFound(w, "Block")
return
}
block := map[string]interface{}{
"chain_id": chainID,
"number": number,
"hash": blockHash,
"parent_hash": parentHash,
"timestamp": timestamp,
"miner": miner,
"transaction_count": transactionCount,
"gas_used": gasUsed,
"gas_limit": gasLimit,
"size": size,
}
if timestampISO.Valid {
block["timestamp_iso"] = timestampISO.String
}
if logsBloom.Valid {
block["logs_bloom"] = logsBloom.String
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"data": block,
})
}