⚠️Blast API (blastapi.io) ends Oct 31. Migrate to Dwellir and skip Alchemy's expensive compute units.
Switch Today →
Skip to main content

debug_traceBlockByNumber

Traces all transactions in a block specified by block number. This is a convenience method that combines block lookup with tracing.

Premium Method
This method is available on paid plans. Upgrade your plan here to start using it.

When to Use This Method

debug_traceBlockByNumber is ideal for:

  • Historical Analysis - Trace blocks from specific heights
  • Sequential Processing - Analyze blocks in order
  • Monitoring - Track blocks as they're produced
  • Research - Study blockchain behavior at specific points

Parameters

  1. Block Number - QUANTITY|TAG

    • Block number as hex
    • Or tags: "latest", "earliest", "pending"
  2. Tracer Configuration - Object

    • tracer - Type of tracer ("callTracer", "prestateTracer")
    • tracerConfig - Additional options
{
"jsonrpc": "2.0",
"method": "debug_traceBlockByNumber",
"params": [
"0x1234", // or "latest"
{
"tracer": "callTracer",
"tracerConfig": {
"onlyTopCall": false
}
}
],
"id": 1
}

Returns

Array of transaction traces for all transactions in the block.

Implementation Examples

import { JsonRpcProvider, toBeHex } from 'ethers';

