From e0ff11048b55a7bb8becd118c406c2be22806ef5 Mon Sep 17 00:00:00 2001 From: trestin Date: Fri, 23 Aug 2024 15:23:09 +0800 Subject: [PATCH] add RaiseAndResolveChallenge --- x/avs/keeper/keeper.go | 52 +++++++++++++++++++++++++++++++++++++++ x/avs/keeper/params.go | 10 ++++++++ x/avs/keeper/task.go | 36 ++++++++++++++++++++++++--- x/avs/keeper/task_test.go | 5 ++++ x/avs/types/errors.go | 2 +- x/avs/types/keys.go | 2 ++ 6 files changed, 102 insertions(+), 5 deletions(-) diff --git a/x/avs/keeper/keeper.go b/x/avs/keeper/keeper.go index 33cbde1a2..790f25977 100644 --- a/x/avs/keeper/keeper.go +++ b/x/avs/keeper/keeper.go @@ -1,6 +1,7 @@ package keeper import ( + "encoding/hex" "fmt" "slices" "strconv" @@ -337,3 +338,54 @@ func (k Keeper) IterateAVSInfo(ctx sdk.Context, fn func(index int64, avsInfo typ i++ } } +func (k Keeper) RaiseAndResolveChallenge(ctx sdk.Context, params *ChallengeParams) error { + + taskInfo, err := k.GetTaskInfo(ctx, strconv.FormatUint(params.TaskID, 10), params.TaskContractAddress.String()) + if err != nil { + return fmt.Errorf("task does not exist,this task address: %s", params.TaskContractAddress) + } + // check Task + if taskInfo.TaskContractAddress != params.TaskContractAddress.String() || taskInfo.TaskId != params.TaskID || + hex.EncodeToString(taskInfo.Hash) != hex.EncodeToString(params.TaskHash) { + return errorsmod.Wrap(err, fmt.Sprintf("error Task hasn't been responded to yet: %s", params.TaskContractAddress)) + + } + // check Task result + res, err := k.GetTaskResultInfo(ctx, params.OperatorAddress.String(), params.TaskContractAddress.String(), + params.TaskID) + if err != nil || res.OperatorAddress != params.OperatorAddress.String() || + res.TaskContractAddress != params.TaskContractAddress.String() || + res.TaskId != params.TaskID || res.TaskResponseHash != hex.EncodeToString(params.TaskResponseHash) { + return errorsmod.Wrap( + types.ErrInconsistentParams, + fmt.Sprintf("Task response does not match the one recorded,task addr: %s ,(TaskContractAddress: %s)"+ + ",(TaskId: %d),(TaskResponseHash: %s)", + params.OperatorAddress, params.TaskContractAddress, params.TaskID, params.TaskResponseHash), + ) + } + // check challenge record + if k.IsExistTaskChallengedInfo(ctx, params.OperatorAddress.String(), + params.TaskContractAddress.String(), params.TaskID) { + return errorsmod.Wrap(types.ErrAlreadyExists, fmt.Sprintf("the challenge has been raised: %s", params.TaskContractAddress)) + } + + // check challenge period + // check epoch,The challenge must be within the challenge window period + avsInfo := k.GetAVSInfoByTaskAddress(ctx, taskInfo.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)) + } + if epoch.CurrentEpoch <= int64(taskInfo.StartingEpoch)+int64(taskInfo.TaskResponsePeriod)+int64(taskInfo.TaskStatisticalPeriod) || //nolint:gosec + epoch.CurrentEpoch > int64(taskInfo.StartingEpoch)+int64(taskInfo.TaskResponsePeriod)+int64(taskInfo.TaskStatisticalPeriod)+int64(taskInfo.TaskChallengePeriod) { //nolint:gosec + return errorsmod.Wrap( + types.ErrSubmitTooLateError, + fmt.Sprintf("SetTaskResultInfo:submit too late, CurrentEpoch:%d", epoch.CurrentEpoch), + ) + } + + return k.SetTaskChallengedInfo(ctx, params.TaskID, params.OperatorAddress.String(), + params.TaskContractAddress, params.CallerAddress) + +} diff --git a/x/avs/keeper/params.go b/x/avs/keeper/params.go index 7a5353da4..097de21c6 100644 --- a/x/avs/keeper/params.go +++ b/x/avs/keeper/params.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "github.com/ethereum/go-ethereum/common" "github.com/ExocoreNetwork/exocore/x/avs/types" "github.com/cosmos/cosmos-sdk/store/prefix" @@ -90,3 +91,12 @@ const ( DeRegisterAction = 2 UpdateAction = 3 ) + +type ChallengeParams struct { + TaskContractAddress common.Address `json:"task_contract_address"` + TaskHash []byte `json:"hash"` + TaskID uint64 `json:"task_id"` + OperatorAddress sdk.AccAddress `json:"operator_address"` + TaskResponseHash []byte `json:"task_response_hash"` + CallerAddress common.Address `json:"caller_address"` +} diff --git a/x/avs/keeper/task.go b/x/avs/keeper/task.go index b01796116..c941b8b81 100644 --- a/x/avs/keeper/task.go +++ b/x/avs/keeper/task.go @@ -112,17 +112,17 @@ func (k Keeper) IterateTaskAVSInfo(ctx sdk.Context, fn func(index int64, taskInf } // GetTaskID Increase the task ID by 1 each time. -func (k Keeper) GetTaskID(ctx sdk.Context, taskaddr common.Address) uint64 { +func (k Keeper) GetTaskID(ctx sdk.Context, taskAddr common.Address) uint64 { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixLatestTaskNum) var id uint64 - if store.Has(taskaddr.Bytes()) { - bz := store.Get(taskaddr.Bytes()) + if store.Has(taskAddr.Bytes()) { + bz := store.Get(taskAddr.Bytes()) id = sdk.BigEndianToUint64(bz) id++ } else { id = 1 } - store.Set(taskaddr.Bytes(), sdk.Uint64ToBigEndian(id)) + store.Set(taskAddr.Bytes(), sdk.Uint64ToBigEndian(id)) return id } @@ -244,6 +244,14 @@ func (k *Keeper) SetTaskResultInfo( "SetTaskResultInfo: task response is nil", ) } + // check taskID + resp, err := types.UnmarshalTaskResponse(info.TaskResponse) + if err != nil || info.TaskId != resp.TaskID { + return errorsmod.Wrap( + types.ErrParamError, + fmt.Sprintf("SetTaskResultInfo: invalid param value:%s", info.Stage), + ) + } // check bls sig flag, err := blst.VerifySignature(info.BlsSignature, taskResponseDigest, pubKey) if !flag || err != nil { @@ -322,3 +330,23 @@ func (k Keeper) GroupTasksByIDAndAddress(tasks []types.TaskResultInfo) map[strin } return taskMap } + +// SetTaskChallengedInfo is used to store the challenger's challenge information. +func (k *Keeper) SetTaskChallengedInfo( + ctx sdk.Context, taskID uint64, operatorAddress string, + taskAddr, challengeAddr common.Address, +) (err error) { + infoKey := assetstype.GetJoinedStoreKey(operatorAddress, taskAddr.String(), + strconv.FormatUint(taskID, 10)) + + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskChallengeResult) + store.Set(infoKey, challengeAddr.Bytes()) + return nil +} + +func (k *Keeper) IsExistTaskChallengedInfo(ctx sdk.Context, operatorAddress, taskContractAddress string, taskID uint64) bool { + infoKey := assetstype.GetJoinedStoreKey(operatorAddress, taskContractAddress, + strconv.FormatUint(taskID, 10)) + store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskChallengeResult) + return store.Has(infoKey) +} diff --git a/x/avs/keeper/task_test.go b/x/avs/keeper/task_test.go index ce878f19a..de4ff6c94 100644 --- a/x/avs/keeper/task_test.go +++ b/x/avs/keeper/task_test.go @@ -43,3 +43,8 @@ func (suite *AVSTestSuite) TestGetTaskId() { taskId = suite.App.AVSManagerKeeper.GetTaskID(suite.Ctx, addr) suite.Equal(uint64(2), taskId) } +func (suite *AVSTestSuite) TestTaskChallengedInfo() { + suite.TestEpochEnd_TaskCalculation() + suite.CommitAfter(suite.EpochDuration) + +} diff --git a/x/avs/types/errors.go b/x/avs/types/errors.go index 3408cd5fb..ed77853e4 100644 --- a/x/avs/types/errors.go +++ b/x/avs/types/errors.go @@ -54,7 +54,7 @@ var ( ) ErrAlreadyExists = errorsmod.Register( ModuleName, 13, - "The task already exists", + "The record already exists", ) ErrTaskIsNotExists = errorsmod.Register( ModuleName, 14, diff --git a/x/avs/types/keys.go b/x/avs/types/keys.go index 26ed01f00..4459e5586 100644 --- a/x/avs/types/keys.go +++ b/x/avs/types/keys.go @@ -26,6 +26,7 @@ const ( prefixAVSAddressToChainID LatestTaskNum TaskResult + TaskChallengeResult ) // ModuleAddress is the native module address for EVM @@ -40,6 +41,7 @@ var ( KeyPrefixAVSAddressToChainID = []byte{prefixAVSAddressToChainID} KeyPrefixLatestTaskNum = []byte{LatestTaskNum} KeyPrefixTaskResult = []byte{TaskResult} + KeyPrefixTaskChallengeResult = []byte{TaskChallengeResult} ) func init() {