Skip to main content

GetBlock

Retrieve a single block at a specific position from the Hyperliquid L1 Gateway.

Full Code Examples

Clone our gRPC Code Examples Repository for complete, runnable implementations in Go, Python, and Node.js.

When to Use This Method#

GetBlock is essential for:

  • Point-in-Time Analysis - Get blockchain state at a specific block or timestamp
  • Backtesting - Retrieve historical block data for strategy analysis
  • Auditing - Verify transactions and state changes at specific points
  • Debugging - Investigate specific blocks during development

Method Signature#

rpc GetBlock(Position) returns (Block) {}

Request Message#

message Position {
// Leave all fields unset or zero to target the latest data.
oneof position {
int64 timestamp_ms = 1; // ms since Unix epoch, inclusive
int64 block_height = 2; // block height, inclusive
}
}

The Position message allows flexible block targeting:

  • timestamp_ms: Get block at or after a specific time (milliseconds since Unix epoch)
  • block_height: Get block at a specific height
  • Empty/zero: Get the latest block

Response Message#

message Block {
// JSON-encoded Hyperliquid block from "replica_cmds".
bytes data = 1;
}

The data field contains a JSON-encoded block with the following structure:

Data Structure#

{
"abci_block": {
"time": "2025-09-08T06:41:57.997372546",
"round": 992814678,
"parent_round": 992814677,
"proposer": "0x5ac99df645f3414876c816caa18b2d234024b487",
"hardfork": {
"version": 57,
"round": 990500929
},
"signed_action_bundles": [
[
"0xb4b1f5a9c233f9d90fd24b9961fd12708b36cc3d56f8fda47f32b667ee8d1227",
{
"signed_actions": [
{
"signature": {
"r": "0x...",
"s": "0x...",
"v": 27
},
"action": {
"type": "order",
"orders": [...]
},
"nonce": 1757313597362
}
],
"broadcaster": "0x67e451964e0421f6e7d07be784f35c530667c2b3",
"broadcaster_nonce": 1757313597367
}
]
]
},
"resps": {
"Full": [
[
"0xb4b1f5a9c233f9d90fd24b9961fd12708b36cc3d56f8fda47f32b667ee8d1227",
[
{
"user": "0xecb63caa47c7c4e77f60f1ce858cf28dc2b82b00",
"res": {
"status": "ok",
"response": {
"type": "order",
"data": {...}
}
}
}
]
]
]
}
}

Field Descriptions#

FieldTypeDescription
abci_block.timestringISO-8601 timestamp with nanosecond precision
abci_block.roundnumberCurrent block number (height)
abci_block.parent_roundnumberPrevious block number
abci_block.proposerstringValidator address that proposed the block
abci_block.hardforkobjectProtocol version information
abci_block.signed_action_bundlesarrayArray of [hash, bundle_data] pairs
resps.FullarrayExecution responses matching bundle structure

For the complete block specification including all action types, see the StreamBlocks documentation.

Implementation Examples#

package main

import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"time"

pb "hyperliquid-grpc-client/api/v2"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)

type BlockData struct {
AbciBlock struct {
Time string `json:"time"`
Round int64 `json:"round"`
ParentRound int64 `json:"parent_round"`
Proposer string `json:"proposer"`
SignedActionBundles []interface{} `json:"signed_action_bundles"`
} `json:"abci_block"`
Resps struct {
Full []interface{} `json:"Full"`
} `json:"resps"`
}

func getBlock(ctx context.Context, client pb.HyperliquidL1GatewayClient, position *pb.Position) (*BlockData, error) {
ctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()

response, err := client.GetBlock(ctx, position)
if err != nil {
return nil, fmt.Errorf("RPC call failed: %v", err)
}

fmt.Printf("Response size: %d bytes\n\n", len(response.Data))

var block BlockData
if err := json.Unmarshal(response.Data, &block); err != nil {
return nil, fmt.Errorf("failed to parse JSON: %v", err)
}

return &block, nil
}

func main() {
endpoint := os.Getenv("HYPERLIQUID_ENDPOINT")
apiKey := os.Getenv("API_KEY")

if endpoint == "" {
log.Fatal("Error: HYPERLIQUID_ENDPOINT environment variable is required.")
}

if apiKey == "" {
log.Fatal("Error: API_KEY environment variable is required.")
}

fmt.Println("Hyperliquid Go gRPC Client - Get Block")
fmt.Println("======================================")
fmt.Printf("Endpoint: %s\n\n", endpoint)

// Set up TLS connection
creds := credentials.NewTLS(nil)

opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithDefaultCallOptions(
grpc.MaxCallRecvMsgSize(150 * 1024 * 1024),
),
}

fmt.Println("Connecting to gRPC server...")
conn, err := grpc.NewClient(endpoint, opts...)
if err != nil {
log.Fatalf("Failed to connect: %v", err)
}
defer conn.Close()

