Skip to content

Commit

Permalink
docs: update state ADR
Browse files Browse the repository at this point in the history
  • Loading branch information
renaynay committed Jul 19, 2022
1 parent 9e5d7c0 commit 910eefd
Showing 1 changed file with 48 additions and 3 deletions.
51 changes: 48 additions & 3 deletions docs/adr/adr-004-state-interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,54 @@ type StateAccessor interface {

### Verification of Balances
In order to check that the balances returned via the `AccountBalance` query are correct, it is necessary to also request
Merkle proofs from the celestia-app and verify them against the latest head's `AppHash`. In order for the `StateAccessor`
to do this, it would need access to the `header.Store`'s `Head()` method in order to get the latest known header of the
node and check its `AppHash`.
Merkle proofs from celestia-app and verify them against the latest head's `AppHash`.

In order for the `StateAccessor` to do this, it would need access to the `header.Store`'s `Head()` method in order to get the latest known header of the node and check its `AppHash`.
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
}
```

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{<store key of module>, <actual key corresponding to requested value>}
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
Expand Down

0 comments on commit 910eefd

Please sign in to comment.