diff --git a/app/ante/cosmos/fees.go b/app/ante/cosmos/fees.go index c53d9dcb8..05ce7cf36 100644 --- a/app/ante/cosmos/fees.go +++ b/app/ante/cosmos/fees.go @@ -184,8 +184,8 @@ func checkTxFeeWithValidatorMinGasPrices(ctx sdk.Context, feeTx sdk.FeeTx) (sdk. } } - priority := getTxPriority(feeCoins, int64(gas)) //#nosec G701 -- gosec warning about integer overflow is not relevant here - return feeCoins, priority, nil + priority := getTxPriority(feeCoins, gas) + return feeCoins, int64(priority), nil } // checkFeeCoinsAgainstMinGasPrices checks if the provided fee coins are greater than or equal to the @@ -200,7 +200,7 @@ func checkFeeCoinsAgainstMinGasPrices(ctx sdk.Context, feeCoins sdk.Coins, gas u // Determine the required fees by multiplying each required minimum gas // price by the gas limit, where fee = ceil(minGasPrice * gasLimit). - glDec := sdk.NewDec(int64(gas)) //#nosec G701 -- gosec warning about integer overflow is not relevant here + glDec := sdk.NewDec(int64(gas)) for i, gp := range minGasPrices { fee := gp.Amount.Mul(glDec) requiredFees[i] = sdk.NewCoin(gp.Denom, fee.Ceil().RoundInt()) @@ -217,13 +217,17 @@ func checkFeeCoinsAgainstMinGasPrices(ctx sdk.Context, feeCoins sdk.Coins, gas u // provided in a transaction. // NOTE: This implementation should be used with a great consideration as it opens potential attack vectors // where txs with multiple coins could not be prioritized as expected. -func getTxPriority(fees sdk.Coins, gas int64) int64 { - var priority int64 +// getTxPriority returns a naive tx priority based on the amount of the smallest denomination of the gas price +// provided in a transaction. +// NOTE: This implementation should be used with a great consideration as it opens potential attack vectors +// where txs with multiple coins could not be prioritized as expected. +func getTxPriority(fees sdk.Coins, gas uint64) uint64 { + var priority uint64 for _, c := range fees { - p := int64(math.MaxInt64) - gasPrice := c.Amount.QuoRaw(gas) - if gasPrice.IsInt64() { - p = gasPrice.Int64() + p := uint64(math.MaxUint64) + gasPrice := c.Amount.QuoRaw(int64(gas)) + if gasPrice.IsUint64() { + p = gasPrice.Uint64() } if priority == 0 || p < priority { priority = p diff --git a/go.mod b/go.mod index daaeac22d..b37a342da 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/armon/go-metrics v0.4.1 github.com/cometbft/cometbft v0.37.4 github.com/cometbft/cometbft-db v0.8.0 - github.com/cosmos/btcutil v1.0.5 github.com/cosmos/cosmos-proto v1.0.0-beta.3 github.com/cosmos/cosmos-sdk v0.47.8 github.com/cosmos/go-bip39 v1.0.0 @@ -92,6 +91,7 @@ require ( github.com/cockroachdb/redact v1.1.5 // indirect github.com/coinbase/rosetta-sdk-go/types v1.0.0 // indirect github.com/confio/ics23/go v0.9.0 // indirect + github.com/cosmos/btcutil v1.0.5 // indirect github.com/cosmos/gogogateway v1.2.0 // indirect github.com/cosmos/iavl v0.20.1 // indirect github.com/cosmos/ics23/go v0.10.0 // indirect diff --git a/precompiles/avs/abi.json b/precompiles/avs/abi.json index a41261e6b..8c057c3a8 100644 --- a/precompiles/avs/abi.json +++ b/precompiles/avs/abi.json @@ -23,7 +23,7 @@ { "indexed": false, "internalType": "bytes", - "name": "data", + "name": "hash", "type": "bytes" }, { @@ -43,6 +43,12 @@ "internalType": "uint64", "name": "thresholdPercentage", "type": "uint64" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "taskStatisticalPeriod", + "type": "uint64" } ], "name": "CreateTask", @@ -340,19 +346,48 @@ { "inputs": [ { - "internalType": "string", - "name": "name", - "type": "string" + "internalType": "bytes", + "name": "taskHash", + "type": "bytes" + }, + { + "internalType": "uint64", + "name": "taskID", + "type": "uint64" }, { "internalType": "bytes", - "name": "data", + "name": "taskResponseHash", "type": "bytes" }, { "internalType": "string", - "name": "taskId", + "name": "operatorAddress", "type": "string" + } + ], + "name": "challenge", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "bytes", + "name": "hash", + "type": "bytes" }, { "internalType": "uint64", @@ -368,6 +403,11 @@ "internalType": "uint64", "name": "thresholdPercentage", "type": "uint64" + }, + { + "internalType": "uint64", + "name": "taskStatisticalPeriod", + "type": "uint64" } ], "name": "createTask", diff --git a/precompiles/avs/avs.go b/precompiles/avs/avs.go index 5024752c0..03fe3b265 100644 --- a/precompiles/avs/avs.go +++ b/precompiles/avs/avs.go @@ -149,6 +149,12 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ ctx.Logger().Error("internal error when calling avs precompile", "module", "avs precompile", "method", method.Name, "err", err) bz, err = method.Outputs.Pack(common.Big0) } + case MethodChallenge: + bz, err = p.Challenge(ctx, evm.Origin, contract, stateDB, method, args) + if err != nil { + ctx.Logger().Error("internal error when calling avs precompile", "module", "avs precompile", "method", method.Name, "err", err) + bz, err = method.Outputs.Pack(false) + } } if err != nil { @@ -171,7 +177,7 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ func (Precompile) IsTransaction(methodID string) bool { switch methodID { case MethodRegisterAVS, MethodDeregisterAVS, MethodUpdateAVS, MethodRegisterOperatorToAVS, - MethodDeregisterOperatorFromAVS, MethodCreateAVSTask, MethodRegisterBLSPublicKey, MethodSubmitProof: + MethodDeregisterOperatorFromAVS, MethodCreateAVSTask, MethodRegisterBLSPublicKey, MethodSubmitProof, MethodChallenge: return true case MethodGetRegisteredPubkey, MethodGetOptinOperators, MethodGetAVSUSDValue, MethodGetOperatorOptedUSDValue: return false diff --git a/precompiles/avs/avs.sol b/precompiles/avs/avs.sol index 841d6eaec..6e66fc09c 100644 --- a/precompiles/avs/avs.sol +++ b/precompiles/avs/avs.sol @@ -102,6 +102,20 @@ interface IAVSManager { uint64 taskStatisticalPeriod ) external returns (bool success); + /// @dev challenge , this function enables a challenger to raise and resolve a challenge. + /// @param taskHash The data supplied by the contract, usually ABI-encoded. + /// @param taskID The id of task. + /// @param taskResponseHash The hash of task response. + /// @param operatorAddress operator address. + function challenge( + bytes calldata taskHash, + uint64 taskID, + bytes calldata taskResponseHash, + string memory operatorAddress + ) external returns (bool success); + + + /// @dev SubmitProof ,After processing the task contract, aggregate the signature and submit the processed proof /// @param taskId The task ID of the task. /// @param taskContractAddress The contract address of AVSTask. diff --git a/precompiles/avs/tx.go b/precompiles/avs/tx.go index 2a181fffb..207757df3 100644 --- a/precompiles/avs/tx.go +++ b/precompiles/avs/tx.go @@ -25,6 +25,7 @@ const ( MethodCreateAVSTask = "createTask" MethodSubmitProof = "submitProof" MethodRegisterBLSPublicKey = "registerBLSPublicKey" + MethodChallenge = "challenge" ) // AVSInfoRegister register the avs related information and change the state in avs keeper module. @@ -177,6 +178,53 @@ func (p Precompile) CreateAVSTask( return method.Outputs.Pack(true) } +// Challenge Middleware uses exocore's default avstask template to create tasks in avstask module. +func (p Precompile) Challenge( + ctx sdk.Context, + origin common.Address, + contract *vm.Contract, + _ vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + if len(args) != len(p.ABI.Methods[MethodChallenge].Inputs) { + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodChallenge].Inputs), len(args)) + } + challengeParams := &avskeeper.ChallengeParams{} + challengeParams.TaskContractAddress = contract.CallerAddress + challengeParams.CallerAddress = origin + + taskHash, ok := args[0].([]byte) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "[]byte", taskHash) + } + challengeParams.TaskHash = taskHash + + taskID, ok := args[1].(uint64) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "uint64", taskID) + } + challengeParams.TaskID = taskID + + taskResponseHash, ok := args[2].([]byte) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 2, "[]byte", taskResponseHash) + } + challengeParams.TaskResponseHash = taskResponseHash + + operatorAddress, ok := args[3].(string) + if !ok || operatorAddress == "" { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 3, "string", operatorAddress) + } + challengeParams.OperatorAddress = sdk.AccAddress(operatorAddress) + err := p.avsKeeper.RaiseAndResolveChallenge(ctx, challengeParams) + if err != nil { + return nil, err + } + + return method.Outputs.Pack(true) +} + // RegisterBLSPublicKey func (p Precompile) RegisterBLSPublicKey( ctx sdk.Context, diff --git a/x/assets/keeper/client_chain.go b/x/assets/keeper/client_chain.go index 4100fcbaa..d0e1255c6 100644 --- a/x/assets/keeper/client_chain.go +++ b/x/assets/keeper/client_chain.go @@ -71,11 +71,10 @@ func (k Keeper) GetAllClientChainInfo(ctx sdk.Context) (infos []assetstype.Clien return ret, nil } -func (k Keeper) GetAllClientChainID(ctx sdk.Context) ([]uint32, error) { - ret := make([]uint32, 0) +func (k Keeper) GetAllClientChainID(ctx sdk.Context) ([]uint64, error) { + ret := make([]uint64, 0) opFunc := func(clientChain *assetstype.ClientChainInfo) error { - // #nosec G701 // already checked - ret = append(ret, uint32(clientChain.LayerZeroChainID)) + ret = append(ret, clientChain.LayerZeroChainID) return nil } err := k.IterateAllClientChains(ctx, false, opFunc) diff --git a/x/avs/keeper/agg.go b/x/avs/keeper/agg.go deleted file mode 100644 index a958f578e..000000000 --- a/x/avs/keeper/agg.go +++ /dev/null @@ -1,51 +0,0 @@ -package keeper - -import ( - sdkmath "cosmossdk.io/math" - sdk "github.com/cosmos/cosmos-sdk/types" -) - -func (k *Keeper) CalculateActualThreshold(ctx sdk.Context, total sdkmath.LegacyDec, avs string) (t sdkmath.LegacyDec) { - usd, err := k.operatorKeeper.GetAVSUSDValue(ctx, avs) - if err != nil { - return sdkmath.LegacyZeroDec() - } - - if usd.IsZero() || total.IsZero() { - return sdkmath.LegacyZeroDec() - } - return total.Quo(usd).Mul(sdk.NewDec(100)) -} - -func Difference(a, b []string) []string { - var different []string //nolint:prealloc - - diffMap := make(map[string]bool) - - // Add all elements of a to the map - for _, item := range a { - diffMap[item] = true - } - - // Remove elements found in b from the map and collect differences - for _, item := range b { - if diffMap[item] { - delete(diffMap, item) - } else { - different = append(different, item) - } - } - - // Calculate the final size for the different slice - finalSize := len(different) + len(diffMap) - - // Pre-allocate the different slice with the final size - different = make([]string, 0, finalSize) - - // Add remaining elements from the map to different - for item := range diffMap { - different = append(different, item) - } - - return different -} diff --git a/x/avs/keeper/epoch_test.go b/x/avs/keeper/epoch_test.go index f7f1cde9f..2516eea52 100644 --- a/x/avs/keeper/epoch_test.go +++ b/x/avs/keeper/epoch_test.go @@ -2,7 +2,6 @@ package keeper_test import ( sdkmath "cosmossdk.io/math" - "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" operatortypes "github.com/ExocoreNetwork/exocore/x/operator/types" "github.com/ethereum/go-ethereum/common" @@ -51,7 +50,7 @@ func (suite *AVSTestSuite) TestEpochEnd_TaskCalculation() { SignedOperators: suite.operatorAddresses, ActualThreshold: 0, } - diff := keeper.Difference(expectInfo.SignedOperators, info.SignedOperators) + diff := avstypes.Difference(expectInfo.SignedOperators, info.SignedOperators) suite.Equal(0, len(diff)) suite.Equal(expectInfo.NoSignedOperators, info.NoSignedOperators) diff --git a/x/avs/keeper/impl_epoch_hook.go b/x/avs/keeper/impl_epoch_hook.go index d29a987d9..bbfeaa609 100644 --- a/x/avs/keeper/impl_epoch_hook.go +++ b/x/avs/keeper/impl_epoch_hook.go @@ -31,7 +31,6 @@ func (wrapper EpochsHooksWrapper) AfterEpochEnd( ) { // get all the task info bypass the epoch end // threshold calculation, signature verification, nosig quantity statistics - // todo: need to consider the calling order taskResList := wrapper.keeper.GetTaskStatisticalEpochEndAVSs(ctx, epochIdentifier, epochNumber) if len(taskResList) != 0 { @@ -78,7 +77,7 @@ func (wrapper EpochsHooksWrapper) AfterEpochEnd( // Handle the error gracefully, continue to the next continue } - diff := Difference(taskInfo.OptInOperators, signedOperatorList) + diff := types.Difference(taskInfo.OptInOperators, signedOperatorList) taskInfo.SignedOperators = signedOperatorList taskInfo.NoSignedOperators = diff taskInfo.OperatorActivePower = &types.OperatorActivePowerList{OperatorPowerList: operatorPowers} diff --git a/x/avs/keeper/miscellaneous_test.go b/x/avs/keeper/miscellaneous_test.go index 32a7fd0e9..2960a8014 100644 --- a/x/avs/keeper/miscellaneous_test.go +++ b/x/avs/keeper/miscellaneous_test.go @@ -3,7 +3,7 @@ package keeper_test import ( "fmt" utiltx "github.com/ExocoreNetwork/exocore/testutil/tx" - "github.com/ExocoreNetwork/exocore/x/avs/keeper" + "github.com/ExocoreNetwork/exocore/x/avs/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -48,7 +48,7 @@ func Test_difference(t *testing.T) { arr1 := []string{"apple", "banana", "cherry"} arr2 := []string{"apple", "cherry", "date"} - diff := keeper.Difference(arr1, arr2) + diff := types.Difference(arr1, arr2) fmt.Println("Differences:", diff) num1 := sdk.MustNewDecFromStr("1.3") num2 := sdk.MustNewDecFromStr("12.3") diff --git a/x/avs/types/types.go b/x/avs/types/types.go index 0691db064..6ed669bf5 100644 --- a/x/avs/types/types.go +++ b/x/avs/types/types.go @@ -122,3 +122,36 @@ func GetTaskResponseDigest(h TaskResponse) ([32]byte, error) { taskResponseDigest := crypto.Keccak256Hash(jsonData) return taskResponseDigest, nil } + +func Difference(a, b []string) []string { + var different []string //nolint:prealloc + + diffMap := make(map[string]bool) + + // Add all elements of a to the map + for _, item := range a { + diffMap[item] = true + } + + // Remove elements found in b from the map and collect differences + for _, item := range b { + if diffMap[item] { + delete(diffMap, item) + } else { + different = append(different, item) + } + } + + // Calculate the final size for the different slice + finalSize := len(different) + len(diffMap) + + // Pre-allocate the different slice with the final size + different = make([]string, 0, finalSize) + + // Add remaining elements from the map to different + for item := range diffMap { + different = append(different, item) + } + + return different +}