본문으로 건너뛰기

Solana Compute Block Metrics

업데이트 날짜:
2025년 11월 12일

개요

Solana's high-performance blockchain generates extensive data that can be challenging to analyze.

In this Function example, we will provide comprehensive block analytics by aggregating crucial metrics that aren't directly available through standard RPC methods. This will enable developers to gain deeper insights into network activity and performance.

Sample Function

The following is the code for the Function to get the vital Solana block analytics data in JavaScript Node.js v20 runtime using the block dataset:

// Initialize the main function
function main(params) {
const dataset = params.metadata.dataset
const network = params.metadata.network

const block = params.data[0]

// Initialize counters and aggregators
let metrics = {
message: `Analysis from the ${dataset} dataset on the ${network} network.`,
blockHeight: block.blockHeight,
blockTime: block.blockTime,

// Compute units
totalComputeUnits: 0,
avgComputeUnitsPerTx: 0,

// Fee metrics
totalFees: 0,
avgFeePerTx: 0,

// Balance changes
totalBalanceChange: 0,

// Program invocations
programInvocations: {},

// Transaction metrics
successfulTxCount: 0,
failedTxCount: 0,

// Account activity
uniqueAccounts: new Set(),
uniqueSigners: new Set(),

// Write set size
totalWritableAccounts: 0,
avgWritableAccountsPerTx: 0,
}

// Process each transaction
block.transactions.forEach(tx => {
// Compute units
metrics.totalComputeUnits += tx.meta.computeUnitsConsumed

// Fees
metrics.totalFees += tx.meta.fee

// Success/Failure count
if (tx.meta.err === null) {
metrics.successfulTxCount++
} else {
metrics.failedTxCount++
}

// Balance changes
const preBalances = tx.meta.preBalances
const postBalances = tx.meta.postBalances
metrics.totalBalanceChange += postBalances.reduce(
(sum, bal, i) => sum + (bal - preBalances[i]),
0
)

// Program invocations from log messages
tx.meta.logMessages?.forEach(log => {
if (log.includes('invoke [1]')) {
const program = log.split(' ')[1]
metrics.programInvocations[program] =
(metrics.programInvocations[program] || 0) + 1
}
})

// Account activity
tx.transaction.message.accountKeys.forEach(acc => {
metrics.uniqueAccounts.add(acc.pubkey)
if (acc.signer) {
metrics.uniqueSigners.add(acc.pubkey)
}
if (acc.writable) {
metrics.totalWritableAccounts++
}
})
})

// Calculate averages
const txCount = metrics.successfulTxCount + metrics.failedTxCount
metrics.avgComputeUnitsPerTx = metrics.totalComputeUnits / txCount
metrics.avgFeePerTx = metrics.totalFees / txCount
metrics.avgWritableAccountsPerTx = metrics.totalWritableAccounts / txCount

// Convert Sets to counts
metrics.uniqueAccountCount = metrics.uniqueAccounts.size
metrics.uniqueSignerCount = metrics.uniqueSigners.size

// Clean up intermediate Set objects
delete metrics.uniqueAccounts
delete metrics.uniqueSigners

return metrics
}

요청

요청

We will invoke the function with the following cURL command. A few notes:

  • Replace the YOUR_API_KEY with your own Quicknode API key - follow this guide for creating an API key.
  • Replace the FUNCTION_ID with the ID of your Function - you can find this in the URL when viewing your Function in the Quicknode Dashboard.
  • Use the block_number parameter to specify the block number you want to analyze. You can also omit this property for the function to run against the latest block.
curl -X POST "https://api.quicknode.com/functions/rest/v1/functions/FUNCTION_ID/call?result_only=true" \
-H "accept: application/json" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"network": "solana-mainnet",
"dataset": "block",
"block_number": 288218963
}'

답변

Resulting in the following response:

