Skip to main content

beefy_getFinalizedHead - JSON-RPC Method

Description

Returns the hash of the latest BEEFY finalized block. BEEFY (Bridge Efficiency Enabling Finality Yielder) is a secondary finality gadget optimized for efficient bridging to external chains like Ethereum. This JSON-RPC method provides the most recent block finalized by BEEFY consensus.

Parameters

This method does not require any parameters.

Returns

FieldTypeDescription
resultstringHex-encoded hash of the latest BEEFY finalized block

Request Example

{
"jsonrpc": "2.0",
"method": "beefy_getFinalizedHead",
"params": [],
"id": 1
}

Response Example

{
"jsonrpc": "2.0",
"result": "0x8a84d1c5fc5c725b26a3c8e126d8f65e1c2d2dc5b3fcbc91e67e7637fa136789",
"id": 1
}

Code Examples

JavaScript

const getBeefyFinalizedHead = async () => {
const response = await fetch('https://api-polkadot.n.dwellir.com', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'beefy_getFinalizedHead',
params: [],
id: 1
})
});

const data = await response.json();
return data.result;
};

// Monitor BEEFY finalization
const monitorBeefy = async () => {
let lastBeefyBlock = null;

setInterval(async () => {
try {
const beefyHead = await getBeefyFinalizedHead();

if (beefyHead !== lastBeefyBlock) {
console.log('New BEEFY finalized block:', beefyHead);

// Get block details
const blockResponse = await fetch('https://api-polkadot.n.dwellir.com', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
jsonrpc: '2.0',
method: 'chain_getBlock',
params: [beefyHead],
id: 2
})
});

const blockData = await blockResponse.json();
const blockNumber = parseInt(blockData.result.block.header.number, 16);
console.log(`BEEFY finalized block #${blockNumber}`);

lastBeefyBlock = beefyHead;
}
} catch (error) {
console.error('Error monitoring BEEFY:', error);
}
}, 10000); // Check every 10 seconds
};

monitorBeefy();

Python

import requests
import json
import time
from typing import Optional

class BeefyMonitor:
def __init__(self, rpc_url: str, api_key: str):
self.rpc_url = rpc_url
self.headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
self.last_beefy_block = None
self.last_grandpa_block = None

def get_beefy_finalized_head(self) -> str:
payload = {
"jsonrpc": "2.0",
"method": "beefy_getFinalizedHead",
"params": [],
"id": 1
}

response = requests.post(
self.rpc_url,
headers=self.headers,
data=json.dumps(payload)
)
return response.json()["result"]

def get_grandpa_finalized_head(self) -> str:
payload = {
"jsonrpc": "2.0",
"method": "chain_getFinalizedHead",
"params": [],
"id": 1
}

response = requests.post(
self.rpc_url,
headers=self.headers,
data=json.dumps(payload)
)
return response.json()["result"]

def get_block_number(self, block_hash: str) -> int:
payload = {
"jsonrpc": "2.0",
"method": "chain_getHeader",
"params": [block_hash],
"id": 1
}

response = requests.post(
self.rpc_url,
headers=self.headers,
data=json.dumps(payload)
)
header = response.json()["result"]
return int(header["number"], 16)

def compare_finality(self):
"""Compare BEEFY and GRANDPA finality"""
beefy_hash = self.get_beefy_finalized_head()
grandpa_hash = self.get_grandpa_finalized_head()

beefy_number = self.get_block_number(beefy_hash)
grandpa_number = self.get_block_number(grandpa_hash)

lag = grandpa_number - beefy_number

print(f"GRANDPA finalized: #{grandpa_number}")
print(f"BEEFY finalized: #{beefy_number}")
print(f"BEEFY lag: {lag} blocks")

return {
"beefy": {"hash": beefy_hash, "number": beefy_number},
"grandpa": {"hash": grandpa_hash, "number": grandpa_number},
"lag": lag
}

def monitor(self, interval: int = 30):
"""Monitor BEEFY finalization progress"""
while True:
try:
status = self.compare_finality()

if self.last_beefy_block != status["beefy"]["number"]:
blocks_finalized = 0
if self.last_beefy_block:
blocks_finalized = status["beefy"]["number"] - self.last_beefy_block

print(f"\nBEEFY finalized {blocks_finalized} new blocks")
self.last_beefy_block = status["beefy"]["number"]

time.sleep(interval)

except Exception as e:
print(f"Error: {e}")
time.sleep(interval)