client := pb.NewHyperliquidL1GatewayClient(conn)
fmt.Println("Connected successfully!\n")

// Get block with API key
ctx := context.Background()
ctx = metadata.AppendToOutgoingContext(ctx, "x-api-key", apiKey)

// Request latest block (empty position)
request := &pb.Position{}

// Or request by block height:
// request := &pb.Position{Position: &pb.Position_BlockHeight{BlockHeight: 992814678}}

// Or request by timestamp:
// request := &pb.Position{Position: &pb.Position_TimestampMs{TimestampMs: 1725778917997}}

fmt.Println("Fetching block...\n")

block, err := getBlock(ctx, client, request)
if err != nil {
log.Fatalf("Failed to get block: %v", err)
}

// Display block information
fmt.Printf("Block Height: %d\n", block.AbciBlock.Round)
fmt.Printf("Parent Block: %d\n", block.AbciBlock.ParentRound)
fmt.Printf("Time: %s\n", block.AbciBlock.Time)
fmt.Printf("Proposer: %s\n", block.AbciBlock.Proposer)
fmt.Printf("Action Bundles: %d\n", len(block.AbciBlock.SignedActionBundles))
}

Common Use Cases#

1. Historical Block Analysis#

def analyze_block_activity(client, block_height):
"""Analyze trading activity in a specific block"""
request = hyperliquid_pb2.Position(block_height=block_height)
response = client.GetBlock(request, metadata=metadata)
block = json.loads(response.data)

abci_block = block.get('abci_block', {})
bundles = abci_block.get('signed_action_bundles', [])

analysis = {
'block_height': abci_block.get('round'),
'timestamp': abci_block.get('time'),
'total_bundles': len(bundles),
'total_actions': 0,
'order_count': 0,
'cancel_count': 0,
'transfer_count': 0
}

for bundle in bundles:
if len(bundle) >= 2:
for action in bundle[1].get('signed_actions', []):
analysis['total_actions'] += 1
action_type = action.get('action', {}).get('type', '')

if action_type == 'order':
analysis['order_count'] += 1
elif action_type in ['cancel', 'cancelByCloid']:
analysis['cancel_count'] += 1
elif action_type in ['spotSend', 'usdSend', 'withdraw3']:
analysis['transfer_count'] += 1

return analysis

2. Block Comparison#

func compareBlocks(client pb.HyperliquidL1GatewayClient, ctx context.Context, height1, height2 int64) {
block1, _ := client.GetBlock(ctx, &pb.Position{Position: &pb.Position_BlockHeight{BlockHeight: height1}})
block2, _ := client.GetBlock(ctx, &pb.Position{Position: &pb.Position_BlockHeight{BlockHeight: height2}})

var data1, data2 map[string]interface{}
json.Unmarshal(block1.Data, &data1)
json.Unmarshal(block2.Data, &data2)

abci1 := data1["abci_block"].(map[string]interface{})
abci2 := data2["abci_block"].(map[string]interface{})

bundles1 := abci1["signed_action_bundles"].([]interface{})
bundles2 := abci2["signed_action_bundles"].([]interface{})

fmt.Printf("Block %d: %d bundles\n", height1, len(bundles1))
fmt.Printf("Block %d: %d bundles\n", height2, len(bundles2))
}

3. Transaction Verification#

async function verifyTransaction(client, metadata, txHash, blockHeight) {
return new Promise((resolve, reject) => {
const request = { block_height: blockHeight };

client.GetBlock(request, metadata, (error, response) => {
if (error) {
reject(error);
return;
}

const block = JSON.parse(response.data);
const bundles = block.abci_block?.signed_action_bundles || [];

for (const bundle of bundles) {
const bundleHash = bundle[0];
if (bundleHash === txHash) {
resolve({
found: true,
block_height: block.abci_block.round,
bundle_data: bundle[1]
});
return;
}
}

resolve({ found: false });
});
});
}

Error Handling#

async function robustGetBlock(client, metadata, position, retries = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
return await new Promise((resolve, reject) => {
client.GetBlock(position, metadata, (error, response) => {
if (error) reject(error);
else resolve(response);
});
});
} catch (error) {
console.warn(`Attempt ${attempt + 1} failed:`, error.message);

if (attempt === retries - 1) {
throw error;
}

// Exponential backoff
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
}

Best Practices#

  1. Position Selection: Use block height for precise queries; timestamps may return different blocks across requests if near block boundaries
  2. Data Validation: Always validate JSON structure before processing
  3. Error Recovery: Implement retry logic with exponential backoff
  4. Resource Management: Close gRPC connections properly to avoid resource leaks
  5. Caching: Cache block data when analyzing the same blocks multiple times

Current Limitations#

  • Data Retention: Historical block data is limited to a 24-hour rolling window
  • Rate Limits: Be mindful of request frequency to avoid overwhelming the service

Resources#

Need help? Contact our support team or check the Hyperliquid gRPC documentation.