Skip to content

Commit

Permalink
reuse VerifyStorageValue in ICQ and state_verifier
Browse files Browse the repository at this point in the history
  • Loading branch information
pr0n00gler committed Nov 26, 2024
1 parent e008388 commit 4a57aac
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 64 deletions.
11 changes: 11 additions & 0 deletions utils/storageverification/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package storageverification

import "cosmossdk.io/errors"

const StateVerificationCodespace = "state_verification"

var (
ErrInvalidType = errors.Register(StateVerificationCodespace, 1, "invalid type")
ErrInvalidStorageValue = errors.Register(StateVerificationCodespace, 2, "failed to check storage value")
ErrInvalidProof = errors.Register(StateVerificationCodespace, 3, "merkle proof is invalid")
)
50 changes: 50 additions & 0 deletions utils/storageverification/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package storageverification

import (
"cosmossdk.io/errors"
ibccommitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"
"github.com/cosmos/ibc-go/v8/modules/core/exported"
ics23 "github.com/cosmos/ics23/go"

"github.com/neutron-org/neutron/v5/x/interchainqueries/types"
)

type VerifyCallback func(index int) error

// VerifyStorageValues verifies stValues slice against proof using proofSpecs
// A caller can provide verifyCallback method that will be called for each storage value from the slice with an index of the value in the slice
// to do any additional user-defined checks of storage values
func VerifyStorageValues(stValues []*types.StorageValue, root exported.Root, proofSpecs []*ics23.ProofSpec, verifyCallback VerifyCallback) error {
for index, value := range stValues {
proof, err := ibccommitmenttypes.ConvertProofs(value.Proof)
if err != nil {
return errors.Wrapf(ErrInvalidType, "failed to convert crypto.ProofOps to MerkleProof: %v", err)
}

if verifyCallback != nil {
if err := verifyCallback(index); err != nil {
return errors.Wrapf(ErrInvalidStorageValue, err.Error())
}
}

path := ibccommitmenttypes.NewMerklePath(value.StoragePrefix, string(value.Key))
// identify what kind proofs (non-existence proof always has *ics23.CommitmentProof_Nonexist as the first item) we got
// and call corresponding method to verify it
switch proof.GetProofs()[0].GetProof().(type) {
// we can get non-existence proof if someone queried some key which is not exists in the storage on remote chain
case *ics23.CommitmentProof_Nonexist:
if err := proof.VerifyNonMembership(proofSpecs, root, path); err != nil {
return errors.Wrapf(ErrInvalidProof, "failed to verify proof: %v", err)
}
value.Value = nil
case *ics23.CommitmentProof_Exist:
if err := proof.VerifyMembership(proofSpecs, root, path, value.Value); err != nil {
return errors.Wrapf(ErrInvalidProof, "failed to verify proof: %v", err)
}
default:
return errors.Wrapf(ErrInvalidProof, "unknown proof type %T", proof.GetProofs()[0].GetProof())
}
}

return nil
}
4 changes: 2 additions & 2 deletions x/interchainqueries/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ func (suite *KeeperTestSuite) TestSubmitInterchainQueryResult() {
},
}
},
iqtypes.ErrInvalidType,
iqtypes.ErrInvalidSubmittedResult,
},
{
"non-registered key in KV result",
Expand Down Expand Up @@ -1239,7 +1239,7 @@ func (suite *KeeperTestSuite) TestSubmitInterchainQueryResult() {
},
}
},
iqtypes.ErrInvalidProof,
iqtypes.ErrInvalidSubmittedResult,
},
{
"query result height is too old",
Expand Down
44 changes: 9 additions & 35 deletions x/interchainqueries/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" //nolint:staticcheck
ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types"
ibccommitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"
ics23 "github.com/cosmos/ics23/go"

"github.com/neutron-org/neutron/v5/utils/storageverification"
"github.com/neutron-org/neutron/v5/x/interchainqueries/types"
)

Expand Down Expand Up @@ -235,43 +234,18 @@ func (m msgServer) SubmitQueryResult(goCtx context.Context, msg *types.MsgSubmit
return nil, err
}