# Usage
monitor = BeefyMonitor("https://api-polkadot.n.dwellir.com", "YOUR_API_KEY")
monitor.monitor(30) # Check every 30 seconds

TypeScript (@polkadot/api)

import { ApiPromise, WsProvider } from '@polkadot/api';

interface FinalityStatus {
beefy: {
hash: string;
number: number;
};
grandpa: {
hash: string;
number: number;
};
lag: number;
}

class BeefyFinalityTracker {
private api: ApiPromise;

async connect(wsUrl: string) {
const provider = new WsProvider(wsUrl);
this.api = await ApiPromise.create({ provider });
}

async getBeefyFinalized(): Promise<string> {
const hash = await this.api.rpc.beefy.getFinalizedHead();
return hash.toHex();
}

async getFinalityStatus(): Promise<FinalityStatus> {
// Get both finalized heads
const [beefyHash, grandpaHash] = await Promise.all([
this.api.rpc.beefy.getFinalizedHead(),
this.api.rpc.chain.getFinalizedHead()
]);

// Get block numbers
const [beefyHeader, grandpaHeader] = await Promise.all([
this.api.rpc.chain.getHeader(beefyHash),
this.api.rpc.chain.getHeader(grandpaHash)
]);

const beefyNumber = beefyHeader.number.toNumber();
const grandpaNumber = grandpaHeader.number.toNumber();

return {
beefy: {
hash: beefyHash.toHex(),
number: beefyNumber
},
grandpa: {
hash: grandpaHash.toHex(),
number: grandpaNumber
},
lag: grandpaNumber - beefyNumber
};
}

async monitorFinality(callback: (status: FinalityStatus) => void) {
// Initial status
const status = await this.getFinalityStatus();
callback(status);

// Subscribe to new GRANDPA finalized heads
await this.api.rpc.chain.subscribeFinalizedHeads(async (header) => {
const status = await this.getFinalityStatus();
callback(status);
});
}

async disconnect() {
await this.api.disconnect();
}
}

// Usage
async function trackBeefy() {
const tracker = new BeefyFinalityTracker();
await tracker.connect('wss://api-polkadot.n.dwellir.com');

await tracker.monitorFinality((status) => {
console.log('Finality Status:');
console.log(` GRANDPA: Block #${status.grandpa.number}`);
console.log(` BEEFY: Block #${status.beefy.number}`);
console.log(` Lag: ${status.lag} blocks`);

if (status.lag > 100) {
console.warn('⚠️ High BEEFY lag detected!');
}
});
}

trackBeefy().catch(console.error);

Bridge Integration Example

// Check if a block is BEEFY finalized for bridge operations
async function isBeefyFinalized(blockHash) {
const beefyHead = await getBeefyFinalizedHead();

// Get block number for comparison
const targetBlock = await getBlockHeader(blockHash);
const beefyBlock = await getBlockHeader(beefyHead);

const targetNumber = parseInt(targetBlock.number, 16);
const beefyNumber = parseInt(beefyBlock.number, 16);

return targetNumber <= beefyNumber;
}

// Wait for BEEFY finalization
async function waitForBeefyFinality(blockHash, maxWaitMs = 300000) {
const startTime = Date.now();

while (Date.now() - startTime < maxWaitMs) {
if (await isBeefyFinalized(blockHash)) {
console.log('Block is BEEFY finalized!');
return true;
}

// Wait before checking again
await new Promise(resolve => setTimeout(resolve, 10000));
}

throw new Error('Timeout waiting for BEEFY finalization');
}

Use Cases

  1. Bridge Operations: Ensure finality before cross-chain transfers
  2. Light Clients: Efficient finality verification for external chains
  3. Monitoring: Track BEEFY finalization performance
  4. Cross-chain Apps: Coordinate actions across multiple chains
  5. Validator Monitoring: Track BEEFY participation

BEEFY vs GRANDPA

AspectGRANDPABEEFY
PurposePrimary finalityBridge-optimized finality
SignaturesEd25519ECDSA/secp256k1
EfficiencyOptimized for SubstrateOptimized for Ethereum verification
LagImmediateLags behind GRANDPA
Use CaseInternal consensusExternal chain bridges

Notes

  • BEEFY typically lags behind GRANDPA finalization
  • BEEFY uses ECDSA signatures for Ethereum compatibility
  • Not all chains have BEEFY enabled
  • BEEFY finality is a subset of GRANDPA finality
  • Used primarily for bridge security