TraceBlockTransactions
Retrieves execution traces for all transactions in a specific block, providing detailed call flow, events, messages, and state changes for each transaction. This method is useful for analyzing block-level activity and debugging multiple transactions at once.
Method Signature
func (provider *Provider) TraceBlockTransactions(
ctx context.Context,
blockID BlockID,
) ([]Trace, error)Source: trace.go
Parameters
ctx(context.Context): Context for request cancellation and timeoutblockID(BlockID): Block identifier (number, hash, or tag)
Returns
[]Trace: Array of execution traces, one for each transaction in the blockerror: Error if the request fails
Type Definitions
- Container Type (
Trace) wraps each transaction'sTxnTracewith its transaction hash for identification. - Trace Types (
TxnTrace) can beInvokeTxnTrace,DeclareTxnTrace,DeployAccountTxnTrace, orL1HandlerTxnTracedepending on the transaction type. - Invocation Types (
FnInvocation,ExecInvocation) represent function calls with parameters, results, nested calls, events, and messages. - State Changes (
StateDiff) show storage updates, deployed contracts, declared classes, and nonce changes caused by the transactions.
The method accepts a BlockID and returns an array of Trace objects, each containing the full execution trace and transaction hash for every transaction in the block.
Trace
type Trace struct {
TraceRoot TxnTrace `json:"trace_root,omitempty"`
TxnHash *felt.Felt `json:"transaction_hash,omitempty"`
}Source: types_trace.go
TxnTrace
type TxnTrace interface{}
var (
_ TxnTrace = (*InvokeTxnTrace)(nil)
_ TxnTrace = (*DeclareTxnTrace)(nil)
_ TxnTrace = (*DeployAccountTxnTrace)(nil)
_ TxnTrace = (*L1HandlerTxnTrace)(nil)
)Source: types_trace.go
InvokeTxnTrace
type InvokeTxnTrace struct {
ValidateInvocation *FnInvocation `json:"validate_invocation,omitempty"`
// the trace of the __execute__ call
ExecuteInvocation ExecInvocation `json:"execute_invocation"`
FeeTransferInvocation *FnInvocation `json:"fee_transfer_invocation,omitempty"`
StateDiff *StateDiff `json:"state_diff,omitempty"`
Type TransactionType `json:"type"`
ExecutionResources ExecutionResources `json:"execution_resources"`
}Source: types_trace.go
BlockID
The blockID parameter specifies which block state to query. You can identify a block in three ways:
type BlockID struct {
Number *uint64 `json:"block_number,omitempty"`
Hash *felt.Felt `json:"block_hash,omitempty"`
Tag BlockTag `json:"tag,omitempty"`
}Source: types_block.go
There are helper functions for creating BlockID. So Instead of manually creating the BlockID struct, use these convenience functions.
-
By Block Number - Get a specific block by its height
blockID := rpc.WithBlockNumber(123456)Source: block.go
-
By Block Hash - Get a specific block by its hash
hash, _ := new(felt.Felt).SetString("0x1234...") blockID := rpc.WithBlockHash(hash)Source: block.go
-
By Block Tag - Get a dynamic block reference
blockID := rpc.WithBlockTag("latest") // Latest accepted block blockID := rpc.WithBlockTag("pending") // Block currently being builtSource: block.go
Usage Example
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/joho/godotenv"
)
func main() {
// Load environment variables from .env file
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
// Get RPC URL from environment variable
rpcURL := os.Getenv("STARKNET_RPC_URL")
if rpcURL == "" {
log.Fatal("STARKNET_RPC_URL not found in .env file")
}
// Initialize provider
provider, err := rpc.NewProvider(context.Background(), rpcURL)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
// Trace all transactions in a specific block
blockID := rpc.WithBlockNumber(99433)
traces, err := provider.TraceBlockTransactions(ctx, blockID)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Block has %d transactions\n\n", len(traces))
// Analyze each transaction trace
for i, trace := range traces {
fmt.Printf("Transaction %d:\n", i+1)
fmt.Printf(" Hash: %s\n", trace.TxnHash)
// Type assert to analyze specific trace types
if invokeTrace, ok := trace.TraceRoot.(rpc.InvokeTxnTrace); ok {
fmt.Printf(" Type: %s\n", invokeTrace.Type)
fmt.Printf(" Total L2 Gas: %d\n", invokeTrace.ExecutionResources.L2Gas)
// Count nested calls
nestedCallCount := len(invokeTrace.ExecuteInvocation.NestedCalls)
fmt.Printf(" Nested Calls: %d\n", nestedCallCount)
// Check for state changes
if invokeTrace.StateDiff != nil {
fmt.Printf(" Storage Updates: %d contracts\n", len(invokeTrace.StateDiff.StorageDiffs))
fmt.Printf(" Nonce Updates: %d accounts\n", len(invokeTrace.StateDiff.Nonces))
}
}
fmt.Println()
}
}Error Handling
traces, err := provider.TraceBlockTransactions(ctx, blockID)
if err != nil {
if errors.Is(err, rpc.ErrBlockNotFound) {
log.Printf("Block not found")
return
}
log.Printf("Error retrieving traces: %v", err)
return
}
// Process traces
totalGas := uint(0)
for _, trace := range traces {
if invokeTrace, ok := trace.TraceRoot.(rpc.InvokeTxnTrace); ok {
totalGas += invokeTrace.ExecutionResources.L2Gas
}
}
fmt.Printf("Total L2 gas for block: %d\n", totalGas)Common Use Cases
- Analyzing block-level gas consumption across all transactions.
- Debugging multiple failed transactions in the same block.
- Building block explorers with detailed execution traces.
- Monitoring state changes and contract interactions at the block level.