{
"message": "Analysis from the block dataset on the solana-mainnet network.",
"blockHeight": 288218963,
"blockTime": 1735198645,
"totalComputeUnits": 41471436,
"avgComputeUnitsPerTx": 27833.178523489933,
"totalFees": 31947701,
"avgFeePerTx": 21441.410067114095,
"totalBalanceChange": -31947701,
"programInvocations": {
"Vote111111111111111111111111111111111111111": 905,
"ComputeBudget111111111111111111111111111111": 827,
"6EF8rrecthR5Dkzon8Nwu78hRvfCKubJ14M5uBEwF6P": 13,
"11111111111111111111111111111111": 394,
"AzHrwdCsEZotAjr7sjenHrHpf1ZKYoGBP6N7HVhEsyen": 1,
"JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4": 168,
"DgakD8xgWC3wSjy2hnkgibo2wFRJMNkrwkk5wkpf596q": 2,
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA": 40,
"AFW9KCZtmtMWuhuLkF5mLY9wsk7SZrpZmuKijzcQ51Ni": 2,
"675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8": 20,
"4pP8eDKACuV7T2rbFPE8CHxGKDYAzSdRsdMsGvz2k4oc": 2,
"HQ2UUt18uJqKaQFJhgV9zaTdQxUZjNrsKFgoEDquBkcx": 3,
"6753FE9MXMv68A5T3Tqp465MHi1wsFSw6beEUM7nPVJf": 5,
"CAMMCzo5YL8w4VFF8KVHrK22GGUsp5VTaW7grrKgrWqK": 4,
"BSfD6SHZigAfDWSjzD5Q41jw8LmKwtmjskPH9XW1mrRW": 4,
"GDDMwNyyx8uB6zrqwBFHjLLG3TBYk2F8Az4yrQC5RzMp": 26,
"ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL": 212,
"PSMxQbAoDWDbvd9ezQJgARyq6R9L5kJAasaLDVcZwf1": 2,
"PhoeNiXZ8ByJGLkxNfZRnkUfjvmuYqLR89jjFHGqdXY": 35,
"DCA265Vj8a9CEuX1eb1LWRnDT7uK6q1xMipnNyatn23M": 15,
"opnb2LAfJYbRMAHHvqjCwQxanZn7ReEHp1k81EohpZb": 20,
"SoLFiHG9TfgtdUXUjWAxi3LtvYuFyDLVhBWxdMZxyCe": 14,
"MEVK7RP6dDTbxAwirSY6R5v66oS5WvzbhAQD9jpy9Lj": 4,
"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr": 6,
"TipgrjcESvvR7G4MUDiR1dWgbFqC6fprUPyZeYVDqFS": 1,
"dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH": 11,
"TT1eRKxi2Rj3oEvsFMe9W5hrcPmpXqKkNj7wC83AhXk": 5,
"8BR3zs8zSXetpnDjCtHWnkpSkNSydWb3PTTDuVKku2uu": 3,
"4MangoMjqJ2firMokCjjGgoK8d4MXcrgL7XJaL3w6fVg": 11,
"BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY": 69,
"darehJcMJFk833wzHe76pFyGPyTNzeN4yQNKTRw8wJM": 8,
"monacoUXKtUi6vKsQwaLyxmXKSievfNWEcYXTgkbCih": 24,
"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb": 1,
"NeonVMyRX5GbCrsAHnUwx1nYYoJAtskU1bWUo6JGNyG": 1,
"TCMPhJdwDryooaGtiocG1u3xcYbRpiJzb283XfCZsDp": 2,
"ZETAxsqBRek56DhiGXrn75yj2NHU3aYUnxvHXpkf3aD": 6,
"cjg3oHmg9uuPsP8D6g29NWvhySJkdYdAo9D25PRbKXJ": 10,
"TSWAPaqyCSx2KABk68Shruf4rp7CxcNi8hAsbdwmHbN": 2,
"9XFCiGhW1Pkx7rGgNcMH3S9bqDjKwgjqqM2cb2YdzpJ3": 8,
"whirLbMiicVdio4qvUfM5KAg6Ct8VwpYzGff3uctyCc": 1,
"BobogA5N2KN2GG4XN3E3rNNRw3L8H1QPXp7QLxGrNHGM": 95,
"SAGE2HAwep459SNq61LHvjxPk4pLPEJLoMETef7f7EE": 2,
"7K3UpbZViPnQDLn2DAM853B9J5GBxd1L1rLHy4KqSmWG": 1,
"9ixSdN1CKjmHqwTessaPYdJGRMgEYCaL34oXyNjYK2mw": 4,
"BANANAjs7FJiPQqJTGFzkZJndT9o7UmKiYYGaJz6frGu": 2,
"ARBv2b5cz4hreK2Pico7jD76oYiDMP2KPhyYrYtTK7qT": 1,
"F3tYgkUtcqn6JnUska1meE2LDzwozEyh4nkH6zMJLdL5": 2,
"8V227E7nJP4y9XJY8tEnw19aiaQc2Cb9xZt1J7a3idbY": 2,
"LBUZKhRxPF3XUpBCjp4YzTKgLccjZhTSDM9YuVaPwxo": 3,
"MoonCVVNZFSYkqNXP6bxHLPL6QQJiMagDL3qcqUQTrG": 1,
"13gDzEXCdocbj8iAiqrScGo47NiSuYENGsRqi3SEAwet": 1,
"L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95": 3,
"9m7YMBgQaxYpUwrjLvS6AA3FmGH83qXgifA5aF5VbEue": 1,
"BLZRi6frs4X4DNLw56V4EXai1b6QVESN1BhHBTYM9VcY": 1,
"9w1D9okTM8xNE7Ntb7LpaAaoLc6LfU9nHFs2h2KTpX1H": 1
},
"successfulTxCount": 1186,
"failedTxCount": 304,
"totalWritableAccounts": 7025,
"avgWritableAccountsPerTx": 4.714765100671141,
"uniqueAccountCount": 3868,
"uniqueSignerCount": 1189
}

Learn more about Quicknode Functions.

여러분의 피드백을 ❤️ 환영합니다!

의견이나 다루었으면 하는 새로운 주제가 있다면 알려주세요. 여러분의 의견을 기다리고 있습니다.

이 문서 공유하기