Skip to content

Commit

Permalink
New spec updates
Browse files Browse the repository at this point in the history
  • Loading branch information
thiagodeev committed Oct 25, 2024
1 parent 9d37844 commit 785676b
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 18 deletions.
5 changes: 3 additions & 2 deletions rpc/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,8 @@ func (provider *Provider) EstimateMessageFee(ctx context.Context, msg MsgFromL1,
return &raw, nil
}

// Get merkle paths in one of the state tries: global state, classes, individual contract
// Get merkle paths in one of the state tries: global state, classes, individual contract.
// A single request can query for any mix of the three types of storage proofs (classes, contracts, and storage)
//
// Parameters:
// - ctx: The context of the function call
Expand All @@ -173,7 +174,7 @@ func (provider *Provider) GetStorageProof(ctx context.Context, storageProofInput
var raw StorageProofResult
if err := do(ctx, provider.c, "starknet_getStorageProof", &raw, storageProofInput); err != nil {

return nil, tryUnwrapToRPCErr(err)
return nil, tryUnwrapToRPCErr(err, ErrBlockNotFound, ErrStorageProofNotSupported)
}
return &raw, nil
}
4 changes: 4 additions & 0 deletions rpc/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -683,3 +683,7 @@ func TestEstimateFee(t *testing.T) {
}
}
}

func TestGetStorageProof(t *testing.T) {
t.Skip("TODO: create a test before merge")
}
4 changes: 4 additions & 0 deletions rpc/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ var (
Code: 41,
Message: "Transaction execution error",
}
ErrStorageProofNotSupported = &RPCError{
Code: 42,
Message: "the node doesn't support storage proofs for blocks that are too far in the past",
}
ErrInvalidContractClass = &RPCError{
Code: 50,
Message: "Invalid contract class",
Expand Down
102 changes: 86 additions & 16 deletions rpc/types_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,9 @@ type ContractClass struct {
ABI string `json:"abi,omitempty"`
}

// You must provide one of these fields
type StorageProofInput struct {
// The hash of the requested block, or number (height) of the requested block, or a block tag
BlockID BlockID `json:"block_id"`
// A list of the class hashes for which we want to prove membership in the classes trie
ClassHashes []*felt.Felt `json:"class_hashes,omitempty"`
// A list of contracts for which we want to prove membership in the global state trie
Expand All @@ -84,33 +85,65 @@ type StorageProofInput struct {
ContractsStorageKeys []ContractStorageKeys `json:"contracts_storage_keys,omitempty"`
}

type StorageProofResult struct {
ClassesProof NodeHashToNode `json:"classes_proof,omitempty"`
ContractsProof NodeHashToNode `json:"contracts_proof,omitempty"`
ContractsStorageProofs []NodeHashToNode `json:"contracts_storage_proofs,omitempty"`
}

type ContractStorageKeys struct {
ContractAddress *felt.Felt `json:"contract_address"`
StorageKeys []*felt.Felt `json:"storage_keys"`
}

// A node_hash -> node mapping of all the nodes in the union of the paths between the requested leaves and the root (for each node present, its sibling is also present)
// 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 effecitvely proving non-membership
type StorageProofResult struct {
ClassesProof NodeHashToNode `json:"classes_proof"`
ContractsProof ContractsProof `json:"contracts_proof"`
ContractsStorageProofs []NodeHashToNode `json:"contracts_storage_proofs"`
GlobalRoots []NodeHashToNode `json:"global_roots"`
}

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"`
}

// 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"`
}

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"`
}

// 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"`
}

type MerkleNode struct {
Path uint `json:"path"`
Length uint `json:"length"`
Value *felt.Felt `json:"value"`
// the hash of the child nodes, if not present then the node is a leaf
ChildrenHashes ChildrenHashes `json:"children_hashes,omitempty"`
// A node in the Merkle-Patricia tree, can be a leaf, binary node, or an edge node
type MerkleNode interface{} // it should be an EdgeNode or BinaryNode

// Represents a path to the highest non-zero descendant node
type EdgeNode struct {
// an 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"`
}

type ChildrenHashes struct {
Left *felt.Felt `json:"left"`
// 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"`
}

Expand Down Expand Up @@ -208,6 +241,43 @@ func (c *DeprecatedContractClass) UnmarshalJSON(content []byte) error {
return nil
}

func (nodeHashToNode *NodeHashToNode) UnmarshalJSON(bytes []byte) error {
valueMap := make(map[string]any)
if err := json.Unmarshal(bytes, &valueMap); err != nil {
return err
}

nodeHash, ok := valueMap["node_hash"]
if !ok {
return fmt.Errorf("missing 'node_hash' in json object")
}
nodeHashFelt, ok := nodeHash.(felt.Felt)
if !ok {
return fmt.Errorf("error casting 'node_hash' to felt.Felt")
}

node, ok := valueMap["node"]
if !ok {
return fmt.Errorf("missing 'node' in json object")
}
var merkleNode MerkleNode
switch nodeT := node.(type) {
case BinaryNode:
merkleNode = nodeT
case EdgeNode:
merkleNode = nodeT
default:
return fmt.Errorf("'node' should be an EdgeNode or BinaryNode")
}

*nodeHashToNode = NodeHashToNode{
NodeHash: &nodeHashFelt,
Node: merkleNode,
}

return nil
}

type SierraEntryPoint struct {
// The index of the function in the program
FunctionIdx int `json:"function_idx"`
Expand Down

0 comments on commit 785676b

Please sign in to comment.