Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Session,Service] Ensure SessionHeader and Service basic validation. #782

Merged
merged 14 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions x/application/module/config/application_configs_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

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

sharedhelpers "github.com/pokt-network/poktroll/x/shared/helpers"
sharedtypes "github.com/pokt-network/poktroll/x/shared/types"
)

Expand Down Expand Up @@ -73,7 +72,7 @@ func ParseApplicationConfigs(configContent []byte) (*ApplicationStakeConfig, err

for _, serviceId := range parsedAppConfig.ServiceIds {
// Validate serviceId
if !sharedhelpers.IsValidServiceId(serviceId) {
if !sharedtypes.IsValidServiceId(serviceId) {
return nil, ErrApplicationConfigInvalidServiceId.Wrapf("%s", serviceId)
}

Expand Down
86 changes: 48 additions & 38 deletions x/proof/keeper/msg_server_submit_proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,9 +549,9 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) {
)

tests := []struct {
desc string
newProofMsg func(t *testing.T) *prooftypes.MsgSubmitProof
expectedErr error
desc string
newProofMsg func(t *testing.T) *prooftypes.MsgSubmitProof
msgSubmitProofToExpectedErrorFn func(*prooftypes.MsgSubmitProof) error
red-0ne marked this conversation as resolved.
Show resolved Hide resolved
}{
{
desc: "proof service ID cannot be empty",
Expand All @@ -568,14 +568,16 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) {
expectedMerkleProofPath,
)
},
expectedErr: status.Error(
codes.InvalidArgument,
prooftypes.ErrProofInvalidSessionId.Wrapf(
"session ID does not match on-chain session ID; expected %q, got %q",
validSessionHeader.GetSessionId(),
"",
).Error(),
),
msgSubmitProofToExpectedErrorFn: func(msgSubmitProof *prooftypes.MsgSubmitProof) error {
sessionError := sessiontypes.ErrSessionInvalidSessionId.Wrapf(
"%q",
msgSubmitProof.GetSessionHeader().GetSessionId(),
)
return status.Error(
codes.InvalidArgument,
prooftypes.ErrProofInvalidSessionHeader.Wrapf("%s", sessionError).Error(),
)
},
},
{
desc: "merkle proof cannot be empty",
Expand All @@ -592,12 +594,14 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) {
proof.Proof = []byte{}
return proof
},
expectedErr: status.Error(
codes.InvalidArgument,
prooftypes.ErrProofInvalidProof.Wrap(
"proof cannot be empty",
).Error(),
),
msgSubmitProofToExpectedErrorFn: func(_ *prooftypes.MsgSubmitProof) error {
return status.Error(
codes.InvalidArgument,
prooftypes.ErrProofInvalidProof.Wrap(
"proof cannot be empty",
).Error(),
)
},
},
{
desc: "proof session ID must match on-chain session ID",
Expand All @@ -610,14 +614,16 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) {
expectedMerkleProofPath,
)
},
expectedErr: status.Error(
codes.InvalidArgument,
prooftypes.ErrProofInvalidSessionId.Wrapf(
"session ID does not match on-chain session ID; expected %q, got %q",
validSessionHeader.GetSessionId(),
wrongSessionIdHeader.GetSessionId(),
).Error(),
),
msgSubmitProofToExpectedErrorFn: func(msgSubmitProof *prooftypes.MsgSubmitProof) error {
return status.Error(
codes.InvalidArgument,
prooftypes.ErrProofInvalidSessionId.Wrapf(
"session ID does not match on-chain session ID; expected %q, got %q",
validSessionHeader.GetSessionId(),
msgSubmitProof.GetSessionHeader().GetSessionId(),
).Error(),
)
},
},
{
desc: "proof supplier must be in on-chain session",
Expand All @@ -630,28 +636,30 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) {
expectedMerkleProofPath,
)
},
expectedErr: status.Error(
codes.InvalidArgument,
prooftypes.ErrProofNotFound.Wrapf(
"supplier operator address %q not found in session ID %q",
wrongSupplierOperatorAddr,
validSessionHeader.GetSessionId(),
).Error(),
),
msgSubmitProofToExpectedErrorFn: func(msgSubmitProof *prooftypes.MsgSubmitProof) error {
return status.Error(
codes.InvalidArgument,
prooftypes.ErrProofNotFound.Wrapf(
"supplier operator address %q not found in session ID %q",
wrongSupplierOperatorAddr,
msgSubmitProof.GetSessionHeader().GetSessionId(),
).Error(),
)
},
},
}