const provider = new JsonRpcProvider('https://api-blast-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

// Block range analyzer
class BlockRangeAnalyzer {
constructor(provider) {
this.provider = provider;
}

async traceBlockByNumber(blockNumber, config = {}) {
const blockHex = typeof blockNumber === 'string' ?
blockNumber : toBeHex(blockNumber);

const traces = await this.provider.send('debug_traceBlockByNumber', [
blockHex,
{
tracer: config.tracer || 'callTracer',
tracerConfig: config.tracerConfig || {
onlyTopCall: false
}
}
]);

return this.processBlockTraces(traces, blockNumber);
}

async traceBlockRange(startBlock, endBlock, config = {}) {
const results = [];

for (let block = startBlock; block <= endBlock; block++) {
console.log(`Tracing block ${block}...`);

try {
const traces = await this.traceBlockByNumber(block, config);
results.push({
blockNumber: block,
success: true,
data: traces
});
} catch (error) {
results.push({
blockNumber: block,
success: false,
error: error.message
});
}

// Rate limiting
await new Promise(resolve => setTimeout(resolve, 100));
}

return this.analyzeRange(results);
}

processBlockTraces(traces, blockNumber) {
const analysis = {
blockNumber: blockNumber,
transactionCount: traces.length,
successfulTxs: 0,
failedTxs: 0,
totalGasUsed: 0,
contractCalls: [],
uniqueContracts: new Set(),
errorTypes: {}
};

traces.forEach((trace, index) => {
const result = trace.result || {};
const gasUsed = parseInt(result.gasUsed || '0x0', 16);

analysis.totalGasUsed += gasUsed;

if (result.error) {
analysis.failedTxs++;
analysis.errorTypes[result.error] =
(analysis.errorTypes[result.error] || 0) + 1;
} else {
analysis.successfulTxs++;
}

// Track contract interactions
if (result.to) {
analysis.uniqueContracts.add(result.to);
analysis.contractCalls.push({
index: index,
to: result.to,
type: result.type,
gasUsed: gasUsed
});
}

// Process sub-calls
if (result.calls) {
this.processSubCalls(result.calls, analysis);
}
});

analysis.uniqueContracts = Array.from(analysis.uniqueContracts);
analysis.successRate = (
(analysis.successfulTxs / analysis.transactionCount) * 100
).toFixed(2) + '%';

return analysis;
}

processSubCalls(calls, analysis) {
for (const call of calls) {
if (call.to) {
analysis.uniqueContracts.add(call.to);
}
if (call.calls) {
this.processSubCalls(call.calls, analysis);
}
}
}

analyzeRange(results) {
const summary = {
blocksAnalyzed: results.length,
successfulBlocks: results.filter(r => r.success).length,
failedBlocks: results.filter(r => !r.success).length,
totalTransactions: 0,
totalGasUsed: 0,
averageTransactionsPerBlock: 0,
averageGasPerBlock: 0,
mostActiveBlock: null,
leastActiveBlock: null
};

const successfulResults = results.filter(r => r.success);

if (successfulResults.length === 0) {
return summary;
}

// Calculate totals
successfulResults.forEach(result => {
summary.totalTransactions += result.data.transactionCount;
summary.totalGasUsed += result.data.totalGasUsed;
});

// Calculate averages
summary.averageTransactionsPerBlock =
summary.totalTransactions / successfulResults.length;
summary.averageGasPerBlock =
summary.totalGasUsed / successfulResults.length;

// Find extremes
const sorted = successfulResults.sort((a, b) =>
b.data.transactionCount - a.data.transactionCount
);

summary.mostActiveBlock = {
number: sorted[0].data.blockNumber,
transactions: sorted[0].data.transactionCount
};

summary.leastActiveBlock = {
number: sorted[sorted.length - 1].data.blockNumber,
transactions: sorted[sorted.length - 1].data.transactionCount
};

return summary;
}

async findSpecificPattern(startBlock, endBlock, pattern) {
const matches = [];

for (let block = startBlock; block <= endBlock; block++) {
const traces = await this.traceBlockByNumber(block);

// Check for pattern
if (pattern.type === 'high_gas') {
const highGasTxs = traces.contractCalls.filter(
call => call.gasUsed > pattern.threshold
);

if (highGasTxs.length > 0) {
matches.push({
block: block,
transactions: highGasTxs
});
}
} else if (pattern.type === 'failed_calls') {
if (traces.failedTxs > 0) {
matches.push({
block: block,
failedCount: traces.failedTxs,
errors: traces.errorTypes
});
}
} else if (pattern.type === 'contract_activity') {
const activity = traces.contractCalls.filter(
call => call.to === pattern.contract
);

if (activity.length > 0) {
matches.push({
block: block,
calls: activity.length,
totalGas: activity.reduce((sum, call) =>
sum + call.gasUsed, 0
)
});
}
}
}

return matches;
}

async compareBlocks(blockNumbers) {
const comparison = {
blocks: [],
metrics: {
gasUsage: [],
transactionCount: [],
successRate: [],
uniqueContracts: []
}
};

for (const blockNum of blockNumbers) {
const analysis = await this.traceBlockByNumber(blockNum);

comparison.blocks.push(analysis);
comparison.metrics.gasUsage.push({
block: blockNum,
gas: analysis.totalGasUsed
});
comparison.metrics.transactionCount.push({
block: blockNum,
count: analysis.transactionCount
});
comparison.metrics.successRate.push({
block: blockNum,
rate: analysis.successRate
});
comparison.metrics.uniqueContracts.push({
block: blockNum,
count: analysis.uniqueContracts.length
});
}

// Calculate statistics
comparison.statistics = {
avgGas: comparison.metrics.gasUsage.reduce(
(sum, m) => sum + m.gas, 0
) / blockNumbers.length,
avgTransactions: comparison.metrics.transactionCount.reduce(
(sum, m) => sum + m.count, 0
) / blockNumbers.length,
gasVariance: this.calculateVariance(
comparison.metrics.gasUsage.map(m => m.gas)
)
};

return comparison;
}

calculateVariance(values) {
const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
const squaredDiffs = values.map(val => Math.pow(val - mean, 2));
return squaredDiffs.reduce((sum, val) => sum + val, 0) / values.length;
}
}

// Real-time block monitor
class BlockMonitor {
constructor(provider) {
this.provider = provider;
this.analyzer = new BlockRangeAnalyzer(provider);
this.monitoring = false;
}

async startMonitoring(callback, config = {}) {
this.monitoring = true;

this.provider.on('block', async (blockNumber) => {
if (!this.monitoring) return;

try {
const analysis = await this.analyzer.traceBlockByNumber(
blockNumber,
config
);

// Check for anomalies
const anomalies = this.detectAnomalies(analysis);

callback({
blockNumber: blockNumber,
analysis: analysis,
anomalies: anomalies,
timestamp: Date.now()
});
} catch (error) {
console.error(`Failed to trace block ${blockNumber}:`, error);
}
});
}

stopMonitoring() {
this.monitoring = false;
this.provider.removeAllListeners('block');
}

detectAnomalies(analysis) {
const anomalies = [];

// High failure rate
if (analysis.failedTxs / analysis.transactionCount > 0.1) {
anomalies.push({
type: 'high_failure_rate',
value: analysis.successRate,
severity: 'warning'
});
}

// Unusual gas usage
const avgGasPerTx = analysis.totalGasUsed / analysis.transactionCount;
if (avgGasPerTx > 500000) {
anomalies.push({
type: 'high_gas_usage',
value: avgGasPerTx,
severity: 'info'
});
}

// Too many unique contracts
if (analysis.uniqueContracts.length > 50) {
anomalies.push({
type: 'high_contract_diversity',
value: analysis.uniqueContracts.length,
severity: 'info'
});
}

return anomalies;
}
}

// Usage examples
const analyzer = new BlockRangeAnalyzer(provider);

// Trace specific block
const blockAnalysis = await analyzer.traceBlockByNumber(12345678);
console.log('Block analysis:', blockAnalysis);

// Trace block range
const rangeAnalysis = await analyzer.traceBlockRange(12345678, 12345688);
console.log('Range summary:', rangeAnalysis);

// Find patterns
const highGasBlocks = await analyzer.findSpecificPattern(
12345678,
12345688,
{ type: 'high_gas', threshold: 1000000 }
);
console.log('High gas blocks:', highGasBlocks);

// Compare blocks
const comparison = await analyzer.compareBlocks([
12345678, 12345688, 12345698
]);
console.log('Block comparison:', comparison);

// Monitor new blocks
const monitor = new BlockMonitor(provider);
monitor.startMonitoring((data) => {
console.log(`Block ${data.blockNumber}:`);
console.log(' Transactions:', data.analysis.transactionCount);
console.log(' Anomalies:', data.anomalies);
});

Common Use Cases

1. Historical Block Analysis

// Analyze historical blocks for research
async function analyzeHistoricalBlocks(blockNumbers) {
const analyzer = new BlockRangeAnalyzer(provider);
const results = {
blocks: [],
trends: {},
outliers: []
};

for (const blockNum of blockNumbers) {
const analysis = await analyzer.traceBlockByNumber(blockNum);
results.blocks.push(analysis);

// Identify outliers
if (analysis.transactionCount > 400 ||
analysis.failedTxs > 10 ||
analysis.totalGasUsed > 15000000) {
results.outliers.push({
block: blockNum,
reason: 'Unusual activity',
metrics: {
transactions: analysis.transactionCount,
failures: analysis.failedTxs,
gas: analysis.totalGasUsed
}
});
}
}

// Calculate trends
results.trends = {
avgTransactions: results.blocks.reduce(
(sum, b) => sum + b.transactionCount, 0
) / results.blocks.length,
avgGas: results.blocks.reduce(
(sum, b) => sum + b.totalGasUsed, 0
) / results.blocks.length,
failureRate: results.blocks.reduce(
(sum, b) => sum + (b.failedTxs / b.transactionCount), 0
) / results.blocks.length * 100
};

return results;
}

2. Network Health Monitoring

// Monitor network health over time
async function monitorNetworkHealth(duration = 100) {
const monitor = new BlockMonitor(provider);
const healthMetrics = {
blocks: [],
alerts: [],
summary: {}
};

const latestBlock = await provider.getBlockNumber();
const startBlock = latestBlock - duration;

for (let block = startBlock; block <= latestBlock; block++) {
const analysis = await analyzer.traceBlockByNumber(block);

const health = {
block: block,
score: calculateHealthScore(analysis),
issues: []
};

// Check for issues
if (analysis.failedTxs > 5) {
health.issues.push('High failure rate');
}

if (analysis.totalGasUsed > 12000000) {
health.issues.push('High gas usage');
}

if (analysis.errorTypes['out of gas']) {
health.issues.push('Out of gas errors detected');
}

healthMetrics.blocks.push(health);

if (health.issues.length > 0) {
healthMetrics.alerts.push({
block: block,
issues: health.issues,
severity: health.score < 50 ? 'critical' : 'warning'
});
}
}

// Generate summary
healthMetrics.summary = {
averageHealth: healthMetrics.blocks.reduce(
(sum, b) => sum + b.score, 0
) / healthMetrics.blocks.length,
criticalBlocks: healthMetrics.alerts.filter(
a => a.severity === 'critical'
).length,
warningBlocks: healthMetrics.alerts.filter(
a => a.severity === 'warning'
).length
};

return healthMetrics;
}

function calculateHealthScore(analysis) {
let score = 100;

// Deduct for failures
score -= (analysis.failedTxs / analysis.transactionCount) * 50;

// Deduct for high gas
if (analysis.totalGasUsed > 15000000) score -= 20;
else if (analysis.totalGasUsed > 12000000) score -= 10;

// Deduct for errors
Object.keys(analysis.errorTypes).forEach(error => {
score -= 5;
});

return Math.max(0, score);
}

3. Smart Contract Activity Timeline

// Build activity timeline for specific contract
async function buildContractTimeline(contractAddress, startBlock, endBlock) {
const timeline = {
contract: contractAddress,
blockRange: { start: startBlock, end: endBlock },
activity: [],
statistics: {
totalCalls: 0,
totalGasUsed: 0,
uniqueCallers: new Set(),
peakActivity: null
}
};

for (let block = startBlock; block <= endBlock; block++) {
const analysis = await analyzer.traceBlockByNumber(block);

const contractActivity = analysis.contractCalls.filter(
call => call.to === contractAddress
);

if (contractActivity.length > 0) {
const blockActivity = {
block: block,
calls: contractActivity.length,
gasUsed: contractActivity.reduce(
(sum, call) => sum + call.gasUsed, 0
),
callers: []
};

// Get unique callers for this block
// Would need to fetch full traces for caller info

timeline.activity.push(blockActivity);
timeline.statistics.totalCalls += contractActivity.length;
timeline.statistics.totalGasUsed += blockActivity.gasUsed;

if (!timeline.statistics.peakActivity ||
blockActivity.calls > timeline.statistics.peakActivity.calls) {
timeline.statistics.peakActivity = blockActivity;
}
}
}

return timeline;
}

Error Handling

Error TypeDescriptionSolution
Invalid block numberBlock doesn't existVerify block number
TimeoutLarge block trace timeoutUse onlyTopCall option
Rate limitToo many requestsImplement rate limiting
async function safeTraceByNumber(blockNumber, retries = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
const result = await provider.send('debug_traceBlockByNumber', [
toBeHex(blockNumber),
{
tracer: 'callTracer',
tracerConfig: {
onlyTopCall: attempt > 0, // Simplify on retry
timeout: `${10 + attempt * 10}s` // Increase timeout
}
}
]);

return result;

} catch (error) {
if (error.message.includes('not found')) {
throw new Error(`Block ${blockNumber} not found`);
}

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

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

Need help? Upgrade your plan here to access debug methods or check the Blast documentation.