From 0796b0b44e8126a61a7733bc0221b7065ba766d9 Mon Sep 17 00:00:00 2001 From: rene <41963722+renaynay@users.noreply.github.com> Date: Tue, 19 Jul 2022 12:24:48 +0200 Subject: [PATCH] docs: update state ADR --- docs/adr/adr-004-state-interaction.md | 59 ++++++++++++++++++--------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/docs/adr/adr-004-state-interaction.md b/docs/adr/adr-004-state-interaction.md index 3619c272da..5a1e6d58c7 100644 --- a/docs/adr/adr-004-state-interaction.md +++ b/docs/adr/adr-004-state-interaction.md @@ -75,27 +75,48 @@ In order for the `StateAccessor` to do this, it would need access to the `header Then, instead of performing a regular `gRPC` query against the celestia-app's bank module, it would perform an ABCI request query via RPC as such: ```go - prefixedAccountKey := append(bank_types.CreateAccountBalancesPrefix(addr.Bytes()), []byte(app.BondDenom)...) - abciReq := abci.RequestQuery{ - Path: fmt.Sprintf("store/%s/key", bank_types.StoreKey), - // we request the balance at the block *previous* to the current head as - // the AppHash committed to the head is calculated by applying the previous - // block's transaction list, not the current block, meaning the head's AppHash - // is actually a result of the previous block's transactions. - Height: head.Height - 1, - Data: prefixedAccountKey, - // we set this value to `true` in order to get proofs in the response - // that we can use to verify against the head's AppHash. - Prove: true, - } - result, err := ca.rpcCli.ABCIQueryWithOptions(ctx, abciReq.Path, abciReq.Data, rpc_client.ABCIQueryOptions{}) - if err != nil { - return nil, err - } + prefixedAccountKey := append(bank_types.CreateAccountBalancesPrefix(addr.Bytes()), []byte(app.BondDenom)...) + abciReq := abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", bank_types.StoreKey), + // we request the balance at the block *previous* to the current head as + // the AppHash committed to the head is calculated by applying the previous + // block's transaction list, not the current block, meaning the head's AppHash + // is actually a result of the previous block's transactions. + Height: head.Height - 1, + Data: prefixedAccountKey, + // we set this value to `true` in order to get proofs in the response + // that we can use to verify against the head's AppHash. + Prove: true, + } + result, err := ca.rpcCli.ABCIQueryWithOptions(ctx, abciReq.Path, abciReq.Data, rpc_client.ABCIQueryOptions{}) + if err != nil { + return nil, err + } ``` -The result of the above request will contain the balance of the queried address and proofs that can be used to verify the returned balance against the current head's `AppHash`. -The proofs are returned as the type `crypto.ProofOps` which itself is not really functional until converted into a more useful type, +The result of the above request will contain the balance of the queried address and proofs that can be used to verify +the returned balance against the current head's `AppHash`. The proofs are returned as the type `crypto.ProofOps` which +itself is not really functional until converted into a more useful wrapper, `MerkleProof`, provided by the `ibc-go` +[23-commitment/types pkg](https://github.com/cosmos/ibc-go/blob/main/modules/core/23-commitment/types/utils.go#L10). + +Using `types.ConvertProofs()` returns a `types.MerkleProof` that wraps a chain of commitment proofs with which you can +verify the membership of the returned balance in the tree of the given root (the `AppHash` from the head), as such: + +```go + // convert proofs into a more digestible format + merkleproof, err := proof_utils.ConvertProofs(result.Response.GetProofOps()) + if err != nil { + return nil, err + } + root := proof_utils.NewMerkleRoot(head.AppHash) + // VerifyMembership expects the path as: + // []string{, } + path := proof_utils.NewMerklePath(bank_types.StoreKey, string(prefixedAccountKey)) + err = merkleproof.VerifyMembership(proof_utils.GetSDKSpecs(), root, path, result.Response.Value) + if err != nil { + return nil, err + } +``` ### Availability of `StateService` during sync The `Syncer` in the `header` package provides one public method, `Finished()`, that indicates whether the syncer has