diff --git a/precompiles/avs/IAVSManager.sol b/precompiles/avs/IAVSManager.sol index 4e390481a..bc4209ca6 100644 --- a/precompiles/avs/IAVSManager.sol +++ b/precompiles/avs/IAVSManager.sol @@ -4,15 +4,43 @@ pragma solidity >=0.8.17; address constant AVSMANAGER_PRECOMPILE_ADDRESS = 0x0000000000000000000000000000000000000901; /// @dev The avs-manager contract's instance. -IAVSManager constant AVSMANAGER_CONTRACT = IAVSManager( - AVSMANAGER_PRECOMPILE_ADDRESS -); - +IAVSManager constant AVSMANAGER_CONTRACT = IAVSManager(AVSMANAGER_PRECOMPILE_ADDRESS); /// @author Exocore Team /// @title AVS-Manager Precompile Contract /// @dev The interface through which solidity contracts will interact with AVS-Manager /// @custom:address 0x0000000000000000000000000000000000000901 + interface IAVSManager { + // note:string and bytes will be hashed. address / uintX will not be hashed when using indexed. + event AVSRegistered(address indexed avsAddr, string sender, string avsName); + event AVSUpdated(address indexed avsAddr, string sender, string avsName); + event AVSDeregistered(address indexed avsAddr, string sender, string avsName); + event OperatorJoined(address indexed avsAddr, string sender); + event OperatorLeft(address indexed avsAddr, string sender); + event TaskCreated( + address indexed taskContractAddress, + uint64 indexed taskId, + string sender, + string name, + bytes hash, + uint64 taskResponsePeriod, + uint64 taskChallengePeriod, + uint64 thresholdPercentage, + uint64 taskStatisticalPeriod + ); + event ChallengeInitiated( + string sender, bytes taskHash, uint64 taskID, bytes taskResponseHash, string operatorAddress + ); + event PublicKeyRegistered(string sender, string name); + event TaskSubmittedByOperator( + address indexed taskContractAddress, + uint64 indexed taskId, + string sender, + bytes taskResponse, + bytes blsSignature, + uint8 phase + ); + /// @dev Register AVS contract to EXO. /// @param sender The external address for calling this method. /// @param avsName The name of AVS. @@ -78,23 +106,15 @@ interface IAVSManager { /// @dev Deregister avs from exo /// @param sender The external address for calling this method. /// @param avsName The name of AVS. - function deregisterAVS( - address sender, - string memory avsName - ) external returns (bool success); + function deregisterAVS(address sender, string memory avsName) external returns (bool success); /// @dev RegisterOperatorToAVS operator opt in current avs /// @param sender The external address for calling this method. - function registerOperatorToAVS( - address sender - ) external returns (bool success); + function registerOperatorToAVS(address sender) external returns (bool success); /// @dev DeregisterOperatorFromAVS operator opt out current avs /// @param sender The external address for calling this method. - function deregisterOperatorFromAVS( - address sender - ) external returns (bool success); - + function deregisterOperatorFromAVS(address sender) external returns (bool success); /// @dev CreateTask , avs owner create a new task /// @param sender The external address for calling this method. @@ -112,7 +132,7 @@ interface IAVSManager { uint64 taskChallengePeriod, uint64 thresholdPercentage, uint64 taskStatisticalPeriod - ) external returns (bool success); + ) external returns (uint64 taskID); /// @dev challenge , this function enables a challenger to raise and resolve a challenge. /// @param sender The external address for calling this method. @@ -128,7 +148,6 @@ interface IAVSManager { string memory operatorAddress ) external returns (bool success); - /// @dev Called by the avs manager service register an operator as the owner of a BLS public key. /// @param sender The external address for calling this method. /// @param name the name of public keys @@ -143,40 +162,65 @@ interface IAVSManager { bytes calldata pubkeyRegistrationMessageHash ) external returns (bool success); + /// @dev operatorSubmitTask , this function enables a operator submit a task result. + /// @param sender The external address for calling this method. + /// @param taskID The id of task. + /// @param taskResponse is the task response data.. + /// @param blsSignature is the operator bls sig info.. + /// @param taskContractAddress is contract address of task. + /// @param phase The phase of the Two-Phase Commit protocol: + /// 1 = Prepare phase (commit preparation) + /// 2 = Commit phase (final commitment) + function operatorSubmitTask( + address sender, + uint64 taskID, + bytes calldata taskResponse, + bytes calldata blsSignature, + address taskContractAddress, + uint8 phase + ) external returns (bool success); - + /// QUERIES /// @dev Returns the pubkey and pubkey hash of an operator /// @param operator is the operator for whom the key is being registered - function getRegisteredPubkey(string memory operator) external pure returns (bytes memory pubkey); + function getRegisteredPubkey(string memory operator) external view returns (bytes memory pubkey); /// @dev Returns the operators of all opt-in in the current avs /// @param avsAddress avs address - function getOptInOperators(address avsAddress) external returns (string[] memory operators); + function getOptInOperators(address avsAddress) external view returns (string[] memory operators); /// @dev getAVSUSDValue is a function to retrieve the USD share of specified Avs. /// @param avsAddr The address of the avs /// @return amount The total USD share of specified operator and Avs. - function getAVSUSDValue( - address avsAddr - ) external view returns (uint256 amount); + function getAVSUSDValue(address avsAddr) external view returns (uint256 amount); /// @dev getOperatorOptedUSDValue is a function to retrieve the USD share of specified operator and Avs. /// @param avsAddr The address of the avs /// @param operatorAddr The address of the operator /// @return amount The total USD share of specified operator and Avs. - function getOperatorOptedUSDValue( - address avsAddr, - string memory operatorAddr - ) external view returns (uint256 amount); + function getOperatorOptedUSDValue(address avsAddr, string memory operatorAddr) + external + view + returns (uint256 amount); - event TaskCreated( - uint64 taskId, - string taskContractAddress, - string name, - bytes hash, - uint64 taskResponsePeriod, - uint64 taskChallengePeriod, - uint64 thresholdPercentage, - uint64 taskStatisticalPeriod - ); - } + /// @dev getAVSEpochIdentifier returns the epoch identifier for the given AVS. + /// @param avsAddr The address of the avs + function getAVSEpochIdentifier(address avsAddr) external view returns (string memory epochIdentifier); + + /// @dev getTaskInfo is a function to query task info. + /// @param taskAddr The address of the avs task + /// @param taskID The id of task. + /// @return info Array containing task information in the following order: + /// [0] = startingEpochNumber + /// [1] = taskResponsePeriod + /// [2] = taskStatisticalPeriod + function getTaskInfo(address taskAddr, uint64 taskID) external view returns (uint64[] memory info); + + /// @dev isOperator checks if the given address is registered as an operator on exocore. + /// @param operatorAddr The address of the operator + function isOperator(address operatorAddr) external view returns (bool); + + /// @dev getCurrentEpoch obtain the specified current epoch based on epochIdentifier. + /// @param epochIdentifier is a descriptive or unique identifier for the epoch + function getCurrentEpoch(string memory epochIdentifier) external view returns (int64 currentEpoch); +} diff --git a/precompiles/avs/abi.json b/precompiles/avs/abi.json index ca475f27d..bdd6ed2dd 100644 --- a/precompiles/avs/abi.json +++ b/precompiles/avs/abi.json @@ -2,16 +2,191 @@ { "anonymous": false, "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "avsAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "avsName", + "type": "string" + } + ], + "name": "AVSDeregistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "avsAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "avsName", + "type": "string" + } + ], + "name": "AVSRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "avsAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "avsName", + "type": "string" + } + ], + "name": "AVSUpdated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "taskHash", + "type": "bytes" + }, { "indexed": false, "internalType": "uint64", - "name": "taskId", + "name": "taskID", "type": "uint64" }, + { + "indexed": false, + "internalType": "bytes", + "name": "taskResponseHash", + "type": "bytes" + }, { "indexed": false, "internalType": "string", + "name": "operatorAddress", + "type": "string" + } + ], + "name": "ChallengeInitiated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "avsAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + } + ], + "name": "OperatorJoined", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "avsAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + } + ], + "name": "OperatorLeft", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + }, + { + "indexed": false, + "internalType": "string", + "name": "name", + "type": "string" + } + ], + "name": "PublicKeyRegistered", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", "name": "taskContractAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint64", + "name": "taskId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "string", + "name": "sender", "type": "string" }, { @@ -54,6 +229,49 @@ "name": "TaskCreated", "type": "event" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "taskContractAddress", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint64", + "name": "taskId", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "string", + "name": "sender", + "type": "string" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "taskResponse", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "blsSignature", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "uint8", + "name": "phase", + "type": "uint8" + } + ], + "name": "TaskSubmittedByOperator", + "type": "event" + }, { "inputs": [ { @@ -134,9 +352,9 @@ "name": "createTask", "outputs": [ { - "internalType": "bool", - "name": "success", - "type": "bool" + "internalType": "uint64", + "name": "taskID", + "type": "uint64" } ], "stateMutability": "nonpayable", @@ -185,6 +403,25 @@ "stateMutability": "nonpayable", "type": "function" }, + { + "inputs": [ + { + "internalType": "address", + "name": "avsAddr", + "type": "address" + } + ], + "name": "getAVSEpochIdentifier", + "outputs": [ + { + "internalType": "string", + "name": "epochIdentifier", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -204,6 +441,25 @@ "stateMutability": "view", "type": "function" }, + { + "inputs": [ + { + "internalType": "string", + "name": "epochIdentifier", + "type": "string" + } + ], + "name": "getCurrentEpoch", + "outputs": [ + { + "internalType": "int64", + "name": "currentEpoch", + "type": "int64" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [ { @@ -244,7 +500,7 @@ "type": "string[]" } ], - "stateMutability": "nonpayable", + "stateMutability": "view", "type": "function" }, { @@ -263,7 +519,94 @@ "type": "bytes" } ], - "stateMutability": "pure", + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "taskAddr", + "type": "address" + }, + { + "internalType": "uint64", + "name": "taskID", + "type": "uint64" + } + ], + "name": "getTaskInfo", + "outputs": [ + { + "internalType": "uint64[]", + "name": "info", + "type": "uint64[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "operatorAddr", + "type": "address" + } + ], + "name": "isOperator", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint64", + "name": "taskID", + "type": "uint64" + }, + { + "internalType": "bytes", + "name": "taskResponse", + "type": "bytes" + }, + { + "internalType": "bytes", + "name": "blsSignature", + "type": "bytes" + }, + { + "internalType": "address", + "name": "taskContractAddress", + "type": "address" + }, + { + "internalType": "uint8", + "name": "phase", + "type": "uint8" + } + ], + "name": "operatorSubmitTask", + "outputs": [ + { + "internalType": "bool", + "name": "success", + "type": "bool" + } + ], + "stateMutability": "nonpayable", "type": "function" }, { @@ -398,45 +741,6 @@ "stateMutability": "nonpayable", "type": "function" }, - { - "inputs": [ - { - "internalType": "string", - "name": "taskId", - "type": "string" - }, - { - "internalType": "string", - "name": "taskContractAddress", - "type": "string" - }, - { - "internalType": "string", - "name": "aggregator", - "type": "string" - }, - { - "internalType": "string", - "name": "avsAddress", - "type": "string" - }, - { - "internalType": "bytes", - "name": "operatorStatus", - "type": "bytes" - } - ], - "name": "submitProof", - "outputs": [ - { - "internalType": "bool", - "name": "success", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, { "inputs": [ { diff --git a/precompiles/avs/avs.go b/precompiles/avs/avs.go index 5cb8cb83f..70a70e554 100644 --- a/precompiles/avs/avs.go +++ b/precompiles/avs/avs.go @@ -123,7 +123,7 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ bz, err = p.CreateAVSTask(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) + bz, err = method.Outputs.Pack(false, uint64(0)) } case MethodRegisterBLSPublicKey: bz, err = p.RegisterBLSPublicKey(ctx, evm.Origin, contract, stateDB, method, args) @@ -133,26 +133,67 @@ func (p Precompile) Run(evm *vm.EVM, contract *vm.Contract, readOnly bool) (bz [ } case MethodGetOptinOperators: bz, err = p.GetOptedInOperatorAccAddrs(ctx, contract, method, args) - case MethodGetRegisteredPubkey: - bz, err = p.GetRegisteredPubkey(ctx, contract, 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([]string{}) + } + case MethodGetAVSEpochIdentifier: + bz, err = p.GetAVSEpochIdentifier(ctx, contract, 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("") + } + case MethodGetTaskInfo: + bz, err = p.GetTaskInfo(ctx, contract, 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([]uint64{}) + } + case MethodIsOperator: + bz, err = p.IsOperator(ctx, contract, 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) + } + case MethodGetAVSUSDValue: bz, err = p.GetAVSUSDValue(ctx, contract, 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(common.Big0) } + + case MethodGetRegisteredPubkey: + bz, err = p.GetRegisteredPubkey(ctx, contract, 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([]byte{}) + } case MethodGetOperatorOptedUSDValue: bz, err = p.GetOperatorOptedUSDValue(ctx, contract, 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(common.Big0) } + case MethodGetCurrentEpoch: + bz, err = p.GetCurrentEpoch(ctx, contract, 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(int64(0)) + } 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) } + + case MethodOperatorSubmitTask: + bz, err = p.OperatorSubmitTask(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 { @@ -175,9 +216,10 @@ 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, MethodChallenge: + MethodDeregisterOperatorFromAVS, MethodCreateAVSTask, MethodRegisterBLSPublicKey, MethodChallenge, MethodOperatorSubmitTask: return true - case MethodGetRegisteredPubkey, MethodGetOptinOperators, MethodGetAVSUSDValue, MethodGetOperatorOptedUSDValue: + case MethodGetRegisteredPubkey, MethodGetOptinOperators, MethodGetAVSUSDValue, MethodGetOperatorOptedUSDValue, + MethodGetAVSEpochIdentifier, MethodGetTaskInfo, MethodIsOperator, MethodGetCurrentEpoch: return false default: return false diff --git a/precompiles/avs/avs_test.go b/precompiles/avs/avs_test.go index ca8b66f14..e634f59c3 100644 --- a/precompiles/avs/avs_test.go +++ b/precompiles/avs/avs_test.go @@ -3,9 +3,9 @@ package avs_test import ( "cosmossdk.io/math" assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" - avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper" "github.com/ExocoreNetwork/exocore/x/avs/types" "math/big" + "strconv" "time" sdkmath "cosmossdk.io/math" @@ -66,6 +66,16 @@ func (suite *AVSManagerPrecompileSuite) TestIsTransaction() { suite.precompile.Methods[avs.MethodRegisterBLSPublicKey].Name, true, }, + { + avs.MethodChallenge, + suite.precompile.Methods[avs.MethodChallenge].Name, + true, + }, + { + avs.MethodOperatorSubmitTask, + suite.precompile.Methods[avs.MethodOperatorSubmitTask].Name, + true, + }, } for _, tc := range testCases { @@ -76,7 +86,7 @@ func (suite *AVSManagerPrecompileSuite) TestIsTransaction() { } func (suite *AVSManagerPrecompileSuite) TestRegisterAVS() { - avsName, operatorAddress, slashAddress, rewardAddress := "avsTest", "exo18cggcpvwspnd5c6ny8wrqxpffj5zmhklprtnph", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" + avsName, slashAddress, rewardAddress := "avsTest", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" avsOwnerAddress := []string{ sdk.AccAddress(suite.Address.Bytes()).String(), sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), @@ -87,17 +97,6 @@ func (suite *AVSManagerPrecompileSuite) TestRegisterAVS() { avsUnbondingPeriod, minSelfDelegation := uint64(3), uint64(3) epochIdentifier := epochstypes.DayEpochID params := []uint64{2, 3, 4, 4} - - registerOperator := func() { - registerReq := &operatortypes.RegisterOperatorReq{ - FromAddress: operatorAddress, - Info: &operatortypes.OperatorInfo{ - EarningsAddr: operatorAddress, - }, - } - _, err := suite.OperatorMsgServer.RegisterOperator(sdk.WrapSDKContext(suite.Ctx), registerReq) - suite.NoError(err) - } commonMalleate := func() (common.Address, []byte) { input, err := suite.precompile.Pack( avs.MethodRegisterAVS, @@ -132,7 +131,6 @@ func (suite *AVSManagerPrecompileSuite) TestRegisterAVS() { { name: "pass for avs-registered", malleate: func() (common.Address, []byte) { - registerOperator() return commonMalleate() }, readOnly: false, @@ -193,7 +191,6 @@ func (suite *AVSManagerPrecompileSuite) TestRegisterAVS() { // Run precompiled contract bz, err := suite.precompile.Run(evm, contract, tc.readOnly) - // Check results if tc.expPass { suite.Require().NoError(err, "expected no error when running the precompile") @@ -210,18 +207,54 @@ func (suite *AVSManagerPrecompileSuite) TestRegisterAVS() { func (suite *AVSManagerPrecompileSuite) TestDeregisterAVS() { avsName := "avsTest" commonMalleate := func() (common.Address, []byte) { - // prepare the call input for delegation test + // prepare the call input for avs test input, err := suite.precompile.Pack( avs.MethodDeregisterAVS, suite.Address, avsName, ) suite.Require().NoError(err, "failed to pack input") - return common.HexToAddress("0x3e108c058e8066DA635321Dc3018294cA82ddEdf"), input + return suite.Address, input } successRet, err := suite.precompile.Methods[avs.MethodDeregisterAVS].Outputs.Pack(true) suite.Require().NoError(err) + setUp := func() { + slashAddress, rewardAddress := "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" + avsOwnerAddress := []string{ + sdk.AccAddress(suite.Address.Bytes()).String(), + sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + } + assetID := suite.AssetIDs + minStakeAmount, taskAddr := uint64(3), "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" + avsUnbondingPeriod, minSelfDelegation := uint64(3), uint64(3) + epochIdentifier := epochstypes.DayEpochID + params := []uint64{2, 3, 4, 4} + avs := &types.AVSInfo{ + Name: avsName, + AvsAddress: suite.Address.String(), + SlashAddr: slashAddress, + RewardAddr: rewardAddress, + AvsOwnerAddress: avsOwnerAddress, + AssetIDs: assetID, + AvsUnbondingPeriod: avsUnbondingPeriod, + MinSelfDelegation: minSelfDelegation, + EpochIdentifier: epochIdentifier, + StartingEpoch: 1, + TaskAddr: taskAddr, + MinStakeAmount: minStakeAmount, + MinOptInOperators: params[0], + MinTotalStakeAmount: params[1], + AvsReward: sdk.MustNewDecFromStr(strconv.Itoa(int(params[1]))), + AvsSlash: sdk.MustNewDecFromStr(strconv.Itoa(int(params[2]))), + } + err := suite.App.AVSManagerKeeper.SetAVSInfo(suite.Ctx, avs) + suite.NoError(err) + for i := 0; i < int(avsUnbondingPeriod)+2; i++ { + suite.CommitAfter(time.Hour*24 + time.Nanosecond) + } + } testcases := []struct { name string malleate func() (common.Address, []byte) @@ -233,7 +266,7 @@ func (suite *AVSManagerPrecompileSuite) TestDeregisterAVS() { { name: "pass for avs-deregister", malleate: func() (common.Address, []byte) { - suite.TestRegisterAVS() + setUp() return commonMalleate() }, readOnly: false, @@ -337,12 +370,34 @@ func (suite *AVSManagerPrecompileSuite) TestUpdateAVS() { params, ) suite.Require().NoError(err, "failed to pack input") - return common.HexToAddress("0x3e108c058e8066DA635321Dc3018294cA82ddEdf"), input + return suite.Address, input } successRet, err := suite.precompile.Methods[avs.MethodUpdateAVS].Outputs.Pack(true) suite.Require().NoError(err) + setUp := func() { + avs := &types.AVSInfo{ + Name: avsName, + AvsAddress: suite.Address.String(), + SlashAddr: slashAddress, + RewardAddr: rewardAddress, + AvsOwnerAddress: avsOwnerAddress, + AssetIDs: assetID, + AvsUnbondingPeriod: avsUnbondingPeriod, + MinSelfDelegation: minSelfDelegation, + EpochIdentifier: epochIdentifier, + StartingEpoch: 1, + TaskAddr: taskAddr, + MinStakeAmount: minStakeAmount, + MinOptInOperators: params[0], + MinTotalStakeAmount: params[1], + AvsReward: sdk.MustNewDecFromStr(strconv.Itoa(int(params[1]))), + AvsSlash: sdk.MustNewDecFromStr(strconv.Itoa(int(params[2]))), + } + err := suite.App.AVSManagerKeeper.SetAVSInfo(suite.Ctx, avs) + suite.NoError(err) + } testcases := []struct { name string malleate func() (common.Address, []byte) @@ -354,7 +409,7 @@ func (suite *AVSManagerPrecompileSuite) TestUpdateAVS() { { name: "pass for avs-update", malleate: func() (common.Address, []byte) { - suite.TestRegisterAVS() + setUp() return commonMalleate() }, readOnly: false, @@ -374,7 +429,7 @@ func (suite *AVSManagerPrecompileSuite) TestUpdateAVS() { contract := vm.NewPrecompile(vm.AccountRef(caller), suite.precompile, big.NewInt(0), uint64(1e6)) contract.Input = input - contractAddr := contract.Address() + contractAddr := suite.Address // Build and sign Ethereum transaction txArgs := evmtypes.EvmTxArgs{ ChainID: suite.App.EvmKeeper.ChainID(), @@ -432,6 +487,11 @@ func (suite *AVSManagerPrecompileSuite) TestUpdateAVS() { func (suite *AVSManagerPrecompileSuite) TestRegisterOperatorToAVS() { // from := s.Address operatorAddress := sdk.AccAddress(suite.Address.Bytes()) + assetID := suite.AssetIDs + minStakeAmount, taskAddr := uint64(3), "0x3e108c058e8066DA635321Dc3018294cA82ddEdf" + avsUnbondingPeriod, minSelfDelegation := uint64(3), uint64(3) + epochIdentifier := epochstypes.DayEpochID + params := []uint64{2, 3, 4, 4} registerOperator := func() { registerReq := &operatortypes.RegisterOperatorReq{ @@ -452,13 +512,43 @@ func (suite *AVSManagerPrecompileSuite) TestRegisterOperatorToAVS() { OperatorShare: math.LegacyNewDecFromBigInt(minPrecisionSelfDelegateAmount), }) } + avsName, slashAddress, rewardAddress := "avsTest", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" + avsOwnerAddress := []string{ + sdk.AccAddress(suite.Address.Bytes()).String(), + sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + } + + setUp := func() { + avs := &types.AVSInfo{ + Name: avsName, + AvsAddress: suite.Address.String(), + SlashAddr: slashAddress, + RewardAddr: rewardAddress, + AvsOwnerAddress: avsOwnerAddress, + AssetIDs: assetID, + AvsUnbondingPeriod: avsUnbondingPeriod, + MinSelfDelegation: minSelfDelegation, + EpochIdentifier: epochIdentifier, + StartingEpoch: 1, + TaskAddr: taskAddr, + MinStakeAmount: minStakeAmount, + MinOptInOperators: params[0], + MinTotalStakeAmount: params[1], + AvsReward: sdk.MustNewDecFromStr(strconv.Itoa(int(params[1]))), + AvsSlash: sdk.MustNewDecFromStr(strconv.Itoa(int(params[2]))), + } + + err := suite.App.AVSManagerKeeper.SetAVSInfo(suite.Ctx, avs) + suite.NoError(err) + } commonMalleate := func() (common.Address, []byte) { input, err := suite.precompile.Pack( avs.MethodRegisterOperatorToAVS, suite.Address, ) suite.Require().NoError(err, "failed to pack input") - return common.HexToAddress("0x3e108c058e8066DA635321Dc3018294cA82ddEdf"), input + return suite.Address, input } successRet, err := suite.precompile.Methods[avs.MethodRegisterAVS].Outputs.Pack(true) suite.Require().NoError(err) @@ -474,14 +564,14 @@ func (suite *AVSManagerPrecompileSuite) TestRegisterOperatorToAVS() { { name: "pass for operator opt-in avs", malleate: func() (common.Address, []byte) { - suite.TestRegisterAVS() registerOperator() + setUp() avsAddr, intput := commonMalleate() asset := suite.Assets[0] _, defaultAssetID := assetstypes.GetStakerIDAndAssetIDFromStr(asset.LayerZeroChainID, "", asset.Address) err = suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, &types.AVSRegisterOrDeregisterParams{ - Action: avskeeper.UpdateAction, - AvsAddress: avsAddr.String(), + Action: types.UpdateAction, + AvsAddress: avsAddr, AssetID: []string{defaultAssetID}, }) suite.NoError(err) @@ -560,13 +650,80 @@ func (suite *AVSManagerPrecompileSuite) TestRegisterOperatorToAVS() { } func (suite *AVSManagerPrecompileSuite) TestDeregisterOperatorFromAVS() { + + // from := s.Address + operatorAddress := sdk.AccAddress(suite.Address.Bytes()) + assetID := suite.AssetIDs + minStakeAmount, taskAddr := uint64(3), "0x3e108c058e8066DA635321Dc3018294cA82ddEdf" + avsUnbondingPeriod, minSelfDelegation := uint64(3), uint64(3) + epochIdentifier := epochstypes.DayEpochID + params := []uint64{2, 3, 4, 4} + + registerOperator := func() { + registerReq := &operatortypes.RegisterOperatorReq{ + FromAddress: operatorAddress.String(), + Info: &operatortypes.OperatorInfo{ + EarningsAddr: operatorAddress.String(), + }, + } + _, err := suite.OperatorMsgServer.RegisterOperator(sdk.WrapSDKContext(suite.Ctx), registerReq) + suite.NoError(err) + asset := suite.Assets[0] + _, assetID := assetstypes.GetStakerIDAndAssetIDFromStr(asset.LayerZeroChainID, "", asset.Address) + selfDelegateAmount := big.NewInt(10) + minPrecisionSelfDelegateAmount := big.NewInt(0).Mul(selfDelegateAmount, big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(asset.Decimals)), nil)) + err = suite.App.AssetsKeeper.UpdateOperatorAssetState(suite.Ctx, operatorAddress, assetID, assetstypes.DeltaOperatorSingleAsset{ + TotalAmount: math.NewIntFromBigInt(minPrecisionSelfDelegateAmount), + TotalShare: math.LegacyNewDecFromBigInt(minPrecisionSelfDelegateAmount), + OperatorShare: math.LegacyNewDecFromBigInt(minPrecisionSelfDelegateAmount), + }) + } + avsName, slashAddress, rewardAddress := "avsTest", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" + avsOwnerAddress := []string{ + sdk.AccAddress(suite.Address.Bytes()).String(), + sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String(), + } + + setUp := func() { + avs := &types.AVSInfo{ + Name: avsName, + AvsAddress: suite.Address.String(), + SlashAddr: slashAddress, + RewardAddr: rewardAddress, + AvsOwnerAddress: avsOwnerAddress, + AssetIDs: assetID, + AvsUnbondingPeriod: avsUnbondingPeriod, + MinSelfDelegation: minSelfDelegation, + EpochIdentifier: epochIdentifier, + StartingEpoch: 1, + TaskAddr: taskAddr, + MinStakeAmount: minStakeAmount, + MinOptInOperators: params[0], + MinTotalStakeAmount: params[1], + AvsReward: sdk.MustNewDecFromStr(strconv.Itoa(int(params[1]))), + AvsSlash: sdk.MustNewDecFromStr(strconv.Itoa(int(params[2]))), + } + + err := suite.App.AVSManagerKeeper.SetAVSInfo(suite.Ctx, avs) + suite.NoError(err) + } + optin := func() { + operatorParams := &types.OperatorOptParams{} + operatorParams.OperatorAddress = operatorAddress + operatorParams.AvsAddress = suite.Address + operatorParams.Action = types.RegisterAction + + err := suite.App.AVSManagerKeeper.OperatorOptAction(suite.Ctx, operatorParams) + suite.NoError(err) + } commonMalleate := func() (common.Address, []byte) { input, err := suite.precompile.Pack( avs.MethodDeregisterOperatorFromAVS, suite.Address, ) suite.Require().NoError(err, "failed to pack input") - return common.HexToAddress("0x3e108c058e8066DA635321Dc3018294cA82ddEdf"), input + return suite.Address, input } successRet, err := suite.precompile.Methods[avs.MethodDeregisterOperatorFromAVS].Outputs.Pack(true) suite.Require().NoError(err) @@ -582,8 +739,9 @@ func (suite *AVSManagerPrecompileSuite) TestDeregisterOperatorFromAVS() { { name: "pass for operator opt-out avs", malleate: func() (common.Address, []byte) { - suite.TestRegisterOperatorToAVS() - // registerOperator() + registerOperator() + setUp() + optin() return commonMalleate() }, readOnly: false, @@ -699,9 +857,7 @@ func (suite *AVSManagerPrecompileSuite) TestRunRegTaskInfo() { // updating the new voting power operatorKeeper.CalculateUSDValue(suite.delegationAmount, usdcPrice.Value, suite.assetDecimal, usdcPrice.Decimal) - suite.CommitAfter(time.Hour*1 + time.Nanosecond) - suite.CommitAfter(time.Hour*1 + time.Nanosecond) - suite.CommitAfter(time.Hour*1 + time.Nanosecond) + suite.CommitAfter(time.Hour*3 + time.Nanosecond) } commonMalleate := func() (common.Address, []byte) { input, err := suite.precompile.Pack( @@ -717,7 +873,7 @@ func (suite *AVSManagerPrecompileSuite) TestRunRegTaskInfo() { suite.Require().NoError(err, "failed to pack input") return suite.Address, input } - successRet, err := suite.precompile.Methods[avs.MethodCreateAVSTask].Outputs.Pack(true) + successRet, err := suite.precompile.Methods[avs.MethodCreateAVSTask].Outputs.Pack(uint64(1)) suite.Require().NoError(err) testcases := []struct { name string diff --git a/precompiles/avs/events.go b/precompiles/avs/events.go index ff26f0fe2..0bf1a5234 100644 --- a/precompiles/avs/events.go +++ b/precompiles/avs/events.go @@ -1,7 +1,10 @@ package avs import ( - avskeep "github.com/ExocoreNetwork/exocore/x/avs/keeper" + "github.com/ethereum/go-ethereum/accounts/abi" + cmn "github.com/evmos/evmos/v16/precompiles/common" + + avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" @@ -9,25 +12,216 @@ import ( ) const ( - // EventTypeRegisterAVSTask defines the event type for the avs CreateAVSTask transaction. - EventTypeRegisterAVSTask = "TaskCreated" + EventTypeAVSRegistered = "AVSRegistered" + EventTypeAVSUpdated = "AVSUpdated" + EventTypeAVSDeregistered = "AVSDeregistered" + EventTypeOperatorJoined = "OperatorJoined" + EventTypeOperatorLeft = "OperatorLeft" + EventTypeTaskCreated = "TaskCreated" + EventTypeChallengeInitiated = "ChallengeInitiated" + EventTypePublicKeyRegistered = "PublicKeyRegistered" + EventTypeTaskSubmittedByOperator = "TaskSubmittedByOperator" ) -// EmitCreateAVSTaskEvent creates a new event emitted on a EmitCreateAVSTaskEvent transaction. -func (p Precompile) EmitCreateAVSTaskEvent(ctx sdk.Context, stateDB vm.StateDB, task *avskeep.TaskInfoParams) error { - // Prepare the event topics - event := p.ABI.Events[EventTypeRegisterAVSTask] +func (p Precompile) emitEvent(ctx sdk.Context, stateDB vm.StateDB, eventName string, inputArgs abi.Arguments, args ...interface{}) error { + event := p.ABI.Events[eventName] + topics := []common.Hash{event.ID} + + packed, err := inputArgs.Pack(args...) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), + }) + + return nil +} + +// EmitAVSRegistered emits an Ethereum event when an AVS (Autonomous Verification Service) is registered. +// +// Parameters: +// - ctx: The SDK context containing information about the current state of the blockchain. +// - stateDB: The Ethereum state database where the event will be stored. +// - avs: A pointer to the AVSRegisterOrDeregisterParams struct containing the details of the AVS registration. +// +// Returns: +// - An error if there is an issue packing the event data or adding the log to the state database. +// - nil if the event is successfully emitted. +func (p Precompile) EmitAVSRegistered(ctx sdk.Context, stateDB vm.StateDB, avs *avstypes.AVSRegisterOrDeregisterParams) error { + event := p.ABI.Events[EventTypeAVSRegistered] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(avs.AvsAddress) + if err != nil { + return err + } + + // Prepare the event data: sender, avsName + arguments := abi.Arguments{event.Inputs[1], event.Inputs[2]} + packed, err := arguments.Pack(avs.CallerAddress.String(), avs.AvsName) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), + }) + return nil +} + +func (p Precompile) EmitAVSUpdated(ctx sdk.Context, stateDB vm.StateDB, avs *avstypes.AVSRegisterOrDeregisterParams) error { + event := p.ABI.Events[EventTypeAVSUpdated] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(avs.AvsAddress) + if err != nil { + return err + } + + // Prepare the event data: sender, avsName + arguments := abi.Arguments{event.Inputs[1], event.Inputs[2]} + packed, err := arguments.Pack(avs.CallerAddress.String(), avs.AvsName) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), + }) + return nil +} + +func (p Precompile) EmitAVSDeregistered(ctx sdk.Context, stateDB vm.StateDB, avs *avstypes.AVSRegisterOrDeregisterParams) error { + event := p.ABI.Events[EventTypeAVSDeregistered] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(avs.AvsAddress) + if err != nil { + return err + } + + // Prepare the event data: sender, avsName + arguments := abi.Arguments{event.Inputs[1], event.Inputs[2]} + packed, err := arguments.Pack(avs.CallerAddress.String(), avs.AvsName) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), + }) + return nil +} + +func (p Precompile) EmitOperatorJoined(ctx sdk.Context, stateDB vm.StateDB, params *avstypes.OperatorOptParams) error { + event := p.ABI.Events[EventTypeOperatorJoined] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(params.AvsAddress) + if err != nil { + return err + } + + // Prepare the event data: operatorAddress + arguments := abi.Arguments{event.Inputs[1]} + packed, err := arguments.Pack(params.OperatorAddress.String()) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), + }) + return nil +} + +func (p Precompile) EmitOperatorOuted(ctx sdk.Context, stateDB vm.StateDB, params *avstypes.OperatorOptParams) error { + event := p.ABI.Events[EventTypeOperatorLeft] + topics := make([]common.Hash, 2) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(params.AvsAddress) + if err != nil { + return err + } + + // Prepare the event data: operatorAddress + arguments := abi.Arguments{event.Inputs[1]} + packed, err := arguments.Pack(params.OperatorAddress.String()) + if err != nil { + return err + } + + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), + }) + return nil +} - topics := make([]common.Hash, 1) +func (p Precompile) EmitTaskCreated(ctx sdk.Context, stateDB vm.StateDB, task *avstypes.TaskInfoParams) error { + event := p.ABI.Events[EventTypeTaskCreated] + topics := make([]common.Hash, 3) // The first topic is always the signature of the event. topics[0] = event.ID var err error + topics[1], err = cmn.MakeTopic(task.TaskContractAddress) + if err != nil { + return err + } - // Pack the arguments to be used as the Data field - arguments := event.Inputs[0:8] - packed, err := arguments.Pack(task.TaskID, task.TaskContractAddress, task.TaskName, task.Hash, task.TaskResponsePeriod, task.TaskChallengePeriod, task.ThresholdPercentage, task.TaskStatisticalPeriod) + topics[2], err = cmn.MakeTopic(task.TaskID) + if err != nil { + return err + } + // Prepare the event data:sender,name, hash, taskResponsePeriod,taskChallengePeriod, + // thresholdPercentage,taskStatisticalPeriod + arguments := abi.Arguments{ + event.Inputs[2], event.Inputs[3], event.Inputs[4], + event.Inputs[5], event.Inputs[6], event.Inputs[7], event.Inputs[8], + } + packed, err := arguments.Pack(task.CallerAddress.String(), task.TaskName, task.Hash, task.TaskResponsePeriod, task.TaskChallengePeriod, + task.ThresholdPercentage, task.TaskStatisticalPeriod) if err != nil { return err } @@ -38,6 +232,55 @@ func (p Precompile) EmitCreateAVSTaskEvent(ctx sdk.Context, stateDB vm.StateDB, Data: packed, BlockNumber: uint64(ctx.BlockHeight()), }) + return nil +} + +func (p Precompile) EmitChallengeInitiated(ctx sdk.Context, stateDB vm.StateDB, params *avstypes.ChallengeParams) error { + arguments := p.ABI.Events[EventTypeChallengeInitiated].Inputs + return p.emitEvent(ctx, stateDB, EventTypeChallengeInitiated, arguments, + params.CallerAddress.String(), + params.TaskHash, + params.TaskID, + params.TaskResponseHash, + params.OperatorAddress.String()) +} + +func (p Precompile) EmitPublicKeyRegistered(ctx sdk.Context, stateDB vm.StateDB, params *avstypes.BlsParams) error { + arguments := p.ABI.Events[EventTypePublicKeyRegistered].Inputs + return p.emitEvent(ctx, stateDB, EventTypePublicKeyRegistered, arguments, + params.OperatorAddress.String(), + params.Name) +} + +func (p Precompile) EmitTaskSubmittedByOperator(ctx sdk.Context, stateDB vm.StateDB, params *avstypes.TaskResultParams) error { + event := p.ABI.Events[EventTypeTaskSubmittedByOperator] + topics := make([]common.Hash, 3) + + // The first topic is always the signature of the event. + topics[0] = event.ID + + var err error + topics[1], err = cmn.MakeTopic(params.TaskContractAddress) + if err != nil { + return err + } + + topics[2], err = cmn.MakeTopic(params.TaskID) + if err != nil { + return err + } + // Prepare the event data:sender,TaskResponse, BlsSignature, Phase + arguments := abi.Arguments{event.Inputs[2], event.Inputs[3], event.Inputs[4], event.Inputs[5]} + packed, err := arguments.Pack(params.CallerAddress.String(), params.TaskResponse, params.BlsSignature, uint8(params.Phase)) + if err != nil { + return err + } + stateDB.AddLog(ðtypes.Log{ + Address: p.Address(), + Topics: topics, + Data: packed, + BlockNumber: uint64(ctx.BlockHeight()), + }) return nil } diff --git a/precompiles/avs/query.go b/precompiles/avs/query.go index 72cea06eb..00cb46213 100644 --- a/precompiles/avs/query.go +++ b/precompiles/avs/query.go @@ -1,9 +1,15 @@ package avs import ( + "errors" "fmt" + "strconv" + "strings" + + errorsmod "cosmossdk.io/errors" exocmn "github.com/ExocoreNetwork/exocore/precompiles/common" + avstype "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" @@ -16,6 +22,11 @@ const ( MethodGetOptinOperators = "getOptInOperators" MethodGetAVSUSDValue = "getAVSUSDValue" MethodGetOperatorOptedUSDValue = "getOperatorOptedUSDValue" + + MethodGetAVSEpochIdentifier = "getAVSEpochIdentifier" + MethodGetTaskInfo = "getTaskInfo" + MethodIsOperator = "isOperator" + MethodGetCurrentEpoch = "getCurrentEpoch" ) func (p Precompile) GetRegisteredPubkey( @@ -27,16 +38,18 @@ func (p Precompile) GetRegisteredPubkey( if len(args) != len(p.ABI.Methods[MethodGetRegisteredPubkey].Inputs) { return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodGetRegisteredPubkey].Inputs), len(args)) } - // the key is set using the operator's acc address so the same logic should apply here addr, ok := args[0].(string) if !ok { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "string", addr) } - blsPubkeyInfo, err := p.avsKeeper.GetOperatorPubKey(ctx, addr) + blsPubKeyInfo, err := p.avsKeeper.GetOperatorPubKey(ctx, addr) if err != nil { + if errors.Is(err, avstype.ErrNoKeyInTheStore) { + return method.Outputs.Pack([]byte{}) + } return nil, err } - return method.Outputs.Pack(blsPubkeyInfo.PubKey) + return method.Outputs.Pack(blsPubKeyInfo.PubKey) } func (p Precompile) GetOptedInOperatorAccAddrs( @@ -54,7 +67,7 @@ func (p Precompile) GetOptedInOperatorAccAddrs( return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "string", addr) } - list, err := p.avsKeeper.GetOptInOperators(ctx, addr.String()) + list, err := p.avsKeeper.GetOperatorKeeper().GetOptedInOperatorListByAVS(ctx, strings.ToLower(addr.String())) if err != nil { return nil, err } @@ -69,7 +82,7 @@ func (p Precompile) GetAVSUSDValue( args []interface{}, ) ([]byte, error) { if len(args) != len(p.ABI.Methods[MethodGetAVSUSDValue].Inputs) { - return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodRegisterAVS].Inputs), len(args)) + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodGetAVSUSDValue].Inputs), len(args)) } addr, ok := args[0].(common.Address) if !ok { @@ -77,6 +90,9 @@ func (p Precompile) GetAVSUSDValue( } amount, err := p.avsKeeper.GetOperatorKeeper().GetAVSUSDValue(ctx, addr.String()) if err != nil { + if errors.Is(err, avstype.ErrNoKeyInTheStore) { + return method.Outputs.Pack(common.Big0) + } return nil, err } return method.Outputs.Pack(amount.BigInt()) @@ -90,7 +106,7 @@ func (p Precompile) GetOperatorOptedUSDValue( args []interface{}, ) ([]byte, error) { if len(args) != len(p.ABI.Methods[MethodGetOperatorOptedUSDValue].Inputs) { - return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodRegisterAVS].Inputs), len(args)) + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodGetOperatorOptedUSDValue].Inputs), len(args)) } avsAddr, ok := args[0].(common.Address) if !ok { @@ -100,9 +116,110 @@ func (p Precompile) GetOperatorOptedUSDValue( if !ok { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "string", operatorAddr) } - amount, err := p.avsKeeper.GetOperatorKeeper().GetOperatorOptedUSDValue(ctx, avsAddr.String(), operatorAddr) + amount, err := p.avsKeeper.GetOperatorKeeper().GetOperatorOptedUSDValue(ctx, strings.ToLower(avsAddr.String()), operatorAddr) if err != nil { + if errors.Is(err, avstype.ErrNoKeyInTheStore) { + return method.Outputs.Pack(common.Big0) + } return nil, err } return method.Outputs.Pack(amount.ActiveUSDValue.BigInt()) } + +func (p Precompile) GetAVSEpochIdentifier( + ctx sdk.Context, + _ *vm.Contract, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + if len(args) != len(p.ABI.Methods[MethodGetAVSEpochIdentifier].Inputs) { + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodGetAVSEpochIdentifier].Inputs), len(args)) + } + addr, ok := args[0].(common.Address) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", addr) + } + + avs, err := p.avsKeeper.GetAVSInfo(ctx, addr.String()) + if err != nil { + // if the avs does not exist, return empty array + if errors.Is(err, avstype.ErrNoKeyInTheStore) { + return method.Outputs.Pack("") + } + return nil, err + } + + return method.Outputs.Pack(avs.GetInfo().EpochIdentifier) +} + +func (p Precompile) IsOperator( + ctx sdk.Context, + _ *vm.Contract, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + if len(args) != len(p.ABI.Methods[MethodIsOperator].Inputs) { + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodIsOperator].Inputs), len(args)) + } + operatorAddr, ok := args[0].(common.Address) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", operatorAddr) + } + + param := operatorAddr[:] + flag := p.avsKeeper.GetOperatorKeeper().IsOperator(ctx, param) + + return method.Outputs.Pack(flag) +} + +func (p Precompile) GetTaskInfo( + ctx sdk.Context, + _ *vm.Contract, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + if len(args) != len(p.ABI.Methods[MethodGetTaskInfo].Inputs) { + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodGetTaskInfo].Inputs), len(args)) + } + addr, ok := args[0].(common.Address) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", addr) + } + taskID, ok := args[1].(uint64) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "uint64", taskID) + } + + task, err := p.avsKeeper.GetTaskInfo(ctx, strconv.FormatUint(taskID, 10), addr.String()) + if err != nil { + // if the avs does not exist, return empty array + if errors.Is(err, avstype.ErrNoKeyInTheStore) { + return method.Outputs.Pack("") + } + return nil, err + } + info := []uint64{task.StartingEpoch, task.TaskResponsePeriod, task.TaskStatisticalPeriod} + + return method.Outputs.Pack(info) +} + +// GetCurrentEpoch obtain the specified current epoch based on epochIdentifier. +func (p Precompile) GetCurrentEpoch( + ctx sdk.Context, + _ *vm.Contract, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + if len(args) != len(p.ABI.Methods[MethodGetCurrentEpoch].Inputs) { + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodGetCurrentEpoch].Inputs), len(args)) + } + epochIdentifier, ok := args[0].(string) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "string", epochIdentifier) + } + epoch, flag := p.avsKeeper.GetEpochKeeper().GetEpochInfo(ctx, epochIdentifier) + if !flag { + return nil, errorsmod.Wrap(avstype.ErrNoKeyInTheStore, fmt.Sprintf("GetCurrentEpoch: epochIdentifier is %s", epochIdentifier)) + } + return method.Outputs.Pack(epoch.CurrentEpoch) +} diff --git a/precompiles/avs/query_test.go b/precompiles/avs/query_test.go index e15725289..4cf9206db 100644 --- a/precompiles/avs/query_test.go +++ b/precompiles/avs/query_test.go @@ -2,6 +2,9 @@ package avs_test import ( "fmt" + epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/prysmaticlabs/prysm/v4/crypto/bls/blst" "math/big" "time" @@ -12,8 +15,10 @@ import ( avsManagerPrecompile "github.com/ExocoreNetwork/exocore/precompiles/avs" exocmn "github.com/ExocoreNetwork/exocore/precompiles/common" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" + avstype "github.com/ExocoreNetwork/exocore/x/avs/types" operatorKeeper "github.com/ExocoreNetwork/exocore/x/operator/keeper" "github.com/ExocoreNetwork/exocore/x/operator/types" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/vm" @@ -313,3 +318,279 @@ func (suite *AVSManagerPrecompileSuite) TestGetOperatorOptedUSDValue() { }) } } + +func (suite *AVSManagerPrecompileSuite) TestGetRegisteredPubkey() { + method := suite.precompile.Methods[avsManagerPrecompile.MethodGetRegisteredPubkey] + privateKey, err := blst.RandKey() + suite.NoError(err) + operatorAddr := "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr" + + publicKey := privateKey.PublicKey() + setUp := func() { + suite.prepareOperator() + + blsPub := &avstype.BlsPubKeyInfo{ + Operator: operatorAddr, + PubKey: publicKey.Marshal(), + Name: "", + } + err = suite.App.AVSManagerKeeper.SetOperatorPubKey(suite.Ctx, blsPub) + suite.NoError(err) + } + testCases := []avsTestCases{ + { + "success - existent pubKey", + func() []interface{} { + setUp() + return []interface{}{ + operatorAddr, + } + }, + func(bz []byte) { + var out []byte + err := suite.precompile.UnpackIntoInterface(&out, avsManagerPrecompile.MethodGetRegisteredPubkey, bz) + suite.Require().NoError(err, "failed to unpack output", err) + suite.Require().Equal(48, len(out)) + suite.Require().Equal(publicKey.Marshal(), out) + }, + 100000, + false, + "", + }, + } + testCases = append(testCases, baseTestCases[0]) + + for _, tc := range testCases { + suite.Run(tc.name, func() { + contract := vm.NewContract(vm.AccountRef(suite.Address), suite.precompile, big.NewInt(0), tc.gas) + + bz, err := suite.precompile.GetRegisteredPubkey(suite.Ctx, contract, &method, tc.malleate()) + + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.errContains) + } else { + suite.Require().NoError(err) + suite.Require().NotEmpty(bz) + tc.postCheck(bz) + } + }) + } +} + +func (suite *AVSManagerPrecompileSuite) TestGetAVSInfo() { + method := suite.precompile.Methods[avsManagerPrecompile.MethodGetAVSEpochIdentifier] + avsAddress := "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + testAVSUnbondingPeriod := 7 + testMinSelfDelegation := 10 + testMinOptInOperators := 100 + testMinTotalStakeAmount := 1000 + testStartingEpoch := 1 + setUp := func() { + avsName := "avsTest" + avsOwnerAddress := []string{"exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj1", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj2"} + assetID := suite.AssetIDs + avs := &avstype.AVSInfo{ + Name: avsName, + AvsAddress: avsAddress, + SlashAddr: utiltx.GenerateAddress().String(), + AvsOwnerAddress: avsOwnerAddress, + AssetIDs: assetID, + AvsUnbondingPeriod: uint64(testAVSUnbondingPeriod), + MinSelfDelegation: uint64(testMinSelfDelegation), + EpochIdentifier: epochstypes.DayEpochID, + StartingEpoch: uint64(testStartingEpoch), + MinOptInOperators: uint64(testMinOptInOperators), + MinTotalStakeAmount: uint64(testMinTotalStakeAmount), + AvsSlash: sdk.MustNewDecFromStr("0.001"), + AvsReward: sdk.MustNewDecFromStr("0.002"), + TaskAddr: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + } + + err := suite.App.AVSManagerKeeper.SetAVSInfo(suite.Ctx, avs) + suite.NoError(err) + } + testCases := []avsTestCases{ + { + "success - existent avs", + func() []interface{} { + setUp() + return []interface{}{ + common.HexToAddress(avsAddress), + } + }, + func(bz []byte) { + var out string + + err := suite.precompile.UnpackIntoInterface(&out, avsManagerPrecompile.MethodGetAVSEpochIdentifier, bz) + suite.Require().NoError(err, "failed to unpack output", err) + suite.Require().Equal(epochstypes.DayEpochID, out) + }, + 100000, + false, + "", + }, + } + testCases = append(testCases, baseTestCases[0]) + + for _, tc := range testCases { + suite.Run(tc.name, func() { + contract := vm.NewContract(vm.AccountRef(suite.Address), suite.precompile, big.NewInt(0), tc.gas) + + bz, err := suite.precompile.GetAVSEpochIdentifier(suite.Ctx, contract, &method, tc.malleate()) + + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.errContains) + } else { + suite.Require().NoError(err) + suite.Require().NotEmpty(bz) + tc.postCheck(bz) + } + }) + } +} + +func (suite *AVSManagerPrecompileSuite) TestIsoperator() { + method := suite.precompile.Methods[avsManagerPrecompile.MethodIsOperator] + opAccAddr, _ := sdk.AccAddressFromBech32("exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr") + + testCases := []avsTestCases{ + { + "success - existent operator", + func() []interface{} { + suite.prepareOperator() + return []interface{}{ + common.BytesToAddress(opAccAddr), + } + }, + func(bz []byte) { + var out bool + err := suite.precompile.UnpackIntoInterface(&out, avsManagerPrecompile.MethodIsOperator, bz) + suite.Require().NoError(err, "failed to unpack output", err) + suite.Require().Equal(true, out) + }, + 100000, + false, + "", + }, + } + testCases = append(testCases, baseTestCases[0]) + + for _, tc := range testCases { + suite.Run(tc.name, func() { + contract := vm.NewContract(vm.AccountRef(suite.Address), suite.precompile, big.NewInt(0), tc.gas) + + bz, err := suite.precompile.IsOperator(suite.Ctx, contract, &method, tc.malleate()) + + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.errContains) + } else { + suite.Require().NoError(err) + suite.Require().NotEmpty(bz) + tc.postCheck(bz) + } + }) + } +} +func (suite *AVSManagerPrecompileSuite) TestGetTaskInfo() { + method := suite.precompile.Methods[avsManagerPrecompile.MethodGetTaskInfo] + taskAddress := "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" + + setUp := func() { + info := &avstype.TaskInfo{ + TaskContractAddress: taskAddress, + Name: "test-avstask-01", + TaskId: uint64(3), + Hash: []byte("active"), + TaskResponsePeriod: 10, + StartingEpoch: 5, + TaskStatisticalPeriod: 60, + TaskTotalPower: sdk.Dec(sdkmath.NewInt(0)), + } + err := suite.App.AVSManagerKeeper.SetTaskInfo(suite.Ctx, info) + suite.NoError(err) + } + testCases := []avsTestCases{ + { + "success - existent task", + func() []interface{} { + setUp() + return []interface{}{ + common.HexToAddress(taskAddress), + uint64(3), + } + }, + func(bz []byte) { + var out []uint64 + + err := suite.precompile.UnpackIntoInterface(&out, avsManagerPrecompile.MethodGetTaskInfo, bz) + suite.Require().NoError(err, "failed to unpack output", err) + suite.Require().Equal([]uint64{5, 10, 60}, out) + }, + 100000, + false, + "", + }, + } + testCases = append(testCases, baseTestCases[0]) + + for _, tc := range testCases { + suite.Run(tc.name, func() { + contract := vm.NewContract(vm.AccountRef(suite.Address), suite.precompile, big.NewInt(0), tc.gas) + + bz, err := suite.precompile.GetTaskInfo(suite.Ctx, contract, &method, tc.malleate()) + + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.errContains) + } else { + suite.Require().NoError(err) + suite.Require().NotEmpty(bz) + tc.postCheck(bz) + } + }) + } +} +func (suite *AVSManagerPrecompileSuite) TestGetCurrentEpoch() { + method := suite.precompile.Methods[avsManagerPrecompile.MethodGetCurrentEpoch] + testCases := []avsTestCases{ + { + "success - existent avs", + func() []interface{} { + return []interface{}{ + epochstypes.DayEpochID, + } + }, + func(bz []byte) { + var out int64 + + err := suite.precompile.UnpackIntoInterface(&out, avsManagerPrecompile.MethodGetCurrentEpoch, bz) + suite.Require().NoError(err, "failed to unpack output", err) + suite.Require().Equal(int64(1), out) + }, + 100000, + false, + "", + }, + } + testCases = append(testCases, baseTestCases[0]) + + for _, tc := range testCases { + suite.Run(tc.name, func() { + contract := vm.NewContract(vm.AccountRef(suite.Address), suite.precompile, big.NewInt(0), tc.gas) + + bz, err := suite.precompile.GetCurrentEpoch(suite.Ctx, contract, &method, tc.malleate()) + + if tc.expErr { + suite.Require().Error(err) + suite.Require().Contains(err.Error(), tc.errContains) + } else { + suite.Require().NoError(err) + suite.Require().NotEmpty(bz) + tc.postCheck(bz) + } + }) + } +} diff --git a/precompiles/avs/tx.go b/precompiles/avs/tx.go index a5d4b663c..4929fed78 100644 --- a/precompiles/avs/tx.go +++ b/precompiles/avs/tx.go @@ -8,7 +8,6 @@ import ( errorsmod "cosmossdk.io/errors" exocmn "github.com/ExocoreNetwork/exocore/precompiles/common" - avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/accounts/abi" @@ -26,14 +25,15 @@ const ( MethodCreateAVSTask = "createTask" MethodRegisterBLSPublicKey = "registerBLSPublicKey" MethodChallenge = "challenge" + MethodOperatorSubmitTask = "operatorSubmitTask" ) -// AVSInfoRegister register the avs related information and change the state in avs keeper module. +// RegisterAVS AVSInfoRegister register the avs related information and change the state in avs keeper module. func (p Precompile) RegisterAVS( ctx sdk.Context, _ common.Address, contract *vm.Contract, - _ vm.StateDB, + stateDB vm.StateDB, method *abi.Method, args []interface{}, ) ([]byte, error) { @@ -43,19 +43,21 @@ func (p Precompile) RegisterAVS( return nil, errorsmod.Wrap(err, "parse args error") } // verification of the calling address to ensure it is avs contract owner - if !slices.Contains(avsParams.AvsOwnerAddress, avsParams.CallerAddress) { + if !slices.Contains(avsParams.AvsOwnerAddress, avsParams.CallerAddress.String()) { return nil, errorsmod.Wrap(err, "not qualified to registerOrDeregister") } // The AVS registration is done by the calling contract. - avsParams.AvsAddress = contract.CallerAddress.String() - avsParams.Action = avskeeper.RegisterAction + avsParams.AvsAddress = contract.CallerAddress + avsParams.Action = avstypes.RegisterAction // Finally, update the AVS information in the keeper. err = p.avsKeeper.UpdateAVSInfo(ctx, avsParams) if err != nil { fmt.Println("Failed to update AVS info", err) return nil, err } - + if err = p.EmitAVSRegistered(ctx, stateDB, avsParams); err != nil { + return nil, err + } return method.Outputs.Pack(true) } @@ -63,7 +65,7 @@ func (p Precompile) DeregisterAVS( ctx sdk.Context, _ common.Address, contract *vm.Contract, - _ vm.StateDB, + stateDB vm.StateDB, method *abi.Method, args []interface{}, ) ([]byte, error) { @@ -75,21 +77,24 @@ func (p Precompile) DeregisterAVS( if !ok || (callerAddress == common.Address{}) { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - avsParams.CallerAddress = sdk.AccAddress(callerAddress[:]).String() + avsParams.CallerAddress = callerAddress[:] avsName, ok := args[1].(string) if !ok || avsName == "" { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "string", avsName) } avsParams.AvsName = avsName - avsParams.AvsAddress = contract.CallerAddress.String() - avsParams.Action = avskeeper.DeRegisterAction + avsParams.AvsAddress = contract.CallerAddress + avsParams.Action = avstypes.DeRegisterAction // validates that this is owner err := p.avsKeeper.UpdateAVSInfo(ctx, avsParams) if err != nil { return nil, err } + if err = p.EmitAVSDeregistered(ctx, stateDB, avsParams); err != nil { + return nil, err + } return method.Outputs.Pack(true) } @@ -97,7 +102,7 @@ func (p Precompile) UpdateAVS( ctx sdk.Context, _ common.Address, contract *vm.Contract, - _ vm.StateDB, + stateDB vm.StateDB, method *abi.Method, args []interface{}, ) ([]byte, error) { @@ -107,14 +112,14 @@ func (p Precompile) UpdateAVS( return nil, errorsmod.Wrap(err, "parse args error") } - avsParams.AvsAddress = contract.CallerAddress.String() - avsParams.Action = avskeeper.UpdateAction - previousAVSInfo, err := p.avsKeeper.GetAVSInfo(ctx, avsParams.AvsAddress) + avsParams.AvsAddress = contract.CallerAddress + avsParams.Action = avstypes.UpdateAction + previousAVSInfo, err := p.avsKeeper.GetAVSInfo(ctx, avsParams.AvsAddress.String()) if err != nil { return nil, err } // If avs UpdateAction check CallerAddress - if !slices.Contains(previousAVSInfo.Info.AvsOwnerAddress, avsParams.CallerAddress) { + if !slices.Contains(previousAVSInfo.Info.AvsOwnerAddress, avsParams.CallerAddress.String()) { return nil, fmt.Errorf("this caller not qualified to update %s", avsParams.CallerAddress) } err = p.avsKeeper.UpdateAVSInfo(ctx, avsParams) @@ -122,6 +127,9 @@ func (p Precompile) UpdateAVS( return nil, err } + if err = p.EmitAVSUpdated(ctx, stateDB, avsParams); err != nil { + return nil, err + } return method.Outputs.Pack(true) } @@ -129,7 +137,7 @@ func (p Precompile) BindOperatorToAVS( ctx sdk.Context, _ common.Address, contract *vm.Contract, - _ vm.StateDB, + stateDB vm.StateDB, method *abi.Method, args []interface{}, ) ([]byte, error) { @@ -141,14 +149,17 @@ func (p Precompile) BindOperatorToAVS( return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - operatorParams := &avskeeper.OperatorOptParams{} - operatorParams.OperatorAddress = sdk.AccAddress(callerAddress[:]).String() - operatorParams.AvsAddress = contract.CallerAddress.String() - operatorParams.Action = avskeeper.RegisterAction + operatorParams := &avstypes.OperatorOptParams{} + operatorParams.OperatorAddress = callerAddress[:] + operatorParams.AvsAddress = contract.CallerAddress + operatorParams.Action = avstypes.RegisterAction err := p.avsKeeper.OperatorOptAction(ctx, operatorParams) if err != nil { return nil, err } + if err = p.EmitOperatorJoined(ctx, stateDB, operatorParams); err != nil { + return nil, err + } return method.Outputs.Pack(true) } @@ -156,7 +167,7 @@ func (p Precompile) UnbindOperatorToAVS( ctx sdk.Context, _ common.Address, contract *vm.Contract, - _ vm.StateDB, + stateDB vm.StateDB, method *abi.Method, args []interface{}, ) ([]byte, error) { @@ -167,14 +178,17 @@ func (p Precompile) UnbindOperatorToAVS( if !ok || (callerAddress == common.Address{}) { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - operatorParams := &avskeeper.OperatorOptParams{} - operatorParams.OperatorAddress = sdk.AccAddress(callerAddress[:]).String() - operatorParams.AvsAddress = contract.CallerAddress.String() - operatorParams.Action = avskeeper.DeRegisterAction + operatorParams := &avstypes.OperatorOptParams{} + operatorParams.OperatorAddress = callerAddress[:] + operatorParams.AvsAddress = contract.CallerAddress + operatorParams.Action = avstypes.DeRegisterAction err := p.avsKeeper.OperatorOptAction(ctx, operatorParams) if err != nil { return nil, err } + if err = p.EmitOperatorOuted(ctx, stateDB, operatorParams); err != nil { + return nil, err + } return method.Outputs.Pack(true) } @@ -191,15 +205,15 @@ func (p Precompile) CreateAVSTask( if err != nil { return nil, err } - params.TaskContractAddress = contract.CallerAddress.String() - err = p.avsKeeper.CreateAVSTask(ctx, params) + params.TaskContractAddress = contract.CallerAddress + taskID, err := p.avsKeeper.CreateAVSTask(ctx, params) if err != nil { return nil, err } - if err = p.EmitCreateAVSTaskEvent(ctx, stateDB, params); err != nil { + if err = p.EmitTaskCreated(ctx, stateDB, params); err != nil { return nil, err } - return method.Outputs.Pack(true) + return method.Outputs.Pack(taskID) } // Challenge Middleware uses exocore's default avstask template to create tasks in avstask module. @@ -207,20 +221,20 @@ func (p Precompile) Challenge( ctx sdk.Context, _ common.Address, contract *vm.Contract, - _ vm.StateDB, + stateDB 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 := &avstypes.ChallengeParams{} challengeParams.TaskContractAddress = contract.CallerAddress callerAddress, ok := args[0].(common.Address) if !ok || (callerAddress == common.Address{}) { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - challengeParams.CallerAddress = sdk.AccAddress(callerAddress[:]).String() + challengeParams.CallerAddress = callerAddress[:] taskHash, ok := args[1].([]byte) if !ok { @@ -255,6 +269,9 @@ func (p Precompile) Challenge( return nil, err } + if err = p.EmitChallengeInitiated(ctx, stateDB, challengeParams); err != nil { + return nil, err + } return method.Outputs.Pack(true) } @@ -263,19 +280,19 @@ func (p Precompile) RegisterBLSPublicKey( ctx sdk.Context, _ common.Address, _ *vm.Contract, - _ vm.StateDB, + stateDB vm.StateDB, method *abi.Method, args []interface{}, ) ([]byte, error) { if len(args) != len(p.ABI.Methods[MethodRegisterBLSPublicKey].Inputs) { return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodRegisterBLSPublicKey].Inputs), len(args)) } - blsParams := &avskeeper.BlsParams{} + blsParams := &avstypes.BlsParams{} callerAddress, ok := args[0].(common.Address) if !ok || (callerAddress == common.Address{}) { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - blsParams.Operator = sdk.AccAddress(callerAddress[:]).String() + blsParams.OperatorAddress = callerAddress[:] name, ok := args[1].(string) if !ok || name == "" { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "string", name) @@ -284,7 +301,7 @@ func (p Precompile) RegisterBLSPublicKey( pubkeyBz, ok := args[2].([]byte) if !ok { - return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 3, "[]byte", pubkeyBz) + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 2, "[]byte", pubkeyBz) } blsParams.PubKey = pubkeyBz @@ -305,5 +322,90 @@ func (p Precompile) RegisterBLSPublicKey( return nil, err } + if err = p.EmitPublicKeyRegistered(ctx, stateDB, blsParams); err != nil { + return nil, err + } + return method.Outputs.Pack(true) +} + +// OperatorSubmitTask operator submit results +func (p Precompile) OperatorSubmitTask( + ctx sdk.Context, + _ common.Address, + _ *vm.Contract, + stateDB vm.StateDB, + method *abi.Method, + args []interface{}, +) ([]byte, error) { + if len(args) != len(p.ABI.Methods[MethodOperatorSubmitTask].Inputs) { + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodOperatorSubmitTask].Inputs), len(args)) + } + resultParams := &avstypes.TaskResultParams{} + + callerAddress, ok := args[0].(common.Address) + if !ok || (callerAddress == common.Address{}) { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) + } + resultParams.CallerAddress = callerAddress[:] + + taskID, ok := args[1].(uint64) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "uint64", args[1]) + } + resultParams.TaskID = taskID + + taskResponse, ok := args[2].([]byte) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 2, "[]byte", taskResponse) + } + resultParams.TaskResponse = taskResponse + + if len(taskResponse) == 0 { + resultParams.TaskResponse = nil + } + + blsSignature, ok := args[3].([]byte) + if !ok { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 3, "[]byte", blsSignature) + } + resultParams.BlsSignature = blsSignature + + taskAddr, ok := args[4].(common.Address) + if !ok || (taskAddr == common.Address{}) { + return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 4, "common.Address", taskAddr) + } + resultParams.TaskContractAddress = taskAddr + + phase, ok := args[5].(uint8) + if !ok { + return nil, fmt.Errorf("invalid phase type: expected uint8, got %T", args[5]) + } + + // The phase of the Two-Phase Commit protocol: + // 1 = Prepare phase (commit preparation) + // 2 = Commit phase (final commitment) + // validation of the phase number + phaseEnum := avstypes.Phase(phase) + if err := avstypes.ValidatePhase(phaseEnum); err != nil { + return nil, fmt.Errorf("invalid phase value: %d. Expected 1 (Prepare) or 2 (Commit)", phase) + } + resultParams.Phase = phaseEnum + + result := &avstypes.TaskResultInfo{ + TaskId: resultParams.TaskID, + OperatorAddress: resultParams.CallerAddress.String(), + TaskContractAddress: resultParams.TaskContractAddress.String(), + TaskResponse: resultParams.TaskResponse, + BlsSignature: resultParams.BlsSignature, + Phase: phaseEnum, + } + err := p.avsKeeper.SetTaskResultInfo(ctx, resultParams.CallerAddress.String(), result) + if err != nil { + return nil, err + } + + if err := p.EmitTaskSubmittedByOperator(ctx, stateDB, resultParams); err != nil { + return nil, err + } return method.Outputs.Pack(true) } diff --git a/precompiles/avs/types.go b/precompiles/avs/types.go index b34a61d61..155325731 100644 --- a/precompiles/avs/types.go +++ b/precompiles/avs/types.go @@ -4,7 +4,6 @@ import ( "fmt" exocmn "github.com/ExocoreNetwork/exocore/precompiles/common" - avskeep "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/ethereum/go-ethereum/common" @@ -24,7 +23,7 @@ func (p Precompile) GetAVSParamsFromInputs(_ sdk.Context, args []interface{}) (* if !ok || (callerAddress == common.Address{}) { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - avsParams.CallerAddress = sdk.AccAddress(callerAddress[:]).String() + avsParams.CallerAddress = callerAddress[:] avsName, ok := args[1].(string) if !ok || avsName == "" { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "string", avsName) @@ -41,19 +40,19 @@ func (p Precompile) GetAVSParamsFromInputs(_ sdk.Context, args []interface{}) (* if !ok || taskAddr == (common.Address{}) { return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 3, "common.Address", taskAddr) } - avsParams.TaskAddr = taskAddr.String() + avsParams.TaskAddr = taskAddr slashContractAddr, ok := args[4].(common.Address) if !ok || (slashContractAddr == common.Address{}) { return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 4, "common.Address", slashContractAddr) } - avsParams.SlashContractAddr = slashContractAddr.String() + avsParams.SlashContractAddr = slashContractAddr rewardContractAddr, ok := args[5].(common.Address) if !ok || (rewardContractAddr == common.Address{}) { return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 5, "common.Address", rewardContractAddr) } - avsParams.RewardContractAddr = rewardContractAddr.String() + avsParams.RewardContractAddr = rewardContractAddr // bech32 avsOwnerAddress, ok := args[6].([]string) @@ -126,7 +125,7 @@ func (p Precompile) GetAVSParamsFromUpdateInputs(_ sdk.Context, args []interface if !ok || (callerAddress == common.Address{}) { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - avsParams.CallerAddress = sdk.AccAddress(callerAddress[:]).String() + avsParams.CallerAddress = callerAddress[:] avsName, ok := args[1].(string) if !ok { @@ -144,19 +143,19 @@ func (p Precompile) GetAVSParamsFromUpdateInputs(_ sdk.Context, args []interface if !ok || taskAddr == (common.Address{}) { return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 3, "common.Address", taskAddr) } - avsParams.TaskAddr = taskAddr.String() + avsParams.TaskAddr = taskAddr slashContractAddr, ok := args[4].(common.Address) if !ok { return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 4, "common.Address", slashContractAddr) } - avsParams.SlashContractAddr = slashContractAddr.String() + avsParams.SlashContractAddr = slashContractAddr rewardContractAddr, ok := args[5].(common.Address) if !ok { return nil, xerrors.Errorf(exocmn.ErrContractInputParaOrType, 5, "common.Address", rewardContractAddr) } - avsParams.RewardContractAddr = rewardContractAddr.String() + avsParams.RewardContractAddr = rewardContractAddr // bech32 avsOwnerAddress, ok := args[6].([]string) @@ -220,16 +219,16 @@ func (p Precompile) GetAVSParamsFromUpdateInputs(_ sdk.Context, args []interface return avsParams, nil } -func (p Precompile) GetTaskParamsFromInputs(_ sdk.Context, args []interface{}) (*avskeep.TaskInfoParams, error) { +func (p Precompile) GetTaskParamsFromInputs(_ sdk.Context, args []interface{}) (*avstypes.TaskInfoParams, error) { if len(args) != len(p.ABI.Methods[MethodCreateAVSTask].Inputs) { - return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, 3, len(args)) + return nil, fmt.Errorf(cmn.ErrInvalidNumberOfArgs, len(p.ABI.Methods[MethodCreateAVSTask].Inputs), len(args)) } - taskParams := &avskeep.TaskInfoParams{} + taskParams := &avstypes.TaskInfoParams{} callerAddress, ok := args[0].(common.Address) if !ok || (callerAddress == common.Address{}) { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 0, "common.Address", callerAddress) } - taskParams.CallerAddress = sdk.AccAddress(callerAddress[:]).String() + taskParams.CallerAddress = callerAddress[:] name, ok := args[1].(string) if !ok || name == "" { return nil, fmt.Errorf(exocmn.ErrContractInputParaOrType, 1, "string", name) diff --git a/precompiles/avs/utils_test.go b/precompiles/avs/utils_test.go index 72b413729..5f52298d8 100644 --- a/precompiles/avs/utils_test.go +++ b/precompiles/avs/utils_test.go @@ -8,7 +8,6 @@ import ( utiltx "github.com/ExocoreNetwork/exocore/testutil/tx" assetskeeper "github.com/ExocoreNetwork/exocore/x/assets/keeper" - avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types" @@ -102,11 +101,11 @@ func (suite *AVSManagerPrecompileSuite) prepareAvs(assetIDs []string, task strin "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj2", } err := suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, &avstypes.AVSRegisterOrDeregisterParams{ - Action: avskeeper.RegisterAction, + Action: avstypes.RegisterAction, EpochIdentifier: epochstypes.HourEpochID, - AvsAddress: suite.avsAddr, + AvsAddress: common.HexToAddress(suite.avsAddr), AssetID: assetIDs, - TaskAddr: task, + TaskAddr: common.HexToAddress(task), AvsOwnerAddress: avsOwnerAddress, }) suite.NoError(err) diff --git a/proto/exocore/avs/v1/query.proto b/proto/exocore/avs/v1/query.proto index 3c4cb11f0..a9a1a41dd 100644 --- a/proto/exocore/avs/v1/query.proto +++ b/proto/exocore/avs/v1/query.proto @@ -37,7 +37,7 @@ message QueryAVSTaskInfoReq { // task_addr is the task contract address,its type should be a sdk.AccAddress string task_addr = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // task_id is the task identifier - string task_id = 2 ; + string task_id = 2; } // QuerySubmitTaskResultReq is the request to obtain the task information. @@ -45,10 +45,9 @@ message QuerySubmitTaskResultReq { // task_addr is the task contract address,its type should be a sdk.AccAddress string task_addr = 1 [(gogoproto.customname) = "TaskAddress"]; // task_id is the task identifier - string task_id = 2 ; + string task_id = 2; // operator_addr is the operator address,its type should be a sdk.AccAddress - string operator_addr = 3 - [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string operator_addr = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"]; } // QueryChallengeInfoReq is the request to obtain the task information. @@ -58,11 +57,9 @@ message QueryChallengeInfoReq { // task_id is the task identifier string task_id = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // operator_addr is the operator address,its type should be a sdk.AccAddress - string operator_addr = 3 - [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string operator_addr = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"]; } - // QuerySubmitTaskResultResponse is the response of avs related information message QuerySubmitTaskResultResponse { // info is the taskResult. diff --git a/proto/exocore/avs/v1/tx.proto b/proto/exocore/avs/v1/tx.proto index 417e32afb..041375524 100644 --- a/proto/exocore/avs/v1/tx.proto +++ b/proto/exocore/avs/v1/tx.proto @@ -44,32 +44,31 @@ message AVSInfo { string chain_id = 15; // avs_reward defines the proportion of reward string avs_reward = 16 - [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; + [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; // avs_slash defines the proportion of slash string avs_slash = 17 - [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; + [(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false]; // asset_reward_commission_epoch_basis is the avs reward distribution based on asset per eopch end. map asset_reward_amount_epoch_basis = 18; } -//Status and proof of each operator +// Status and proof of each operator message OperatorStatus { // operator address string operator_address = 1; - //Status of the operator,(slash,reward,no) + // Status of the operator,(slash,reward,no) string status = 2; // proof data which is supplied by the contract, usually ABI-encoded bytes proof_data = 3; - } -//RewardSlashProof is the task info. +// RewardSlashProof is the task info. message RewardSlashProof { // task_id of task string task_id = 1; // contract address of avstask string task_contract_address = 2; - //aggregator address + // aggregator address string aggregator = 3; // address of avs string avs_address = 4; @@ -92,15 +91,14 @@ message TaskInfo { // Statistical period: threshold calculation, signature verification, // nosig quantity statistics, operator submits messages corresponding to signatures uint64 task_statistical_period = 6; - //challenge period for task + // challenge period for task uint64 task_challenge_period = 7; - //Signature threshold percentage + // Signature threshold percentage uint64 threshold_percentage = 8; // Effective current epoch, accounting for current_epoch + 1 // and current_epoch is the integer identifier of the epoch module uint64 starting_epoch = 9; - // actual_threshold is the Actual threshold uint64 actual_threshold = 10; // opt_in_count when creating a task, the actual opt-in operator counts at this moment @@ -112,15 +110,14 @@ message TaskInfo { // err_signed_count is the number of operators with final incorrect signatures repeated string err_signed_operators = 14; // task_total_power is the USD value owned by the avs task itself. - string task_total_power = 15 - [ + string task_total_power = 15 [ (cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false, (gogoproto.customname) = "TaskTotalPower" ]; // operator_active_power_list is a power list of operators opt-in to the current task - OperatorActivePowerList operator_active_power= 16; + OperatorActivePowerList operator_active_power = 16; } // OperatorActivePowerList is the power list of operators opt-in to the current task. // Because power is always changing, record the power of all operators @@ -135,8 +132,7 @@ message OperatorActivePowerInfo { // operator_addr is the operator address. string operator_addr = 1; // active_power is the USD value owned by the operator itself. - string active_power = 2 - [ + string active_power = 2 [ (cosmos_proto.scalar) = "cosmos.Dec", (gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec", (gogoproto.nullable) = false, @@ -147,11 +143,10 @@ message OperatorActivePowerInfo { message BlsPubKeyInfo { // operator address string operator = 1; - //the name of public keys + // the name of public keys string name = 2; // the bls public keys of the operator bytes pub_key = 3; - } // RegisterAVSTaskReq is the request to register a new task for avs. message RegisterAVSTaskReq { @@ -174,8 +169,7 @@ message RegisterAVSReq { // from_address is the source option (cosmos.msg.v1.signer) = "FromAddress"; // from_address is the source - string from_address = 1 - [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string from_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // avs information AVSInfo info = 2; } @@ -185,8 +179,7 @@ message RegisterAVSResponse { // from_address is the source option (cosmos.msg.v1.signer) = "FromAddress"; // from_address is the source - string from_address = 1 - [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string from_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // avs information AVSInfo info = 2; } @@ -195,8 +188,7 @@ message RegisterAVSResponse { message DeRegisterAVSReq { option (cosmos.msg.v1.signer) = "FromAddress"; // from_address is the source address - string from_address = 1 - [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string from_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // avs information AVSInfo info = 2; } @@ -206,12 +198,20 @@ message DeRegisterAVSResponse { // from_address is the source address option (cosmos.msg.v1.signer) = "FromAddress"; // from_address is the source address - string from_address = 1 - [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string from_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // avs information AVSInfo info = 2; } - +// It is a two-phase submission with two values, 1 and 2 +enum Phase { + option (gogoproto.goproto_enum_prefix) = false; + // Default value when phase is not specified + PHASE_UNSPECIFIED = 0 [(gogoproto.enumvalue_customname) = "PhaseUnspecified"]; + // First phase where operators prepare and submit their initial responses + PHASE_PREPARE = 1 [(gogoproto.enumvalue_customname) = "PhasePrepare"]; + // Second phase where operators commit their prepared responses + PHASE_DO_COMMIT = 2 [(gogoproto.enumvalue_customname) = "PhaseDoCommit"]; +} // TaskResultInfo is the operator sign task info result. message TaskResultInfo { // operator_address operator address @@ -226,9 +226,9 @@ message TaskResultInfo { string task_contract_address = 5; // task_id is the task id uint64 task_id = 6; - // stage this field is used to solve the problem of task results being copied by other operators. - // It is a two-stage submission with two values, 1 and 2 - string stage = 7; + // phase this field is used to solve the problem of task results being copied by other operators. + // It is a two-phase submission with two values, 1 and 2 + Phase phase = 7; } // SubmitTaskResultReq is the request to submit task results. @@ -239,8 +239,7 @@ message SubmitTaskResultReq { option (gogoproto.goproto_getters) = false; // from_address is the address of the operator (sdk.AccAddress). - string from_address = 1 - [(cosmos_proto.scalar) = "cosmos.AddressString"]; + string from_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // info is the taskResult. TaskResultInfo info = 2; } @@ -250,11 +249,11 @@ message SubmitTaskResultResponse {} service Msg { option (cosmos.msg.v1.service) = true; // RegisterAVS registers a new AVS with corresponding operator. - rpc RegisterAVS (RegisterAVSReq) returns (RegisterAVSResponse) { + rpc RegisterAVS(RegisterAVSReq) returns (RegisterAVSResponse) { option (google.api.http).post = "/exocore/avs/v1/tx/RegisterAVS"; }; // DelegateAssetToOperator delegates asset to operator. - rpc DeRegisterAVS (DeRegisterAVSReq) returns (DeRegisterAVSResponse) { + rpc DeRegisterAVS(DeRegisterAVSReq) returns (DeRegisterAVSResponse) { option (google.api.http).post = "/exocore/avs/v1/tx/DeRegisterAVS"; }; // RegisterAVSTask registers a new task. @@ -262,7 +261,7 @@ service Msg { option (google.api.http).post = "/exocore/avs/v1/tx/RegisterAVSTask"; }; // SubmitTaskResult operator submit task results . - rpc SubmitTaskResult (SubmitTaskResultReq) returns (SubmitTaskResultResponse) { + rpc SubmitTaskResult(SubmitTaskResultReq) returns (SubmitTaskResultResponse) { option (google.api.http).post = "/exocore/avs/v1/tx/SubmitTaskResult"; }; } \ No newline at end of file diff --git a/x/avs/client/cli/tx.go b/x/avs/client/cli/tx.go index 269c791e5..b73524a26 100644 --- a/x/avs/client/cli/tx.go +++ b/x/avs/client/cli/tx.go @@ -19,7 +19,7 @@ const ( FlagBlsSignature = "bls-signature" FlagTaskContractAddress = "task-contract-address" FlagTaskID = "task-id" - FlagStage = "stage" + FlagPhase = "phase" ) // GetTxCmd returns the transaction commands for this module @@ -54,8 +54,10 @@ func CmdSubmitTaskResult() *cobra.Command { return err } - msg := newBuildMsg(clientCtx, cmd.Flags()) - + msg, err := newBuildMsg(clientCtx, cmd.Flags()) + if err != nil { + return err + } // this calls ValidateBasic internally so we don't need to do that. return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) }, @@ -78,14 +80,14 @@ func CmdSubmitTaskResult() *cobra.Command { f.Uint64( FlagTaskID, 1, "The task id", ) - f.String( - FlagStage, "", "The stage is a two-stage submission with two values, 1 and 2", + f.Uint32( + FlagPhase, 0, "The phase is a two-phase submission with two values, 1 and 2", ) // #nosec G703 // this only errors if the flag isn't defined. _ = cmd.MarkFlagRequired(FlagTaskID) _ = cmd.MarkFlagRequired(FlagBlsSignature) _ = cmd.MarkFlagRequired(FlagTaskContractAddress) - _ = cmd.MarkFlagRequired(FlagStage) + _ = cmd.MarkFlagRequired(FlagPhase) // transaction level flags from the SDK flags.AddTxFlagsToCmd(cmd) @@ -95,21 +97,29 @@ func CmdSubmitTaskResult() *cobra.Command { func newBuildMsg( clientCtx client.Context, fs *pflag.FlagSet, -) *types.SubmitTaskResultReq { +) (*types.SubmitTaskResultReq, error) { sender := clientCtx.GetFromAddress() operatorAddress, _ := fs.GetString(FlagOperatorAddress) if operatorAddress == "" { operatorAddress = sender.String() } taskResponse, _ := fs.GetString(FlagTaskResponse) - taskRes, _ := hex.DecodeString(taskResponse) + taskRes, err := hex.DecodeString(taskResponse) + if err != nil { + return nil, err + } blsSignature, _ := fs.GetString(FlagBlsSignature) - sig, _ := hex.DecodeString(blsSignature) + sig, err := hex.DecodeString(blsSignature) + if err != nil { + return nil, err + } taskContractAddress, _ := fs.GetString(FlagTaskContractAddress) taskID, _ := fs.GetUint64(FlagTaskID) - stage, _ := fs.GetString(FlagStage) - + phase, _ := fs.GetUint32(FlagPhase) + if err := types.ValidatePhase(types.Phase(phase)); err != nil { + return nil, err + } msg := &types.SubmitTaskResultReq{ FromAddress: sender.String(), Info: &types.TaskResultInfo{ @@ -118,8 +128,8 @@ func newBuildMsg( BlsSignature: sig, TaskContractAddress: taskContractAddress, TaskId: taskID, - Stage: stage, + Phase: types.Phase(phase), }, } - return msg + return msg, nil } diff --git a/x/avs/keeper/avs.go b/x/avs/keeper/avs.go index 88029157b..8f91b53a1 100644 --- a/x/avs/keeper/avs.go +++ b/x/avs/keeper/avs.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" "strconv" + "strings" errorsmod "cosmossdk.io/errors" sdkmath "cosmossdk.io/math" @@ -46,7 +47,9 @@ func (k *Keeper) GetAVSSlashContract(ctx sdk.Context, avsAddr string) (string, e if err != nil { return "", errorsmod.Wrap(err, fmt.Sprintf("GetAVSSlashContract: key is %s", avsAddr)) } - + if avsInfo.Info.SlashAddr == (common.Address{}).String() { + return "", nil + } return avsInfo.Info.SlashAddr, nil } @@ -72,7 +75,7 @@ func (k *Keeper) GetEpochEndAVSs(ctx sdk.Context, epochIdentifier string, ending // it should be returned here, since the operator module should start tracking this. // #nosec G115 if epochIdentifier == avsInfo.EpochIdentifier && endingEpochNumber >= int64(avsInfo.StartingEpoch)-1 { - avsList = append(avsList, avsInfo.AvsAddress) + avsList = append(avsList, strings.ToLower(avsInfo.AvsAddress)) } return false }) @@ -85,9 +88,10 @@ func (k *Keeper) GetEpochEndAVSs(ctx sdk.Context, epochIdentifier string, ending // TODO:this function is frequently used while its implementation iterates over existing avs to find the target avs by task contract address, we should use a reverse mapping to avoid iteration func (k *Keeper) GetAVSInfoByTaskAddress(ctx sdk.Context, taskAddr string) types.AVSInfo { var avs types.AVSInfo - if taskAddr == "" { + if taskAddr == "" || taskAddr == (common.Address{}).String() { return avs } + taskAddr = strings.ToLower(taskAddr) k.IterateAVSInfo(ctx, func(_ int64, avsInfo types.AVSInfo) (stop bool) { if taskAddr == avsInfo.GetTaskAddr() { avs = avsInfo @@ -103,6 +107,9 @@ func (k *Keeper) GetTaskStatisticalEpochEndAVSs(ctx sdk.Context, epochIdentifier var taskResList []types.TaskResultInfo k.IterateResultInfo(ctx, func(_ int64, info types.TaskResultInfo) (stop bool) { avsInfo := k.GetAVSInfoByTaskAddress(ctx, info.TaskContractAddress) + if avsInfo.AvsAddress == "" { + return false + } taskInfo, err := k.GetTaskInfo(ctx, strconv.FormatUint(info.TaskId, 10), info.TaskContractAddress) if err != nil { return false @@ -161,8 +168,8 @@ func (k Keeper) RegisterAVSWithChainID( return common.Address{}, err } // SetAVSInfo expects HexAddress for the AvsAddress - params.AvsAddress = avsAddrStr - params.Action = RegisterAction + params.AvsAddress = avsAddr + params.Action = types.RegisterAction if err := k.UpdateAVSInfo(ctx, params); err != nil { return common.Address{}, err diff --git a/x/avs/keeper/avs_test.go b/x/avs/keeper/avs_test.go index 0bdc36ba0..3ab1ed807 100644 --- a/x/avs/keeper/avs_test.go +++ b/x/avs/keeper/avs_test.go @@ -3,11 +3,13 @@ package keeper_test import ( "cosmossdk.io/math" assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" + "github.com/ethereum/go-ethereum/common" "math/big" + "strings" "time" - avstypes "github.com/ExocoreNetwork/exocore/x/avs/keeper" "github.com/ExocoreNetwork/exocore/x/avs/types" + avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" delegationtypes "github.com/ExocoreNetwork/exocore/x/delegation/types" epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types" operatorTypes "github.com/ExocoreNetwork/exocore/x/operator/types" @@ -26,7 +28,7 @@ func (suite *AVSTestSuite) TestAVS() { SlashAddr: utiltx.GenerateAddress().String(), AvsOwnerAddress: avsOwnerAddress, AssetIDs: assetID, - AvsUnbondingPeriod: 7, + AvsUnbondingPeriod: 2, MinSelfDelegation: 10, EpochIdentifier: epochstypes.DayEpochID, StartingEpoch: 1, @@ -62,20 +64,20 @@ func (suite *AVSTestSuite) TestAVS() { } func (suite *AVSTestSuite) TestUpdateAVSInfo_Register() { - avsName, avsAddres, slashAddress, rewardAddress := "avsTest", "exo18cggcpvwspnd5c6ny8wrqxpffj5zmhklprtnph", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" + avsName, avsAddres, slashAddress, rewardAddress := "avsTest", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB", "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" avsOwnerAddress := []string{"exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj1", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj2"} assetID := suite.AssetIDs avsParams := &types.AVSRegisterOrDeregisterParams{ AvsName: avsName, - AvsAddress: avsAddres, + AvsAddress: common.HexToAddress(avsAddres), Action: avstypes.RegisterAction, - RewardContractAddr: rewardAddress, + RewardContractAddr: common.HexToAddress(rewardAddress), AvsOwnerAddress: avsOwnerAddress, AssetID: assetID, MinSelfDelegation: uint64(10), - UnbondingPeriod: uint64(7), - SlashContractAddr: slashAddress, + UnbondingPeriod: uint64(2), + SlashContractAddr: common.HexToAddress(slashAddress), EpochIdentifier: epochstypes.DayEpochID, } @@ -85,7 +87,7 @@ func (suite *AVSTestSuite) TestUpdateAVSInfo_Register() { info, err := suite.App.AVSManagerKeeper.GetAVSInfo(suite.Ctx, avsAddres) suite.NoError(err) - suite.Equal(avsAddres, info.GetInfo().AvsAddress) + suite.Equal(strings.ToLower(avsAddres), info.GetInfo().AvsAddress) err = suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, avsParams) suite.Error(err) @@ -94,19 +96,19 @@ func (suite *AVSTestSuite) TestUpdateAVSInfo_Register() { func (suite *AVSTestSuite) TestUpdateAVSInfo_DeRegister() { // Test case setup - avsName, avsAddres, slashAddress := "avsTest", suite.avsAddress.String(), "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutash" + avsName, avsAddress, slashAddress := "avsTest", suite.avsAddress.String(), "0xDF907c29719154eb9872f021d21CAE6E5025d7aB" avsOwnerAddress := []string{"exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj1", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj2"} assetID := suite.AssetIDs avsParams := &types.AVSRegisterOrDeregisterParams{ AvsName: avsName, - AvsAddress: avsAddres, + AvsAddress: common.HexToAddress(avsAddress), Action: avstypes.DeRegisterAction, AvsOwnerAddress: avsOwnerAddress, AssetID: assetID, MinSelfDelegation: uint64(10), - UnbondingPeriod: uint64(7), - SlashContractAddr: slashAddress, + UnbondingPeriod: uint64(2), + SlashContractAddr: common.HexToAddress(slashAddress), EpochIdentifier: epochstypes.DayEpochID, } @@ -117,40 +119,47 @@ func (suite *AVSTestSuite) TestUpdateAVSInfo_DeRegister() { avsParams.Action = avstypes.RegisterAction err = suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, avsParams) suite.NoError(err) - info, err := suite.App.AVSManagerKeeper.GetAVSInfo(suite.Ctx, avsAddres) - suite.Equal(avsAddres, info.GetInfo().AvsAddress) + info, err := suite.App.AVSManagerKeeper.GetAVSInfo(suite.Ctx, avsAddress) + suite.Equal(strings.ToLower(avsAddress), info.GetInfo().AvsAddress) + + epoch, _ := suite.App.EpochsKeeper.GetEpochInfo(suite.Ctx, epochstypes.DayEpochID) + // Numbered loops for epoch ends + for epochEnd := epoch.CurrentEpoch; epochEnd <= int64(info.Info.StartingEpoch)+2; epochEnd++ { + suite.CommitAfter(time.Hour * 24) + epoch, found := suite.App.EpochsKeeper.GetEpochInfo(suite.Ctx, epochstypes.DayEpochID) + suite.Equal(found, true) + suite.Equal(epoch.CurrentEpoch, epochEnd+1) + } avsParams.Action = avstypes.DeRegisterAction - avsParams.CallerAddress = "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr" + avsParams.CallerAddress, err = sdk.AccAddressFromBech32("exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr") err = suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, avsParams) suite.NoError(err) - info, err = suite.App.AVSManagerKeeper.GetAVSInfo(suite.Ctx, avsAddres) + info, err = suite.App.AVSManagerKeeper.GetAVSInfo(suite.Ctx, avsAddress) suite.Error(err) suite.Contains(err.Error(), types.ErrNoKeyInTheStore.Error()) } func (suite *AVSTestSuite) TestUpdateAVSInfoWithOperator_Register() { avsAddress := suite.avsAddress - operatorAddress := sdk.AccAddress(utiltx.GenerateAddress().Bytes()).String() + operatorAddress := sdk.AccAddress(utiltx.GenerateAddress().Bytes()) - opAccAddr, err := sdk.AccAddressFromBech32(operatorAddress) - suite.NoError(err) operatorParams := &avstypes.OperatorOptParams{ - AvsAddress: avsAddress.String(), + AvsAddress: avsAddress, Action: avstypes.RegisterAction, OperatorAddress: operatorAddress, } // operator Not Exist - err = suite.App.AVSManagerKeeper.OperatorOptAction(suite.Ctx, operatorParams) + err := suite.App.AVSManagerKeeper.OperatorOptAction(suite.Ctx, operatorParams) suite.Error(err) suite.Contains(err.Error(), delegationtypes.ErrOperatorNotExist.Error()) // register operator but avs not register // register operator registerReq := &operatorTypes.RegisterOperatorReq{ - FromAddress: opAccAddr.String(), + FromAddress: operatorAddress.String(), Info: &operatorTypes.OperatorInfo{ - EarningsAddr: opAccAddr.String(), + EarningsAddr: operatorAddress.String(), }, } _, err = suite.OperatorMsgServer.RegisterOperator(sdk.WrapSDKContext(suite.Ctx), registerReq) @@ -161,7 +170,7 @@ func (suite *AVSTestSuite) TestUpdateAVSInfoWithOperator_Register() { _, assetID := assetstypes.GetStakerIDAndAssetIDFromStr(asset.LayerZeroChainID, "", asset.Address) selfDelegateAmount := big.NewInt(10) minPrecisionSelfDelegateAmount := big.NewInt(0).Mul(selfDelegateAmount, big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(asset.Decimals)), nil)) - err = suite.App.AssetsKeeper.UpdateOperatorAssetState(suite.Ctx, opAccAddr, assetID, assetstypes.DeltaOperatorSingleAsset{ + err = suite.App.AssetsKeeper.UpdateOperatorAssetState(suite.Ctx, operatorAddress, assetID, assetstypes.DeltaOperatorSingleAsset{ TotalAmount: math.NewIntFromBigInt(minPrecisionSelfDelegateAmount), TotalShare: math.LegacyNewDecFromBigInt(minPrecisionSelfDelegateAmount), OperatorShare: math.LegacyNewDecFromBigInt(minPrecisionSelfDelegateAmount), diff --git a/x/avs/keeper/epoch_test.go b/x/avs/keeper/epoch_test.go index eb9ab2e44..779251da6 100644 --- a/x/avs/keeper/epoch_test.go +++ b/x/avs/keeper/epoch_test.go @@ -23,7 +23,7 @@ func (suite *AVSTestSuite) TestEpochEnd_TaskCalculation() { suite.CommitAfter(suite.EpochDuration) suite.CommitAfter(suite.EpochDuration) suite.CommitAfter(suite.EpochDuration) - info, err := suite.App.AVSManagerKeeper.GetTaskInfo(suite.Ctx, strconv.FormatUint(suite.taskId, 10), common.Address(suite.taskAddress.Bytes()).String()) + info, err := suite.App.AVSManagerKeeper.GetTaskInfo(suite.Ctx, strconv.Itoa(int(suite.taskId)), common.Address(suite.taskAddress.Bytes()).String()) suite.NoError(err) expectInfo := &avstypes.TaskInfo{ TaskContractAddress: suite.taskAddress.String(), diff --git a/x/avs/keeper/keeper.go b/x/avs/keeper/keeper.go index 50265144d..80286befa 100644 --- a/x/avs/keeper/keeper.go +++ b/x/avs/keeper/keeper.go @@ -5,6 +5,7 @@ import ( "fmt" "slices" "strconv" + "strings" "github.com/prysmaticlabs/prysm/v4/crypto/bls" "github.com/prysmaticlabs/prysm/v4/crypto/bls/blst" @@ -62,6 +63,11 @@ func (k Keeper) GetOperatorKeeper() types.OperatorKeeper { return k.operatorKeeper } +// GetEpochKeeper returns the operatorKeeper from the Keeper struct. +func (k Keeper) GetEpochKeeper() types.EpochsKeeper { + return k.epochsKeeper +} + func (k Keeper) ValidateAssetIDs(ctx sdk.Context, assetIDs []string) error { for _, assetID := range assetIDs { if !k.assetsKeeper.IsStakingAsset(ctx, assetID) { @@ -72,7 +78,7 @@ func (k Keeper) ValidateAssetIDs(ctx sdk.Context, assetIDs []string) error { } func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregisterParams) error { - avsInfo, _ := k.GetAVSInfo(ctx, params.AvsAddress) + avsInfo, _ := k.GetAVSInfo(ctx, params.AvsAddress.String()) action := params.Action epochIdentifier := params.EpochIdentifier if avsInfo != nil && avsInfo.Info.EpochIdentifier != "" { @@ -83,11 +89,11 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi return errorsmod.Wrap(types.ErrEpochNotFound, fmt.Sprintf("epoch info not found %s", epochIdentifier)) } switch action { - case RegisterAction: + case types.RegisterAction: if avsInfo != nil { return errorsmod.Wrap(types.ErrAlreadyRegistered, fmt.Sprintf("the avsaddress is :%s", params.AvsAddress)) } - if k.GetAVSInfoByTaskAddress(ctx, params.TaskAddr).AvsAddress != "" { + if k.GetAVSInfoByTaskAddress(ctx, params.TaskAddr.String()).AvsAddress != "" { return errorsmod.Wrap(types.ErrAlreadyRegistered, fmt.Sprintf("this TaskAddr has already been used by other AVS,the TaskAddr is :%s", params.TaskAddr)) } startingEpoch := uint64(epoch.CurrentEpoch + 1) @@ -102,9 +108,9 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi avs := &types.AVSInfo{ Name: params.AvsName, - AvsAddress: params.AvsAddress, - RewardAddr: params.RewardContractAddr, - SlashAddr: params.SlashContractAddr, + AvsAddress: strings.ToLower(params.AvsAddress.String()), + RewardAddr: strings.ToLower(params.RewardContractAddr.String()), + SlashAddr: strings.ToLower(params.SlashContractAddr.String()), AvsOwnerAddress: params.AvsOwnerAddress, AssetIDs: params.AssetID, MinSelfDelegation: params.MinSelfDelegation, @@ -112,7 +118,7 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi EpochIdentifier: epochIdentifier, StartingEpoch: startingEpoch, MinOptInOperators: params.MinOptInOperators, - TaskAddr: params.TaskAddr, + TaskAddr: strings.ToLower(params.TaskAddr.String()), MinStakeAmount: params.MinStakeAmount, // Effective at CurrentEpoch+1, avoid immediate effects and ensure that the first epoch time of avs is equal to a normal identifier MinTotalStakeAmount: params.MinTotalStakeAmount, // #nosec G115 @@ -122,18 +128,18 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi } return k.SetAVSInfo(ctx, avs) - case DeRegisterAction: + case types.DeRegisterAction: if avsInfo == nil { return errorsmod.Wrap(types.ErrUnregisterNonExistent, fmt.Sprintf("the avsaddress is :%s", params.AvsAddress)) } // If avs DeRegisterAction check CallerAddress - if !slices.Contains(avsInfo.Info.AvsOwnerAddress, params.CallerAddress) { + if !slices.Contains(avsInfo.Info.AvsOwnerAddress, params.CallerAddress.String()) { return errorsmod.Wrap(types.ErrCallerAddressUnauthorized, fmt.Sprintf("this caller not qualified to deregister %s", params.CallerAddress)) } // If avs DeRegisterAction check UnbondingPeriod // #nosec G115 - if epoch.CurrentEpoch-int64(avsInfo.GetInfo().StartingEpoch) > int64(avsInfo.Info.AvsUnbondingPeriod) { + if epoch.CurrentEpoch-int64(avsInfo.GetInfo().StartingEpoch) <= int64(avsInfo.Info.AvsUnbondingPeriod) { return errorsmod.Wrap(types.ErrUnbondingPeriod, fmt.Sprintf("not qualified to deregister %s", avsInfo)) } @@ -141,25 +147,19 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi if avsInfo.Info.Name != params.AvsName { return errorsmod.Wrap(types.ErrAvsNameMismatch, fmt.Sprintf("Unregistered AVS name is incorrect %s", params.AvsName)) } - return k.DeleteAVSInfo(ctx, params.AvsAddress) - case UpdateAction: + return k.DeleteAVSInfo(ctx, params.AvsAddress.String()) + case types.UpdateAction: if avsInfo == nil { return errorsmod.Wrap(types.ErrUnregisterNonExistent, fmt.Sprintf("the avsaddress is :%s", params.AvsAddress)) } // Check here to ensure that the task address is only used by one avs - avsAddress := k.GetAVSInfoByTaskAddress(ctx, params.TaskAddr).AvsAddress + avsAddress := k.GetAVSInfoByTaskAddress(ctx, params.TaskAddr.String()).AvsAddress if avsAddress != "" && avsAddress != avsInfo.Info.AvsAddress { return errorsmod.Wrap(types.ErrAlreadyRegistered, fmt.Sprintf("this TaskAddr has already been used by other AVS,the TaskAddr is :%s", params.TaskAddr)) } // TODO: The AvsUnbondingPeriod is used for undelegation, but this check currently blocks updates to AVS information. Remove this check to allow AVS updates, while detailed control mechanisms for updates should be considered and implemented in the future. // If avs UpdateAction check UnbondingPeriod - // #nosec G115 - // if int64(avsInfo.Info.AvsUnbondingPeriod) < (epoch.CurrentEpoch - int64(avsInfo.GetInfo().StartingEpoch)) { - // return errorsmod.Wrap(types.ErrUnbondingPeriod, fmt.Sprintf("not qualified to deregister %s", avsInfo)) - // } - // If avs UpdateAction check CallerAddress - avs := avsInfo.Info if params.AvsName != "" { @@ -168,14 +168,14 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi if params.MinStakeAmount > 0 { avs.MinStakeAmount = params.MinStakeAmount } - if params.TaskAddr != "" { - avs.TaskAddr = params.TaskAddr + if params.TaskAddr.String() != "" { + avs.TaskAddr = strings.ToLower(params.TaskAddr.String()) } - if params.SlashContractAddr != "" { - avs.SlashAddr = params.SlashContractAddr + if params.SlashContractAddr.String() != "" { + avs.SlashAddr = strings.ToLower(params.SlashContractAddr.String()) } - if params.RewardContractAddr != "" { - avs.RewardAddr = params.RewardContractAddr + if params.RewardContractAddr.String() != "" { + avs.RewardAddr = strings.ToLower(params.RewardContractAddr.String()) } if params.AvsOwnerAddress != nil { avs.AvsOwnerAddress = params.AvsOwnerAddress @@ -211,7 +211,7 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi // #nosec G115 avs.AvsReward = sdk.NewDecWithPrec(int64(params.AvsReward), 2) } - avs.AvsAddress = params.AvsAddress + avs.AvsAddress = params.AvsAddress.String() avs.StartingEpoch = uint64(epoch.CurrentEpoch + 1) return k.SetAVSInfo(ctx, avs) @@ -220,38 +220,40 @@ func (k Keeper) UpdateAVSInfo(ctx sdk.Context, params *types.AVSRegisterOrDeregi } } -func (k Keeper) CreateAVSTask(ctx sdk.Context, params *TaskInfoParams) error { - avsInfo := k.GetAVSInfoByTaskAddress(ctx, params.TaskContractAddress) +func (k Keeper) CreateAVSTask(ctx sdk.Context, params *types.TaskInfoParams) (uint64, error) { + avsInfo := k.GetAVSInfoByTaskAddress(ctx, params.TaskContractAddress.String()) if avsInfo.AvsAddress == "" { - return errorsmod.Wrap(types.ErrUnregisterNonExistent, fmt.Sprintf("the taskaddr is :%s", params.TaskContractAddress)) + return types.InvalidTaskID, errorsmod.Wrap(types.ErrUnregisterNonExistent, fmt.Sprintf("the taskaddr is :%s", params.TaskContractAddress)) } // If avs CreateAVSTask check CallerAddress - if !slices.Contains(avsInfo.AvsOwnerAddress, params.CallerAddress) { - return errorsmod.Wrap(types.ErrCallerAddressUnauthorized, fmt.Sprintf("this caller not qualified to CreateAVSTask %s", params.CallerAddress)) + if !slices.Contains(avsInfo.AvsOwnerAddress, params.CallerAddress.String()) { + return types.InvalidTaskID, errorsmod.Wrap(types.ErrCallerAddressUnauthorized, fmt.Sprintf("this caller not qualified to CreateAVSTask %s", params.CallerAddress)) } taskPowerTotal, err := k.operatorKeeper.GetAVSUSDValue(ctx, avsInfo.AvsAddress) - - if err != nil || taskPowerTotal.IsZero() || taskPowerTotal.IsNegative() { - return errorsmod.Wrap(types.ErrVotingPowerIncorrect, fmt.Sprintf("the votingpower of avs is <<=0,avs addr is:%s", avsInfo.AvsAddress)) + if err != nil { + return types.InvalidTaskID, errorsmod.Wrap(err, "failed to get AVS USD value") + } + if taskPowerTotal.IsZero() || taskPowerTotal.IsNegative() { + return types.InvalidTaskID, errorsmod.Wrap(types.ErrVotingPowerIncorrect, fmt.Sprintf("the voting power of AVS is zero or negative, AVS address: %s", avsInfo.AvsAddress)) } epoch, found := k.epochsKeeper.GetEpochInfo(ctx, avsInfo.EpochIdentifier) if !found { - return errorsmod.Wrap(types.ErrEpochNotFound, fmt.Sprintf("epoch info not found %s", avsInfo.EpochIdentifier)) + return types.InvalidTaskID, errorsmod.Wrap(types.ErrEpochNotFound, fmt.Sprintf("epoch info not found %s", avsInfo.EpochIdentifier)) } - if k.IsExistTask(ctx, strconv.FormatUint(params.TaskID, 10), params.TaskContractAddress) { - return errorsmod.Wrap(types.ErrAlreadyExists, fmt.Sprintf("the task is :%s", strconv.FormatUint(params.TaskID, 10))) + if k.IsExistTask(ctx, strconv.FormatUint(params.TaskID, 10), params.TaskContractAddress.String()) { + return types.InvalidTaskID, errorsmod.Wrap(types.ErrAlreadyExists, fmt.Sprintf("the task is :%s", strconv.FormatUint(params.TaskID, 10))) } - operatorList, err := k.GetOptInOperators(ctx, avsInfo.AvsAddress) + operatorList, err := k.operatorKeeper.GetOptedInOperatorListByAVS(ctx, avsInfo.AvsAddress) if err != nil { - return errorsmod.Wrap(err, "CreateAVSTask: failed to get opt-in operators") + return types.InvalidTaskID, errorsmod.Wrap(err, "CreateAVSTask: failed to get opt-in operators") } - params.TaskID = k.GetTaskID(ctx, common.HexToAddress(params.TaskContractAddress)) + params.TaskID = k.GetTaskID(ctx, common.HexToAddress(params.TaskContractAddress.String())) task := &types.TaskInfo{ Name: params.TaskName, Hash: params.Hash, - TaskContractAddress: params.TaskContractAddress, + TaskContractAddress: strings.ToLower(params.TaskContractAddress.String()), TaskId: params.TaskID, TaskChallengePeriod: params.TaskChallengePeriod, ThresholdPercentage: params.ThresholdPercentage, @@ -261,46 +263,37 @@ func (k Keeper) CreateAVSTask(ctx sdk.Context, params *TaskInfoParams) error { ActualThreshold: 0, OptInOperators: operatorList, } - return k.SetTaskInfo(ctx, task) + return task.TaskId, k.SetTaskInfo(ctx, task) } -func (k Keeper) RegisterBLSPublicKey(ctx sdk.Context, params *BlsParams) error { +func (k Keeper) RegisterBLSPublicKey(ctx sdk.Context, params *types.BlsParams) error { // check bls signature to prevent rogue key attacks sig := params.PubkeyRegistrationSignature msgHash := params.PubkeyRegistrationMessageHash pubKey, _ := bls.PublicKeyFromBytes(params.PubKey) valid, err := blst.VerifySignature(sig, [32]byte(msgHash), pubKey) if err != nil || !valid { - return errorsmod.Wrap(types.ErrSigNotMatchPubKey, fmt.Sprintf("the operator is :%s", params.Operator)) + return errorsmod.Wrap(types.ErrSigNotMatchPubKey, fmt.Sprintf("the operator is :%s", params.OperatorAddress)) } - if k.IsExistPubKey(ctx, params.Operator) { - return errorsmod.Wrap(types.ErrAlreadyExists, fmt.Sprintf("the operator is :%s", params.Operator)) + if k.IsExistPubKey(ctx, params.OperatorAddress.String()) { + return errorsmod.Wrap(types.ErrAlreadyExists, fmt.Sprintf("the operator is :%s", params.OperatorAddress)) } bls := &types.BlsPubKeyInfo{ Name: params.Name, - Operator: params.Operator, + Operator: strings.ToLower(params.OperatorAddress.String()), PubKey: params.PubKey, } return k.SetOperatorPubKey(ctx, bls) } -func (k Keeper) GetOptInOperators(ctx sdk.Context, avsAddr string) ([]string, error) { - return k.operatorKeeper.GetOptedInOperatorListByAVS(ctx, avsAddr) -} - -func (k Keeper) OperatorOptAction(ctx sdk.Context, params *OperatorOptParams) error { - operatorAddress := params.OperatorAddress - opAccAddr, err := sdk.AccAddressFromBech32(operatorAddress) - if err != nil { - return errorsmod.Wrap(err, fmt.Sprintf("error occurred when parse acc address from Bech32,the addr is:%s", operatorAddress)) - } - +func (k Keeper) OperatorOptAction(ctx sdk.Context, params *types.OperatorOptParams) error { + opAccAddr := params.OperatorAddress if !k.operatorKeeper.IsOperator(ctx, opAccAddr) { - return errorsmod.Wrap(delegationtypes.ErrOperatorNotExist, fmt.Sprintf("UpdateAVSInfo: invalid operator address:%s", operatorAddress)) + return errorsmod.Wrap(delegationtypes.ErrOperatorNotExist, fmt.Sprintf("UpdateAVSInfo: invalid operator address:%s", opAccAddr.String())) } - f, err := k.IsAVS(ctx, params.AvsAddress) + f, err := k.IsAVS(ctx, params.AvsAddress.String()) if err != nil { return errorsmod.Wrap(err, fmt.Sprintf("error occurred when get avs info,this avs address: %s", params.AvsAddress)) } @@ -309,10 +302,10 @@ func (k Keeper) OperatorOptAction(ctx sdk.Context, params *OperatorOptParams) er } switch params.Action { - case RegisterAction: - return k.operatorKeeper.OptIn(ctx, opAccAddr, params.AvsAddress) - case DeRegisterAction: - return k.operatorKeeper.OptOut(ctx, opAccAddr, params.AvsAddress) + case types.RegisterAction: + return k.operatorKeeper.OptIn(ctx, opAccAddr, strings.ToLower(params.AvsAddress.String())) + case types.DeRegisterAction: + return k.operatorKeeper.OptOut(ctx, opAccAddr, strings.ToLower(params.AvsAddress.String())) default: return errorsmod.Wrap(types.ErrInvalidAction, fmt.Sprintf("Invalid action: %d", params.Action)) } @@ -386,7 +379,7 @@ func (k Keeper) IterateAVSInfo(ctx sdk.Context, fn func(index int64, avsInfo typ } } -func (k Keeper) RaiseAndResolveChallenge(ctx sdk.Context, params *ChallengeParams) error { +func (k Keeper) RaiseAndResolveChallenge(ctx sdk.Context, params *types.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) @@ -424,6 +417,9 @@ func (k Keeper) RaiseAndResolveChallenge(ctx sdk.Context, params *ChallengeParam // check challenge period // check epoch,The challenge must be within the challenge window period avsInfo := k.GetAVSInfoByTaskAddress(ctx, taskInfo.TaskContractAddress) + if avsInfo.AvsAddress == "" { + return errorsmod.Wrap(types.ErrUnregisterNonExistent, fmt.Sprintf("the taskaddr is :%s", taskInfo.TaskContractAddress)) + } epoch, found := k.epochsKeeper.GetEpochInfo(ctx, avsInfo.EpochIdentifier) if !found { return errorsmod.Wrap(types.ErrEpochNotFound, fmt.Sprintf("epoch info not found %s", @@ -441,6 +437,6 @@ func (k Keeper) RaiseAndResolveChallenge(ctx sdk.Context, params *ChallengeParam fmt.Sprintf("SetTaskResultInfo:submit too late, CurrentEpoch:%d", epoch.CurrentEpoch), ) } - return k.SetTaskChallengedInfo(ctx, params.TaskID, params.OperatorAddress.String(), params.CallerAddress, + return k.SetTaskChallengedInfo(ctx, params.TaskID, params.OperatorAddress.String(), params.CallerAddress.String(), params.TaskContractAddress) } diff --git a/x/avs/keeper/multi_operator_submit_task_test.go b/x/avs/keeper/multi_operator_submit_task_test.go index dda8de157..9c17628a6 100644 --- a/x/avs/keeper/multi_operator_submit_task_test.go +++ b/x/avs/keeper/multi_operator_submit_task_test.go @@ -7,7 +7,6 @@ import ( sdkmath "cosmossdk.io/math" assetskeeper "github.com/ExocoreNetwork/exocore/x/assets/keeper" assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" - avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types" epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types" @@ -86,13 +85,13 @@ func (suite *AVSTestSuite) prepareMulDelegation(operatorAddress sdk.AccAddress, func (suite *AVSTestSuite) prepareMulAvs(assetIDs []string) { err := suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, &avstypes.AVSRegisterOrDeregisterParams{ AvsName: "avs01", - Action: avskeeper.RegisterAction, + Action: avstypes.RegisterAction, EpochIdentifier: epochstypes.HourEpochID, - AvsAddress: suite.avsAddr, + AvsAddress: common.HexToAddress(suite.avsAddr), AssetID: assetIDs, - TaskAddr: suite.taskAddress.String(), - SlashContractAddr: "", - RewardContractAddr: "", + TaskAddr: suite.taskAddress, + SlashContractAddr: common.Address{}, + RewardContractAddr: common.Address{}, MinSelfDelegation: 0, AvsOwnerAddress: nil, UnbondingPeriod: 7, @@ -202,7 +201,7 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseOne_Mul() { TaskResponseHash: "", TaskResponse: nil, BlsSignature: sig.Marshal(), - Stage: avstypes.TwoPhaseCommitOne, + Phase: avstypes.Phase(avstypes.PhasePrepare), } err := suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, operatorAddress, info) suite.Require().NoError(err) @@ -230,7 +229,7 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseTwo_Mul() { TaskResponseHash: hash.String(), TaskResponse: jsonData, BlsSignature: sig.Marshal(), - Stage: avstypes.TwoPhaseCommitTwo, + Phase: avstypes.Phase(avstypes.PhaseDoCommit), } err = suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, operatorAddress, info) suite.NoError(err) diff --git a/x/avs/keeper/params.go b/x/avs/keeper/params.go index 5db1b8d13..22740d996 100644 --- a/x/avs/keeper/params.go +++ b/x/avs/keeper/params.go @@ -3,8 +3,6 @@ package keeper import ( "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/ExocoreNetwork/exocore/x/avs/types" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" @@ -32,72 +30,3 @@ func (k Keeper) SetParams(ctx sdk.Context, params *types.Params) error { store.Set(types.ParamsKey, bz) return nil } - -type OperatorOptParams struct { - Name string - BlsPublicKey string - IsRegistered bool - Action uint64 - OperatorAddress string - Status string - AvsAddress string -} - -type TaskInfoParams struct { - TaskContractAddress string `json:"task_contract_address"` - TaskName string `json:"name"` - Hash []byte `json:"hash"` - TaskID uint64 `json:"task_id"` - TaskResponsePeriod uint64 `json:"task_response_period"` - TaskStatisticalPeriod uint64 `json:"task_statistical_period"` - TaskChallengePeriod uint64 `json:"task_challenge_period"` - ThresholdPercentage uint64 `json:"threshold_percentage"` - StartingEpoch uint64 `json:"starting_epoch"` - OperatorAddress string `json:"operator_address"` - TaskResponseHash string `json:"task_response_hash"` - TaskResponse []byte `json:"task_response"` - BlsSignature []byte `json:"bls_signature"` - Stage string `json:"stage"` - ActualThreshold uint64 `json:"actual_threshold"` - OptInCount uint64 `json:"opt_in_count"` - SignedCount uint64 `json:"signed_count"` - NoSignedCount uint64 `json:"no_signed_count"` - ErrSignedCount uint64 `json:"err_signed_count"` - CallerAddress string `json:"caller_address"` -} -type BlsParams struct { - Operator string - Name string - PubKey []byte - PubkeyRegistrationSignature []byte - PubkeyRegistrationMessageHash []byte -} - -type ProofParams struct { - TaskID string - TaskContractAddress string - AvsAddress string - Aggregator string - OperatorStatus []OperatorStatusParams - CallerAddress string -} -type OperatorStatusParams struct { - OperatorAddress string - Status string - ProofData string -} - -const ( - RegisterAction = 1 - 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 string `json:"caller_address"` -} diff --git a/x/avs/keeper/submit_task_test.go b/x/avs/keeper/submit_task_test.go index ce266cd3b..1302b7e06 100644 --- a/x/avs/keeper/submit_task_test.go +++ b/x/avs/keeper/submit_task_test.go @@ -1,15 +1,15 @@ package keeper_test import ( - "github.com/ethereum/go-ethereum/common/math" "math/big" "strconv" "time" + "github.com/ethereum/go-ethereum/common/math" + sdkmath "cosmossdk.io/math" assetskeeper "github.com/ExocoreNetwork/exocore/x/assets/keeper" assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" - avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" delegationtype "github.com/ExocoreNetwork/exocore/x/delegation/types" epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types" @@ -79,13 +79,13 @@ func (suite *AVSTestSuite) prepareDelegation(isDelegation bool, assetAddr common func (suite *AVSTestSuite) prepareAvs(assetIDs []string) { err := suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, &avstypes.AVSRegisterOrDeregisterParams{ AvsName: "avs01", - Action: avskeeper.RegisterAction, + Action: avstypes.RegisterAction, EpochIdentifier: epochstypes.HourEpochID, - AvsAddress: suite.avsAddr, + AvsAddress: common.HexToAddress(suite.avsAddr), AssetID: assetIDs, - TaskAddr: suite.taskAddress.String(), - SlashContractAddr: "", - RewardContractAddr: "", + TaskAddr: suite.taskAddress, + SlashContractAddr: common.Address{}, + RewardContractAddr: common.Address{}, MinSelfDelegation: 3, AvsOwnerAddress: nil, UnbondingPeriod: 7, @@ -143,7 +143,7 @@ func (suite *AVSTestSuite) prepareTaskInfo() { err = suite.App.AVSManagerKeeper.SetTaskInfo(suite.Ctx, info) suite.NoError(err) - getTaskInfo, err := suite.App.AVSManagerKeeper.GetTaskInfo(suite.Ctx, strconv.FormatUint(suite.taskId, 10), common.Address(suite.taskAddress.Bytes()).String()) + getTaskInfo, err := suite.App.AVSManagerKeeper.GetTaskInfo(suite.Ctx, strconv.Itoa(int(suite.taskId)), common.Address(suite.taskAddress.Bytes()).String()) suite.NoError(err) suite.Equal(*info, *getTaskInfo) } @@ -188,7 +188,7 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseOne() { TaskResponseHash: "", TaskResponse: nil, BlsSignature: sig.Marshal(), - Stage: avstypes.TwoPhaseCommitOne, + Phase: avstypes.Phase(avstypes.PhasePrepare), } err = suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, suite.operatorAddr.String(), info) suite.NoError(err) @@ -217,7 +217,7 @@ func (suite *AVSTestSuite) TestSubmitTask_OnlyPhaseTwo() { TaskResponseHash: hash.String(), TaskResponse: jsonData, BlsSignature: sig.Marshal(), - Stage: avstypes.TwoPhaseCommitTwo, + Phase: avstypes.Phase(avstypes.PhaseDoCommit), } err = suite.App.AVSManagerKeeper.SetTaskResultInfo(suite.Ctx, suite.operatorAddr.String(), info) suite.NoError(err) diff --git a/x/avs/keeper/task.go b/x/avs/keeper/task.go index f748a3d7c..3dd890c6d 100644 --- a/x/avs/keeper/task.go +++ b/x/avs/keeper/task.go @@ -5,6 +5,7 @@ import ( "fmt" "sort" "strconv" + "strings" "github.com/ethereum/go-ethereum/crypto" @@ -24,7 +25,7 @@ func (k Keeper) SetTaskInfo(ctx sdk.Context, task *types.TaskInfo) (err error) { return types.ErrInvalidAddr } store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixAVSTaskInfo) - infoKey := assetstype.GetJoinedStoreKey(task.TaskContractAddress, strconv.FormatUint(task.TaskId, 10)) + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(task.TaskContractAddress), strconv.FormatUint(task.TaskId, 10)) bz := k.cdc.MustMarshal(task) store.Set(infoKey, bz) return nil @@ -35,7 +36,7 @@ func (k *Keeper) GetTaskInfo(ctx sdk.Context, taskID, taskContractAddress string return nil, types.ErrInvalidAddr } store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixAVSTaskInfo) - infoKey := assetstype.GetJoinedStoreKey(taskContractAddress, taskID) + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(taskContractAddress), taskID) value := store.Get(infoKey) if value == nil { return nil, errorsmod.Wrap(types.ErrNoKeyInTheStore, @@ -49,7 +50,7 @@ func (k *Keeper) GetTaskInfo(ctx sdk.Context, taskID, taskContractAddress string func (k *Keeper) IsExistTask(ctx sdk.Context, taskID, taskContractAddress string) bool { store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixAVSTaskInfo) - infoKey := assetstype.GetJoinedStoreKey(taskContractAddress, taskID) + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(taskContractAddress), taskID) return store.Has(infoKey) } @@ -171,18 +172,21 @@ func (k *Keeper) SetTaskResultInfo( } // check prescribed period - // If submitted in the first stage, in order to avoid plagiarism by other operators, + // If submitted in the first phase, 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 + // At the same time, it must be submitted within the response deadline in the first phase avsInfo := k.GetAVSInfoByTaskAddress(ctx, info.TaskContractAddress) + if avsInfo.AvsAddress == "" { + return errorsmod.Wrap(types.ErrUnregisterNonExistent, fmt.Sprintf("the taskaddr is :%s", 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: + switch info.Phase { + case types.PhasePrepare: if k.IsExistTaskResultInfo(ctx, info.OperatorAddress, info.TaskContractAddress, info.TaskId) { return errorsmod.Wrap( types.ErrResAlreadyExists, @@ -205,7 +209,7 @@ func (k *Keeper) SetTaskResultInfo( info.TaskResponseHash, info.TaskResponse), ) } - // check epoch,The first stage submission must be within the response window period + // check epoch,The first phase submission must be within the response window period // #nosec G115 if epoch.CurrentEpoch > int64(task.StartingEpoch)+int64(task.TaskResponsePeriod) { return errorsmod.Wrap( @@ -213,14 +217,14 @@ func (k *Keeper) SetTaskResultInfo( fmt.Sprintf("SetTaskResultInfo:submit too late, CurrentEpoch:%d", epoch.CurrentEpoch), ) } - infoKey := assetstype.GetJoinedStoreKey(info.OperatorAddress, info.TaskContractAddress, + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(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) return nil - case types.TwoPhaseCommitTwo: + case types.PhaseDoCommit: // check task response if info.TaskResponse == nil { return errorsmod.Wrap( @@ -239,7 +243,7 @@ func (k *Keeper) SetTaskResultInfo( info.OperatorAddress, info.TaskContractAddress, info.TaskId, info.BlsSignature), ) } - // check epoch,The second stage submission must be within the statistical window period + // check epoch,The second phase submission must be within the statistical window period // #nosec G115 if epoch.CurrentEpoch <= int64(task.StartingEpoch)+int64(task.TaskResponsePeriod) { return errorsmod.Wrap( @@ -274,7 +278,7 @@ func (k *Keeper) SetTaskResultInfo( ) } - infoKey := assetstype.GetJoinedStoreKey(info.OperatorAddress, info.TaskContractAddress, strconv.FormatUint(info.TaskId, 10)) + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(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) @@ -283,13 +287,13 @@ func (k *Keeper) SetTaskResultInfo( default: return errorsmod.Wrap( types.ErrParamError, - fmt.Sprintf("SetTaskResultInfo: invalid param value:%s", info.Stage), + fmt.Sprintf("SetTaskResultInfo: invalid param value:%d", info.Phase), ) } } func (k *Keeper) IsExistTaskResultInfo(ctx sdk.Context, operatorAddress, taskContractAddress string, taskID uint64) bool { - infoKey := assetstype.GetJoinedStoreKey(operatorAddress, taskContractAddress, + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(operatorAddress), strings.ToLower(taskContractAddress), strconv.FormatUint(taskID, 10)) store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskResult) return store.Has(infoKey) @@ -300,7 +304,7 @@ func (k *Keeper) GetTaskResultInfo(ctx sdk.Context, operatorAddress, taskContrac return nil, types.ErrInvalidAddr } store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskResult) - infoKey := assetstype.GetJoinedStoreKey(operatorAddress, taskContractAddress, + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(operatorAddress), strings.ToLower(taskContractAddress), strconv.FormatUint(taskID, 10)) value := store.Get(infoKey) if value == nil { @@ -359,7 +363,7 @@ func (k *Keeper) SetTaskChallengedInfo( ctx sdk.Context, taskID uint64, operatorAddress, challengeAddr string, taskAddr common.Address, ) (err error) { - infoKey := assetstype.GetJoinedStoreKey(operatorAddress, taskAddr.String(), + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(operatorAddress), strings.ToLower(taskAddr.String()), strconv.FormatUint(taskID, 10)) store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskChallengeResult) @@ -373,7 +377,7 @@ func (k *Keeper) SetTaskChallengedInfo( } func (k *Keeper) IsExistTaskChallengedInfo(ctx sdk.Context, operatorAddress, taskContractAddress string, taskID uint64) bool { - infoKey := assetstype.GetJoinedStoreKey(operatorAddress, taskContractAddress, + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(operatorAddress), strings.ToLower(taskContractAddress), strconv.FormatUint(taskID, 10)) store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskChallengeResult) return store.Has(infoKey) @@ -384,7 +388,7 @@ func (k *Keeper) GetTaskChallengedInfo(ctx sdk.Context, operatorAddress, taskCon return "", types.ErrInvalidAddr } store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefixTaskChallengeResult) - infoKey := assetstype.GetJoinedStoreKey(operatorAddress, taskContractAddress, + infoKey := assetstype.GetJoinedStoreKey(strings.ToLower(operatorAddress), strings.ToLower(taskContractAddress), strconv.FormatUint(taskID, 10)) value := store.Get(infoKey) if value == nil { diff --git a/x/avs/types/errors.go b/x/avs/types/errors.go index f052ea0a1..3db686b13 100644 --- a/x/avs/types/errors.go +++ b/x/avs/types/errors.go @@ -76,12 +76,12 @@ var ( ErrParamError = errorsmod.Register( ModuleName, 18, - "The parameter must be 1 or 2", + "The parameter must be 0 or 1", ) ErrParamNotEmptyError = errorsmod.Register( ModuleName, 19, - "In the first stage, the parameter must be empty.", + "In the first phase, the parameter must be empty.", ) ErrSubmitTooLateError = errorsmod.Register( ModuleName, 20, diff --git a/x/avs/types/expected_keepers.go b/x/avs/types/expected_keepers.go index e60ddc94e..0aab387f0 100644 --- a/x/avs/types/expected_keepers.go +++ b/x/avs/types/expected_keepers.go @@ -42,6 +42,8 @@ type OperatorKeeper interface { GetOptedInOperatorListByAVS(ctx sdk.Context, avsAddr string) ([]string, error) GetOperatorOptedUSDValue(ctx sdk.Context, avsAddr, operatorAddr string) (operatortypes.OperatorOptedUSDValue, error) GetAVSUSDValue(ctx sdk.Context, avsAddr string) (sdkmath.LegacyDec, error) + SetOperatorInfo(ctx sdk.Context, addr string, info *operatortypes.OperatorInfo) (err error) + OperatorInfo(ctx sdk.Context, addr string) (info *operatortypes.OperatorInfo, err error) } // AssetsKeeper represents the expected keeper interface for the assets module. diff --git a/x/avs/types/stage.go b/x/avs/types/stage.go deleted file mode 100644 index 3486737c7..000000000 --- a/x/avs/types/stage.go +++ /dev/null @@ -1,8 +0,0 @@ -package types - -const ( - // TwoPhaseCommitOne The first stage of the two-stage submission. - TwoPhaseCommitOne = "1" - // TwoPhaseCommitTwo The second stage of submission. - TwoPhaseCommitTwo = "2" -) diff --git a/x/avs/types/tx.pb.go b/x/avs/types/tx.pb.go index 99a74f995..d54782356 100644 --- a/x/avs/types/tx.pb.go +++ b/x/avs/types/tx.pb.go @@ -33,6 +33,38 @@ var _ = math.Inf // proto package needs to be updated. const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package +// It is a two-phase submission with two values, 1 and 2 +type Phase int32 + +const ( + // Default value when phase is not specified + PhaseUnspecified Phase = 0 + // First phase where operators prepare and submit their initial responses + PhasePrepare Phase = 1 + // Second phase where operators commit their prepared responses + PhaseDoCommit Phase = 2 +) + +var Phase_name = map[int32]string{ + 0: "PHASE_UNSPECIFIED", + 1: "PHASE_PREPARE", + 2: "PHASE_DO_COMMIT", +} + +var Phase_value = map[string]int32{ + "PHASE_UNSPECIFIED": 0, + "PHASE_PREPARE": 1, + "PHASE_DO_COMMIT": 2, +} + +func (x Phase) String() string { + return proto.EnumName(Phase_name, int32(x)) +} + +func (Phase) EnumDescriptor() ([]byte, []int) { + return fileDescriptor_ef1ed06249b07d86, []int{0} +} + // AVSinfo represent the information of avs type AVSInfo struct { // name of avs as an arbitrary string @@ -1012,9 +1044,9 @@ type TaskResultInfo struct { TaskContractAddress string `protobuf:"bytes,5,opt,name=task_contract_address,json=taskContractAddress,proto3" json:"task_contract_address,omitempty"` // task_id is the task id TaskId uint64 `protobuf:"varint,6,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"` - // stage this field is used to solve the problem of task results being copied by other operators. - // It is a two-stage submission with two values, 1 and 2 - Stage string `protobuf:"bytes,7,opt,name=stage,proto3" json:"stage,omitempty"` + // phase this field is used to solve the problem of task results being copied by other operators. + // It is a two-phase submission with two values, 1 and 2 + Phase Phase `protobuf:"varint,7,opt,name=phase,proto3,enum=exocore.avs.v1.Phase" json:"phase,omitempty"` } func (m *TaskResultInfo) Reset() { *m = TaskResultInfo{} } @@ -1092,11 +1124,11 @@ func (m *TaskResultInfo) GetTaskId() uint64 { return 0 } -func (m *TaskResultInfo) GetStage() string { +func (m *TaskResultInfo) GetPhase() Phase { if m != nil { - return m.Stage + return m.Phase } - return "" + return PhaseUnspecified } // SubmitTaskResultReq is the request to submit task results. @@ -1178,6 +1210,7 @@ func (m *SubmitTaskResultResponse) XXX_DiscardUnknown() { var xxx_messageInfo_SubmitTaskResultResponse proto.InternalMessageInfo func init() { + proto.RegisterEnum("exocore.avs.v1.Phase", Phase_name, Phase_value) proto.RegisterType((*AVSInfo)(nil), "exocore.avs.v1.AVSInfo") proto.RegisterMapType((map[string]int64)(nil), "exocore.avs.v1.AVSInfo.AssetRewardAmountEpochBasisEntry") proto.RegisterType((*OperatorStatus)(nil), "exocore.avs.v1.OperatorStatus") @@ -1200,112 +1233,119 @@ func init() { func init() { proto.RegisterFile("exocore/avs/v1/tx.proto", fileDescriptor_ef1ed06249b07d86) } var fileDescriptor_ef1ed06249b07d86 = []byte{ - // 1667 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0xcf, 0x6f, 0x1b, 0xc7, - 0x15, 0xd6, 0x4a, 0x94, 0x44, 0x3e, 0x52, 0x14, 0x35, 0xa2, 0xc3, 0x35, 0xdd, 0x92, 0xc2, 0xba, - 0x4e, 0x64, 0x25, 0x26, 0x6d, 0xa5, 0x28, 0x0c, 0xf7, 0x24, 0x55, 0x6e, 0x2a, 0xa4, 0xb1, 0x85, - 0xa5, 0x9a, 0x16, 0xed, 0x61, 0x31, 0xe4, 0x8e, 0x56, 0x0b, 0x2d, 0x77, 0xd8, 0x9d, 0x21, 0x6d, - 0xf7, 0x50, 0x14, 0x3e, 0x15, 0x41, 0x51, 0xb4, 0x08, 0xd0, 0x73, 0xee, 0xbd, 0x18, 0x45, 0x2e, - 0x05, 0xda, 0x7b, 0x8e, 0x41, 0x7a, 0x29, 0x7a, 0x30, 0x0a, 0xb9, 0x80, 0xdb, 0xff, 0xa2, 0x98, - 0x37, 0xb3, 0x14, 0x97, 0x94, 0xac, 0xba, 0x39, 0x24, 0x17, 0x73, 0xe7, 0xfd, 0x9a, 0xef, 0xbd, - 0x79, 0xef, 0x9b, 0xb1, 0xa0, 0xc6, 0x1e, 0xf3, 0x1e, 0x4f, 0x58, 0x9b, 0x8e, 0x44, 0x7b, 0x74, - 0xa7, 0x2d, 0x1f, 0xb7, 0x06, 0x09, 0x97, 0x9c, 0x94, 0x8d, 0xa2, 0x45, 0x47, 0xa2, 0x35, 0xba, - 0x53, 0x5f, 0xa3, 0xfd, 0x30, 0xe6, 0x6d, 0xfc, 0x57, 0x9b, 0xd4, 0x6b, 0x3d, 0x2e, 0xfa, 0x5c, - 0xb4, 0xfb, 0x22, 0x50, 0xae, 0x7d, 0x11, 0x18, 0xc5, 0x55, 0xad, 0xf0, 0x70, 0xd5, 0xd6, 0x0b, - 0xa3, 0xaa, 0x06, 0x3c, 0xe0, 0x5a, 0xae, 0xbe, 0x8c, 0xf4, 0x1b, 0x01, 0xe7, 0x41, 0xc4, 0xda, - 0x74, 0x10, 0xb6, 0x69, 0x1c, 0x73, 0x49, 0x65, 0xc8, 0x63, 0xe3, 0xe3, 0xfc, 0x75, 0x19, 0x96, - 0x77, 0x3e, 0xec, 0xec, 0xc7, 0x47, 0x9c, 0x10, 0xc8, 0xc5, 0xb4, 0xcf, 0x6c, 0x6b, 0xc3, 0xda, - 0x2c, 0xb8, 0xf8, 0x4d, 0x9a, 0x50, 0xa4, 0x23, 0xe1, 0x51, 0xdf, 0x4f, 0x98, 0x10, 0xf6, 0x3c, - 0xaa, 0x80, 0x8e, 0xc4, 0x8e, 0x96, 0x90, 0x4d, 0xa8, 0xf4, 0xc3, 0xd8, 0x13, 0x92, 0x9e, 0x30, - 0x8f, 0xf6, 0xf9, 0x30, 0x96, 0xf6, 0xc2, 0x86, 0xb5, 0x99, 0x73, 0xcb, 0xfd, 0x30, 0xee, 0x28, - 0xf1, 0x0e, 0x4a, 0xc9, 0x35, 0x28, 0x48, 0x2a, 0x4e, 0x30, 0x96, 0x9d, 0xc3, 0x40, 0x79, 0x25, - 0x50, 0x91, 0xc8, 0x37, 0x01, 0x44, 0x44, 0xc5, 0xb1, 0xd6, 0x2e, 0xa2, 0xb6, 0x80, 0x12, 0x54, - 0x37, 0xa1, 0x98, 0xb0, 0x47, 0x34, 0xf1, 0xb5, 0x7e, 0x49, 0xc3, 0xd0, 0x22, 0x34, 0xd8, 0x82, - 0x35, 0x85, 0x93, 0x3f, 0x8a, 0x59, 0x32, 0x46, 0xbb, 0xbc, 0xb1, 0xb0, 0x59, 0x70, 0x57, 0xe9, - 0x48, 0x3c, 0x54, 0xf2, 0x14, 0xf2, 0x4d, 0x28, 0x50, 0x21, 0x98, 0xf4, 0x42, 0x5f, 0xd8, 0x79, - 0x65, 0xb3, 0x5b, 0x3a, 0x7d, 0xde, 0xcc, 0xef, 0x28, 0xe1, 0xfe, 0x9e, 0x70, 0xf3, 0xa8, 0xde, - 0xf7, 0x05, 0xb9, 0x0d, 0x55, 0x15, 0x76, 0x18, 0x77, 0x79, 0xec, 0x87, 0x71, 0xe0, 0x0d, 0x58, - 0x12, 0x72, 0xdf, 0x2e, 0x60, 0x86, 0x84, 0x8e, 0xc4, 0x8f, 0x52, 0xd5, 0x01, 0x6a, 0x48, 0x0b, - 0xd6, 0xb1, 0x1e, 0x2c, 0x3a, 0xf2, 0x7c, 0x16, 0xb1, 0x00, 0xcb, 0x6d, 0x03, 0x3a, 0xac, 0xa9, - 0x92, 0xb0, 0xe8, 0x68, 0x6f, 0xac, 0x20, 0x37, 0xa1, 0xc2, 0x06, 0xbc, 0x77, 0xec, 0x85, 0x3e, - 0x8b, 0x65, 0x78, 0x14, 0xb2, 0xc4, 0x2e, 0x62, 0x7a, 0xab, 0x28, 0xdf, 0x1f, 0x8b, 0x49, 0x1b, - 0xaa, 0x2a, 0x34, 0x1f, 0x48, 0x0f, 0x7f, 0x58, 0x42, 0x25, 0x4f, 0x84, 0x5d, 0x1a, 0xc7, 0x7e, - 0x38, 0x90, 0xfb, 0xf1, 0xc3, 0x54, 0x41, 0xde, 0x85, 0x37, 0x94, 0x83, 0xe4, 0x92, 0x46, 0xd9, - 0x13, 0x5a, 0x41, 0x17, 0x85, 0xf4, 0x50, 0x29, 0x27, 0x8f, 0xe9, 0x06, 0x94, 0x85, 0xa4, 0x89, - 0x54, 0xd9, 0x22, 0x02, 0xbb, 0x8c, 0xc6, 0x2b, 0xa9, 0xf4, 0xbe, 0x12, 0x92, 0xab, 0x90, 0xef, - 0x1d, 0xd3, 0x30, 0xf6, 0x42, 0xdf, 0x5e, 0x45, 0xbc, 0xcb, 0xb8, 0xde, 0xf7, 0xc9, 0x07, 0xa0, - 0x1a, 0xc4, 0xd3, 0xa7, 0x63, 0x57, 0x94, 0x72, 0xb7, 0xf5, 0xd9, 0xf3, 0xe6, 0xdc, 0x3f, 0x9e, - 0x37, 0xdf, 0x0c, 0x42, 0x79, 0x3c, 0xec, 0xb6, 0x7a, 0xbc, 0x6f, 0x9a, 0xd7, 0xfc, 0xdc, 0x12, - 0xfe, 0x49, 0x5b, 0x3e, 0x19, 0x30, 0xd1, 0xda, 0x63, 0x3d, 0xb7, 0x40, 0x47, 0xc2, 0xc5, 0x00, - 0xe4, 0x7d, 0x50, 0x0b, 0x0f, 0x9b, 0xc1, 0x5e, 0xfb, 0xbf, 0xa2, 0xe5, 0xe9, 0x48, 0x74, 0x94, - 0x3f, 0xf9, 0x25, 0x34, 0xf5, 0xd9, 0xa7, 0xed, 0x84, 0x49, 0xeb, 0x44, 0xbd, 0x2e, 0x15, 0xa1, - 0xb0, 0xc9, 0xc6, 0xc2, 0x66, 0x71, 0xfb, 0x6e, 0x2b, 0x3b, 0xa4, 0x2d, 0x33, 0x25, 0x2d, 0xec, - 0x12, 0x0d, 0x4d, 0x57, 0x0c, 0xeb, 0xb1, 0xab, 0x5c, 0xef, 0xc7, 0x32, 0x79, 0xe2, 0x5e, 0xa3, - 0x17, 0x5b, 0xd4, 0x1f, 0xc0, 0xc6, 0x65, 0x01, 0x48, 0x05, 0x16, 0x4e, 0xd8, 0x13, 0x33, 0x86, - 0xea, 0x93, 0x54, 0x61, 0x71, 0x44, 0xa3, 0x21, 0xc3, 0xf9, 0x5b, 0x70, 0xf5, 0xe2, 0xde, 0xfc, - 0x5d, 0xcb, 0x49, 0xa0, 0x9c, 0x9e, 0x77, 0x47, 0x52, 0x39, 0x54, 0xdd, 0x5d, 0x49, 0x5b, 0x63, - 0x3c, 0x08, 0x3a, 0xd4, 0x6a, 0x2a, 0x4f, 0x07, 0xe1, 0x0d, 0x58, 0x12, 0xe8, 0x64, 0xe6, 0xda, - 0xac, 0xd4, 0x30, 0x0e, 0x12, 0xce, 0x8f, 0x3c, 0x9f, 0x4a, 0x8a, 0xd3, 0x5c, 0x72, 0x0b, 0x28, - 0xd9, 0xa3, 0x92, 0x3a, 0xff, 0xb1, 0xa0, 0xa2, 0xf1, 0x63, 0x4d, 0x0f, 0x94, 0x82, 0xd4, 0x60, - 0x19, 0xa7, 0x3b, 0xf4, 0xcd, 0x6e, 0x4b, 0x6a, 0xb9, 0xef, 0x93, 0x6d, 0xb8, 0x82, 0x8a, 0x1e, - 0x8f, 0x65, 0x42, 0x7b, 0x72, 0x8a, 0x4b, 0xd6, 0x95, 0xf2, 0x7b, 0x46, 0x97, 0x02, 0x6b, 0x00, - 0xd0, 0x20, 0x48, 0xd4, 0x8c, 0xf0, 0x04, 0x01, 0x28, 0xd2, 0x19, 0x4b, 0xa6, 0x59, 0x29, 0x37, - 0xc3, 0x4a, 0xef, 0xc1, 0x38, 0x59, 0xcf, 0xa4, 0xb8, 0x88, 0xc7, 0xda, 0x98, 0x3e, 0xd6, 0x6c, - 0xf5, 0xdc, 0x32, 0xcf, 0xac, 0x9d, 0x67, 0x4b, 0x90, 0x3f, 0x54, 0x89, 0x28, 0x82, 0xbc, 0x30, - 0x15, 0xeb, 0xe2, 0x54, 0x52, 0x52, 0x9d, 0x9f, 0x20, 0x55, 0x02, 0xb9, 0x63, 0xd5, 0xcc, 0xba, - 0xb2, 0xf8, 0x3d, 0x59, 0xbf, 0x1c, 0xce, 0x5b, 0x5a, 0xbf, 0xdb, 0x50, 0x45, 0x45, 0xc2, 0xc4, - 0x80, 0xc7, 0x82, 0xa5, 0x14, 0xb4, 0xa8, 0x29, 0x48, 0xe9, 0x5c, 0xa3, 0x32, 0x14, 0xf4, 0x1d, - 0xa8, 0xa1, 0x87, 0x4a, 0x3c, 0x14, 0x32, 0xec, 0xd1, 0x28, 0x75, 0x5a, 0x42, 0x27, 0xcc, 0xa2, - 0x73, 0xa6, 0x35, 0x7e, 0xe3, 0xf4, 0x8e, 0x69, 0x14, 0xb1, 0x38, 0x18, 0x6f, 0xb5, 0xac, 0xd9, - 0x02, 0xd3, 0x4b, 0x75, 0xc6, 0xe7, 0x0e, 0x54, 0xe5, 0x71, 0xc2, 0xc4, 0x31, 0x8f, 0x7c, 0x65, - 0xde, 0x63, 0xb1, 0xa4, 0x01, 0xb3, 0xf3, 0xc6, 0x25, 0xd5, 0x1d, 0x8c, 0x55, 0xe7, 0x10, 0x4c, - 0xe1, 0x3c, 0x82, 0xb9, 0x09, 0x15, 0xda, 0x93, 0x43, 0x1a, 0x79, 0xe3, 0x20, 0x86, 0x45, 0x57, - 0xb5, 0xfc, 0x30, 0x15, 0xab, 0x3b, 0x68, 0x86, 0x14, 0x8b, 0xc8, 0xfd, 0x65, 0x9e, 0x65, 0xc4, - 0x9b, 0x50, 0x11, 0x61, 0x10, 0x33, 0x3f, 0x43, 0x9f, 0x78, 0x4b, 0x68, 0xf9, 0x99, 0x69, 0x0b, - 0xd6, 0x63, 0xee, 0xcd, 0x58, 0xaf, 0xa0, 0xf5, 0x5a, 0xcc, 0x3b, 0x53, 0xf6, 0xb7, 0xa1, 0xca, - 0x92, 0x64, 0xd6, 0xa1, 0x8c, 0x0e, 0x84, 0x25, 0xc9, 0xb4, 0xc7, 0x63, 0xa8, 0x60, 0xbd, 0x35, - 0x3f, 0x0f, 0xf8, 0x23, 0x96, 0x68, 0x2a, 0xdd, 0x7d, 0xf0, 0x7a, 0xfc, 0x76, 0xfa, 0xbc, 0x59, - 0x56, 0x4d, 0x8a, 0x5c, 0x7e, 0xa0, 0xe2, 0x7c, 0xf1, 0xe9, 0x2d, 0x30, 0x6f, 0x03, 0xc5, 0x7f, - 0x65, 0x99, 0xd1, 0x92, 0x9f, 0xc1, 0x95, 0x33, 0x8e, 0xe8, 0xc9, 0x70, 0xc4, 0xcc, 0xf6, 0x8a, - 0xac, 0x8b, 0xdb, 0x6f, 0x5d, 0x34, 0x24, 0x3b, 0x68, 0x8b, 0x31, 0x7e, 0x18, 0x0a, 0xe9, 0xae, - 0xf3, 0x59, 0x85, 0x93, 0x40, 0xed, 0x02, 0x7b, 0xf2, 0x63, 0x18, 0x7b, 0xe8, 0x0d, 0xbd, 0x28, - 0x14, 0xd2, 0xb6, 0x70, 0x34, 0xff, 0x97, 0x5d, 0xd5, 0x18, 0xba, 0x6b, 0x69, 0x8c, 0x71, 0x60, - 0xe7, 0x4f, 0xd6, 0xb9, 0x9b, 0xe2, 0xd4, 0x5e, 0x87, 0x95, 0x0c, 0x21, 0x9a, 0x69, 0x2d, 0x4d, - 0xb2, 0x21, 0x49, 0xa0, 0x94, 0x29, 0x04, 0x8e, 0xeb, 0xee, 0xc3, 0xd7, 0x3e, 0x87, 0x55, 0x75, - 0xbd, 0x4f, 0x20, 0x98, 0x3a, 0x88, 0x22, 0x9d, 0x28, 0xd4, 0x4f, 0x60, 0x65, 0x37, 0x12, 0x07, - 0xc3, 0xee, 0xfb, 0xec, 0x09, 0x22, 0xad, 0x43, 0x3e, 0x05, 0x65, 0x40, 0x8e, 0xd7, 0xe7, 0xf2, - 0x48, 0x0d, 0x96, 0x07, 0xc3, 0xae, 0xa7, 0x2e, 0x0b, 0x4d, 0x25, 0x4b, 0x03, 0x0c, 0xe6, 0xfc, - 0xd9, 0x02, 0xe2, 0xb2, 0x20, 0x14, 0x92, 0x25, 0x3b, 0x1f, 0x76, 0x0e, 0x91, 0x23, 0x7e, 0x4e, - 0xbe, 0x0b, 0xa5, 0xa3, 0x84, 0xf7, 0xb3, 0xb4, 0xb5, 0x6b, 0x7f, 0xf1, 0xe9, 0xad, 0xaa, 0xc1, - 0x68, 0x58, 0xab, 0x23, 0x93, 0x30, 0x0e, 0xdc, 0xa2, 0xb2, 0x4e, 0x89, 0xec, 0x1d, 0xc8, 0xa9, - 0x2e, 0x42, 0x00, 0xc5, 0x6d, 0x7b, 0xfa, 0xb0, 0x52, 0x92, 0x74, 0xd1, 0xea, 0xde, 0xdd, 0x5f, - 0x7f, 0xd2, 0x9c, 0xfb, 0xf7, 0x27, 0xcd, 0xb9, 0xa7, 0x2f, 0x9f, 0x6d, 0x15, 0xbf, 0x7f, 0x16, - 0xe7, 0xa3, 0x97, 0xcf, 0xb6, 0xae, 0x4d, 0x14, 0xef, 0x70, 0x82, 0x33, 0x95, 0xbf, 0x73, 0x15, - 0x6a, 0x33, 0xd0, 0x35, 0xbd, 0x39, 0xbf, 0xb1, 0xa0, 0x3c, 0xa1, 0xfb, 0xd2, 0x29, 0xbd, 0x0d, - 0xb9, 0x30, 0x3e, 0xe2, 0x26, 0xa5, 0xda, 0x05, 0x37, 0xbe, 0x8b, 0x46, 0xf7, 0x2a, 0xd3, 0x99, - 0x38, 0xbf, 0xb7, 0x60, 0x3d, 0x03, 0x47, 0xc3, 0xfc, 0x4a, 0x31, 0xfd, 0xd6, 0x82, 0xca, 0x1e, - 0xfb, 0x1a, 0x15, 0xe9, 0x63, 0x0b, 0xae, 0x4c, 0x01, 0xfa, 0x1a, 0x94, 0xe9, 0x0f, 0xf3, 0x50, - 0x36, 0xad, 0x35, 0x8c, 0xb0, 0xef, 0x5e, 0xe7, 0xdd, 0xf4, 0x0e, 0x90, 0xec, 0x95, 0x8c, 0xb7, - 0xb9, 0x9e, 0xcc, 0xca, 0xe4, 0x85, 0xfc, 0x03, 0x75, 0xb3, 0x5f, 0x87, 0x95, 0x8c, 0xb5, 0x99, - 0xd5, 0xd2, 0xa4, 0xa1, 0x32, 0xea, 0x46, 0x02, 0x6f, 0x0f, 0x2a, 0x87, 0x09, 0xc3, 0x47, 0x40, - 0xc9, 0x2d, 0x75, 0x23, 0xd1, 0x49, 0x65, 0x17, 0xbf, 0x3f, 0x16, 0x2f, 0x7e, 0x7f, 0x4c, 0xbc, - 0x2b, 0x96, 0x32, 0xef, 0x8a, 0x2a, 0x2c, 0x0a, 0xbc, 0xaa, 0x97, 0xd1, 0x59, 0x2f, 0x9c, 0xbf, - 0x58, 0xb0, 0xde, 0x19, 0x76, 0xfb, 0xa1, 0x3c, 0x2b, 0xcf, 0x97, 0x6e, 0xa1, 0xed, 0xcc, 0x61, - 0x35, 0xce, 0xa3, 0x8e, 0xb3, 0x83, 0x30, 0x67, 0xf6, 0xed, 0x57, 0x11, 0x48, 0x6d, 0x82, 0x40, - 0x52, 0xda, 0x47, 0xf2, 0xa8, 0x83, 0x3d, 0x8b, 0x5e, 0x97, 0x78, 0xfb, 0x8f, 0x39, 0x58, 0xf8, - 0x40, 0x04, 0xe4, 0x17, 0x50, 0x9c, 0x68, 0x47, 0x32, 0x03, 0x27, 0x3b, 0x3c, 0xf5, 0xeb, 0xaf, - 0xd4, 0x1b, 0x66, 0x7a, 0xf3, 0xe9, 0xdf, 0xfe, 0xf5, 0xf1, 0xfc, 0x86, 0xd3, 0x68, 0xcf, 0xfc, - 0x9f, 0xbf, 0x3d, 0xb9, 0xd9, 0x53, 0x0b, 0x56, 0x32, 0xd3, 0x40, 0x36, 0xa6, 0xc3, 0x4f, 0x4f, - 0x6f, 0xfd, 0xc6, 0x25, 0x16, 0x06, 0xc2, 0x26, 0x42, 0x70, 0x9c, 0x8d, 0x73, 0x20, 0x64, 0xb7, - 0xfc, 0xc8, 0x82, 0xd5, 0x29, 0x8a, 0x25, 0xce, 0x2b, 0xb2, 0x34, 0xd7, 0x47, 0xfd, 0xad, 0x4b, - 0x6d, 0x0c, 0x94, 0x2d, 0x84, 0xf2, 0x2d, 0xc7, 0x79, 0x75, 0x35, 0x70, 0x63, 0x45, 0x58, 0xd3, - 0x47, 0x46, 0x66, 0x6a, 0x7e, 0x4e, 0x4b, 0xd6, 0x37, 0x2f, 0x37, 0x32, 0x78, 0xde, 0x46, 0x3c, - 0x37, 0x9c, 0xeb, 0xe7, 0xe0, 0x99, 0x76, 0xaa, 0x2f, 0xfe, 0xea, 0xe5, 0xb3, 0x2d, 0x6b, 0xf7, - 0xbd, 0xcf, 0x4e, 0x1b, 0xd6, 0xe7, 0xa7, 0x0d, 0xeb, 0x9f, 0xa7, 0x0d, 0xeb, 0x77, 0x2f, 0x1a, - 0x73, 0x9f, 0xbf, 0x68, 0xcc, 0xfd, 0xfd, 0x45, 0x63, 0xee, 0xa7, 0xb7, 0x26, 0x1e, 0x03, 0xf7, - 0x75, 0xbc, 0x07, 0x4c, 0x3e, 0xe2, 0xc9, 0xc9, 0x38, 0xfc, 0x63, 0xdc, 0x00, 0xdf, 0x05, 0xdd, - 0x25, 0xfc, 0x43, 0xcb, 0xbb, 0xff, 0x0d, 0x00, 0x00, 0xff, 0xff, 0xe6, 0x35, 0x06, 0xa1, 0x0e, - 0x12, 0x00, 0x00, + // 1787 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x41, 0x6f, 0x1b, 0xc7, + 0x15, 0xd6, 0x4a, 0x94, 0x44, 0x3e, 0x52, 0x14, 0x35, 0xa2, 0xc3, 0x35, 0xdd, 0x92, 0xc4, 0xba, + 0x76, 0x64, 0x39, 0x26, 0x6d, 0xa5, 0x28, 0x0c, 0xf7, 0x24, 0x59, 0x4a, 0x42, 0xa4, 0xb6, 0x88, + 0xa5, 0x9c, 0x16, 0xed, 0x61, 0x31, 0xe4, 0x8e, 0xc8, 0x85, 0xc8, 0x1d, 0x76, 0x67, 0x48, 0xdb, + 0x3d, 0x14, 0x85, 0x2f, 0x0d, 0x84, 0xa2, 0x68, 0x91, 0xb3, 0x81, 0x00, 0x3d, 0x16, 0x05, 0x8c, + 0x22, 0x97, 0x02, 0xed, 0x3d, 0xc7, 0x20, 0xbd, 0x14, 0x3d, 0x18, 0x85, 0x5c, 0xc0, 0xed, 0xbf, + 0x28, 0xe6, 0xed, 0x2c, 0xc5, 0x25, 0x25, 0xbb, 0x6e, 0x0e, 0xf5, 0xc5, 0xda, 0x79, 0xdf, 0x7b, + 0x6f, 0xde, 0x7b, 0x33, 0xef, 0x7b, 0x63, 0x42, 0x81, 0x3d, 0xe2, 0x6d, 0x1e, 0xb0, 0x1a, 0x1d, + 0x89, 0xda, 0xe8, 0x56, 0x4d, 0x3e, 0xaa, 0x0e, 0x02, 0x2e, 0x39, 0xc9, 0x6a, 0xa0, 0x4a, 0x47, + 0xa2, 0x3a, 0xba, 0x55, 0x5c, 0xa3, 0x7d, 0xcf, 0xe7, 0x35, 0xfc, 0x37, 0x54, 0x29, 0x16, 0xda, + 0x5c, 0xf4, 0xb9, 0xa8, 0xf5, 0x45, 0x47, 0x99, 0xf6, 0x45, 0x47, 0x03, 0x17, 0x43, 0xc0, 0xc1, + 0x55, 0x2d, 0x5c, 0x68, 0x28, 0xdf, 0xe1, 0x1d, 0x1e, 0xca, 0xd5, 0x97, 0x96, 0x7e, 0xab, 0xc3, + 0x79, 0xa7, 0xc7, 0x6a, 0x74, 0xe0, 0xd5, 0xa8, 0xef, 0x73, 0x49, 0xa5, 0xc7, 0x7d, 0x6d, 0x63, + 0xfd, 0x65, 0x19, 0x96, 0xb7, 0x3f, 0x69, 0xd6, 0xfd, 0x43, 0x4e, 0x08, 0x24, 0x7c, 0xda, 0x67, + 0xa6, 0x51, 0x31, 0x36, 0x52, 0x36, 0x7e, 0x93, 0x32, 0xa4, 0xe9, 0x48, 0x38, 0xd4, 0x75, 0x03, + 0x26, 0x84, 0x39, 0x8f, 0x10, 0xd0, 0x91, 0xd8, 0x0e, 0x25, 0x64, 0x03, 0x72, 0x7d, 0xcf, 0x77, + 0x84, 0xa4, 0x47, 0xcc, 0xa1, 0x7d, 0x3e, 0xf4, 0xa5, 0xb9, 0x50, 0x31, 0x36, 0x12, 0x76, 0xb6, + 0xef, 0xf9, 0x4d, 0x25, 0xde, 0x46, 0x29, 0xb9, 0x04, 0x29, 0x49, 0xc5, 0x11, 0xfa, 0x32, 0x13, + 0xe8, 0x28, 0xa9, 0x04, 0xca, 0x13, 0xf9, 0x36, 0x80, 0xe8, 0x51, 0xd1, 0x0d, 0xd1, 0x45, 0x44, + 0x53, 0x28, 0x41, 0xb8, 0x0c, 0xe9, 0x80, 0x3d, 0xa4, 0x81, 0x1b, 0xe2, 0x4b, 0x61, 0x18, 0xa1, + 0x08, 0x15, 0x36, 0x61, 0x4d, 0xc5, 0xc9, 0x1f, 0xfa, 0x2c, 0x18, 0x47, 0xbb, 0x5c, 0x59, 0xd8, + 0x48, 0xd9, 0xab, 0x74, 0x24, 0xf6, 0x95, 0x3c, 0x0a, 0xf9, 0x1a, 0xa4, 0xa8, 0x10, 0x4c, 0x3a, + 0x9e, 0x2b, 0xcc, 0xa4, 0xd2, 0xd9, 0xc9, 0x9c, 0x3c, 0x2f, 0x27, 0xb7, 0x95, 0xb0, 0xbe, 0x2b, + 0xec, 0x24, 0xc2, 0x75, 0x57, 0x90, 0x9b, 0x90, 0x57, 0x6e, 0x87, 0x7e, 0x8b, 0xfb, 0xae, 0xe7, + 0x77, 0x9c, 0x01, 0x0b, 0x3c, 0xee, 0x9a, 0x29, 0xcc, 0x90, 0xd0, 0x91, 0x78, 0x10, 0x41, 0x0d, + 0x44, 0x48, 0x15, 0xd6, 0xb1, 0x1e, 0xac, 0x77, 0xe8, 0xb8, 0xac, 0xc7, 0x3a, 0x58, 0x6e, 0x13, + 0xd0, 0x60, 0x4d, 0x95, 0x84, 0xf5, 0x0e, 0x77, 0xc7, 0x00, 0xb9, 0x06, 0x39, 0x36, 0xe0, 0xed, + 0xae, 0xe3, 0xb9, 0xcc, 0x97, 0xde, 0xa1, 0xc7, 0x02, 0x33, 0x8d, 0xe9, 0xad, 0xa2, 0xbc, 0x3e, + 0x16, 0x93, 0x1a, 0xe4, 0x95, 0x6b, 0x3e, 0x90, 0x0e, 0xfe, 0x61, 0x01, 0x95, 0x3c, 0x10, 0x66, + 0x66, 0xec, 0x7b, 0x7f, 0x20, 0xeb, 0xfe, 0x7e, 0x04, 0x90, 0xf7, 0xe1, 0x1d, 0x65, 0x20, 0xb9, + 0xa4, 0xbd, 0xf8, 0x09, 0xad, 0xa0, 0x89, 0x8a, 0xf4, 0x40, 0x81, 0x93, 0xc7, 0x74, 0x05, 0xb2, + 0x42, 0xd2, 0x40, 0xaa, 0x6c, 0x31, 0x02, 0x33, 0x8b, 0xca, 0x2b, 0x91, 0x74, 0x4f, 0x09, 0xc9, + 0x45, 0x48, 0xb6, 0xbb, 0xd4, 0xf3, 0x1d, 0xcf, 0x35, 0x57, 0x31, 0xde, 0x65, 0x5c, 0xd7, 0x5d, + 0x72, 0x0f, 0xd4, 0x05, 0x71, 0xc2, 0xd3, 0x31, 0x73, 0x0a, 0xdc, 0xa9, 0x7e, 0xf9, 0xbc, 0x3c, + 0xf7, 0xf7, 0xe7, 0xe5, 0xab, 0x1d, 0x4f, 0x76, 0x87, 0xad, 0x6a, 0x9b, 0xf7, 0xf5, 0xe5, 0xd5, + 0x7f, 0x6e, 0x08, 0xf7, 0xa8, 0x26, 0x1f, 0x0f, 0x98, 0xa8, 0xee, 0xb2, 0xb6, 0x9d, 0xa2, 0x23, + 0x61, 0xa3, 0x03, 0xf2, 0x31, 0xa8, 0x85, 0x83, 0x97, 0xc1, 0x5c, 0xfb, 0x9f, 0xbc, 0x25, 0xe9, + 0x48, 0x34, 0x95, 0x3d, 0xf9, 0x39, 0x94, 0xc3, 0xb3, 0x8f, 0xae, 0x13, 0x26, 0x1d, 0x26, 0xea, + 0xb4, 0xa8, 0xf0, 0x84, 0x49, 0x2a, 0x0b, 0x1b, 0xe9, 0xad, 0xdb, 0xd5, 0x78, 0x93, 0x56, 0x75, + 0x97, 0x54, 0xf1, 0x96, 0x84, 0xa1, 0x85, 0x15, 0xc3, 0x7a, 0xec, 0x28, 0xd3, 0x3d, 0x5f, 0x06, + 0x8f, 0xed, 0x4b, 0xf4, 0x7c, 0x8d, 0xe2, 0x7d, 0xa8, 0xbc, 0xce, 0x01, 0xc9, 0xc1, 0xc2, 0x11, + 0x7b, 0xac, 0xdb, 0x50, 0x7d, 0x92, 0x3c, 0x2c, 0x8e, 0x68, 0x6f, 0xc8, 0xb0, 0xff, 0x16, 0xec, + 0x70, 0x71, 0x67, 0xfe, 0xb6, 0x61, 0x05, 0x90, 0x8d, 0xce, 0xbb, 0x29, 0xa9, 0x1c, 0xaa, 0xdb, + 0x9d, 0x8b, 0xae, 0xc6, 0xb8, 0x11, 0x42, 0x57, 0xab, 0x91, 0x3c, 0x6a, 0x84, 0x77, 0x60, 0x49, + 0xa0, 0x91, 0xee, 0x6b, 0xbd, 0x52, 0xcd, 0x38, 0x08, 0x38, 0x3f, 0x74, 0x5c, 0x2a, 0x29, 0x76, + 0x73, 0xc6, 0x4e, 0xa1, 0x64, 0x97, 0x4a, 0x6a, 0xfd, 0xdb, 0x80, 0x5c, 0x18, 0x3f, 0xd6, 0xb4, + 0xa1, 0x00, 0x52, 0x80, 0x65, 0xec, 0x6e, 0xcf, 0xd5, 0xbb, 0x2d, 0xa9, 0x65, 0xdd, 0x25, 0x5b, + 0x70, 0x01, 0x81, 0x36, 0xf7, 0x65, 0x40, 0xdb, 0x72, 0x8a, 0x4b, 0xd6, 0x15, 0x78, 0x57, 0x63, + 0x51, 0x60, 0x25, 0x00, 0xda, 0xe9, 0x04, 0xaa, 0x47, 0x78, 0x80, 0x01, 0x28, 0xd2, 0x19, 0x4b, + 0xa6, 0x59, 0x29, 0x31, 0xc3, 0x4a, 0x1f, 0xc2, 0x38, 0x59, 0x47, 0xa7, 0xb8, 0x88, 0xc7, 0x5a, + 0x9a, 0x3e, 0xd6, 0x78, 0xf5, 0xec, 0x2c, 0x8f, 0xad, 0xad, 0x67, 0x4b, 0x90, 0x3c, 0x50, 0x89, + 0x28, 0x82, 0x3c, 0x37, 0x15, 0xe3, 0xfc, 0x54, 0x22, 0x52, 0x9d, 0x9f, 0x20, 0x55, 0x02, 0x89, + 0xae, 0xba, 0xcc, 0x61, 0x65, 0xf1, 0x7b, 0xb2, 0x7e, 0x09, 0xec, 0xb7, 0xa8, 0x7e, 0x37, 0x21, + 0x8f, 0x40, 0xc0, 0xc4, 0x80, 0xfb, 0x82, 0x45, 0x14, 0xb4, 0x18, 0x52, 0x90, 0xc2, 0x6c, 0x0d, + 0x69, 0x0a, 0xfa, 0x1e, 0x14, 0xd0, 0x42, 0x25, 0xee, 0x09, 0xe9, 0xb5, 0x69, 0x2f, 0x32, 0x5a, + 0x42, 0x23, 0xcc, 0xa2, 0x79, 0x8a, 0x6a, 0xbb, 0x71, 0x7a, 0x5d, 0xda, 0xeb, 0x31, 0xbf, 0x33, + 0xde, 0x6a, 0x39, 0x64, 0x0b, 0x4c, 0x2f, 0xc2, 0xb4, 0xcd, 0x2d, 0xc8, 0xcb, 0x6e, 0xc0, 0x44, + 0x97, 0xf7, 0x5c, 0xa5, 0xde, 0x66, 0xbe, 0xa4, 0x1d, 0x66, 0x26, 0xb5, 0x49, 0x84, 0x35, 0xc6, + 0xd0, 0x19, 0x04, 0x93, 0x3a, 0x8b, 0x60, 0xae, 0x41, 0x8e, 0xb6, 0xe5, 0x90, 0xf6, 0x9c, 0xb1, + 0x13, 0xcd, 0xa2, 0xab, 0xa1, 0xfc, 0x20, 0x12, 0xab, 0x19, 0x34, 0x43, 0x8a, 0x69, 0xe4, 0xfe, + 0x2c, 0x8f, 0x33, 0xe2, 0x35, 0xc8, 0x09, 0xaf, 0xe3, 0x33, 0x37, 0x46, 0x9f, 0x38, 0x25, 0x42, + 0xf9, 0xa9, 0x6a, 0x15, 0xd6, 0x7d, 0xee, 0xcc, 0x68, 0xaf, 0xa0, 0xf6, 0x9a, 0xcf, 0x9b, 0x53, + 0xfa, 0x37, 0x21, 0xcf, 0x82, 0x60, 0xd6, 0x20, 0x8b, 0x06, 0x84, 0x05, 0xc1, 0xb4, 0xc5, 0x23, + 0xc8, 0x61, 0xbd, 0x43, 0x7e, 0x1e, 0xf0, 0x87, 0x2c, 0x08, 0xa9, 0x74, 0xe7, 0xfe, 0x9b, 0xf1, + 0xdb, 0xc9, 0xf3, 0x72, 0x56, 0x5d, 0x52, 0xe4, 0xf2, 0x86, 0xf2, 0xf3, 0xf5, 0x17, 0x37, 0x40, + 0xbf, 0x0d, 0x14, 0xff, 0x65, 0x65, 0x0c, 0x25, 0x3f, 0x81, 0x0b, 0xa7, 0x1c, 0xd1, 0x96, 0xde, + 0x88, 0xe9, 0xed, 0x15, 0x59, 0xa7, 0xb7, 0xde, 0x3d, 0xaf, 0x49, 0xb6, 0x51, 0x17, 0x7d, 0xfc, + 0xc0, 0x13, 0xd2, 0x5e, 0xe7, 0xb3, 0x80, 0x15, 0x40, 0xe1, 0x1c, 0x7d, 0xf2, 0x43, 0x18, 0x5b, + 0x84, 0x1b, 0x3a, 0x3d, 0x4f, 0x48, 0xd3, 0xc0, 0xd6, 0xfc, 0x6f, 0x76, 0x55, 0x6d, 0x68, 0xaf, + 0x45, 0x3e, 0xc6, 0x8e, 0xad, 0x3f, 0x1a, 0x67, 0x6e, 0x8a, 0x5d, 0x7b, 0x19, 0x56, 0x62, 0x84, + 0xa8, 0xbb, 0x35, 0x33, 0xc9, 0x86, 0x24, 0x80, 0x4c, 0xac, 0x10, 0xd8, 0xae, 0x3b, 0xfb, 0x6f, + 0x7c, 0x0e, 0xab, 0x6a, 0xbc, 0x4f, 0x44, 0x30, 0x75, 0x10, 0x69, 0x3a, 0x51, 0xa8, 0x1f, 0xc1, + 0xca, 0x4e, 0x4f, 0x34, 0x86, 0xad, 0x8f, 0xd9, 0x63, 0x8c, 0xb4, 0x08, 0xc9, 0x28, 0x28, 0x1d, + 0xe4, 0x78, 0x7d, 0x26, 0x8f, 0x14, 0x60, 0x79, 0x30, 0x6c, 0x39, 0x6a, 0x58, 0x84, 0x54, 0xb2, + 0x34, 0x40, 0x67, 0xd6, 0x9f, 0x0c, 0x20, 0x36, 0xeb, 0x78, 0x42, 0xb2, 0x60, 0xfb, 0x93, 0xe6, + 0x01, 0x72, 0xc4, 0x4f, 0xc9, 0xf7, 0x21, 0x73, 0x18, 0xf0, 0x7e, 0x9c, 0xb6, 0x76, 0xcc, 0xaf, + 0xbf, 0xb8, 0x91, 0xd7, 0x31, 0x6a, 0xd6, 0x6a, 0xca, 0xc0, 0xf3, 0x3b, 0x76, 0x5a, 0x69, 0x47, + 0x44, 0xf6, 0x1e, 0x24, 0xd4, 0x2d, 0xc2, 0x00, 0xd2, 0x5b, 0xe6, 0xf4, 0x61, 0x45, 0x24, 0x69, + 0xa3, 0xd6, 0x9d, 0xdb, 0x9f, 0x7e, 0x5e, 0x9e, 0xfb, 0xd7, 0xe7, 0xe5, 0xb9, 0x27, 0x2f, 0x9f, + 0x6d, 0xa6, 0x3f, 0x38, 0xf5, 0x73, 0xfc, 0xf2, 0xd9, 0xe6, 0xa5, 0x89, 0xe2, 0x1d, 0x4c, 0x70, + 0xa6, 0xb2, 0xb7, 0x2e, 0x42, 0x61, 0x26, 0xf4, 0x90, 0xde, 0xac, 0x5f, 0x19, 0x90, 0x9d, 0xc0, + 0xbe, 0x71, 0x4a, 0xd7, 0x21, 0xe1, 0xf9, 0x87, 0x5c, 0xa7, 0x54, 0x38, 0x67, 0xe2, 0xdb, 0xa8, + 0x74, 0x27, 0x37, 0x9d, 0x89, 0xf5, 0x5b, 0x03, 0xd6, 0x63, 0xe1, 0x84, 0x61, 0xfe, 0x5f, 0x63, + 0xfa, 0xb5, 0x01, 0xb9, 0x5d, 0xf6, 0x16, 0x15, 0xe9, 0x33, 0x03, 0x2e, 0x4c, 0x05, 0xf4, 0x16, + 0x94, 0xe9, 0x0f, 0xf3, 0x90, 0xd5, 0x57, 0x6b, 0xd8, 0xc3, 0x7b, 0xf7, 0x26, 0xef, 0xa6, 0xf7, + 0x80, 0xc4, 0x47, 0x32, 0x4e, 0xf3, 0xb0, 0x33, 0x73, 0x93, 0x03, 0xf9, 0x23, 0x35, 0xd9, 0x2f, + 0xc3, 0x4a, 0x4c, 0x5b, 0xf7, 0x6a, 0x66, 0x52, 0x51, 0x29, 0xb5, 0x7a, 0x02, 0xa7, 0x07, 0x95, + 0xc3, 0x80, 0xe1, 0x23, 0x20, 0x63, 0x67, 0x5a, 0x3d, 0xd1, 0x8c, 0x64, 0xe7, 0xbf, 0x3f, 0x16, + 0xcf, 0x7f, 0x7f, 0x4c, 0xbc, 0x2b, 0x96, 0x62, 0xef, 0x8a, 0xeb, 0xb0, 0x38, 0xe8, 0x52, 0xc1, + 0x70, 0xba, 0x67, 0xb7, 0x2e, 0x4c, 0x97, 0xb0, 0xa1, 0x40, 0x3b, 0xd4, 0xb1, 0xfe, 0x6c, 0xc0, + 0x7a, 0x73, 0xd8, 0xea, 0x7b, 0xf2, 0xb4, 0x6a, 0xdf, 0xf8, 0x66, 0x6d, 0xc5, 0xce, 0xb0, 0x74, + 0x16, 0xa3, 0x9c, 0x9e, 0x8f, 0x3e, 0xca, 0xef, 0xbe, 0x8a, 0x57, 0x0a, 0x13, 0xbc, 0x12, 0x4d, + 0x03, 0xe4, 0x94, 0x22, 0x98, 0xb3, 0xd1, 0x87, 0x95, 0xdf, 0xfc, 0xa5, 0x01, 0x8b, 0x98, 0x2b, + 0xb9, 0x0e, 0x6b, 0x8d, 0x8f, 0xb6, 0x9b, 0x7b, 0xce, 0x83, 0xfb, 0xcd, 0xc6, 0xde, 0xdd, 0xfa, + 0x07, 0xf5, 0xbd, 0xdd, 0xdc, 0x5c, 0x31, 0x7f, 0xfc, 0xb4, 0x92, 0x43, 0x8d, 0x07, 0xbe, 0x18, + 0xb0, 0xb6, 0xfa, 0xcf, 0x98, 0xab, 0x0e, 0x2c, 0x54, 0x6e, 0xd8, 0x7b, 0x8d, 0x6d, 0x7b, 0x2f, + 0x67, 0x14, 0x73, 0xc7, 0x4f, 0x2b, 0x19, 0x54, 0x6c, 0x04, 0x6c, 0x40, 0x03, 0x46, 0xae, 0xc2, + 0x6a, 0xa8, 0xb4, 0xbb, 0xef, 0xdc, 0xdd, 0xbf, 0x77, 0xaf, 0x7e, 0x90, 0x9b, 0x2f, 0xae, 0x1d, + 0x3f, 0xad, 0xac, 0xa0, 0xda, 0x2e, 0xbf, 0xcb, 0xfb, 0x7d, 0x4f, 0x16, 0x13, 0x9f, 0xfe, 0xae, + 0x34, 0xb7, 0xf5, 0xfb, 0x04, 0x2c, 0xdc, 0x13, 0x1d, 0xf2, 0x33, 0x48, 0x4f, 0xf4, 0x0b, 0x99, + 0x29, 0x4c, 0xbc, 0xbb, 0x8b, 0x97, 0x5f, 0x89, 0x6b, 0xea, 0xbc, 0xfa, 0xe4, 0xaf, 0xff, 0xfc, + 0x6c, 0xbe, 0x62, 0x95, 0x6a, 0x33, 0x3f, 0x4a, 0xd4, 0x26, 0x37, 0x7b, 0x62, 0xc0, 0x4a, 0xac, + 0x5d, 0x49, 0x65, 0xda, 0xfd, 0x34, 0xbd, 0x14, 0xaf, 0xbc, 0x46, 0x43, 0x87, 0xb0, 0x81, 0x21, + 0x58, 0x56, 0xe5, 0x8c, 0x10, 0xe2, 0x5b, 0x1e, 0x1b, 0xb0, 0x3a, 0x35, 0x03, 0x88, 0xf5, 0x8a, + 0x2c, 0xf5, 0x7c, 0x2b, 0xbe, 0xfb, 0x5a, 0x1d, 0x1d, 0xca, 0x26, 0x86, 0xf2, 0x1d, 0xcb, 0x7a, + 0x75, 0x35, 0x70, 0x63, 0xc5, 0xa8, 0xd3, 0x97, 0x87, 0xcc, 0xd4, 0xfc, 0x8c, 0xe6, 0x28, 0x6e, + 0xbc, 0x5e, 0x49, 0xc7, 0x73, 0x1d, 0xe3, 0xb9, 0x62, 0x5d, 0x3e, 0x23, 0x9e, 0x69, 0xa3, 0xe2, + 0xe2, 0x2f, 0x5e, 0x3e, 0xdb, 0x34, 0x76, 0x3e, 0xfc, 0xf2, 0xa4, 0x64, 0x7c, 0x75, 0x52, 0x32, + 0xfe, 0x71, 0x52, 0x32, 0x7e, 0xf3, 0xa2, 0x34, 0xf7, 0xd5, 0x8b, 0xd2, 0xdc, 0xdf, 0x5e, 0x94, + 0xe6, 0x7e, 0x7c, 0x63, 0xe2, 0xb5, 0xb2, 0x17, 0xfa, 0xbb, 0xcf, 0xe4, 0x43, 0x1e, 0x1c, 0x8d, + 0xdd, 0x3f, 0xc2, 0x0d, 0xf0, 0xe1, 0xd2, 0x5a, 0xc2, 0x5f, 0x82, 0xde, 0xff, 0x4f, 0x00, 0x00, + 0x00, 0xff, 0xff, 0xdb, 0xbf, 0x57, 0x92, 0xaf, 0x12, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2289,12 +2329,10 @@ func (m *TaskResultInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if len(m.Stage) > 0 { - i -= len(m.Stage) - copy(dAtA[i:], m.Stage) - i = encodeVarintTx(dAtA, i, uint64(len(m.Stage))) + if m.Phase != 0 { + i = encodeVarintTx(dAtA, i, uint64(m.Phase)) i-- - dAtA[i] = 0x3a + dAtA[i] = 0x38 } if m.TaskId != 0 { i = encodeVarintTx(dAtA, i, uint64(m.TaskId)) @@ -2792,9 +2830,8 @@ func (m *TaskResultInfo) Size() (n int) { if m.TaskId != 0 { n += 1 + sovTx(uint64(m.TaskId)) } - l = len(m.Stage) - if l > 0 { - n += 1 + l + sovTx(uint64(l)) + if m.Phase != 0 { + n += 1 + sovTx(uint64(m.Phase)) } return n } @@ -5504,10 +5541,10 @@ func (m *TaskResultInfo) Unmarshal(dAtA []byte) error { } } case 7: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field Stage", wireType) + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Phase", wireType) } - var stringLen uint64 + m.Phase = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTx @@ -5517,24 +5554,11 @@ func (m *TaskResultInfo) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + m.Phase |= Phase(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTx - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTx - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.Stage = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) diff --git a/x/avs/types/types.go b/x/avs/types/types.go index 5a031c568..c87f9a952 100644 --- a/x/avs/types/types.go +++ b/x/avs/types/types.go @@ -8,6 +8,8 @@ import ( "sort" "strings" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/accounts/abi" ibcclienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types" @@ -46,19 +48,21 @@ var ( ChainIDPrefix = []byte("chain-id-prefix") ) +const InvalidTaskID = 0 + type AVSRegisterOrDeregisterParams struct { // AvsName is the name of the AVS as an arbitrary string. AvsName string // AvsAddress is the hex address of the AVS. - AvsAddress string + AvsAddress common.Address // MinStakeAmount is the minimum amount of stake for a task to be considered valid. MinStakeAmount uint64 // TaskAddr is the hex address of the task contract. - TaskAddr string + TaskAddr common.Address // SlashContractAddr is the hex address of the slash contract. - SlashContractAddr string + SlashContractAddr common.Address // RewardContractAddr is the hex address of the reward contract. - RewardContractAddr string + RewardContractAddr common.Address // AvsOwnerAddress is the list of bech32 addresses of the AVS owners. AvsOwnerAddress []string // AssetID is the list of asset IDs that the AVS is allowed to use. @@ -69,12 +73,11 @@ type AVSRegisterOrDeregisterParams struct { EpochIdentifier string MinOptInOperators uint64 MinTotalStakeAmount uint64 - // CallerAddress is the bech32 address of the precompile caller. - CallerAddress string - ChainID string - AvsReward uint64 - AvsSlash uint64 - Action uint64 + CallerAddress sdk.AccAddress + ChainID string + AvsReward uint64 + AvsSlash uint64 + Action OperatorAction } var ( diff --git a/x/avs/types/utils.go b/x/avs/types/utils.go new file mode 100644 index 000000000..35e6fde5b --- /dev/null +++ b/x/avs/types/utils.go @@ -0,0 +1,99 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common" +) + +type OperatorOptParams struct { + Name string `json:"name"` + BlsPublicKey string `json:"bls_public_key"` + IsRegistered bool `json:"is_registered"` + Action OperatorAction `json:"action"` + OperatorAddress sdk.AccAddress `json:"operator_address"` + Status string `json:"status"` + AvsAddress common.Address `json:"avs_address"` +} + +type TaskInfoParams struct { + TaskContractAddress common.Address `json:"task_contract_address"` + TaskName string `json:"name"` + Hash []byte `json:"hash"` + TaskID uint64 `json:"task_id"` + TaskResponsePeriod uint64 `json:"task_response_period"` + TaskStatisticalPeriod uint64 `json:"task_statistical_period"` + TaskChallengePeriod uint64 `json:"task_challenge_period"` + ThresholdPercentage uint64 `json:"threshold_percentage"` + StartingEpoch uint64 `json:"starting_epoch"` + OperatorAddress sdk.AccAddress `json:"operator_address"` + TaskResponseHash string `json:"task_response_hash"` + TaskResponse []byte `json:"task_response"` + BlsSignature []byte `json:"bls_signature"` + ActualThreshold uint64 `json:"actual_threshold"` + OptInCount uint64 `json:"opt_in_count"` + SignedCount uint64 `json:"signed_count"` + NoSignedCount uint64 `json:"no_signed_count"` + ErrSignedCount uint64 `json:"err_signed_count"` + CallerAddress sdk.AccAddress `json:"caller_address"` +} +type BlsParams struct { + OperatorAddress sdk.AccAddress + Name string + PubKey []byte + PubkeyRegistrationSignature []byte + PubkeyRegistrationMessageHash []byte +} + +type ProofParams struct { + TaskID string + TaskContractAddress common.Address + AvsAddress common.Address + Aggregator string + OperatorStatus []OperatorStatusParams + CallerAddress sdk.AccAddress +} +type OperatorStatusParams struct { + OperatorAddress sdk.AccAddress + Status string + ProofData string +} + +// OperatorAction represents the type of action an operator can perform +type OperatorAction uint64 + +const ( + RegisterAction OperatorAction = 1 + DeRegisterAction OperatorAction = 2 + UpdateAction OperatorAction = 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 sdk.AccAddress `json:"caller_address"` +} + +type TaskResultParams struct { + OperatorAddress sdk.AccAddress `json:"operator_address"` + TaskResponseHash string `json:"task_response_hash"` + TaskResponse []byte `json:"task_response"` + BlsSignature []byte `json:"bls_signature"` + TaskContractAddress common.Address `json:"task_contract_address"` + TaskID uint64 `json:"task_id"` + Phase Phase `json:"phase"` + CallerAddress sdk.AccAddress `json:"caller_address"` +} + +func ValidatePhase(phase Phase) error { + switch phase { + case PhasePrepare, PhaseDoCommit: + return nil + default: + return fmt.Errorf("invalid phase value: %d", phase) + } +} diff --git a/x/dogfood/keeper/abci.go b/x/dogfood/keeper/abci.go index 067b952f9..f09480ae3 100644 --- a/x/dogfood/keeper/abci.go +++ b/x/dogfood/keeper/abci.go @@ -20,6 +20,7 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { return []abci.ValidatorUpdate{} } defer k.ClearEpochEnd(ctx) + logger := k.Logger(ctx) chainIDWithoutRevision := avstypes.ChainIDWithoutRevision(ctx.ChainID()) // start by clearing the previous consensus keys for the chain. // each AVS can have a separate epoch and hence this function is a part of this module @@ -30,7 +31,10 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { for _, undelegation := range undelegations.GetList() { err := k.delegationKeeper.DecrementUndelegationHoldCount(ctx, undelegation) if err != nil { - k.Logger(ctx).Error("error decrementing undelegation hold count", "error", err) + logger.Error( + "error decrementing undelegation hold count", + "error", err, + ) } k.ClearUndelegationMaturityEpoch(ctx, undelegation) } @@ -42,7 +46,10 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { ctx, addr, chainIDWithoutRevision, ) if err != nil { - k.Logger(ctx).Error("error completing operator key removal", "error", err) + logger.Error( + "error completing operator key removal", + "error", err, + ) } } k.ClearPendingOptOuts(ctx) @@ -73,7 +80,10 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { pubKey, err := validator.ConsPubKey() if err != nil { // indicates an error in deserialization, and should never happen. - k.Logger(ctx).Error("error deserializing consensus public key", "error", err) + logger.Error( + "error deserializing consensus public key", + "error", err, + ) continue } addressString := sdk.GetConsAddress(pubKey).String() @@ -84,23 +94,28 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { ctx, operators, chainIDWithoutRevision, ) if err != nil { - k.Logger(ctx).Error("error getting vote power for chain", "error", err) + logger.Error( + "error getting vote power for chain", + "error", err, + ) return []abci.ValidatorUpdate{} } operators, keys, powers = utils.SortByPower(operators, keys, powers) maxVals := k.GetMaxValidators(ctx) - k.Logger(ctx).Info("max validators", "maxVals", maxVals, "len(operators)", len(operators)) + logger.Info("before loop", "maxVals", maxVals, "len(operators)", len(operators)) // the capacity of this list is twice the maximum number of validators. // this is because we can have a maximum of maxVals validators, and we can also have // a maximum of maxVals validators that are removed. res := make([]keytypes.WrappedConsKeyWithPower, 0, maxVals*2) for i := range operators { + logger.Debug("loop", i) // #nosec G701 // ok on 64-bit systems. if i >= int(maxVals) { // we have reached the maximum number of validators, amongst all the validators. // even if there are intersections with the previous validator set, this will // only be reached if we exceed the threshold. // if there are no intersections, this case is glaringly obvious. + logger.Debug("max validators reached", "i", i) break } power := powers[i] @@ -108,6 +123,7 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { // we have reached the bottom of the rung. // assumption is that negative vote power isn't provided by the module. // the consensus engine will reject it anyway and panic. + logger.Debug("power less than 1", "i", i) break } // find the previous power. @@ -117,10 +133,24 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { if found { // if the power has changed, queue an update. skip, otherwise. if prevPower != power { + logger.Debug( + "power changed", + "i", i, + "operator", operators[i].String(), + "power", power, + "prevPower", prevPower, + ) res = append(res, keytypes.WrappedConsKeyWithPower{ Key: wrappedKey, Power: power, }) + } else { + logger.Debug( + "power not changed", + "i", i, + "operator", operators[i].String(), + "power", power, + ) } // remove the validator from the previous map, so that 0 power // is not queued for it. @@ -131,11 +161,21 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { Key: wrappedKey, Power: power, }) + logger.Debug( + "new validator", + "i", i, + "operator", operators[i].String(), + "power", power, + ) } // all powers, regardless of whether the key exists, are added to the total power. totalPower = totalPower.Add(sdk.NewInt(power)) } - k.Logger(ctx).Info("total power", "totalPower", totalPower, "len(res)", len(res)) + logger.Info( + "before removal", + "totalPower", totalPower, + "len(res)", len(res), + ) // the remaining validators in prevMap have been removed. // we need to queue a change in power to 0 for them. for _, validator := range prevList { // O(N) @@ -152,7 +192,10 @@ func (k Keeper) EndBlock(ctx sdk.Context) []abci.ValidatorUpdate { // so the previous power of these validators does not need to be subtracted. } } - k.Logger(ctx).Info("total power", "totalPower", totalPower, "len(res)", len(res)) + logger.Info( + "after removal", + "len(res)", len(res), + ) // if there are any updates, set total power on lookup index. if len(res) > 0 { k.SetLastTotalPower(ctx, totalPower) diff --git a/x/dogfood/keeper/msg_server.go b/x/dogfood/keeper/msg_server.go index 63a810670..32e03755d 100644 --- a/x/dogfood/keeper/msg_server.go +++ b/x/dogfood/keeper/msg_server.go @@ -4,9 +4,10 @@ import ( "context" "strings" + "github.com/ethereum/go-ethereum/common" + "cosmossdk.io/errors" "github.com/ExocoreNetwork/exocore/utils" - avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" "github.com/ExocoreNetwork/exocore/x/dogfood/types" epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types" @@ -121,13 +122,13 @@ func (k Keeper) UpdateParams( } err := k.avsKeeper.UpdateAVSInfo(c, &avstypes.AVSRegisterOrDeregisterParams{ AvsName: c.ChainID(), - AvsAddress: avsAddr, + AvsAddress: common.HexToAddress(avsAddr), AssetID: nextParams.AssetIDs, UnbondingPeriod: uint64(nextParams.EpochsUntilUnbonded), MinSelfDelegation: nextParams.MinSelfDelegation.Uint64(), EpochIdentifier: nextParams.EpochIdentifier, ChainID: c.ChainID(), - Action: avskeeper.UpdateAction, + Action: avstypes.UpdateAction, }) if err != nil { return nil, errors.Wrap(types.ErrUpdateAVSInfo, err.Error()) diff --git a/x/dogfood/keeper/opt_out_test.go b/x/dogfood/keeper/opt_out_test.go index c69f7e71d..dba934dfa 100644 --- a/x/dogfood/keeper/opt_out_test.go +++ b/x/dogfood/keeper/opt_out_test.go @@ -29,9 +29,10 @@ func (suite *KeeperTestSuite) TestBasicOperations() { suite.NoError(err) suite.CheckLengthOfValidatorUpdates(0, nil, "register operator but don't opt in") - // opt-in with a key + // opt-in with a key - it will fail because there is not enough self delegation to opt-in chainIDWithoutRevision := avstypes.ChainIDWithoutRevision(suite.Ctx.ChainID()) - _, avsAddress := suite.App.AVSManagerKeeper.IsAVSByChainID(suite.Ctx, chainIDWithoutRevision) + found, avsAddress := suite.App.AVSManagerKeeper.IsAVSByChainID(suite.Ctx, chainIDWithoutRevision) + suite.True(found, "AVS not found") key := utiltx.GenerateConsensusKey() _, err = suite.OperatorMsgServer.OptIntoAVS(sdk.WrapSDKContext(suite.Ctx), &operatortypes.OptIntoAVSReq{ FromAddress: operatorAddressString, @@ -114,7 +115,7 @@ func (suite *KeeperTestSuite) TestBasicOperations() { assetDecimals, 0, // price decimals ) - // opt in again when the self delegation meet the requirement + // opt in successfully after the self delegation meet the requirement _, err = suite.OperatorMsgServer.OptIntoAVS(sdk.WrapSDKContext(suite.Ctx), &operatortypes.OptIntoAVSReq{ FromAddress: operatorAddressString, AvsAddress: avsAddress, diff --git a/x/operator/keeper/grpc_query.go b/x/operator/keeper/grpc_query.go index 1273cff3b..a66e53acb 100644 --- a/x/operator/keeper/grpc_query.go +++ b/x/operator/keeper/grpc_query.go @@ -3,6 +3,7 @@ package keeper import ( "context" "errors" + "strings" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" @@ -203,7 +204,7 @@ func (k *Keeper) QueryOperatorSlashInfo(goCtx context.Context, req *types.QueryO ctx := sdk.UnwrapSDKContext(goCtx) res := make([]*types.OperatorSlashInfoByID, 0) - slashPrefix := types.AppendMany(types.KeyPrefixOperatorSlashInfo, assetstype.GetJoinedStoreKeyForPrefix(req.OperatorAddr, req.AvsAddress)) + slashPrefix := types.AppendMany(types.KeyPrefixOperatorSlashInfo, assetstype.GetJoinedStoreKeyForPrefix(req.OperatorAddr, strings.ToLower(req.AvsAddress))) store := prefix.NewStore(ctx.KVStore(k.storeKey), slashPrefix) pageRes, err := query.Paginate(store, req.Pagination, func(key []byte, value []byte) error { ret := &types.OperatorSlashInfo{} diff --git a/x/operator/keeper/impl_epoch_hook.go b/x/operator/keeper/impl_epoch_hook.go index 478a62439..432b6333f 100644 --- a/x/operator/keeper/impl_epoch_hook.go +++ b/x/operator/keeper/impl_epoch_hook.go @@ -29,7 +29,7 @@ func (wrapper EpochsHooksWrapper) AfterEpochEnd( // todo: need to consider the calling order avsList := wrapper.keeper.avsKeeper.GetEpochEndAVSs(ctx, epochIdentifier, epochNumber) for _, avs := range avsList { - // avs address should be hex + // avs address is checksummed hex, we should convert it to lowercase err := wrapper.keeper.UpdateVotingPower(ctx, avs) if err != nil { ctx.Logger().Error("Failed to update voting power", "avs", avs, "error", err) diff --git a/x/operator/keeper/operator.go b/x/operator/keeper/operator.go index 86a9975ad..72f292ddc 100644 --- a/x/operator/keeper/operator.go +++ b/x/operator/keeper/operator.go @@ -2,6 +2,7 @@ package keeper import ( "fmt" + "strings" errorsmod "cosmossdk.io/errors" @@ -106,7 +107,7 @@ func (k *Keeper) HandleOptedInfo(ctx sdk.Context, operatorAddr, avsAddr string, return errorsmod.Wrap(err, "HandleOptedInfo: error occurred when parse acc address from Bech32") } store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixOperatorOptedAVSInfo) - infoKey := assetstype.GetJoinedStoreKey(operatorAddr, avsAddr) + infoKey := assetstype.GetJoinedStoreKey(operatorAddr, strings.ToLower(avsAddr)) // get info from the store value := store.Get(infoKey) if value == nil { @@ -130,7 +131,7 @@ func (k *Keeper) SetOptedInfo(ctx sdk.Context, operatorAddr, avsAddr string, inf if err != nil { return assetstype.ErrInvalidOperatorAddr } - infoKey := assetstype.GetJoinedStoreKey(operatorAddr, avsAddr) + infoKey := assetstype.GetJoinedStoreKey(operatorAddr, strings.ToLower(avsAddr)) bz := k.cdc.MustMarshal(info) store.Set(infoKey, bz) @@ -143,7 +144,7 @@ func (k *Keeper) GetOptedInfo(ctx sdk.Context, operatorAddr, avsAddr string) (in return nil, errorsmod.Wrap(err, "GetOptedInfo: error occurred when parse acc address from Bech32") } store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixOperatorOptedAVSInfo) - infoKey := assetstype.GetJoinedStoreKey(operatorAddr, avsAddr) + infoKey := assetstype.GetJoinedStoreKey(operatorAddr, strings.ToLower(avsAddr)) value := store.Get(infoKey) if value == nil { return nil, errorsmod.Wrap(operatortypes.ErrNoKeyInTheStore, fmt.Sprintf("GetOptedInfo: operator is %s, avs address is %s", opAccAddr, avsAddr)) @@ -235,7 +236,7 @@ func (k *Keeper) GetOptedInOperatorListByAVS(ctx sdk.Context, avsAddr string) ([ if err != nil { return nil, err } - if avsAddr == keys[1] { + if strings.ToLower(avsAddr) == keys[1] { operatorList = append(operatorList, keys[0]) } } diff --git a/x/operator/keeper/operator_slash_state.go b/x/operator/keeper/operator_slash_state.go index 683fd8cef..72296f7c7 100644 --- a/x/operator/keeper/operator_slash_state.go +++ b/x/operator/keeper/operator_slash_state.go @@ -1,6 +1,8 @@ package keeper import ( + "strings" + assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" errorsmod "cosmossdk.io/errors" @@ -23,7 +25,7 @@ func (k *Keeper) UpdateOperatorSlashInfo(ctx sdk.Context, operatorAddr, avsAddr, if err != nil { return assetstype.ErrInvalidOperatorAddr } - slashInfoKey := assetstype.GetJoinedStoreKey(operatorAddr, avsAddr, slashID) + slashInfoKey := assetstype.GetJoinedStoreKey(operatorAddr, strings.ToLower(avsAddr), slashID) if store.Has(slashInfoKey) { return errorsmod.Wrapf(operatortypes.ErrSlashInfoExist, "slashInfoKey:%s", slashInfoKey) } @@ -54,7 +56,7 @@ func (k *Keeper) UpdateOperatorSlashInfo(ctx sdk.Context, operatorAddr, avsAddr, // Additionally, it might be used when implementing the veto function func (k *Keeper) GetOperatorSlashInfo(ctx sdk.Context, avsAddr, operatorAddr, slashID string) (changeState *operatortypes.OperatorSlashInfo, err error) { store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixOperatorSlashInfo) - slashInfoKey := assetstype.GetJoinedStoreKey(operatorAddr, avsAddr, slashID) + slashInfoKey := assetstype.GetJoinedStoreKey(operatorAddr, strings.ToLower(avsAddr), slashID) value := store.Get(slashInfoKey) if value == nil { return nil, errorsmod.Wrapf(operatortypes.ErrNoKeyInTheStore, "GetOperatorSlashInfo: key is %s", slashInfoKey) @@ -67,7 +69,7 @@ func (k *Keeper) GetOperatorSlashInfo(ctx sdk.Context, avsAddr, operatorAddr, sl // AllOperatorSlashInfo return all slash information for the specified operator and AVS func (k *Keeper) AllOperatorSlashInfo(ctx sdk.Context, avsAddr, operatorAddr string) (map[string]*operatortypes.OperatorSlashInfo, error) { store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixOperatorSlashInfo) - prefix := assetstype.GetJoinedStoreKey(operatorAddr, avsAddr) + prefix := assetstype.GetJoinedStoreKey(operatorAddr, strings.ToLower(avsAddr)) ret := make(map[string]*operatortypes.OperatorSlashInfo, 0) iterator := sdk.KVStorePrefixIterator(store, prefix) diff --git a/x/operator/keeper/opt_test.go b/x/operator/keeper/opt_test.go index 7a2b77d45..56e54a175 100644 --- a/x/operator/keeper/opt_test.go +++ b/x/operator/keeper/opt_test.go @@ -5,7 +5,6 @@ import ( "time" assetskeeper "github.com/ExocoreNetwork/exocore/x/assets/keeper" - avskeeper "github.com/ExocoreNetwork/exocore/x/avs/keeper" avstypes "github.com/ExocoreNetwork/exocore/x/avs/types" epochstypes "github.com/ExocoreNetwork/exocore/x/epochs/types" @@ -94,9 +93,9 @@ func (suite *OperatorTestSuite) prepare() { func (suite *OperatorTestSuite) prepareAvs(assetIDs []string) { err := suite.App.AVSManagerKeeper.UpdateAVSInfo(suite.Ctx, &avstypes.AVSRegisterOrDeregisterParams{ - Action: avskeeper.RegisterAction, + Action: avstypes.RegisterAction, EpochIdentifier: epochstypes.HourEpochID, - AvsAddress: suite.avsAddr, + AvsAddress: common.HexToAddress(suite.avsAddr), AssetID: assetIDs, }) suite.NoError(err) diff --git a/x/operator/keeper/usd_value.go b/x/operator/keeper/usd_value.go index fc1fdb5f2..16fb42e44 100644 --- a/x/operator/keeper/usd_value.go +++ b/x/operator/keeper/usd_value.go @@ -3,6 +3,7 @@ package keeper import ( "errors" "fmt" + "strings" assetstype "github.com/ExocoreNetwork/exocore/x/assets/types" delegationkeeper "github.com/ExocoreNetwork/exocore/x/delegation/keeper" @@ -27,7 +28,7 @@ func (k *Keeper) UpdateOperatorUSDValue(ctx sdk.Context, avsAddr, operatorAddr s if operatorAddr == "" { return errorsmod.Wrap(operatortypes.ErrParameterInvalid, "UpdateOperatorUSDValue the operatorAddr is empty") } - key = assetstype.GetJoinedStoreKey(avsAddr, operatorAddr) + key = assetstype.GetJoinedStoreKey(strings.ToLower(avsAddr), operatorAddr) usdInfo := operatortypes.OperatorOptedUSDValue{ SelfUSDValue: sdkmath.LegacyNewDec(0), @@ -62,7 +63,7 @@ func (k *Keeper) InitOperatorUSDValue(ctx sdk.Context, avsAddr, operatorAddr str if operatorAddr == "" { return errorsmod.Wrap(operatortypes.ErrParameterInvalid, "InitOperatorUSDValue the operatorAddr is empty") } - key = assetstype.GetJoinedStoreKey(avsAddr, operatorAddr) + key = assetstype.GetJoinedStoreKey(strings.ToLower(avsAddr), operatorAddr) if store.Has(key) { return errorsmod.Wrap(operatortypes.ErrKeyAlreadyExist, fmt.Sprintf("avsAddr operatorAddr is: %s, %s", avsAddr, operatorAddr)) } @@ -87,7 +88,7 @@ func (k *Keeper) DeleteOperatorUSDValue(ctx sdk.Context, avsAddr, operatorAddr s if operatorAddr == "" { return errorsmod.Wrap(operatortypes.ErrParameterInvalid, "DeleteOperatorUSDValue the operatorAddr is empty") } - key = assetstype.GetJoinedStoreKey(avsAddr, operatorAddr) + key = assetstype.GetJoinedStoreKey(strings.ToLower(avsAddr), operatorAddr) store.Delete(key) return nil @@ -95,7 +96,7 @@ func (k *Keeper) DeleteOperatorUSDValue(ctx sdk.Context, avsAddr, operatorAddr s func (k *Keeper) DeleteAllOperatorsUSDValueForAVS(ctx sdk.Context, avsAddr string) error { store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixUSDValueForOperator) - iterator := sdk.KVStorePrefixIterator(store, operatortypes.IterateOperatorsForAVSPrefix(avsAddr)) + iterator := sdk.KVStorePrefixIterator(store, operatortypes.IterateOperatorsForAVSPrefix(strings.ToLower(avsAddr))) defer iterator.Close() for ; iterator.Valid(); iterator.Next() { @@ -126,7 +127,7 @@ func (k *Keeper) GetOperatorOptedUSDValue(ctx sdk.Context, avsAddr, operatorAddr if operatorAddr == "" { return operatortypes.OperatorOptedUSDValue{}, errorsmod.Wrap(operatortypes.ErrParameterInvalid, "GetOperatorOptedUSDValue the operatorAddr is empty") } - key = assetstype.GetJoinedStoreKey(avsAddr, operatorAddr) + key = assetstype.GetJoinedStoreKey(strings.ToLower(avsAddr), operatorAddr) value := store.Get(key) if value == nil { return operatortypes.OperatorOptedUSDValue{}, errorsmod.Wrap(operatortypes.ErrNoKeyInTheStore, fmt.Sprintf("GetOperatorOptedUSDValue: key is %s", key)) @@ -147,7 +148,7 @@ func (k *Keeper) UpdateAVSUSDValue(ctx sdk.Context, avsAddr string, opAmount sdk return errorsmod.Wrap(operatortypes.ErrValueIsNilOrZero, fmt.Sprintf("UpdateAVSUSDValue the opAmount is:%v", opAmount)) } store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixUSDValueForAVS) - key := []byte(avsAddr) + key := []byte(strings.ToLower(avsAddr)) totalValue := operatortypes.DecValueField{Amount: sdkmath.LegacyNewDec(0)} value := store.Get(key) if value != nil { @@ -169,7 +170,7 @@ func (k *Keeper) SetAVSUSDValue(ctx sdk.Context, avsAddr string, amount sdkmath. return errorsmod.Wrap(operatortypes.ErrValueIsNilOrZero, fmt.Sprintf("SetAVSUSDValue the amount is:%v", amount)) } store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixUSDValueForAVS) - key := []byte(avsAddr) + key := []byte(strings.ToLower(avsAddr)) setValue := operatortypes.DecValueField{Amount: amount} bz := k.cdc.MustMarshal(&setValue) store.Set(key, bz) @@ -178,7 +179,7 @@ func (k *Keeper) SetAVSUSDValue(ctx sdk.Context, avsAddr string, amount sdkmath. func (k *Keeper) DeleteAVSUSDValue(ctx sdk.Context, avsAddr string) error { store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixUSDValueForAVS) - key := []byte(avsAddr) + key := []byte(strings.ToLower(avsAddr)) store.Delete(key) return nil } @@ -192,7 +193,7 @@ func (k *Keeper) GetAVSUSDValue(ctx sdk.Context, avsAddr string) (sdkmath.Legacy operatortypes.KeyPrefixUSDValueForAVS, ) var ret operatortypes.DecValueField - key := []byte(avsAddr) + key := []byte(strings.ToLower(avsAddr)) value := store.Get(key) if value == nil { return sdkmath.LegacyDec{}, errorsmod.Wrap(operatortypes.ErrNoKeyInTheStore, fmt.Sprintf("GetAVSUSDValue: key is %s", key)) @@ -206,7 +207,7 @@ func (k *Keeper) GetAVSUSDValue(ctx sdk.Context, avsAddr string) (sdkmath.Legacy // `isUpdate` is a flag to indicate whether the change of the state should be set to the store. func (k *Keeper) IterateOperatorsForAVS(ctx sdk.Context, avsAddr string, isUpdate bool, opFunc func(operator string, optedUSDValues *operatortypes.OperatorOptedUSDValue) error) error { store := prefix.NewStore(ctx.KVStore(k.storeKey), operatortypes.KeyPrefixUSDValueForOperator) - iterator := sdk.KVStorePrefixIterator(store, operatortypes.IterateOperatorsForAVSPrefix(avsAddr)) + iterator := sdk.KVStorePrefixIterator(store, operatortypes.IterateOperatorsForAVSPrefix(strings.ToLower(avsAddr))) defer iterator.Close() for ; iterator.Valid(); iterator.Next() {