StorageProof
Get merkle paths in one of the state tries: global state, classes, or individual contract storage. A single request can query for any mix of the three types of storage proofs (classes, contracts, and storage).
Method Signature
func (provider *Provider) StorageProof(
ctx context.Context,
storageProofInput StorageProofInput,
) (*StorageProofResult, error)Source: contract.go
Parameters
ctx(context.Context): Context for request cancellation and timeoutsstorageProofInput(StorageProofInput): Input containing optional and required fields for the request
Returns
*StorageProofResult: The requested storage proofs. Note that if a requested leaf has the default value, the path to it may end in an edge node whose path is not a prefix of the requested leaf, thus effectively proving non-membershiperror: Error if the block is not found or storage proofs are not supported
Type Definitions
StorageProofInput
type StorageProofInput struct {
// Required. The hash of the requested block, or number (height) of the
// requested block, or a block tag
BlockID BlockID `json:"block_id"`
// Optional. A list of the class hashes for which we want to prove
// membership in the classes trie
ClassHashes []*felt.Felt `json:"class_hashes,omitempty"`
// Optional. A list of contracts for which we want to prove membership in the
// global state trie
ContractAddresses []*felt.Felt `json:"contract_addresses,omitempty"`
// Optional. A list of (contract_address, storage_keys) pairs
ContractsStorageKeys []ContractStorageKeys `json:"contracts_storage_keys,omitempty"`
}Source: types_contract.go
ContractStorageKeys
type ContractStorageKeys struct {
ContractAddress *felt.Felt `json:"contract_address"`
StorageKeys []*felt.Felt `json:"storage_keys"`
}Source: types_contract.go
StorageProofResult
The requested storage proofs. Note that if a requested leaf has the default value, the path to it may end in an edge node whose path is not a prefix of the requested leaf, thus effectively proving non-membership.
type StorageProofResult struct {
ClassesProof []NodeHashToNode `json:"classes_proof"`
ContractsProof ContractsProof `json:"contracts_proof"`
ContractsStorageProofs [][]NodeHashToNode `json:"contracts_storage_proofs"`
GlobalRoots GlobalRoots `json:"global_roots"`
}Source: types_contract.go
NodeHashToNode
A node_hash -> node mapping of all the nodes in the union of the paths between the requested leaves and the root.
type NodeHashToNode struct {
NodeHash *felt.Felt `json:"node_hash"`
Node MerkleNode `json:"node"`
}Source: types_contract.go
MerkleNode
A node in the Merkle-Patricia tree, can be a binary node or an edge node.
type MerkleNode struct {
Type string
Data any
}Source: types_contract.go
The MerkleNode unmarshals into either an EdgeNode or BinaryNode based on the JSON structure.
EdgeNode
Represents a path to the highest non-zero descendant node.
type EdgeNode struct {
// an unsigned integer whose binary representation represents the path from
// the current node to its highest non-zero descendant (bounded by 2^251)
Path NumAsHex `json:"path"`
// the length of the path (bounded by 251)
Length uint `json:"length"`
// the hash of the unique non-zero maximal-height descendant node
Child *felt.Felt `json:"child"`
}Source: types_contract.go
BinaryNode
An internal node whose both children are non-zero.
type BinaryNode struct {
// the hash of the left child
Left *felt.Felt `json:"left"`
// the hash of the right child
Right *felt.Felt `json:"right"`
}Source: types_contract.go
ContractsProof
type ContractsProof struct {
// The nodes in the union of the paths from the contracts tree root to the
// requested leaves
Nodes []NodeHashToNode `json:"nodes"`
ContractLeavesData []ContractLeavesData `json:"contract_leaves_data"`
}Source: types_contract.go
ContractLeavesData
The nonce and class hash for each requested contract address, in the order in which they appear in the request. These values are needed to construct the associated leaf node.
type ContractLeavesData struct {
Nonce *felt.Felt `json:"nonce"`
ClassHash *felt.Felt `json:"class_hash"`
StorageRoot *felt.Felt `json:"storage_root,omitempty"`
}Source: types_contract.go
GlobalRoots
type GlobalRoots struct {
ContractsTreeRoot *felt.Felt `json:"contracts_tree_root"`
ClassesTreeRoot *felt.Felt `json:"classes_tree_root"`
// the associated block hash (needed in case the caller used a block tag
// for the block_id parameter)
BlockHash *felt.Felt `json:"block_hash"`
}Source: types_contract.go
Basic Usage
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/starknet.go/rpc"
"github.com/joho/godotenv"
)
func main() {
// Load environment variables from .env file
godotenv.Load()
// Get RPC URL from environment variable
rpcURL := os.Getenv("STARKNET_RPC_URL")
if rpcURL == "" {
log.Fatal("STARKNET_RPC_URL environment variable is not set")
}
// Initialize provider
provider, err := rpc.NewProvider(context.Background(), rpcURL)
if err != nil {
log.Fatal(err)
}
// Contract address to get storage proof for
contractAddr, _ := new(felt.Felt).SetString("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
// Storage keys to prove
storageKey1, _ := new(felt.Felt).SetString("0x1")
storageKey2, _ := new(felt.Felt).SetString("0x2")
// Create storage proof input
input := rpc.StorageProofInput{
BlockID: rpc.BlockID{Tag: "latest"},
ContractsStorageKeys: []rpc.ContractStorageKeys{
{
ContractAddress: contractAddr,
StorageKeys: []*felt.Felt{storageKey1, storageKey2},
},
},
}
// Get storage proof
proof, err := provider.StorageProof(context.Background(), input)
if err != nil {
log.Fatal(err)
}
// Access proof data
fmt.Printf("Contracts Tree Root: %s\n", proof.GlobalRoots.ContractsTreeRoot)
fmt.Printf("Classes Tree Root: %s\n", proof.GlobalRoots.ClassesTreeRoot)
fmt.Printf("Block Hash: %s\n", proof.GlobalRoots.BlockHash)
fmt.Printf("Number of contract proof nodes: %d\n", len(proof.ContractsProof.Nodes))
fmt.Printf("Number of storage proofs: %d\n", len(proof.ContractsStorageProofs))
}For more comprehensive examples including proving class membership, proving contract existence, mixed proof requests, processing Merkle nodes, and historical state proofs, see RPC Examples - StorageProof.
Important Notes
-
Non-membership Proofs: If a requested leaf has the default value, the path may end in an edge node whose path is not a prefix of the requested leaf, thus effectively proving non-membership.
-
Node Support: Not all Starknet nodes support storage proofs. Make sure your RPC endpoint implements
starknet_getStorageProof. -
Block Limitations:
- Cannot use pending blocks (proofs require finalized state)
- Historical proofs may not be available for very old blocks
- When using block tags, the
GlobalRoots.BlockHashfield contains the actual block hash
-
Performance: Storage proofs can be large for deep Merkle trees. Consider:
- Batching multiple keys in a single request
- Caching proofs for frequently verified values
- Using recent blocks when possible (faster to generate)
RPC Specification
- Method:
starknet_getStorageProof - Version: RPC v0.9.0+
Related Methods
- StorageAt - Get storage value without proof
- StateUpdate - Get all state changes in a block
- BlockWithTxs - Get block details