for index, result := range msg.Result.KvResults {
proof, err := ibccommitmenttypes.ConvertProofs(result.Proof)
if err != nil {
ctx.Logger().Debug("SubmitQueryResult: failed to ConvertProofs",
"error", err, "query", query, "message", msg)
return nil, errors.Wrapf(types.ErrInvalidType, "failed to convert crypto.ProofOps to MerkleProof: %v", err)
if err := storageverification.VerifyStorageValues(msg.Result.KvResults, consensusState.GetRoot(), clientState.ProofSpecs, func(index int) error {
if !bytes.Equal(msg.Result.KvResults[index].Key, query.Keys[index].Key) {
return errors.Wrapf(types.ErrInvalidSubmittedResult, "KV key from result is not equal to registered query key: %v != %v", msg.Result.KvResults[index].Key, query.Keys[index].Key)
}

if !bytes.Equal(result.Key, query.Keys[index].Key) {
return nil, errors.Wrapf(types.ErrInvalidSubmittedResult, "KV key from result is not equal to registered query key: %v != %v", result.Key, query.Keys[index].Key)
if msg.Result.KvResults[index].StoragePrefix != query.Keys[index].Path {
return errors.Wrapf(types.ErrInvalidSubmittedResult, "KV path from result is not equal to registered query storage prefix: %v != %v", msg.Result.KvResults[index].StoragePrefix, query.Keys[index].Path)
}

if result.StoragePrefix != query.Keys[index].Path {
return nil, errors.Wrapf(types.ErrInvalidSubmittedResult, "KV path from result is not equal to registered query storage prefix: %v != %v", result.StoragePrefix, query.Keys[index].Path)
}

path := ibccommitmenttypes.NewMerklePath(result.StoragePrefix, string(result.Key))
// identify what kind proofs (non-existence proof always has *ics23.CommitmentProof_Nonexist as the first item) we got
// and call corresponding method to verify it
switch proof.GetProofs()[0].GetProof().(type) {
// we can get non-existence proof if someone queried some key which is not exists in the storage on remote chain
case *ics23.CommitmentProof_Nonexist:
if err := proof.VerifyNonMembership(clientState.ProofSpecs, consensusState.GetRoot(), path); err != nil {
ctx.Logger().Debug("SubmitQueryResult: failed to VerifyNonMembership",
"error", err, "query", query, "message", msg, "path", path)
return nil, errors.Wrapf(types.ErrInvalidProof, "failed to verify proof: %v", err)
}
result.Value = nil
case *ics23.CommitmentProof_Exist:
if err := proof.VerifyMembership(clientState.ProofSpecs, consensusState.GetRoot(), path, result.Value); err != nil {
ctx.Logger().Debug("SubmitQueryResult: failed to VerifyMembership",
"error", err, "query", query, "message", msg, "path", path)
return nil, errors.Wrapf(types.ErrInvalidProof, "failed to verify proof: %v", err)
}
default:
return nil, errors.Wrapf(types.ErrInvalidProof, "unknown proof type %T", proof.GetProofs()[0].GetProof())
}
return nil
}); err != nil {
return nil, errors.Wrapf(types.ErrInvalidSubmittedResult, "failed to verify submitted result: %v", err)
}

if err = m.saveKVQueryResult(ctx, query, msg.Result); err != nil {
Expand Down
32 changes: 5 additions & 27 deletions x/state-verifier/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,13 @@ import (
"cosmossdk.io/log"
"cosmossdk.io/store/prefix"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
ibccommitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types"
tendermint "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint"
ics23 "github.com/cosmos/ics23/go"

"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/neutron-org/neutron/v5/utils/storageverification"
icqtypes "github.com/neutron-org/neutron/v5/x/interchainqueries/types"
"github.com/neutron-org/neutron/v5/x/state-verifier/types"
)
Expand Down Expand Up @@ -100,29 +99,8 @@ func (k *Keeper) Verify(ctx sdk.Context, blockHeight int64, values []*icqtypes.S
return errors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
}

for _, value := range values {
proof, err := ibccommitmenttypes.ConvertProofs(value.Proof)
if err != nil {
return errors.Wrapf(sdkerrors.ErrInvalidType, "failed to convert crypto.ProofOps to MerkleProof: %v", err)
}

path := ibccommitmenttypes.NewMerklePath(value.StoragePrefix, string(value.Key))
// identify what kind proofs (non-existence proof always has *ics23.CommitmentProof_Nonexist as the first item) we got
// and call corresponding method to verify it
switch proof.GetProofs()[0].GetProof().(type) {
// we can get non-existence proof if someone queried some key which is not exists in the storage on remote chain
case *ics23.CommitmentProof_Nonexist:
if err := proof.VerifyNonMembership(ibccommitmenttypes.GetSDKSpecs(), cs.Root, path); err != nil {
return errors.Wrapf(icqtypes.ErrInvalidProof, "failed to verify proof: %v", err)
}
value.Value = nil
case *ics23.CommitmentProof_Exist:
if err := proof.VerifyMembership(ibccommitmenttypes.GetSDKSpecs(), cs.Root, path, value.Value); err != nil {
return errors.Wrapf(icqtypes.ErrInvalidProof, "failed to verify proof: %v", err)
}
default:
return errors.Wrapf(icqtypes.ErrInvalidProof, "unknown proof type %T", proof.GetProofs()[0].GetProof())
}
if err := storageverification.VerifyStorageValues(values, cs.Root, ibccommitmenttypes.GetSDKSpecs(), nil); err != nil {
return errors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
}

return nil
Expand Down

0 comments on commit 4a57aac

Please sign in to comment.