// Submit the corresponding proof.
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
proofMsg := test.newProofMsg(t)
msgSubmitProof := test.newProofMsg(t)

// Advance the block height to the proof path seed height.
earliestSupplierProofCommitHeight := shared.GetEarliestSupplierProofCommitHeight(
&sharedParams,
proofMsg.GetSessionHeader().GetSessionEndBlockHeight(),
msgSubmitProof.GetSessionHeader().GetSessionEndBlockHeight(),
blockHeaderHash,
proofMsg.GetSupplierOperatorAddress(),
msgSubmitProof.GetSupplierOperatorAddress(),
)
ctx = keepertest.SetBlockHeight(ctx, earliestSupplierProofCommitHeight-1)

Expand All @@ -662,9 +670,11 @@ func TestMsgServer_SubmitProof_Error(t *testing.T) {
// Advance the block height to the earliest proof commit height.
ctx = keepertest.SetBlockHeight(ctx, earliestSupplierProofCommitHeight)

submitProofRes, err := srv.SubmitProof(ctx, proofMsg)
submitProofRes, err := srv.SubmitProof(ctx, msgSubmitProof)

require.ErrorContains(t, err, test.expectedErr.Error())
expectedErr := test.msgSubmitProofToExpectedErrorFn(msgSubmitProof)
require.ErrorIs(t, err, expectedErr)
require.ErrorContains(t, err, expectedErr.Error())
require.Nil(t, submitProofRes)

proofRes, err := keepers.AllProofs(ctx, &prooftypes.QueryAllProofsRequest{})
Expand Down
1 change: 1 addition & 0 deletions x/proof/types/message_create_claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func NewMsgCreateClaim(
}
}

