From 7b8b7ad256ff3b09bfab610f1f3ceb1598350bfa Mon Sep 17 00:00:00 2001 From: trestin Date: Fri, 1 Nov 2024 17:35:07 +0800 Subject: [PATCH] fix set task result info err --- app/app.go | 2 +- x/avs/keeper/genesis.go | 5 +- x/avs/keeper/keeper.go | 152 ++++++++++++++++ x/avs/keeper/msg_server.go | 2 +- .../keeper/multi_operator_submit_task_test.go | 4 +- x/avs/keeper/submit_task_test.go | 4 +- x/avs/keeper/task.go | 170 +----------------- 7 files changed, 166 insertions(+), 173 deletions(-) diff --git a/app/app.go b/app/app.go index f84763c36..4208a2e35 100644 --- a/app/app.go +++ b/app/app.go @@ -994,8 +994,8 @@ func NewExocoreApp( evmtypes.ModuleName, // must be before avs, since dogfood calls avs which calls this exominttypes.ModuleName, assetsTypes.ModuleName, - avsManagerTypes.ModuleName, // before dogfood, since dogfood registers itself as an AVS operatorTypes.ModuleName, // must be before delegation + avsManagerTypes.ModuleName, // before dogfood, since dogfood registers itself as an AVS delegationTypes.ModuleName, stakingtypes.ModuleName, // must be after delegation // must be after staking to `IterateValidators` but it is not implemented anyway diff --git a/x/avs/keeper/genesis.go b/x/avs/keeper/genesis.go index 3a6e5712b..d16d67222 100644 --- a/x/avs/keeper/genesis.go +++ b/x/avs/keeper/genesis.go @@ -37,10 +37,7 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state types.GenesisState) { } // Set all the task result infos for _, elem := range state.TaskResultInfos { - err := k.SetTaskResultInfo(ctx, elem.OperatorAddress, &elem) //nolint:gosec - if err != nil { - panic(errorsmod.Wrap(err, "failed to set all task result info")) - } + k.SetTaskResultInfo(ctx, &elem) } // Set all the task challenge infos err := k.SetAllTaskChallengedInfo(ctx, state.ChallengeInfos) diff --git a/x/avs/keeper/keeper.go b/x/avs/keeper/keeper.go index 322e09ad8..2850b88a6 100644 --- a/x/avs/keeper/keeper.go +++ b/x/avs/keeper/keeper.go @@ -1,8 +1,10 @@ package keeper import ( + "bytes" "encoding/hex" "fmt" + "github.com/ethereum/go-ethereum/crypto" "slices" "strconv" @@ -462,3 +464,153 @@ func (k Keeper) RaiseAndResolveChallenge(ctx sdk.Context, params *ChallengeParam return k.SetTaskChallengedInfo(ctx, params.TaskID, params.OperatorAddress.String(), params.CallerAddress, params.TaskContractAddress) } + +func (k Keeper) SubmitTaskResult(ctx sdk.Context, addr string, info *types.TaskResultInfo) error { + // the operator's `addr` must match the from address. + if addr != info.OperatorAddress { + return errorsmod.Wrap( + types.ErrInvalidAddr, + "SetTaskResultInfo:from address is not equal to the operator address", + ) + } + opAccAddr, _ := sdk.AccAddressFromBech32(info.OperatorAddress) + // check operator + if !k.operatorKeeper.IsOperator(ctx, opAccAddr) { + return errorsmod.Wrap( + delegationtypes.ErrOperatorNotExist, + fmt.Sprintf("SetTaskResultInfo:invalid operator address:%s", opAccAddr), + ) + } + // check operator bls pubkey + keyInfo, err := k.GetOperatorPubKey(ctx, info.OperatorAddress) + if err != nil || keyInfo.PubKey == nil { + return errorsmod.Wrap( + types.ErrPubKeyIsNotExists, + fmt.Sprintf("SetTaskResultInfo:get operator address:%s", opAccAddr), + ) + } + pubKey, err := blst.PublicKeyFromBytes(keyInfo.PubKey) + if err != nil || pubKey == nil { + return errorsmod.Wrap( + types.ErrParsePubKey, + fmt.Sprintf("SetTaskResultInfo:get operator address:%s", opAccAddr), + ) + } + // check task contract + task, err := k.GetTaskInfo(ctx, strconv.FormatUint(info.TaskId, 10), info.TaskContractAddress) + if err != nil || task.TaskContractAddress == "" { + return errorsmod.Wrap( + types.ErrTaskIsNotExists, + fmt.Sprintf("SetTaskResultInfo: task info not found: %s (Task ID: %d)", + info.TaskContractAddress, info.TaskId), + ) + } + + // check prescribed period + // If submitted in the first stage, in order to avoid plagiarism by other operators, + // TaskResponse and TaskResponseHash must be null values + // At the same time, it must be submitted within the response deadline in the first stage + avsInfo := k.GetAVSInfoByTaskAddress(ctx, info.TaskContractAddress) + epoch, found := k.epochsKeeper.GetEpochInfo(ctx, avsInfo.EpochIdentifier) + if !found { + return errorsmod.Wrap(types.ErrEpochNotFound, fmt.Sprintf("epoch info not found %s", + avsInfo.EpochIdentifier)) + } + + switch info.Stage { + case types.TwoPhaseCommitOne: + if k.IsExistTaskResultInfo(ctx, info.OperatorAddress, info.TaskContractAddress, info.TaskId) { + return errorsmod.Wrap( + types.ErrResAlreadyExists, + fmt.Sprintf("SetTaskResultInfo: task result is already exists, "+ + "OperatorAddress: %s (TaskContractAddress: %s),(Task ID: %d)", + info.OperatorAddress, info.TaskContractAddress, info.TaskId), + ) + } + // check parameters + if info.BlsSignature == nil { + return errorsmod.Wrap( + types.ErrParamNotEmptyError, + fmt.Sprintf("SetTaskResultInfo: invalid param BlsSignature is not be null (BlsSignature: %s)", info.BlsSignature), + ) + } + if info.TaskResponseHash != "" || info.TaskResponse != nil { + return errorsmod.Wrap( + types.ErrParamNotEmptyError, + fmt.Sprintf("SetTaskResultInfo: invalid param TaskResponseHash: %s (TaskResponse: %d)", + info.TaskResponseHash, info.TaskResponse), + ) + } + // check epoch,The first stage submission must be within the response window period + // #nosec G115 + if epoch.CurrentEpoch > int64(task.StartingEpoch)+int64(task.TaskResponsePeriod) { + return errorsmod.Wrap( + types.ErrSubmitTooLateError, + fmt.Sprintf("SetTaskResultInfo:submit too late, CurrentEpoch:%d", epoch.CurrentEpoch), + ) + } + k.SetTaskResultInfo(ctx, info) + return nil + + case types.TwoPhaseCommitTwo: + // check task response + if info.TaskResponse == nil { + return errorsmod.Wrap( + types.ErrNotNull, + fmt.Sprintf("SetTaskResultInfo: invalid param (TaskResponse: %d)", + info.TaskResponse), + ) + } + // check parameters + res, err := k.GetTaskResultInfo(ctx, info.OperatorAddress, info.TaskContractAddress, info.TaskId) + if err != nil || !bytes.Equal(res.BlsSignature, info.BlsSignature) { + return errorsmod.Wrap( + types.ErrInconsistentParams, + fmt.Sprintf("SetTaskResultInfo: invalid param OperatorAddress: %s ,(TaskContractAddress: %s)"+ + ",(TaskId: %d),(BlsSignature: %s)", + info.OperatorAddress, info.TaskContractAddress, info.TaskId, info.BlsSignature), + ) + } + // check epoch,The second stage submission must be within the statistical window period + // #nosec G115 + if epoch.CurrentEpoch <= int64(task.StartingEpoch)+int64(task.TaskResponsePeriod) { + return errorsmod.Wrap( + types.ErrSubmitTooSoonError, + fmt.Sprintf("SetTaskResultInfo:the TaskResponse period has not started , CurrentEpoch:%d", epoch.CurrentEpoch), + ) + } + if epoch.CurrentEpoch > int64(task.StartingEpoch)+int64(task.TaskResponsePeriod)+int64(task.TaskStatisticalPeriod) { + return errorsmod.Wrap( + types.ErrSubmitTooLateError, + fmt.Sprintf("SetTaskResultInfo:submit too late, CurrentEpoch:%d", epoch.CurrentEpoch), + ) + } + + // calculate hash by original task + taskResponseDigest := crypto.Keccak256Hash(info.TaskResponse) + info.TaskResponseHash = taskResponseDigest.String() + // check taskID + resp, err := types.UnmarshalTaskResponse(info.TaskResponse) + if err != nil || info.TaskId != resp.TaskID { + return errorsmod.Wrap( + types.ErrInconsistentParams, + fmt.Sprintf("SetTaskResultInfo: invalid TaskId param value:%s", info.TaskResponse), + ) + } + // check bls sig + flag, err := blst.VerifySignature(info.BlsSignature, taskResponseDigest, pubKey) + if !flag || err != nil { + return errorsmod.Wrap( + types.ErrSigVerifyError, + fmt.Sprintf("SetTaskResultInfo: invalid task address: %s (Task ID: %d)", info.TaskContractAddress, info.TaskId), + ) + } + k.SetTaskResultInfo(ctx, info) + return nil + default: + return errorsmod.Wrap( + types.ErrParamError, + fmt.Sprintf("SetTaskResultInfo: invalid param value:%s", info.Stage), + ) + } +} diff --git a/x/avs/keeper/msg_server.go b/x/avs/keeper/msg_server.go index bf0811448..fa46d2985 100644 --- a/x/avs/keeper/msg_server.go +++ b/x/avs/keeper/msg_server.go @@ -20,7 +20,7 @@ var _ types.MsgServer = &MsgServerImpl{} func (m MsgServerImpl) SubmitTaskResult(goCtx context.Context, req *types.SubmitTaskResultReq) (*types.SubmitTaskResultResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - if err := m.keeper.SetTaskResultInfo(ctx, req.FromAddress, req.Info); err != nil { + if err := m.keeper.SubmitTaskResult(ctx, req.FromAddress, req.Info); err != nil { return nil, err } return &types.SubmitTaskResultResponse{}, nil diff --git a/x/avs/keeper/multi_operator_submit_task_test.go b/x/avs/keeper/multi_operator_submit_task_test.go index dda8de157..52bb14e11 100644 --- a/x/avs/keeper/multi_operator_submit_task_test.go +++ b/x/avs/keeper/multi_operator_submit_task_test.go @@ -204,7 +204,7 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseOne_Mul() { BlsSignature: sig.Marshal(), Stage: avstypes.TwoPhaseCommitOne, } - err := suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, operatorAddress, info) + err := suite.App.AVSManagerKeeper.SubmitTaskResult(suite.Ctx, operatorAddress, info) suite.Require().NoError(err) } } @@ -232,7 +232,7 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseTwo_Mul() { BlsSignature: sig.Marshal(), Stage: avstypes.TwoPhaseCommitTwo, } - err = suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, operatorAddress, info) + err = suite.App.AVSManagerKeeper.SubmitTaskResult(suite.Ctx, operatorAddress, info) suite.NoError(err) } } diff --git a/x/avs/keeper/submit_task_test.go b/x/avs/keeper/submit_task_test.go index ce266cd3b..b33948115 100644 --- a/x/avs/keeper/submit_task_test.go +++ b/x/avs/keeper/submit_task_test.go @@ -190,7 +190,7 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseOne() { BlsSignature: sig.Marshal(), Stage: avstypes.TwoPhaseCommitOne, } - err = suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, suite.operatorAddr.String(), info) + err = suite.App.AVSManagerKeeper.SubmitTaskResult(suite.Ctx, suite.operatorAddr.String(), info) suite.NoError(err) } @@ -219,6 +219,6 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseTwo() { BlsSignature: sig.Marshal(), Stage: avstypes.TwoPhaseCommitTwo, } - err = suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, suite.operatorAddr.String(), info) + err = suite.App.AVSManagerKeeper.SubmitTaskResult(suite.Ctx, suite.operatorAddr.String(), info) suite.NoError(err) } diff --git a/x/avs/keeper/task.go b/x/avs/keeper/task.go index be585e33d..879cba440 100644 --- a/x/avs/keeper/task.go +++ b/x/avs/keeper/task.go @@ -1,23 +1,18 @@ package keeper import ( - "bytes" "fmt" "sort" "strconv" "strings" - "github.com/ethereum/go-ethereum/crypto" - errorsmod "cosmossdk.io/errors" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" "github.com/ExocoreNetwork/exocore/x/avs/types" - delegationtypes "github.com/ExocoreNetwork/exocore/x/delegation/types" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" - "github.com/prysmaticlabs/prysm/v4/crypto/bls/blst" ) func (k Keeper) SetTaskInfo(ctx sdk.Context, task *types.TaskInfo) (err error) { @@ -188,164 +183,13 @@ func (k *Keeper) GetAllTaskNums(ctx sdk.Context) ([]types.TaskID, error) { // SetTaskResultInfo is used to store the operator's sign task information. func (k *Keeper) SetTaskResultInfo( - ctx sdk.Context, addr string, info *types.TaskResultInfo, -) (err error) { - // the operator's `addr` must match the from address. - if addr != info.OperatorAddress { - return errorsmod.Wrap( - types.ErrInvalidAddr, - "SetTaskResultInfo:from address is not equal to the operator address", - ) - } - opAccAddr, _ := sdk.AccAddressFromBech32(info.OperatorAddress) - // check operator - if !k.operatorKeeper.IsOperator(ctx, opAccAddr) { - return errorsmod.Wrap( - delegationtypes.ErrOperatorNotExist, - fmt.Sprintf("SetTaskResultInfo:invalid operator address:%s", opAccAddr), - ) - } - // check operator bls pubkey - keyInfo, err := k.GetOperatorPubKey(ctx, info.OperatorAddress) - if err != nil || keyInfo.PubKey == nil { - return errorsmod.Wrap( - types.ErrPubKeyIsNotExists, - fmt.Sprintf("SetTaskResultInfo:get operator address:%s", opAccAddr), - ) - } - pubKey, err := blst.PublicKeyFromBytes(keyInfo.PubKey) - if err != nil || pubKey == nil { - return errorsmod.Wrap( - types.ErrParsePubKey, - fmt.Sprintf("SetTaskResultInfo:get operator address:%s", opAccAddr), - ) - } - // check task contract - task, err := k.GetTaskInfo(ctx, strconv.FormatUint(info.TaskId, 10), info.TaskContractAddress) - if err != nil || task.TaskContractAddress == "" { - return errorsmod.Wrap( - types.ErrTaskIsNotExists, - fmt.Sprintf("SetTaskResultInfo: task info not found: %s (Task ID: %d)", - info.TaskContractAddress, info.TaskId), - ) - } - - // check prescribed period - // If submitted in the first stage, in order to avoid plagiarism by other operators, - // TaskResponse and TaskResponseHash must be null values - // At the same time, it must be submitted within the response deadline in the first stage - avsInfo := k.GetAVSInfoByTaskAddress(ctx, info.TaskContractAddress) - epoch, found := k.epochsKeeper.GetEpochInfo(ctx, avsInfo.EpochIdentifier) - if !found { - return errorsmod.Wrap(types.ErrEpochNotFound, fmt.Sprintf("epoch info not found %s", - avsInfo.EpochIdentifier)) - } - - switch info.Stage { - case types.TwoPhaseCommitOne: - if k.IsExistTaskResultInfo(ctx, info.OperatorAddress, info.TaskContractAddress, info.TaskId) { - return errorsmod.Wrap( - types.ErrResAlreadyExists, - fmt.Sprintf("SetTaskResultInfo: task result is already exists, "+ - "OperatorAddress: %s (TaskContractAddress: %s),(Task ID: %d)", - info.OperatorAddress, info.TaskContractAddress, info.TaskId), - ) - } - // check parameters - if info.BlsSignature == nil { - return errorsmod.Wrap( - types.ErrParamNotEmptyError, - fmt.Sprintf("SetTaskResultInfo: invalid param BlsSignature is not be null (BlsSignature: %s)", info.BlsSignature), - ) - } - if info.TaskResponseHash != "" || info.TaskResponse != nil { - return errorsmod.Wrap( - types.ErrParamNotEmptyError, - fmt.Sprintf("SetTaskResultInfo: invalid param TaskResponseHash: %s (TaskResponse: %d)", - info.TaskResponseHash, info.TaskResponse), - ) - } - // check epoch,The first stage submission must be within the response window period - // #nosec G115 - if epoch.CurrentEpoch > int64(task.StartingEpoch)+int64(task.TaskResponsePeriod) { - return errorsmod.Wrap( - types.ErrSubmitTooLateError, - fmt.Sprintf("SetTaskResultInfo:submit too late, CurrentEpoch:%d", epoch.CurrentEpoch), - ) - } - infoKey := assetstype.GetJoinedStoreKey(info.OperatorAddress, info.TaskContractAddress, - strconv.FormatUint(info.TaskId, 10)) - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskResult) - bz := k.cdc.MustMarshal(info) - store.Set(infoKey, bz) - return nil - - case types.TwoPhaseCommitTwo: - // check task response - if info.TaskResponse == nil { - return errorsmod.Wrap( - types.ErrNotNull, - fmt.Sprintf("SetTaskResultInfo: invalid param (TaskResponse: %d)", - info.TaskResponse), - ) - } - // check parameters - res, err := k.GetTaskResultInfo(ctx, info.OperatorAddress, info.TaskContractAddress, info.TaskId) - if err != nil || !bytes.Equal(res.BlsSignature, info.BlsSignature) { - return errorsmod.Wrap( - types.ErrInconsistentParams, - fmt.Sprintf("SetTaskResultInfo: invalid param OperatorAddress: %s ,(TaskContractAddress: %s)"+ - ",(TaskId: %d),(BlsSignature: %s)", - info.OperatorAddress, info.TaskContractAddress, info.TaskId, info.BlsSignature), - ) - } - // check epoch,The second stage submission must be within the statistical window period - // #nosec G115 - if epoch.CurrentEpoch <= int64(task.StartingEpoch)+int64(task.TaskResponsePeriod) { - return errorsmod.Wrap( - types.ErrSubmitTooSoonError, - fmt.Sprintf("SetTaskResultInfo:the TaskResponse period has not started , CurrentEpoch:%d", epoch.CurrentEpoch), - ) - } - if epoch.CurrentEpoch > int64(task.StartingEpoch)+int64(task.TaskResponsePeriod)+int64(task.TaskStatisticalPeriod) { - return errorsmod.Wrap( - types.ErrSubmitTooLateError, - fmt.Sprintf("SetTaskResultInfo:submit too late, CurrentEpoch:%d", epoch.CurrentEpoch), - ) - } - - // calculate hash by original task - taskResponseDigest := crypto.Keccak256Hash(info.TaskResponse) - info.TaskResponseHash = taskResponseDigest.String() - // check taskID - resp, err := types.UnmarshalTaskResponse(info.TaskResponse) - if err != nil || info.TaskId != resp.TaskID { - return errorsmod.Wrap( - types.ErrInconsistentParams, - fmt.Sprintf("SetTaskResultInfo: invalid TaskId param value:%s", info.TaskResponse), - ) - } - // check bls sig - flag, err := blst.VerifySignature(info.BlsSignature, taskResponseDigest, pubKey) - if !flag || err != nil { - return errorsmod.Wrap( - types.ErrSigVerifyError, - fmt.Sprintf("SetTaskResultInfo: invalid task address: %s (Task ID: %d)", info.TaskContractAddress, info.TaskId), - ) - } - - infoKey := assetstype.GetJoinedStoreKey(info.OperatorAddress, info.TaskContractAddress, strconv.FormatUint(info.TaskId, 10)) - - store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskResult) - bz := k.cdc.MustMarshal(info) - store.Set(infoKey, bz) - return nil - default: - return errorsmod.Wrap( - types.ErrParamError, - fmt.Sprintf("SetTaskResultInfo: invalid param value:%s", info.Stage), - ) - } + ctx sdk.Context, info *types.TaskResultInfo, +) { + infoKey := assetstype.GetJoinedStoreKey(info.OperatorAddress, strings.ToLower(info.TaskContractAddress), + strconv.FormatUint(info.TaskId, 10)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskResult) + bz := k.cdc.MustMarshal(info) + store.Set(infoKey, bz) } func (k *Keeper) IsExistTaskResultInfo(ctx sdk.Context, operatorAddress, taskContractAddress string, taskID uint64) bool {