Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[feat] add the new slash implementation and some missed RPC and CLI #61

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion precompiles/avsTask/task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package task_test

import (
"encoding/hex"
"math/big"

"github.com/ExocoreNetwork/exocore/x/avs/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"math/big"

"github.com/ExocoreNetwork/exocore/app"
"github.com/ExocoreNetwork/exocore/precompiles/avsTask"
Expand Down
37 changes: 37 additions & 0 deletions proto/exocore/delegation/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package exocore.delegation.v1;

import "cosmos/query/v1/query.proto";
import "cosmos_proto/cosmos.proto";
import "exocore/delegation/v1/tx.proto";
import "gogoproto/gogo.proto";
import "google/api/annotations.proto";

Expand Down Expand Up @@ -81,6 +82,28 @@ message UndelegationHoldCountResponse {
uint64 hold_count = 1;
}

// UndelegationsReq is the request to obtain all delegations
// by staker id and asset id.
message UndelegationsReq {
// staker_id is the staker id.
string staker_id = 1 [(gogoproto.customname) = "StakerID"];
// asset_id is the asset id.
string asset_id = 2 [(gogoproto.customname) = "AssetID"];
}

// UndelegationsByHeightReq is the request to obtain all undelegations waiting to be completed
// by height.
message UndelegationsByHeightReq {
// block_height is the block height to query.
uint64 block_height = 1;
}

// UndelegationRecordList is the response to query undelegations.
message UndelegationRecordList {
// UndelegationRecord is the returned undelegations
repeated UndelegationRecord undelegations = 1;
}

// Query is the service API for the delegation module.
service Query {
// DelegationInfo queries the delegation information for {stakerID, assetID}.
Expand All @@ -100,5 +123,19 @@ service Query {
option (cosmos.query.v1.module_query_safe) = true;
option (google.api.http).get = "/exocore/delegation/v1/QueryUndelegationHoldCount/{record_key}";
}

// QueryUndelegations queries all undelegations for
// {staker, asset}.
rpc QueryUndelegations(UndelegationsReq) returns (UndelegationRecordList) {
option (cosmos.query.v1.module_query_safe) = true;
option (google.api.http).get = "/exocore/delegation/v1/QueryUndelegations";
}

// QueryUndelegationsByHeight queries all undelegations waiting to be completed by
// {height}.
rpc QueryUndelegationsByHeight(UndelegationsByHeightReq) returns (UndelegationRecordList) {
option (cosmos.query.v1.module_query_safe) = true;
option (google.api.http).get = "/exocore/delegation/v1/QueryUndelegationsByHeight";
}
}

82 changes: 72 additions & 10 deletions proto/exocore/operator/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,54 @@ message QueryAllOperatorsResponse {
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryOperatorConsKeyRequest is a request to obtain the consensus public key of the operator.
// OperatorAVSAddressDetails includes the address of operator and AVS
message OperatorAVSAddressDetails {
// operator_addr should be the string type of sdk.AccAddress
string operator_addr = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
MaxMustermann2 marked this conversation as resolved.
Show resolved Hide resolved
// avs_address is the address of the AVS - either an 0x address or a chainID.
string avs_address = 2 [(gogoproto.customname) = "AVSAddress"];
MaxMustermann2 marked this conversation as resolved.
Show resolved Hide resolved
}

// QueryOperatorUSDValueRequest is the request to obtain the USD value for operator.
message QueryOperatorUSDValueRequest {
// details is the operator and AVS address
OperatorAVSAddressDetails details = 1;
}

// QueryAVSUSDValueRequest is the request to obtain the USD value for AVS.
message QueryAVSUSDValueRequest {
// avs_address is the AVS address opted-in by the operator
string avs_address = 1
[(gogoproto.customname) = "AVSAddress"];
}

// QueryOperatorSlashInfoRequest is the request to obtain the slash information for the specified
// operator and AVS
message QueryOperatorSlashInfoRequest {
// details is the operator and AVS address
OperatorAVSAddressDetails details = 1;
// pagination related options.
cosmos.base.query.v1beta1.PageRequest pagination = 2;
}

// OperatorSlashInfoByID includes the slash information and the slashID
message OperatorSlashInfoByID {
// slash_id is stored as the key of the slash information,
// so it will be parsed and padding here.
string slash_id = 1 [(gogoproto.customname) = "SlashID"];
// info is the specified detailed information for the slashing event.
OperatorSlashInfo info = 2;
}

// QueryOperatorSlashInfoResponse is the response for GetOperatorSlashInfoRequest
message QueryOperatorSlashInfoResponse{
// all_slash_info is a list of the slash information for the specified operator and AVS
repeated OperatorSlashInfoByID all_slash_info = 1;
// pagination related response.
cosmos.base.query.v1beta1.PageResponse pagination = 2;
}

// QueryOperatorConsKeyRequest is the request to obtain the consensus public key of the operator
message QueryOperatorConsKeyRequest {
// operator_acc_addr is the operator account address.
string operator_acc_addr = 1;
Expand All @@ -44,7 +91,7 @@ message QueryOperatorConsKeyRequest {
// QueryOperatorConsKeyResponse is the response for QueryOperatorConsKeyRequest.
message QueryOperatorConsKeyResponse {
// public_key is the consensus public key of the operator.
tendermint.crypto.PublicKey public_key = 1 [ (gogoproto.nullable) = false ];
tendermint.crypto.PublicKey public_key = 1 [(gogoproto.nullable) = false];
// opting_out is a flag to indicate if the operator is opting out of consensus.
bool opting_out = 2;
}
Expand Down Expand Up @@ -147,17 +194,17 @@ service Query {

// QueryOperatorConsKeyForChainID queries the consensus public key for the operator
rpc QueryOperatorConsKeyForChainID(QueryOperatorConsKeyRequest) returns (
QueryOperatorConsKeyResponse
) {
QueryOperatorConsKeyResponse
) {
option (google.api.http) = {
get: "/exocore/operator/v1/operator_cons_key/{operator_acc_addr}/{chain}"
};
}

// QueryOperatorConsAddressForChainID queries the consensus address for the operator.
rpc QueryOperatorConsAddressForChainID(QueryOperatorConsAddressRequest) returns (
QueryOperatorConsAddressResponse
) {
QueryOperatorConsAddressResponse
) {
option (google.api.http) = {
get: "/exocore/operator/v1/operator_cons_addr/{operator_acc_addr}/{chain}"
};
Expand All @@ -166,18 +213,33 @@ service Query {
// QueryAllOperatorConsKeysByChainID queries all operators and their consensus public keys
// for a specific chain ID
rpc QueryAllOperatorConsKeysByChainID(QueryAllOperatorConsKeysByChainIDRequest) returns (
QueryAllOperatorConsKeysByChainIDResponse
) {
QueryAllOperatorConsKeysByChainIDResponse
) {
option (google.api.http) = {
get: "/exocore/operator/v1/all_operator_cons_keys/{chain}"
};
}

// QueryOperatorUSDValue queries the opted-in USD value for the operator
rpc QueryOperatorUSDValue(QueryOperatorUSDValueRequest) returns(DecValueField){
option (google.api.http).get = "/exocore/operator/v1/QueryOperatorUSDValue";
}

// QueryAVSUSDValue queries the USD value for the AVS
rpc QueryAVSUSDValue(QueryAVSUSDValueRequest) returns(DecValueField){
option (google.api.http).get = "/exocore/operator/v1/QueryAVSUSDValue";
}

// QueryOperatorSlashInfo queries the slash information for the specified operator and AVS
rpc QueryOperatorSlashInfo(QueryOperatorSlashInfoRequest) returns(QueryOperatorSlashInfoResponse){
option (google.api.http).get = "/exocore/operator/v1/QueryOperatorSlashInfo";
}

// QueryAllOperatorConsAddrsByChainID queries all operators and their consensus addresses
// for a specific chain ID
rpc QueryAllOperatorConsAddrsByChainID(QueryAllOperatorConsAddrsByChainIDRequest) returns (
QueryAllOperatorConsAddrsByChainIDResponse
) {
QueryAllOperatorConsAddrsByChainIDResponse
) {
option (google.api.http) = {
get: "/exocore/operator/v1/all_operator_cons_addrs/{chain}"
};
Expand Down
62 changes: 56 additions & 6 deletions proto/exocore/operator/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,56 @@
SLASH_TYPE_NO_INSTANTANEOUS_SLASH = 2;
}

// SlashFromUndelegation records the slash detail from the undelegation
message SlashFromUndelegation {
// staker_id is the staker id.
string staker_id = 1 [(gogoproto.customname) = "StakerID"];
// asset_id is the asset id.
string asset_id = 2 [(gogoproto.customname) = "AssetID"];
// amount is the slashed amount from the undelegation.
string amount = 3
[
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
}
// SlashFromAssetsPool records the slash detail from the operator assets pool
message SlashFromAssetsPool {
// asset_id is the asset id.
string asset_id = 1 [(gogoproto.customname) = "AssetID"];
// amount is the slashed amount from the assets pool.
string amount = 2
[
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Int",
(gogoproto.nullable) = false
];
}


// SlashExecutionInfo is the actual execution state for a slash event
message SlashExecutionInfo {
// slash_proportion is the new calculated proportion when execute the slash
string slash_proportion = 1
[
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// slash_value is the usd value of all slashed assets
string slash_value = 2
[
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// SlashUndelegations records all slash info related to the undelegation
repeated SlashFromUndelegation slash_undelegations = 3;
// SlashFromAssetsPool records all slash info related to the assets pool
repeated SlashFromAssetsPool slash_assets_pool = 4;
}
TimmyExogenous marked this conversation as resolved.
Show resolved Hide resolved

// OperatorSlashInfo is the slash info of operator
message OperatorSlashInfo {
// slash_contract is the address of slash contract
Expand All @@ -101,19 +151,19 @@
int64 submitted_height = 2;
// event_height is the exocore block height at which the slash event occurs
int64 event_height = 3;
// processed_height is the exocore block height at which the slash event is processed
int64 processed_height = 4;
// is_vetoed is a flag to indicate if this slash is vetoed
bool is_vetoed = 5;
bool is_vetoed = 4;

Check failure on line 155 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "4" with name "is_vetoed" on message "OperatorSlashInfo" changed option "json_name" from "processedHeight" to "isVetoed".

Check failure on line 155 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "4" on message "OperatorSlashInfo" changed type from "int64" to "bool".

Check failure on line 155 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "4" on message "OperatorSlashInfo" changed name from "processed_height" to "is_vetoed".
TimmyExogenous marked this conversation as resolved.
Show resolved Hide resolved
// slash_proportion is the proportion of assets that need to be slashed
string slash_proportion = 6
string slash_proportion = 5

Check failure on line 157 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "5" with name "slash_proportion" on message "OperatorSlashInfo" changed option "json_name" from "isVetoed" to "slashProportion".

Check failure on line 157 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "5" on message "OperatorSlashInfo" changed type from "bool" to "string".

Check failure on line 157 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "5" on message "OperatorSlashInfo" changed name from "is_vetoed" to "slash_proportion".
leonz789 marked this conversation as resolved.
Show resolved Hide resolved
[
(cosmos_proto.scalar) = "cosmos.Dec",
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// type indicates the slash type.
SlashType slash_type = 7;
// slash_type indicates the slash type of specified AVS.
uint32 slash_type = 6;

Check failure on line 164 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "6" with name "slash_type" on message "OperatorSlashInfo" changed option "json_name" from "slashProportion" to "slashType".

Check failure on line 164 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "6" on message "OperatorSlashInfo" changed type from "string" to "uint32".

Check failure on line 164 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "6" on message "OperatorSlashInfo" changed name from "slash_proportion" to "slash_type".
// SlashExecutionInfo stores the slashed execution information
SlashExecutionInfo execution_info = 7;

Check failure on line 166 in proto/exocore/operator/v1/tx.proto

View workflow job for this annotation

GitHub Actions / break-check

Field "7" with name "execution_info" on message "OperatorSlashInfo" changed option "json_name" from "slashType" to "executionInfo".
}

// RegisterOperatorReq is the request to register a new operator.
Expand Down
9 changes: 7 additions & 2 deletions x/assets/keeper/operator_asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (k Keeper) GetOperatorAssetInfos(ctx sdk.Context, operatorAddr sdk.Address,
ret[assetID] = state
return nil
}
err = k.IteratorAssetsForOperator(ctx, operatorAddr.String(), assetsFilter, opFunc)
err = k.IteratorAssetsForOperator(ctx, false, operatorAddr.String(), assetsFilter, opFunc)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -96,7 +96,7 @@ func (k Keeper) UpdateOperatorAssetState(ctx sdk.Context, operatorAddr sdk.Addre
// IteratorAssetsForOperator iterates all assets for the specified operator
// if `assetsFilter` is nil, the `opFunc` will handle all assets, it equals to an iterator without filter
// if `assetsFilter` isn't nil, the `opFunc` will only handle the assets that is in the filter map.
func (k Keeper) IteratorAssetsForOperator(ctx sdk.Context, operator string, assetsFilter map[string]interface{}, opFunc func(assetID string, state *assetstype.OperatorAssetInfo) error) error {
func (k Keeper) IteratorAssetsForOperator(ctx sdk.Context, isUpdate bool, operator string, assetsFilter map[string]interface{}, opFunc func(assetID string, state *assetstype.OperatorAssetInfo) error) error {
store := prefix.NewStore(ctx.KVStore(k.storeKey), assetstype.KeyPrefixOperatorAssetInfos)
iterator := sdk.KVStorePrefixIterator(store, []byte(operator))
defer iterator.Close()
Expand All @@ -116,6 +116,11 @@ func (k Keeper) IteratorAssetsForOperator(ctx sdk.Context, operator string, asse
if err != nil {
return err
}
if isUpdate {
TimmyExogenous marked this conversation as resolved.
Show resolved Hide resolved
// store the updated state
bz := k.cdc.MustMarshal(&amounts)
store.Set(iterator.Key(), bz)
}
}
return nil
}
4 changes: 2 additions & 2 deletions x/assets/types/codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
var (
amino = codec.NewLegacyAmino()

// ModuleCdc references the global erc20 module codec. Note, the codec should
// ModuleCdc references the global module codec. Note, the codec should
// ONLY be used in certain instances of tests and for JSON encoding.
//
// The actual codec used for serialization should be provided to modules/erc20 and
// The actual codec used for serialization should be provided to modules and
// defined at the application level.
ModuleCdc = codec.NewProtoCodec(codectypes.NewInterfaceRegistry())

Expand Down
6 changes: 6 additions & 0 deletions x/assets/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ func GetJoinedStoreKey(keys ...string) []byte {
return []byte(strings.Join(keys, "/"))
}

func GetJoinedStoreKeyForPrefix(keys ...string) []byte {
ret := []byte(strings.Join(keys, "/"))
ret = append(ret, '/')
return ret
}

func ParseJoinedKey(key []byte) (keys []string, err error) {
stringList := strings.Split(string(key), "/")
return stringList, nil
Expand Down
15 changes: 6 additions & 9 deletions x/avs/keeper/avs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ func (suite *AVSTestSuite) TestAVS() {

suite.NoError(err)
suite.Equal(avsAddres, info.GetInfo().AvsAddress)

}

func (suite *AVSTestSuite) TestAVSInfoUpdate_Register() {
Expand Down Expand Up @@ -64,8 +63,8 @@ func (suite *AVSTestSuite) TestAVSInfoUpdate_Register() {
err = suite.App.AVSManagerKeeper.AVSInfoUpdate(suite.Ctx, avsParams)
suite.Error(err)
suite.Contains(err.Error(), types.ErrAlreadyRegistered.Error())

}

TimmyExogenous marked this conversation as resolved.
Show resolved Hide resolved
func (suite *AVSTestSuite) TestAVSInfoUpdate_DeRegister() {
// Test case setup
avsName, avsAddres, slashAddress := "avsTest", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutash"
Expand Down Expand Up @@ -100,7 +99,6 @@ func (suite *AVSTestSuite) TestAVSInfoUpdate_DeRegister() {
info, err = suite.App.AVSManagerKeeper.GetAVSInfo(suite.Ctx, avsAddres)
suite.Error(err)
suite.Contains(err.Error(), types.ErrNoKeyInTheStore.Error())

}

func (suite *AVSTestSuite) TestAVSInfoUpdateWithOperator_Register() {
Expand All @@ -116,7 +114,7 @@ func (suite *AVSTestSuite) TestAVSInfoUpdateWithOperator_Register() {
suite.Error(err)
suite.Contains(err.Error(), delegationtypes.ErrOperatorNotExist.Error())

//register operator but avs not register
// register operator but avs not register
info := &operatortype.OperatorInfo{
EarningsAddr: suite.AccAddress.String(),
ApproveAddr: "",
Expand All @@ -135,7 +133,7 @@ func (suite *AVSTestSuite) TestAVSInfoUpdateWithOperator_Register() {
suite.Error(err)
suite.Contains(err.Error(), types.ErrNoKeyInTheStore.Error())

//register avs
// register avs
avsName, avsAddres, slashAddress := "avsTest", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutash"
avsOwnerAddress := []string{"exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkjr", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj1", "exo13h6xg79g82e2g2vhjwg7j4r2z2hlncelwutkj2"}
assetID := []string{"11", "22", "33"}
Expand All @@ -158,19 +156,18 @@ func (suite *AVSTestSuite) TestAVSInfoUpdateWithOperator_Register() {
operatorParams.AvsAddress = avsAddres
err = suite.App.AVSManagerKeeper.AVSInfoUpdateWithOperator(suite.Ctx, operatorParams)
suite.NoError(err)
//duplicate register operator
// duplicate register operator
err = suite.App.AVSManagerKeeper.AVSInfoUpdateWithOperator(suite.Ctx, operatorParams)
suite.Error(err)
suite.Contains(err.Error(), types.ErrAlreadyRegistered.Error())
//deregister operator
// deregister operator
operatorParams.Action = avstypes.DeRegisterAction
err = suite.App.AVSManagerKeeper.AVSInfoUpdateWithOperator(suite.Ctx, operatorParams)
suite.NoError(err)

//duplicate deregister operator
// duplicate deregister operator
operatorParams.Action = avstypes.DeRegisterAction
err = suite.App.AVSManagerKeeper.AVSInfoUpdateWithOperator(suite.Ctx, operatorParams)
suite.Error(err)
suite.Contains(err.Error(), types.ErrUnregisterNonExistent.Error())

}
Loading
Loading