From 955060d203516b53b5e8bbf01990745befa81eba Mon Sep 17 00:00:00 2001 From: leonz789 Date: Wed, 25 Sep 2024 16:05:11 +0800 Subject: [PATCH 1/3] use real interface from delegation to update validatorlist for staker --- x/oracle/keeper/keeper.go | 13 ++++++++----- x/oracle/keeper/native_token.go | 22 +++++++++++++++------- x/oracle/keeper/native_token_test.go | 4 ++-- x/oracle/keeper/prices.go | 2 +- x/oracle/types/expected_keepers.go | 6 ++++++ 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/x/oracle/keeper/keeper.go b/x/oracle/keeper/keeper.go index 546a8f877..dbfe370af 100644 --- a/x/oracle/keeper/keeper.go +++ b/x/oracle/keeper/keeper.go @@ -23,6 +23,7 @@ type ( paramstore paramtypes.Subspace // authority string common.KeeperDogfood + delegationKeeper types.DelegationKeeper } ) @@ -34,6 +35,7 @@ func NewKeeper( memKey storetypes.StoreKey, ps paramtypes.Subspace, sKeeper common.KeeperDogfood, + delegationKeeper types.DelegationKeeper, ) Keeper { // set KeyTable if it has not already been set if !ps.HasKeyTable() { @@ -41,11 +43,12 @@ func NewKeeper( } return Keeper{ - cdc: cdc, - storeKey: storeKey, - memKey: memKey, - paramstore: ps, - KeeperDogfood: sKeeper, + cdc: cdc, + storeKey: storeKey, + memKey: memKey, + paramstore: ps, + KeeperDogfood: sKeeper, + delegationKeeper: delegationKeeper, } } diff --git a/x/oracle/keeper/native_token.go b/x/oracle/keeper/native_token.go index 99416781d..401869a0c 100644 --- a/x/oracle/keeper/native_token.go +++ b/x/oracle/keeper/native_token.go @@ -3,10 +3,14 @@ package keeper import ( "errors" "fmt" + "strings" sdkmath "cosmossdk.io/math" + utils "github.com/ExocoreNetwork/exocore/utils" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" "github.com/ExocoreNetwork/exocore/x/oracle/types" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/ethereum/go-ethereum/common/hexutil" ) // deposit: update staker's totalDeposit @@ -31,9 +35,7 @@ func (k Keeper) GetStakerInfo(ctx sdk.Context, assetID, stakerAddr string) types return stakerInfo } -func (k Keeper) UpdateNativeTokenValidatorListForStaker(ctx sdk.Context, chainID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error { - // TODO: use definition from assets module - assetID := "0xe_" + chainID +func (k Keeper) UpdateNSTValidatorListForStaker(ctx sdk.Context, assetID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error { // emit an event to tell that a staker's validator list has changed ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeCreatePrice, @@ -159,8 +161,9 @@ func (k Keeper) GetStakerList(ctx sdk.Context, assetID string) types.StakerList return *stakerList } -// UpdateNativeTokenByBalanceChange updates balance info for staker under native-restaking asset of assetID when its balance changed by slash/refund on the source chain (beacon chain for eth) -func (k Keeper) UpdateNativeTokenByBalanceChange(ctx sdk.Context, assetID string, rawData []byte, roundID uint64) error { +// UpdateNSTByBalanceChange updates balance info for staker under native-restaking asset of assetID when its balance changed by slash/refund on the source chain (beacon chain for eth) +func (k Keeper) UpdateNSTByBalanceChange(ctx sdk.Context, assetID string, rawData []byte, roundID uint64) error { + _, chainID, _ := assetstypes.ParseID(assetID) if len(rawData) < 32 { return errors.New("length of indicate maps for stakers shoule be exactly 32 bytes") } @@ -202,8 +205,9 @@ func (k Keeper) UpdateNativeTokenByBalanceChange(ctx sdk.Context, assetID string return errors.New("effective balance should never exceeds 32") } if delta := int64(balance) - newBalance.Balance; delta != 0 { - // TODO: call assetsmodule. func(k Keeper) UpdateNativeRestakingBalance(ctx sdk.Context, stakerID, assetID string, amount sdkmath.Int) error - _ = balance + if err := k.delegationKeeper.UpdateNativeRestakingBalance(ctx, getStakerID(stakerAddr, chainID), assetID, sdkmath.NewInt(delta)); err != nil { + return err + } newBalance.Balance = int64(balance) } // newBalance.Balance += int64(change) @@ -290,3 +294,7 @@ func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, er } return stakerChanges, nil } + +func getStakerID(stakerAddr string, chainID uint64) string { + return strings.Join([]string{stakerAddr, hexutil.EncodeUint64(chainID)}, utils.DelimiterForID) +} diff --git a/x/oracle/keeper/native_token_test.go b/x/oracle/keeper/native_token_test.go index 0e1d5b2eb..f88c972ed 100644 --- a/x/oracle/keeper/native_token_test.go +++ b/x/oracle/keeper/native_token_test.go @@ -65,7 +65,7 @@ func (ks *KeeperSuite) TestNativeTokenLifeCycleOneStaker() { {0, -10}, } rawData := convertBalanceChangeToBytes(stakerChanges) - ks.k.UpdateNativeTokenByBalanceChange(ks.ctx, assetID, rawData, 9) + ks.k.UpdateNSTByBalanceChange(ks.ctx, assetID, rawData, 9) // - 2.1 check stakerInfo stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) ks.Equal(types.BalanceInfo{ @@ -96,7 +96,7 @@ func (ks *KeeperSuite) TestNativeTokenLifeCycleOneStaker() { {0, -5}, } rawData = convertBalanceChangeToBytes(stakerChanges) - ks.k.UpdateNativeTokenByBalanceChange(ks.ctx, assetID, rawData, 11) + ks.k.UpdateNSTByBalanceChange(ks.ctx, assetID, rawData, 11) // - 4.1 check stakerInfo stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) ks.Equal(types.BalanceInfo{ diff --git a/x/oracle/keeper/prices.go b/x/oracle/keeper/prices.go index 2d6fe98e3..309054245 100644 --- a/x/oracle/keeper/prices.go +++ b/x/oracle/keeper/prices.go @@ -218,7 +218,7 @@ func (k Keeper) AppendPriceTR(ctx sdk.Context, tokenID uint64, priceTR types.Pri assetIDs := p.GetAssetIDsFromTokenID(tokenID) for _, assetID := range assetIDs { if assetstypes.IsNST(assetID) { - if err := k.UpdateNativeTokenByBalanceChange(ctx, assetID, []byte(priceTR.Price), roundID); err != nil { + if err := k.UpdateNSTByBalanceChange(ctx, assetID, []byte(priceTR.Price), roundID); err != nil { // we just report this error in log to notify validators k.Logger(ctx).Error(types.ErrUpdateNativeTokenVirtualPriceFail.Error(), "error", err) } diff --git a/x/oracle/types/expected_keepers.go b/x/oracle/types/expected_keepers.go index 6aa6e9778..a10647e61 100644 --- a/x/oracle/types/expected_keepers.go +++ b/x/oracle/types/expected_keepers.go @@ -1,6 +1,7 @@ package types import ( + sdkmath "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -16,3 +17,8 @@ type BankKeeper interface { SpendableCoins(ctx sdk.Context, addr sdk.AccAddress) sdk.Coins // Methods imported from bank should be defined here } + +// DelegationKeeper defines the expected interfaces needed to update nst token balance change +type DelegationKeeper interface { + UpdateNativeRestakingBalance(ctx sdk.Context, stakerID, assetID string, amount sdkmath.Int) error +} From af013e227a7413b86ed023570adb099ecc1dd4be Mon Sep 17 00:00:00 2001 From: leonz789 Date: Wed, 25 Sep 2024 17:35:22 +0800 Subject: [PATCH 2/3] refactor --- app/app.go | 1 + precompiles/assets/tx.go | 2 +- testutil/keeper/oracle.go | 2 + testutil/utils.go | 21 ++ x/assets/types/expected_keepers.go | 2 +- .../keeper/update_native_restaking_balance.go | 11 +- .../update_native_restaking_balance_test.go | 4 +- x/oracle/keeper/native_token.go | 3 +- x/oracle/keeper/native_token_test.go | 195 +++++++++--------- x/oracle/types/expected_keepers.go | 2 +- 10 files changed, 130 insertions(+), 113 deletions(-) diff --git a/app/app.go b/app/app.go index 6be8a651a..835f99ebb 100644 --- a/app/app.go +++ b/app/app.go @@ -584,6 +584,7 @@ func NewExocoreApp( app.OracleKeeper = oracleKeeper.NewKeeper( appCodec, keys[oracleTypes.StoreKey], memKeys[oracleTypes.MemStoreKey], app.GetSubspace(oracleTypes.ModuleName), app.StakingKeeper, + &app.DelegationKeeper, ) // the SDK slashing module is used to slash validators in the case of downtime. it tracks diff --git a/precompiles/assets/tx.go b/precompiles/assets/tx.go index d1403a452..983e09c87 100644 --- a/precompiles/assets/tx.go +++ b/precompiles/assets/tx.go @@ -64,7 +64,7 @@ func (p Precompile) DepositOrWithdraw( } _, assetID := assetstypes.GetStakerIDAndAssetID(depositWithdrawParams.ClientChainLzID, depositWithdrawParams.StakerAddress, depositWithdrawParams.AssetsAddress) - err = p.assetsKeeper.UpdateNativeTokenValidatorListForStaker(ctx, assetID, + err = p.assetsKeeper.UpdateNSTValidatorListForStaker(ctx, assetID, hexutil.Encode(depositWithdrawParams.StakerAddress), hexutil.Encode(depositWithdrawParams.ValidatorPubkey), opAmount) diff --git a/testutil/keeper/oracle.go b/testutil/keeper/oracle.go index 6c0e259df..67aac248e 100644 --- a/testutil/keeper/oracle.go +++ b/testutil/keeper/oracle.go @@ -16,6 +16,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" typesparams "github.com/cosmos/cosmos-sdk/x/params/types" + delegationkeeper "github.com/ExocoreNetwork/exocore/x/delegation/keeper" dogfoodkeeper "github.com/ExocoreNetwork/exocore/x/dogfood/keeper" "github.com/stretchr/testify/require" ) @@ -45,6 +46,7 @@ func OracleKeeper(t testing.TB) (*keeper.Keeper, sdk.Context) { memStoreKey, paramsSubspace, dogfoodkeeper.Keeper{}, + delegationkeeper.Keeper{}, ) ctx := sdk.NewContext(stateStore, tmproto.Header{ diff --git a/testutil/utils.go b/testutil/utils.go index 2b033cf58..09d4a8a2a 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -103,6 +103,11 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc suite.ClientChains[0].LayerZeroChainID, "", suite.Assets[0].Address, ) + NSTAssetAddr := assetstypes.GenerateNSTAddr( + suite.ClientChains[0].AddressLength, + ) + _, assetIDNST := assetstypes.GetStakerIDAndAssetID(suite.ClientChains[0].LayerZeroChainID, []byte{}, NSTAssetAddr) + // x/assets initialization - deposits (client chains and tokens are from caller) power := int64(101) power2 := int64(100) @@ -123,6 +128,14 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc PendingUndelegationAmount: sdk.ZeroInt(), }, }, + { + AssetID: assetIDNST, + Info: assetstypes.StakerAssetInfo{ + TotalDepositAmount: depositAmount, + WithdrawableAmount: depositAmount, + PendingUndelegationAmount: sdk.ZeroInt(), + }, + }, }, }, { @@ -136,6 +149,14 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc PendingUndelegationAmount: sdk.ZeroInt(), }, }, + { + AssetID: assetIDNST, + Info: assetstypes.StakerAssetInfo{ + TotalDepositAmount: depositAmount2, + WithdrawableAmount: depositAmount2, + PendingUndelegationAmount: sdk.ZeroInt(), + }, + }, }, }, } diff --git a/x/assets/types/expected_keepers.go b/x/assets/types/expected_keepers.go index 0a6293356..a5cbc1f8c 100644 --- a/x/assets/types/expected_keepers.go +++ b/x/assets/types/expected_keepers.go @@ -9,7 +9,7 @@ import ( type OracleKeeper interface { GetSpecifiedAssetsPrice(ctx sdk.Context, assetID string) (oracletypes.Price, error) RegisterNewTokenAndSetTokenFeeder(ctx sdk.Context, oInfo *oracletypes.OracleInfo) error - UpdateNativeTokenValidatorListForStaker(ctx sdk.Context, chainID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error + UpdateNSTValidatorListForStaker(ctx sdk.Context, chainID, stakerAddr, validatorPubkey string, amount sdkmath.Int) error } type BankKeeper interface { diff --git a/x/delegation/keeper/update_native_restaking_balance.go b/x/delegation/keeper/update_native_restaking_balance.go index 50c4aa65c..c078d407f 100644 --- a/x/delegation/keeper/update_native_restaking_balance.go +++ b/x/delegation/keeper/update_native_restaking_balance.go @@ -11,10 +11,9 @@ const ( MaxSlashProportion = 1 ) -func (k Keeper) UpdateNativeRestakingBalance( +func (k Keeper) UpdateNSTBalance( ctx sdk.Context, stakerID, assetID string, amount sdkmath.Int, ) error { - // todo: check if the assetID is native retaking token if amount.IsPositive() { // If the balance increases due to the client chain PoS staking reward, the increased // amount can be considered a virtual deposit event. However, the increased amount needs @@ -54,7 +53,7 @@ func (k Keeper) UpdateNativeRestakingBalance( if err != nil { return err } - ctx.Logger().Info("UpdateNativeRestakingBalance slash from withdrawable amount", "stakerID", stakerID, "assetID", assetID, "slashFromWithdrawable", slashFromWithdrawable, "pendingSlashAmount", pendingSlashAmount) + ctx.Logger().Info("UpdateNSTBalance slash from withdrawable amount", "stakerID", stakerID, "assetID", assetID, "slashFromWithdrawable", slashFromWithdrawable, "pendingSlashAmount", pendingSlashAmount) // slash from pending undelegations if pendingSlashAmount.IsPositive() { @@ -72,7 +71,7 @@ func (k Keeper) UpdateNativeRestakingBalance( if err != nil { return true, err } - ctx.Logger().Info("UpdateNativeRestakingBalance slash from undelegation", "stakerID", stakerID, "assetID", assetID, "operator", undelegation.OperatorAddr, "undelegationKey", undelegationKey, "slashAmount", slashAmount, "pendingSlashAmount", pendingSlashAmount) + ctx.Logger().Info("UpdateNSTBalance slash from undelegation", "stakerID", stakerID, "assetID", assetID, "operator", undelegation.OperatorAddr, "undelegationKey", undelegationKey, "slashAmount", slashAmount, "pendingSlashAmount", pendingSlashAmount) if !pendingSlashAmount.IsPositive() { // return ture to break the iteration if there isn't remaining amount to be slashed return true, nil @@ -116,7 +115,7 @@ func (k Keeper) UpdateNativeRestakingBalance( return true, err } pendingSlashAmount = pendingSlashAmount.Sub(actualSlashAmount) - ctx.Logger().Info("UpdateNativeRestakingBalance slash from delegated share", "stakerID", stakerID, "assetID", assetID, "operator", keys.OperatorAddr, "slashProportion", slashProportion, "slashShare", slashShare, "actualSlashAmount", actualSlashAmount, "pendingSlashAmount", pendingSlashAmount) + ctx.Logger().Info("UpdateNSTBalance slash from delegated share", "stakerID", stakerID, "assetID", assetID, "operator", keys.OperatorAddr, "slashProportion", slashProportion, "slashShare", slashShare, "actualSlashAmount", actualSlashAmount, "pendingSlashAmount", pendingSlashAmount) return false, nil } err = k.IterateDelegationsForStakerAndAsset(ctx, stakerID, assetID, opFunc) @@ -128,7 +127,7 @@ func (k Keeper) UpdateNativeRestakingBalance( // In this case, we only print a log as a reminder. This situation will only occur when the total slashing amount // from the client chain and Exocore chain is greater than the total staking amount. if pendingSlashAmount.IsPositive() { - ctx.Logger().Info("UpdateNativeRestakingBalance all staking funds has been slashed, the remaining amount is:", "stakerID", stakerID, "assetID", assetID, "pendingSlashAmount", pendingSlashAmount) + ctx.Logger().Info("UpdateNSTBalance all staking funds has been slashed, the remaining amount is:", "stakerID", stakerID, "assetID", assetID, "pendingSlashAmount", pendingSlashAmount) } } return nil diff --git a/x/delegation/keeper/update_native_restaking_balance_test.go b/x/delegation/keeper/update_native_restaking_balance_test.go index 9377275ed..7a2bf81c9 100644 --- a/x/delegation/keeper/update_native_restaking_balance_test.go +++ b/x/delegation/keeper/update_native_restaking_balance_test.go @@ -6,7 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -func (suite *DelegationTestSuite) TestUpdateNativeRestakingBalance() { +func (suite *DelegationTestSuite) TestUpdateNSTBalance() { // test case: slash 80 // withdrawable: 60 slash: 60 -> 0 // undelegation: 10 slash: 10 -> 0 @@ -35,7 +35,7 @@ func (suite *DelegationTestSuite) TestUpdateNativeRestakingBalance() { slashAmount := sdkmath.NewInt(80) actualSlashAmount := sdkmath.NewInt(79) stakerID, assetID := assettypes.GetStakerIDAndAssetID(suite.clientChainLzID, suite.Address[:], suite.assetAddr.Bytes()) - err = suite.App.DelegationKeeper.UpdateNativeRestakingBalance(suite.Ctx, stakerID, assetID, slashAmount.Neg()) + err = suite.App.DelegationKeeper.UpdateNSTBalance(suite.Ctx, stakerID, assetID, slashAmount.Neg()) suite.NoError(err) // check the asset state for the slashed staker diff --git a/x/oracle/keeper/native_token.go b/x/oracle/keeper/native_token.go index 401869a0c..682a6a0aa 100644 --- a/x/oracle/keeper/native_token.go +++ b/x/oracle/keeper/native_token.go @@ -205,7 +205,7 @@ func (k Keeper) UpdateNSTByBalanceChange(ctx sdk.Context, assetID string, rawDat return errors.New("effective balance should never exceeds 32") } if delta := int64(balance) - newBalance.Balance; delta != 0 { - if err := k.delegationKeeper.UpdateNativeRestakingBalance(ctx, getStakerID(stakerAddr, chainID), assetID, sdkmath.NewInt(delta)); err != nil { + if err := k.delegationKeeper.UpdateNSTBalance(ctx, getStakerID(stakerAddr, chainID), assetID, sdkmath.NewInt(delta)); err != nil { return err } newBalance.Balance = int64(balance) @@ -295,6 +295,7 @@ func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, er return stakerChanges, nil } +// TODO use []byte and assetstypes.GetStakerIDAndAssetID for stakerAddr representation func getStakerID(stakerAddr string, chainID uint64) string { return strings.Join([]string{stakerAddr, hexutil.EncodeUint64(chainID)}, utils.DelimiterForID) } diff --git a/x/oracle/keeper/native_token_test.go b/x/oracle/keeper/native_token_test.go index f88c972ed..035d18813 100644 --- a/x/oracle/keeper/native_token_test.go +++ b/x/oracle/keeper/native_token_test.go @@ -4,11 +4,6 @@ import ( "encoding/binary" "strings" - sdkmath "cosmossdk.io/math" - - "github.com/ExocoreNetwork/exocore/x/oracle/types" - - "github.com/ethereum/go-ethereum/common" "github.com/imroc/biu" ) @@ -35,102 +30,100 @@ import ( // 1. removed stakerInfo // 2. removed stakerList -func (ks *KeeperSuite) TestNativeTokenLifeCycleOneStaker() { - operator := ks.Operators[0] - stakerStr := common.Address(operator.Bytes()).String() - chainID := "beaconchain" - // TODO: update after assets module got the definition - assetID := "0xe_" + chainID - validators := []string{"0xv1", "0xv2"} - // 1. deposit amount 100 - // 100 is not a possible nubmer with one validator, it's ok to use this as a start and we'll check the number to be updated to a right number(uncer 32 with one validator) - amount100 := sdkmath.NewIntFromUint64(100) - amount32 := sdkmath.NewIntFromUint64(32) - ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[0], amount100) - // - 1.1 check stakerInfo - stakerInfo := ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) - ks.Equal(types.BalanceInfo{ - Block: 2, - RoundID: 0, - Change: types.Action_ACTION_DEPOSIT, - Balance: 100, - }, *stakerInfo.BalanceList[0]) - ks.Equal([]string{validators[0]}, stakerInfo.ValidatorPubkeyList) - // - 1.2 check stakerList - stakerList := ks.k.GetStakerList(ks.ctx, assetID) - ks.Equal(stakerList.StakerAddrs[0], stakerStr) - - // 2. Msg. minus staker's balance - stakerChanges := [][]int{ - {0, -10}, - } - rawData := convertBalanceChangeToBytes(stakerChanges) - ks.k.UpdateNSTByBalanceChange(ks.ctx, assetID, rawData, 9) - // - 2.1 check stakerInfo - stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) - ks.Equal(types.BalanceInfo{ - Block: 2, - RoundID: 9, - Change: types.Action_ACTION_SLASH_REFUND, - // this is expected to be 32-10=22, not 100-10 - Balance: 22, - }, *stakerInfo.BalanceList[1]) - - // 3. deposit more. 100 - ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[1], amount32) // 999 - // - 3.1 check stakerInfo - stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) - ks.Equal(types.BalanceInfo{ - Block: 2, - RoundID: 9, - Index: 1, - Change: types.Action_ACTION_DEPOSIT, - Balance: 54, - }, *stakerInfo.BalanceList[2]) - ks.Equal(validators, stakerInfo.ValidatorPubkeyList) - - // 4. Msg. add staker's balance - // at this point the system correct number should be 32*2-10 = 52, if some validator do refund, means the delta should be less than 10 - stakerChanges = [][]int{ - // means delta from -10 change to -5 - {0, -5}, - } - rawData = convertBalanceChangeToBytes(stakerChanges) - ks.k.UpdateNSTByBalanceChange(ks.ctx, assetID, rawData, 11) - // - 4.1 check stakerInfo - stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) - ks.Equal(types.BalanceInfo{ - Balance: 59, - Block: 2, - RoundID: 11, - Index: 0, - Change: types.Action_ACTION_SLASH_REFUND, - }, *stakerInfo.BalanceList[3]) - - // 5. withdraw - amount30N := sdkmath.NewInt(-30) - ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[0], amount30N) - // - 5.1 check stakerInfo - stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) - ks.Equal(types.BalanceInfo{ - Balance: 29, - Block: 2, - RoundID: 11, - Index: 1, - Change: types.Action_ACTION_WITHDRAW, - }, *stakerInfo.BalanceList[4]) - // withdraw will remove this validator - ks.Equal([]string{validators[1]}, stakerInfo.ValidatorPubkeyList) - - // 6.withdrawall - amount100N := sdkmath.NewInt(-29) - ks.k.UpdateNativeTokenValidatorListForStaker(ks.ctx, chainID, stakerStr, validators[1], amount100N) - // - 6.1 check stakerInfo - stakerInfo = ks.k.GetStakerInfo(ks.ctx, assetID, stakerStr) - ks.Equal(types.StakerInfo{}, stakerInfo) - // - 6.2 check stakerList - stakerList = ks.k.GetStakerList(ks.ctx, assetID) -} +// func (ks *KeeperSuite) TestNSTLifeCycleOneStaker() { +// operator := ks.Operators[0] +// stakerStr := common.Address(operator.Bytes()).String() +// assetID := "0xe_0x65" +// validators := []string{"0xv1", "0xv2"} +// // 1. deposit amount 100 +// // 100 is not a possible nubmer with one validator, it's ok to use this as a start and we'll check the number to be updated to a right number(uncer 32 with one validator) +// amount100 := sdkmath.NewIntFromUint64(100) +// amount32 := sdkmath.NewIntFromUint64(32) +// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount100) +// // - 1.1 check stakerInfo +// stakerInfo := ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) +// ks.Equal(types.BalanceInfo{ +// Block: 1, +// RoundID: 0, +// Change: types.Action_ACTION_DEPOSIT, +// Balance: 100, +// }, *stakerInfo.BalanceList[0]) +// ks.Equal([]string{validators[0]}, stakerInfo.ValidatorPubkeyList) +// // - 1.2 check stakerList +// stakerList := ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID) +// ks.Equal(stakerList.StakerAddrs[0], stakerStr) +// +// // 2. Msg. minus staker's balance +// stakerChanges := [][]int{ +// {0, -10}, +// } +// rawData := convertBalanceChangeToBytes(stakerChanges) +// ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 9) +// // - 2.1 check stakerInfo +// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) +// ks.Equal(types.BalanceInfo{ +// Block: 2, +// RoundID: 9, +// Change: types.Action_ACTION_SLASH_REFUND, +// // this is expected to be 32-10=22, not 100-10 +// Balance: 22, +// }, *stakerInfo.BalanceList[1]) +// +// // 3. deposit more. 100 +// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount32) // 999 +// // - 3.1 check stakerInfo +// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) +// ks.Equal(types.BalanceInfo{ +// Block: 2, +// RoundID: 9, +// Index: 1, +// Change: types.Action_ACTION_DEPOSIT, +// Balance: 54, +// }, *stakerInfo.BalanceList[2]) +// ks.Equal(validators, stakerInfo.ValidatorPubkeyList) +// +// // 4. Msg. add staker's balance +// // at this point the system correct number should be 32*2-10 = 52, if some validator do refund, means the delta should be less than 10 +// stakerChanges = [][]int{ +// // means delta from -10 change to -5 +// {0, -5}, +// } +// rawData = convertBalanceChangeToBytes(stakerChanges) +// ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 11) +// // - 4.1 check stakerInfo +// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) +// ks.Equal(types.BalanceInfo{ +// Balance: 59, +// Block: 2, +// RoundID: 11, +// Index: 0, +// Change: types.Action_ACTION_SLASH_REFUND, +// }, *stakerInfo.BalanceList[3]) +// +// // 5. withdraw +// amount30N := sdkmath.NewInt(-30) +// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount30N) +// // - 5.1 check stakerInfo +// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) +// ks.Equal(types.BalanceInfo{ +// Balance: 29, +// Block: 2, +// RoundID: 11, +// Index: 1, +// Change: types.Action_ACTION_WITHDRAW, +// }, *stakerInfo.BalanceList[4]) +// // withdraw will remove this validator +// ks.Equal([]string{validators[1]}, stakerInfo.ValidatorPubkeyList) +// +// // 6.withdrawall +// amount100N := sdkmath.NewInt(-29) +// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount100N) +// // - 6.1 check stakerInfo +// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) +// ks.Equal(types.StakerInfo{}, stakerInfo) +// // - 6.2 check stakerList +// stakerList = ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID) +// } func convertBalanceChangeToBytes(stakerChanges [][]int) []byte { if len(stakerChanges) == 0 { diff --git a/x/oracle/types/expected_keepers.go b/x/oracle/types/expected_keepers.go index a10647e61..5baca6c57 100644 --- a/x/oracle/types/expected_keepers.go +++ b/x/oracle/types/expected_keepers.go @@ -20,5 +20,5 @@ type BankKeeper interface { // DelegationKeeper defines the expected interfaces needed to update nst token balance change type DelegationKeeper interface { - UpdateNativeRestakingBalance(ctx sdk.Context, stakerID, assetID string, amount sdkmath.Int) error + UpdateNSTBalance(ctx sdk.Context, stakerID, assetID string, amount sdkmath.Int) error } From d483e1f3c0d42413e8a1700e2ac6cf495eb9deb7 Mon Sep 17 00:00:00 2001 From: leonz789 Date: Thu, 26 Sep 2024 00:38:10 +0800 Subject: [PATCH 3/3] fix ut --- testutil/utils.go | 27 +--- x/oracle/keeper/keeper_suite_test.go | 30 +++++ x/oracle/keeper/native_token.go | 2 +- x/oracle/keeper/native_token_test.go | 193 ++++++++++++++------------- 4 files changed, 136 insertions(+), 116 deletions(-) diff --git a/testutil/utils.go b/testutil/utils.go index 09d4a8a2a..0ad44a175 100644 --- a/testutil/utils.go +++ b/testutil/utils.go @@ -50,6 +50,7 @@ type BaseTestSuite struct { App *exocoreapp.ExocoreApp Address common.Address AccAddress sdk.AccAddress + StakerAddr string PrivKey cryptotypes.PrivKey Signer keyring.Signer @@ -95,6 +96,7 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc suite.ClientChains[0].LayerZeroChainID, common.Address(operator1.Bytes()).String(), "", ) + suite.StakerAddr = common.Address(operator1.Bytes()).String() stakerID2, _ := assetstypes.GetStakerIDAndAssetIDFromStr( suite.ClientChains[0].LayerZeroChainID, common.Address(operator2.Bytes()).String(), "", @@ -103,11 +105,6 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc suite.ClientChains[0].LayerZeroChainID, "", suite.Assets[0].Address, ) - NSTAssetAddr := assetstypes.GenerateNSTAddr( - suite.ClientChains[0].AddressLength, - ) - _, assetIDNST := assetstypes.GetStakerIDAndAssetID(suite.ClientChains[0].LayerZeroChainID, []byte{}, NSTAssetAddr) - // x/assets initialization - deposits (client chains and tokens are from caller) power := int64(101) power2 := int64(100) @@ -128,14 +125,6 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc PendingUndelegationAmount: sdk.ZeroInt(), }, }, - { - AssetID: assetIDNST, - Info: assetstypes.StakerAssetInfo{ - TotalDepositAmount: depositAmount, - WithdrawableAmount: depositAmount, - PendingUndelegationAmount: sdk.ZeroInt(), - }, - }, }, }, { @@ -149,14 +138,6 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc PendingUndelegationAmount: sdk.ZeroInt(), }, }, - { - AssetID: assetIDNST, - Info: assetstypes.StakerAssetInfo{ - TotalDepositAmount: depositAmount2, - WithdrawableAmount: depositAmount2, - PendingUndelegationAmount: sdk.ZeroInt(), - }, - }, }, }, } @@ -197,6 +178,10 @@ func (suite *BaseTestSuite) SetupWithGenesisValSet(genAccs []authtypes.GenesisAc AssetBasicInfo: suite.Assets[0], StakingTotalAmount: depositAmount.Add(depositAmount2), }, + // { + // AssetBasicInfo: suite.Assets[1], + // StakingTotalAmount: depositAmount.Add(math.NewInt(132)), + // }, }, depositsByStaker, operatorAssets, ) genesisState[assetstypes.ModuleName] = app.AppCodec().MustMarshalJSON(assetsGenesis) diff --git a/x/oracle/keeper/keeper_suite_test.go b/x/oracle/keeper/keeper_suite_test.go index 46e371025..c27615419 100644 --- a/x/oracle/keeper/keeper_suite_test.go +++ b/x/oracle/keeper/keeper_suite_test.go @@ -4,7 +4,9 @@ import ( "context" "testing" + "cosmossdk.io/math" "github.com/ExocoreNetwork/exocore/testutil" + assetstypes "github.com/ExocoreNetwork/exocore/x/assets/types" "github.com/ExocoreNetwork/exocore/x/oracle/keeper" "github.com/ExocoreNetwork/exocore/x/oracle/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -80,6 +82,34 @@ func (suite *KeeperSuite) Reset() { func (suite *KeeperSuite) SetupTest() { suite.DoSetupTest() + + depositAmountNST := math.NewInt(132) + suite.App.AssetsKeeper.SetStakingAssetInfo(suite.Ctx, &assetstypes.StakingAssetInfo{ + AssetBasicInfo: assetstypes.AssetInfo{ + Name: "Native Restaking ETH", + Symbol: "NSTETH", + Address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + Decimals: 6, + LayerZeroChainID: suite.ClientChains[0].LayerZeroChainID, + MetaInfo: "native restaking token", + }, + StakingTotalAmount: depositAmountNST, + }) + + stakerID, _ := assetstypes.GetStakerIDAndAssetIDFromStr( + suite.ClientChains[0].LayerZeroChainID, + ks.StakerAddr, "", + ) + NSTAssetAddr := assetstypes.GenerateNSTAddr( + suite.ClientChains[0].AddressLength, + ) + _, assetIDNST := assetstypes.GetStakerIDAndAssetID(suite.ClientChains[0].LayerZeroChainID, []byte{}, NSTAssetAddr) + suite.App.AssetsKeeper.UpdateStakerAssetState(ks.Ctx, stakerID, assetIDNST, assetstypes.DeltaStakerSingleAsset{ + TotalDepositAmount: depositAmountNST, + WithdrawableAmount: depositAmountNST, + PendingUndelegationAmount: sdk.ZeroInt(), + }) + validators := suite.ValSet.Validators suite.valAddr1, _ = sdk.ValAddressFromBech32(sdk.ValAddress(validators[0].Address).String()) suite.valAddr2, _ = sdk.ValAddressFromBech32(sdk.ValAddress(validators[1].Address).String()) diff --git a/x/oracle/keeper/native_token.go b/x/oracle/keeper/native_token.go index 682a6a0aa..e0476ab61 100644 --- a/x/oracle/keeper/native_token.go +++ b/x/oracle/keeper/native_token.go @@ -297,5 +297,5 @@ func parseBalanceChange(rawData []byte, sl types.StakerList) (map[string]int, er // TODO use []byte and assetstypes.GetStakerIDAndAssetID for stakerAddr representation func getStakerID(stakerAddr string, chainID uint64) string { - return strings.Join([]string{stakerAddr, hexutil.EncodeUint64(chainID)}, utils.DelimiterForID) + return strings.Join([]string{strings.ToLower(stakerAddr), hexutil.EncodeUint64(chainID)}, utils.DelimiterForID) } diff --git a/x/oracle/keeper/native_token_test.go b/x/oracle/keeper/native_token_test.go index 035d18813..453f10506 100644 --- a/x/oracle/keeper/native_token_test.go +++ b/x/oracle/keeper/native_token_test.go @@ -4,6 +4,9 @@ import ( "encoding/binary" "strings" + sdkmath "cosmossdk.io/math" + + "github.com/ExocoreNetwork/exocore/x/oracle/types" "github.com/imroc/biu" ) @@ -30,100 +33,102 @@ import ( // 1. removed stakerInfo // 2. removed stakerList -// func (ks *KeeperSuite) TestNSTLifeCycleOneStaker() { -// operator := ks.Operators[0] -// stakerStr := common.Address(operator.Bytes()).String() -// assetID := "0xe_0x65" -// validators := []string{"0xv1", "0xv2"} -// // 1. deposit amount 100 -// // 100 is not a possible nubmer with one validator, it's ok to use this as a start and we'll check the number to be updated to a right number(uncer 32 with one validator) -// amount100 := sdkmath.NewIntFromUint64(100) -// amount32 := sdkmath.NewIntFromUint64(32) -// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount100) -// // - 1.1 check stakerInfo -// stakerInfo := ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) -// ks.Equal(types.BalanceInfo{ -// Block: 1, -// RoundID: 0, -// Change: types.Action_ACTION_DEPOSIT, -// Balance: 100, -// }, *stakerInfo.BalanceList[0]) -// ks.Equal([]string{validators[0]}, stakerInfo.ValidatorPubkeyList) -// // - 1.2 check stakerList -// stakerList := ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID) -// ks.Equal(stakerList.StakerAddrs[0], stakerStr) -// -// // 2. Msg. minus staker's balance -// stakerChanges := [][]int{ -// {0, -10}, -// } -// rawData := convertBalanceChangeToBytes(stakerChanges) -// ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 9) -// // - 2.1 check stakerInfo -// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) -// ks.Equal(types.BalanceInfo{ -// Block: 2, -// RoundID: 9, -// Change: types.Action_ACTION_SLASH_REFUND, -// // this is expected to be 32-10=22, not 100-10 -// Balance: 22, -// }, *stakerInfo.BalanceList[1]) -// -// // 3. deposit more. 100 -// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount32) // 999 -// // - 3.1 check stakerInfo -// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) -// ks.Equal(types.BalanceInfo{ -// Block: 2, -// RoundID: 9, -// Index: 1, -// Change: types.Action_ACTION_DEPOSIT, -// Balance: 54, -// }, *stakerInfo.BalanceList[2]) -// ks.Equal(validators, stakerInfo.ValidatorPubkeyList) -// -// // 4. Msg. add staker's balance -// // at this point the system correct number should be 32*2-10 = 52, if some validator do refund, means the delta should be less than 10 -// stakerChanges = [][]int{ -// // means delta from -10 change to -5 -// {0, -5}, -// } -// rawData = convertBalanceChangeToBytes(stakerChanges) -// ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 11) -// // - 4.1 check stakerInfo -// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) -// ks.Equal(types.BalanceInfo{ -// Balance: 59, -// Block: 2, -// RoundID: 11, -// Index: 0, -// Change: types.Action_ACTION_SLASH_REFUND, -// }, *stakerInfo.BalanceList[3]) -// -// // 5. withdraw -// amount30N := sdkmath.NewInt(-30) -// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount30N) -// // - 5.1 check stakerInfo -// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) -// ks.Equal(types.BalanceInfo{ -// Balance: 29, -// Block: 2, -// RoundID: 11, -// Index: 1, -// Change: types.Action_ACTION_WITHDRAW, -// }, *stakerInfo.BalanceList[4]) -// // withdraw will remove this validator -// ks.Equal([]string{validators[1]}, stakerInfo.ValidatorPubkeyList) -// -// // 6.withdrawall -// amount100N := sdkmath.NewInt(-29) -// ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount100N) -// // - 6.1 check stakerInfo -// stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) -// ks.Equal(types.StakerInfo{}, stakerInfo) -// // - 6.2 check stakerList -// stakerList = ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID) -// } +func (ks *KeeperSuite) TestNSTLifeCycleOneStaker() { + // operator := ks.Operators[0] + // stakerStr := common.Address(operator.Bytes()).String() + stakerStr := ks.StakerAddr + assetID := "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee_0x65" + validators := []string{"0xv1", "0xv2"} + // 1. deposit amount 100 + // 100 is not a possible nubmer with one validator, it's ok to use this as a start and we'll check the number to be updated to a right number(uncer 32 with one validator) + amount100 := sdkmath.NewIntFromUint64(100) + amount32 := sdkmath.NewIntFromUint64(32) + ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount100) + + // - 1.1 check stakerInfo + stakerInfo := ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) + ks.Equal(types.BalanceInfo{ + Block: 1, + RoundID: 0, + Change: types.Action_ACTION_DEPOSIT, + Balance: 100, + }, *stakerInfo.BalanceList[0]) + ks.Equal([]string{validators[0]}, stakerInfo.ValidatorPubkeyList) + // - 1.2 check stakerList + stakerList := ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID) + ks.Equal(stakerList.StakerAddrs[0], stakerStr) + + // 2. Msg. minus staker's balance + stakerChanges := [][]int{ + {0, -10}, + } + rawData := convertBalanceChangeToBytes(stakerChanges) + ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 9) + // - 2.1 check stakerInfo + stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) + ks.Equal(types.BalanceInfo{ + Block: 1, + RoundID: 9, + Change: types.Action_ACTION_SLASH_REFUND, + // this is expected to be 32-10=22, not 100-10 + Balance: 22, + }, *stakerInfo.BalanceList[1]) + + // 3. deposit more. 100 + ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount32) // 999 + // - 3.1 check stakerInfo + stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) + ks.Equal(types.BalanceInfo{ + Block: 1, + RoundID: 9, + Index: 1, + Change: types.Action_ACTION_DEPOSIT, + Balance: 54, + }, *stakerInfo.BalanceList[2]) + ks.Equal(validators, stakerInfo.ValidatorPubkeyList) + + // 4. Msg. add staker's balance + // at this point the system correct number should be 32*2-10 = 52, if some validator do refund, means the delta should be less than 10 + stakerChanges = [][]int{ + // means delta from -10 change to -5 + {0, -5}, + } + rawData = convertBalanceChangeToBytes(stakerChanges) + ks.App.OracleKeeper.UpdateNSTByBalanceChange(ks.Ctx, assetID, rawData, 11) + // - 4.1 check stakerInfo + stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) + ks.Equal(types.BalanceInfo{ + Balance: 59, + Block: 1, + RoundID: 11, + Index: 0, + Change: types.Action_ACTION_SLASH_REFUND, + }, *stakerInfo.BalanceList[3]) + + // 5. withdraw + amount30N := sdkmath.NewInt(-30) + ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[0], amount30N) + // - 5.1 check stakerInfo + stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) + ks.Equal(types.BalanceInfo{ + Balance: 29, + Block: 1, + RoundID: 11, + Index: 1, + Change: types.Action_ACTION_WITHDRAW, + }, *stakerInfo.BalanceList[4]) + // withdraw will remove this validator + ks.Equal([]string{validators[1]}, stakerInfo.ValidatorPubkeyList) + + // 6.withdrawall + amount100N := sdkmath.NewInt(-29) + ks.App.OracleKeeper.UpdateNSTValidatorListForStaker(ks.Ctx, assetID, stakerStr, validators[1], amount100N) + // - 6.1 check stakerInfo + stakerInfo = ks.App.OracleKeeper.GetStakerInfo(ks.Ctx, assetID, stakerStr) + ks.Equal(types.StakerInfo{}, stakerInfo) + // - 6.2 check stakerList + stakerList = ks.App.OracleKeeper.GetStakerList(ks.Ctx, assetID) +} func convertBalanceChangeToBytes(stakerChanges [][]int) []byte { if len(stakerChanges) == 0 {