// ValidateBasic performs basic stateless validation of a MsgCreateClaim.
func (msg *MsgCreateClaim) ValidateBasic() error {
// Validate the supplier operator address
if _, err := sdk.AccAddressFromBech32(msg.GetSupplierOperatorAddress()); err != nil {
Expand Down
19 changes: 7 additions & 12 deletions x/proof/types/message_submit_proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ func NewMsgSubmitProof(supplierOperatorAddress string, sessionHeader *sessiontyp
}
}

// ValidateBasic ensures that the bech32 operator address strings for the supplier and
// application addresses are valid and that the proof and service ID are not empty.
//
// TODO_BETA: Call `msg.GetSessionHeader().ValidateBasic()` once its implemented
// ValidateBasic performs basic stateless validation of a MsgSubmitProof.
func (msg *MsgSubmitProof) ValidateBasic() error {
if _, err := sdk.AccAddressFromBech32(msg.GetSupplierOperatorAddress()); err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf(
Expand All @@ -30,16 +27,14 @@ func (msg *MsgSubmitProof) ValidateBasic() error {
)
}

if _, err := sdk.AccAddressFromBech32(msg.GetSessionHeader().GetApplicationAddress()); err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf(
"application address: %q, error: %s",
msg.GetSessionHeader().GetApplicationAddress(),
err,
)
// Retrieve & validate the session header
sessionHeader := msg.SessionHeader
if sessionHeader == nil {
return ErrProofInvalidSessionHeader.Wrapf("session header is nil")
}

if msg.GetSessionHeader().GetService().GetId() == "" {
return ErrProofInvalidService.Wrap("proof service ID %q cannot be empty")
if err := sessionHeader.ValidateBasic(); err != nil {
return ErrProofInvalidSessionHeader.Wrapf("%s", err)
}

if len(msg.GetProof()) == 0 {
Expand Down
44 changes: 27 additions & 17 deletions x/proof/types/message_submit_proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ func TestMsgSubmitProof_ValidateBasic(t *testing.T) {
testClosestMerkleProof := []byte{1, 2, 3, 4}

tests := []struct {
desc string
msg MsgSubmitProof
expectedErr error
desc string
msg MsgSubmitProof
sessionHeaderToExpectedErrorFn func(sessiontypes.SessionHeader) error
}{
{
desc: "application bech32 address is invalid",
Expand All @@ -34,11 +34,14 @@ func TestMsgSubmitProof_ValidateBasic(t *testing.T) {
},
Proof: testClosestMerkleProof,
},
expectedErr: sdkerrors.ErrInvalidAddress.Wrapf(
"application address: %q, error: %s",
"not_a_bech32_address",
"decoding bech32 failed: invalid separator index -1",
),
sessionHeaderToExpectedErrorFn: func(sh sessiontypes.SessionHeader) error {
sessionError := sessiontypes.ErrSessionInvalidAppAddress.Wrapf(
"%q; (%s)",
sh.ApplicationAddress,
"decoding bech32 failed: invalid separator index -1",
)
return ErrProofInvalidSessionHeader.Wrapf("%s", sessionError)
},
},
{
desc: "supplier operator bech32 address is invalid",
Expand All @@ -53,11 +56,13 @@ func TestMsgSubmitProof_ValidateBasic(t *testing.T) {
},
Proof: testClosestMerkleProof,
},
expectedErr: sdkerrors.ErrInvalidAddress.Wrapf(
"supplier operator address %q, error: %s",
"not_a_bech32_address",
"decoding bech32 failed: invalid separator index -1",
),
sessionHeaderToExpectedErrorFn: func(sh sessiontypes.SessionHeader) error {
return sdkerrors.ErrInvalidAddress.Wrapf(
"supplier operator address %q, error: %s",
red-0ne marked this conversation as resolved.
Show resolved Hide resolved
"not_a_bech32_address",
"decoding bech32 failed: invalid separator index -1",
)
},
},
{
desc: "session service ID is empty",
Expand All @@ -72,7 +77,11 @@ func TestMsgSubmitProof_ValidateBasic(t *testing.T) {
},
Proof: testClosestMerkleProof,
},
expectedErr: ErrProofInvalidService.Wrap("proof service ID %q cannot be empty"),
sessionHeaderToExpectedErrorFn: func(sh sessiontypes.SessionHeader) error {
serviceError := sharedtypes.ErrSharedInvalidService.Wrapf("ID: %q", sh.Service.Id)
sessionError := sessiontypes.ErrSessionInvalidService.Wrapf("%s", serviceError)
return ErrProofInvalidSessionHeader.Wrapf("%s", sessionError)
},
},
{
desc: "valid message metadata",
Expand All @@ -92,9 +101,10 @@ func TestMsgSubmitProof_ValidateBasic(t *testing.T) {
for _, test := range tests {
t.Run(test.desc, func(t *testing.T) {
err := test.msg.ValidateBasic()
if test.expectedErr != nil {
require.ErrorIs(t, err, test.expectedErr)
require.ErrorContains(t, err, test.expectedErr.Error())
if test.sessionHeaderToExpectedErrorFn != nil {
expectedErr := test.sessionHeaderToExpectedErrorFn(*test.msg.SessionHeader)
require.ErrorIs(t, err, expectedErr)
require.ErrorContains(t, err, expectedErr.Error())
return
}
require.NoError(t, err)
Expand Down
2 changes: 2 additions & 0 deletions x/service/types/message_add_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func (msg *MsgAddService) ValidateBasic() error {
if err := ValidateComputeUnitsPerRelay(msg.Service.ComputeUnitsPerRelay); err != nil {
return err
}

return nil
}

Expand All @@ -57,5 +58,6 @@ func ValidateComputeUnitsPerRelay(computeUnitsPerRelay uint64) error {
} else if computeUnitsPerRelay > ComputeUnitsPerRelayMax {
return ErrServiceInvalidComputeUnitsPerRelay.Wrapf("compute units per relay must be less than %d", ComputeUnitsPerRelayMax)
}

return nil
}
5 changes: 2 additions & 3 deletions x/session/keeper/session_hydrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (

"github.com/pokt-network/poktroll/x/session/types"
"github.com/pokt-network/poktroll/x/shared"
sharedhelpers "github.com/pokt-network/poktroll/x/shared/helpers"
sharedtypes "github.com/pokt-network/poktroll/x/shared/types"
)

Expand Down Expand Up @@ -118,8 +117,8 @@ func (k Keeper) hydrateSessionID(ctx context.Context, sh *sessionHydrator) error
// TODO_MAINNET: In the future, we will need to validate that the Service is
// a valid service depending on whether or not its permissioned or permissionless

if !sharedhelpers.IsValidService(sh.sessionHeader.Service) {
return types.ErrSessionHydration.Wrapf("invalid service: %v", sh.sessionHeader.Service)
if err := sh.sessionHeader.Service.ValidateBasic(); err != nil {
return types.ErrSessionHydration.Wrapf("%s", err)
}

sh.sessionHeader.SessionId, sh.sessionIDBz = k.GetSessionId(
Expand Down
7 changes: 3 additions & 4 deletions x/session/types/query_get_session_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"

sharedhelpers "github.com/pokt-network/poktroll/x/shared/helpers"
sharedtypes "github.com/pokt-network/poktroll/x/shared/types"
)

Expand All @@ -23,12 +22,12 @@ func NewQueryGetSessionRequest(appAddress, serviceId string, blockHeight int64)
func (query *QueryGetSessionRequest) ValidateBasic() error {
// Validate the application address
if _, err := sdk.AccAddressFromBech32(query.ApplicationAddress); err != nil {
return ErrSessionInvalidAppAddress.Wrapf("invalid app address for session being retrieved %s; (%v)", query.ApplicationAddress, err)
return ErrSessionInvalidAppAddress.Wrapf("%s", err)
}

// Validate the Service ID
if !sharedhelpers.IsValidService(query.Service) {
return ErrSessionInvalidService.Wrapf("invalid service for session being retrieved %s;", query.Service)
if err := query.Service.ValidateBasic(); err != nil {
return ErrSessionInvalidService.Wrapf("invalid service for session being retrieved %s; %s", query.Service, err)
}

// Validate the height for which a session is being retrieved
Expand Down
15 changes: 8 additions & 7 deletions x/session/types/session_header.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@ package types

import (
sdk "github.com/cosmos/cosmos-sdk/types"

sharedhelpers "github.com/pokt-network/poktroll/x/shared/helpers"
)

// TODO_BETA: Ensure this is used everywhere a SessionHeader is validated.
// ValidateBasic performs basic stateless validation of a SessionHeader.
func (sh *SessionHeader) ValidateBasic() error {
// Validate the application address
if _, err := sdk.AccAddressFromBech32(sh.ApplicationAddress); err != nil {
return ErrSessionInvalidAppAddress.Wrapf("invalid application address: %s; (%v)", sh.ApplicationAddress, err)
return ErrSessionInvalidAppAddress.Wrapf("%q; (%s)", sh.ApplicationAddress, err)
}

// Validate the session ID
if len(sh.SessionId) == 0 {
return ErrSessionInvalidSessionId.Wrapf("invalid session ID: %s", sh.SessionId)
return ErrSessionInvalidSessionId.Wrapf("%q", sh.SessionId)
}

// Validate the service
if sh.Service == nil || !sharedhelpers.IsValidService(sh.Service) {
return ErrSessionInvalidService.Wrapf("invalid service: %s", sh.Service)
if sh.Service == nil {
return ErrSessionInvalidService.Wrapf("missing service")
}

if err := sh.Service.ValidateBasic(); err != nil {
return ErrSessionInvalidService.Wrapf("%s", err)
}

// Sessions can only start at height 1
Expand Down
Loading
Loading